Cairo library: cairo_line_to Function - cairo

I have legacy code which use cairo library to draw png and calling following function. I could not understand the following code. I know it is weired question that took some piece of code and ask question. But great if anyone provide.
#define IMAGE_SIZE_W 1024
#define IMAGE_SIZE_H 768
#define GRAPH_MARGIN_L 48
#define GRAPH_MARGIN_R 21
#define GRAPH_MARGIN_B 27
#define GRAPH_MARGIN_T 22
#define GRAPH_SIZE_W (IMAGE_SIZE_W-(GRAPH_MARGIN_L+GRAPH_MARGIN_R))
#define GRAPH_SIZE_H (IMAGE_SIZE_H-(GRAPH_MARGIN_B+GRAPH_MARGIN_T))
#define SCALE_TO_CANVAS(v,low,high,fws,margin,a,b) (((a+b*((v-low)/(high-low)))*fws)+margin)
#define SCALE_TO_CANVAS_Y(v,low,high) SCALE_TO_CANVAS(v,low,high,GRAPH_SIZE_H,GRAPH_MARGIN_T,1,-1)
#define SCALE_TO_CANVAS_X(v,low,high) SCALE_TO_CANVAS(v,low,high,GRAPH_SIZE_W,GRAPH_MARGIN_L,0,1)
void line_to_point(cairo_t *cr,float x, float y){
cairo_line_to(cr,x,y);
}
void move_to_point(cairo_t *cr,float x, float y){
cairo_move_to(cr,x,y);
}
We have data in x and y and ploting x and y. The caller function is
/* counter number of x and y row
for(i = 0; i< counter; i++)
{
move_to_point(cr,SCALE_TO_CANVAS_X(xvals[i-1],lowX,highX),SCALE_TO_CANVAS_Y(yvals[i-1],lowY,highY));
line_to_point(cr,SCALE_TO_CANVAS_X(x,lowX,highX),SCALE_TO_CANVAS_Y(y,lowY,highY));
}
Than after it calls write_png which is kind of straight forward function.
if you look, SCALE_TO_CANVAS done lot of calculation which I am not able to figure out.
cairo_line_to x and y have modified value and plot it.

I haven't looked too closely, but I would guess that your x data is between lowX and highX and your y data between lowY and highY. This data is scaled so that it it fits into the image surface (which means between 0x0 and 1024x768).
Also, this seems to add a margin on all sides (L/R/B/T would mean left, right, bottom, top).
If you want an explanation of the math used instead of just its meaning, just ask.
Edit:
Ok, we have data that describes points in a graph. The top-left corner of our input data is at position (lowX, lowY), the bottom right corner is at (highX, highY).
The area that we are drawing to has a size of 1024x768. Thus, we want to scale the input data so that it fits into this space. To make things a little more complicated, we want to keep an empty margin around the graph. This takes GRAPH_MARGIN_L pixels on the left, GRAPH_MARGIN_T pixels on the top, etc.
So the drawing area has its top-left corner at (GRAPH_MARGIN_L, GRAPH_MARGIN_T) and its bottom right corner at (1024-GRAPH_MARGIN_R, 768-GRAPH_MARGIN_B). So we are looking for a formula that maps (lowX, lowY) to (GRAPH_MARGIN_L, GRAPH_MARGIN_T) and (highX, highY) to (1024-GRAPH_MARGIN_R, 768-GRAPH_MARGIN_B).
In the following, let's just look at one of the two coordinates of the point, e.g. the x coordinate. For a point x, we first calculate a percentage that describes how far along the axis it is. 0% should mean "at the top/left end", 100% is "at the bottom/right end". The available space begins at lowX and goes to highX, so there are highX-lowX possible values. Thus, x-lowX (so that "top/left" really is at zero) falls somewhere into this range and (x-lowX)*100/(highX-lowX) is the percentage that we are looking for.
This percentage should now be mapped into the target area. First we multiple this by the width of the target space (and dividing by 100, so that the percentge goes away), so that we have a value that spans the possible range. Then we have to add the lowest possible value, so that instead of starting at zero and going up to the possible width (which is high-low), we have a value that is between low and high.
All together, the formula becomes smallestTargetX+(x-lowX)/(highX-lowX)*widthOfTheTargetArea, or in terms of your defines: GRAPH_MARGIN_L+(x-lowX)/(highX-lowX)*GRAPH_SIZE_W.
The additional variables a and b that are used in GRAPH_TO_CANVAS are used for "swapping directions". It seems like instead of having (0, 0) in the top-left corner and positive coordinates going to the right/bottom, your coordinate system has (0, 0) in the bottom-left corner and positive coordinates go to the right/top. To handle this, the percentages calculated above are multiplied with -1 and 1 is added to the coordinate, to make the mapping really map the points to each others that it should. These are the last two arguments for the GRAPH_TO_CANVAS macro.
I hope this helps you understand that macros.

Related

How to quantify line shape with ImageJ macro

I would like to quantify the shape of a line on the wings of butterflies which can vary from quite straight to squiggly similar to the horizon in a landscape, or similar to a graph (per each x value there is only 1 y value), although overall orientation varies. My idea is to use the free hand tool to trace the line of interest and then let an ImageJ macro quantify it (automating this may be tricky because there are many line-like structures). Two traits seem useful to me;
the proportion between the length of the drawn line and the straight line between the end points.
'Dispersion' of the line such as calculated in the Directionality plugin.
Other traits such as what proportion of the line is below or under the straight line that connects the extremes may also be useful.
How can this be coded? I am building an interactive macro that prompts the measuring of various traits for an open image.
Hopefully the below (non-functional) code will convey what I am trying to do.
//line shape analysis
run("Select None");
setTool("free hand");
waitForUser("Trace the line between point A and B");
length= measure();
String command = "Directionality";
new PlugInFilterRunner(da, command, "nbins=60, start=-90, method=gradient");
get data...
//to get distance between points A and B
run("Select None");
setTool("multipoint");
waitForUser("Distances","Click on points A and B \nAfter they appear, you can click and drag them if you need to readjust.");
getSelectionCoordinates(xCoordinates, yCoordinates);
xcoordsp = xCoordinates;
ycoordsp = yCoordinates;
makeLine(xcoordsp[0], ycoordsp[0], xcoordsp[1], ycoordsp[1]);
List.setMeasurements;
StrLength = List.getValue("Length");
I have looked online for solutions but found surprisingly little about this relatively simple issue.
warm regards,
Freerk
Here is a simple solution to determine to what extent the line deviates from a straight line between pint A and B. The 'straightness' is the proportion between the two measures.
// To meausure line length to compare to length of straight line aka Euclidean distance
run("Select None");
setTool("polyline");
waitForUser("Trace the line between point V5 and V3 by clickinmg at each corner finish by double click"); // Points V5 and V3 refer to point A and B It can be adjusted
run("Measure");
getStatistics(Perim);
FLR=Perim; // FLR For forewing lenght real
// to get Euclidian distance between points A and B
run("Select None");
setTool("multipoint");
waitForUser("Distances","Click on points A and B \nAfter they appear, you can click and drag them if you need to readjust.");
getSelectionCoordinates(xCoordinates, yCoordinates);
xcoordsp = xCoordinates;
ycoordsp = yCoordinates;
makeLine(xcoordsp[0], ycoordsp[0], xcoordsp[1], ycoordsp[1]);
List.setMeasurements;
FLS = List.getValue("Length"); // FLS For forewing length straight
}
I would still be grateful for more sophistcated line parameters

How to adjust bar absolute width in MATLAB

I'm confused with the bar with adjustment in MATLAB, for example, when use bar like:
bar(randsample(0:0.0001:1,100),randn(100,1))
I get an image like this:
It seems like the bar is too thin to have a good look. After searching for help, I can use the code like:
bar(randsample(0:0.0001:1,100),randn(100,1),50)
and I get this:
Seems much better. But if I change the sample number from 100 to 10, the same code won't work.
bar(randsample(0:0.0001:1,10),randn(10,1),50)
I hope I have explained my issue clear. It seems like the third parameter of the bar function is a relative width, which correlates to the input size of the first and second parameter. Can I fix the absolute bar width no matter how many data points input? or there is a better function to draw figures like this? Thanks a lot for any help!
user #am304 is right about the width parameter
What happened in your code is that you set x values to results from randsample(0:0.0001:1,10)
If you give your plot a width of 1 it means that 2 bars which are directly next to each other would touch each other with an equally spaced x.
In your case, you have an irregular x spacing.
The width of the bar is determined by the minimum distance between two x values (which you get from randsample()). Sometimes this space - and therefore the width of your bar - is very tiny. Sometimes it is broader.
Change the with to 1 and make multiple plots. You will notice that two are always touching each other and no one is overlapping and all the others have spaces in between. If you change the width to 50 the plots will somethimes overlap heavily (depending on the randomness from randsample) because your bars are 50 times bigger then the minimum width between two x values.
In case of your randsample(0:0.0001:1,100) example it is just more likely that two values are close to each other, therefore increasing the width helps you see something (because the bars overlap).
From the documentation:
bar(___,width) sets the relative bar width, which controls the
separation of bars within a group. Specify width as a scalar value.
Use this option with any of the input argument combinations in the
previous syntaxes.
The example provided is as follows:
Set the width of each bar to 40 percent of the total space available
for each bar.
y = [75 91 105 123.5 131 150 179 203 226 249 281.5];
bar(y,0.4)
So bottom line is: the width is specified as a % of the total space available for each bar. Yoru problem comes from the fact that you have far too many bars, so the space available for each bar is tiny. Setting the width to 50 or 5000% of the space available just means that each bar will overlap quite substantially on the neighbouring bars. Because you have so many, the middle plot looks "reasonable" as I suspect a lot of the bars are overlapped and a lot of them are at zero, so you just can't see them. If you go down to a sensible number of bars, as in your last example, then setting the width to 5000% looks ridiculous as you found out.
So to summarise: reduce the number of bars and specify the bar width between >0 and 1 (1 being no gap, all the bars touching each other).
A better way to plot things with random x locations is to use stem. By default, it draws a line from the zero line to the datum, with a circle representing each datum. But this can be modified. For example:
stem(randsample(0:0.0001:1,100),randn(100,1), 'Marker','none', 'LineWidth',4)
creates a plot similar to your second attempt, but with bars of a fixed width (4 points).

Stair plot to vertical bar plot in Matlab

I want to create a vertical bar plot. This is my code:
bar (x, sensiv);
title ('Promedio X')
xlabel('Nm')
ylabel('Refl.')
The problem is it looks like a stair plot. I've tried to add (x,sensiv, 'stacked') but it doesn't work. It looks grouped, as you can see in the next image:
graph http://imageshack.us/a/img689/9449/capturawv.jpg
I think it's because of x-axis but I couldn't change it. How can I do it? Does somebody knows how can I do it?
EDIT
Thanks Colin! I've tried to zoom and I understand what you mean and I've tried with different values, as slayton and you said.
I think that maybe it's the way I've code the plot, it is possible?
abc=0;
for p=(61:201)
abc(p)=out1_c;
end
for p=(151:301)
abc(p)=out2_c;
end
for p=(231:380)
abc(p)=out3_c;
end
for p=(381:596)
abc(p)=out4_c;
end
for p=(1152:1531)
abc(p)=out5_c;
end
for p=(1651:2051)
abc(p)=out7_c;
end
for p=(2052:2151)
abc(p)= 0;
end
The default value for the width of the bars in a bar plot is 0.8, so given that you're not currently specifying the width, you should have gaps in between each bar. This is going to sound really obvious, but have you tried zooming in on the bar plot that is created? For some datasets, the bar function will return a plot that looks like a stair plot, but in fact has gaps if you zoom in far enough. If this is the case, then you should be able to get the gaps you want by tinkering with the width parameter as suggested by slayton.
EDIT
Okay. First things first. If you want to post additional information, you should add it to your question, NOT post it as a new answer! You can do this by clicking the edit button just below where your question is on the page. To make things more readable, you might preface your edit with a capitalized bold-face heading "EDIT" as I have done here. If you are able, try now to move the additional information you've given back into your question, and then delete the answer.
Second, I have to be honest, the additional information you posted was somewhat confusing. However, I think I understand what you want now. You want 7 bars coming up to the heights out1_c, out2_c, ..., out7_c (variable names taken from your additional information) with a small gap between each bar, and the x-axis to reflect (approximately) the intervals 450-550, 550-650, etc.
Well, if you want 7 bars, then you want your input to only have seven elements. Set:
y = [out1_c; out2_c; out3_c; out4_c; out5_c; out6_c; out7_c];
y now gives you the heights your bars will come up to on the y-axis. To locate the bars on the x-axis, define a vector x that also has seven elements, where each element gives the midpoint of where you want the bar to be on the x-axis. For example:
x = [100; 200; 300; 400; 500; 600; 700];
Then just use bar(x, y). This should get you started.
A final point on the code you posted, you can actually completely avoid the loops: read up on vectorization. But if you are going to insist on loops, the first and most important rule is to preallocate your vectors/matrices. In your code abc starts out as a scalar (a 1 by 1 matrix), but then for every p, you are adding an element at index p. What is actually happening in the background is for every p, matlab is scrapping the current abc you have in memory, and building it again from scratch with the additional element. As you might expect, this will slow down your code by many orders of magnitude.
You can set the width of the individual bars by passing a value between 0 and 1 to bar. Passing 1 indicates that there should be no space between the bars
bar(x,y,1)
Passing anything less than 1 will reduce the bar sizes and introduce spacing between the individual bars
bar(x,y,.5)

animation issues with objects returning back to the screen from the left side once they are out of the right side

I was just wondering how to animate for example clouds which return back from the left side of the screen once they are outside the right side of the screen
I´ve tried with clouds.center = CGPouintMake(clouds.center.x + cloudvelocity, clouds.center.y + cloudvelocity) but I can only make them go from left to right and in a decline line.
In other words...
I have troubles making them go in a straight line from left to right and return bac to the screen from the left side of the screen once they are outside the right side of the screen.
can anyone help me?
The main thing you'll probably want to take advantage of is modular arithmetic, which is the same as asking what the remainder would be if you divided by a certain amount. So, for example:
28 mod 6 = 4
% is the integer modulus operator, but with floating point numbers you need to call the library method fmod (which takes and returns doubles) or fmodf (which takes and returns single precision floats). E.g.
NSLog(#"%0.0f", fmodf(28.0f, 6.0f));
Would log '4'.
In your case you have positions that constantly change, but you want the results to be constrained to a certain window size. Supposing it's 1024 points across, you want location 1024+n to be the same as location n, which is the same as 2048+n, 3072+n, etc. What you want to do then is to keep only the remainder when divided by 1024. So, e.g.
clouds.center = CGPointMake(fmodf(clouds.center.x + cloudvelocity, 1024.0f),
fmodf(clouds.center.y + cloudvelocity, 768.0f))
Or whatever your view dimensions are.
The first potential issue is that negative numbers don't necessarily work the way you want them to. E.g.
fmodf(-23.0f, 1024.0f));
is -23.0f (as are the related fmodfs of -(1024.0f + 23.0f), -(2048.0f + 23.0f), etc). You can handle that by checking for values less than 0 and adding 1024.0f if you get one.
If you know that your computed value can go negative, but never more than 1024.0f negative then you can just do:
clouds.center = CGPointMake(fmodf(1024.0f + clouds.center.x + cloudvelocity, 1024.0f),
fmodf(768.0f + clouds.center.y + cloudvelocity, 768.0f))
Since obviously the addition of 1024.0f will have no effect on the result if the number is positive. If you don't mind two calls to fmodf then obviously:
clouds.center = CGPointMake(
fmodf(1024.0f + fmodf(clouds.center.x + cloudvelocity, 1024.0f), 1024.0f),
fmodf(768.0f + fmodf(clouds.center.y + cloudvelocity, 768.0f), 768.0f))
Will work for any input value.
The second potential issue is that you're wrapping the centre of the cloud only. So it'll just jump from one side of the screen back to the other — you'll never have the cloud half on one side of the screen and half on the other. Assuming the cloud is less than a screen wide, possible solutions are (i) draw each cloud twice, with the second either 1024 pixels to the left if the cloud centre is greater than the screen modpoint or 1024 pixels to the right otherwise; (ii) make a virtue of it and use a conceptual wraparound area of, say, 2048 pixels rather than 1024, putting the visible part in the middle. So the cloud will go completely off screen to the right, then jump to the left without anybody being able to see it, and re-emerge from that side.

Reverse Integer Values

I have a scenario which I think I can convey giving PC Monitor example (not real though).
Assume I have two monitors both of different resolution and properties. One monitor draws mouse cursor on screen from top (0) to bottom (max-value) and other draws mouse from bottom (0) to top (max-value). In other words both have reverse y-axis of each other in drawing mouse cursor and I need to write a formula that will convert one monitor cursor position to another and vice versa given one monitor x and y cursor positions.
What formula is the best suited for this?
right_x = (1 - left_x / left_width) * right_width
right_y = (1 - left_y / left_height) * right_height
The left_x and left_y (as well as the resolutions for each display) would need to be known.