Vertical scaling with Raphael (transform) - raphael

I have a question regarding vertical scaling with Raphael using transform. I tried the following code:
var transform = "sx"+dx;
selRect.transform(transform);
but that doesn't seem to do the trick. Anyone ideas how to solve this one?
Thanks in advance.

Try using
var transform = "S1," + dx;
Also, don't forget you can optionally indicate the point you want to scale around... so
var bbox = selRect.getBBox();
var transform1 = "S1," + dx + ",0,0";
var transform2 = "S1," + dx + "," + ( bbox.width / 2 ) + "," + ( bbox.height / 2 );
Will offset the resulting rect differently. It can certainly come in handy on occasion!

Related

Finding a "movement direction" (angle) of a point

I'm working on a pretty cool project where I'm collecting data about the movement of a cursor, but I've run into an issue where I think I could use some help. I am constantly reading in data about the x and y position of the cursor (along with other relevant data), and once the cursor exceeds a certain threshold in the y-dimension, I need to calculate the movement direction (angle). Let me illustrate with a figure I drew:
What tends to happen is that the cursor moves in a somewhat straight line, but then curves towards the end of the movement. I need to calculate theta, i.e., the angle of the blue vector with respect to the positive x-axis. The idea I came up with is to use the last 2 samples to largely determine what the movement direction is, otherwise if I use too many samples I would skew what the actual angle is. To give an extreme case let me follow up with another picture:
Here each dot represents a sample. Note that if I use BOTH dots, the real angle I want will be wrong (again, I need to find the direction the cursor was moving in last, which is the vector drawn at the end of the line). I dont expect this case to come up much, but was wondering if there would be a way to solve for it if it does.
Lastly, note that the these motions can occur in either the first or second quadrant, if that makes a difference.
I'd really appreciate any help here. I'm coding this in C++ but I think I could translate any answer. Thanks.
This should get you started http://jsfiddle.net/0ao9oa7a/
Get all of the recorded points
Filter out points that are close together (I use 5 pixels)
Find the angles of each consecutive pair of points (atan2)
Find the absolute differences between each consecutive pair of angles
Throw away all of the angles before the max difference
Average the remaining angles (average all point vectors then atan2 back into an angle)
Code
function process(points) {
if(points.length === 0) {
txt = "Not enough points\n" + txt;
return null;
}
// compress points, removing those that are too close together
var newPoints = [];
newPoints.push(points[0]);
for(var i = 1; i < points.length; i++) {
if(Math.sqrt(Math.pow(points[i].x - newPoints[newPoints.length - 1].x, 2) + Math.pow(points[i].y - newPoints[newPoints.length - 1].y, 2)) > 5) {
newPoints.push(points[i]);
}
}
points = newPoints;
if(points.length < 2) {
txt = "Not enough points\n" + txt;
return null;
}
// get all of the angles
var angles = [];
for(var i=0; i < points.length - 1; i++) {
var rad = Math.atan2(points[i + 1].y - points[i].y, points[i + 1].x - points[i].x);
angles[i] = rad;
txt += "x: " + (points[i].x|0) + " y: " + (points[i].y|0) + " x: " + (points[i+1].x|0) + " y: " + (points[i+1].y|0) + " [" + ((rad * 180 / Math.PI)|0) + "]" + "\n";
}
txt += "\n";
// get all of the diffs between angles
// save the index of the max diff
var absDiffs = [];
var maxDiff = -1;
var maxDiffAngleIndex = -1;
for(var i=0; i < points.length - 1; i++) {
var delta = Math.abs(angles[i] - angles[i + 1]);
if(delta >= maxDiff) {
maxDiff = delta;
maxDiffAngleIndex = i + 1;
}
}
if(maxDiffAngleIndex == -1) {
txt = "Angle: " + angles[0] + " : " + (angles[0] * 180 / Math.PI) + "\n" + txt;
return angles[0];
} else if(maxDiffAngleIndex == angles.length - 1) {
txt = "Angle: " + angles[angle.length - 1] + " : " + (angles[angles.length - 1] * 180 / Math.PI) + "\n" + txt;
return angles[angles.length - 1];
} else {
// find the average angle from the index to the end
var sumX = 0;
var sumY = 0;
for(var i = maxDiffAngleIndex; i < angles.length; i++) {
sumX += Math.cos(angles[i]);
sumY += Math.sin(angles[i]);
}
var avgX = sumX / (angles.length - maxDiffAngleIndex);
var avgY = sumY / (angles.length - maxDiffAngleIndex);
//
var avgAngle = Math.atan2(avgY, avgX);
txt = "Angle: " + avgAngle + " : " + (avgAngle * 180 / Math.PI) + "\n" + txt;
return avgAngle;
}
}
As I can see, the “movement direction” (angle) of a point would be the angular coefficient of two dots, one dot at the end of the vector and the other one at the begnning.
Cause we can only find the angle with two dots, so we can make a line, since the direction vector would be (B-A), where A and B are the points I already told you about.
We can calcule this using the formula of the angular coefficient of a line:
m = Tan θ = Δy / Δx
And that is simply:
Tan θ = (yB – yA) / (xB – xA)
Where θ is the “movement direction” (angle) and (x,y) are the coordinates of the points A and B.
Talking about the quadrant, you will only need to use the trigonometric circle to know the sinal of the value of Tan θ, so take a look at this image:
And of course, after you find the value of Tan θ, you will need to use it to find the arctan θ, and that will be your final answer.

Calculate angle of rotation

I have a rectangle on the scene and I want to rotate it with mouse.
The rectangle has his own origin point. Clicking on the scene represents start of rotation and mouse moving represent angle of rotation.
where:
O - origin of rotation point
A - anchor point (saved in OnMousePress event)
C - current point (from OnMouseMove event)
so I calculate the angle in next steps:
Fistly, I get lengths of triangle sides:
AO = sqrt( (O.x - A.x)^2 + (O.y - A.y)^2 )
CO = sqrt( (O.x - C.x)^2 + (O.y - C.y)^2 )
AC = sqrt( (C.x - A.x)^2 + (C.y - A.y)^2 )
and then I calculate the angle (a):
a = arccos ( (AO^2 + CO^2 - AC^2) / (2 * AO * CO) )
it works, but this calculation look too complicated taking into account that I need to repeat on it all OnMouseMove call.
So my question - is there another way to calculate the angle? I write it in c++ so some code snippet will be apprecated.
You can find angle between vectors OA and OC through their scalar product and cross product:
OA = (OA.X, OA.Y) = (A.X-O.X, A.Y-O.Y)
OC = (OC.X, OC.Y) = (C.X-O.X, C.Y-O.Y)
SP = OA * OC = OA.X*OC.X+OA.Y*OC.Y
CP = OA x OC = OA.X*OC.Y-OA.Y*OC.X
Angle = atan2(CP, SP)
Example: O = (0,0), A = (-1, 0), C = (-2, 1)
SP = 2, CP = -1, Angle = -0.463
This method allows to avoid sqrt calculations, and determines rotation direction (unlike arccos)
You use a dot product of vectors OA and OC divided by their magnitude to calculate cosine of the angle and then use acos() function to find the angle.
float cosAngle = (x1 * x2 + y1 * y2) / sqrt(x1*x1 + y1*y1) * sqrt(x2*x2 + y2*y2);
float angle = acos(cosAngle);

Half circle using raphael

I'm very new to using raphael js library and I'm trying to figure it all out. I'm trying to create a chart based on percentages where 100% would be a full circle. The circle part I have figured out, but how would I go about changing it to show a half-circle for 50% or a quarter of a circle for 25%?
I recommend looking at the code behind this example on the Raphael home page. It should be easy enough to modify it to suit your needs.
This function in particular is what you're looking for
var rad = Math.PI / 180;
function sector(cx, cy, r, startAngle, endAngle, params) {
var x1 = cx + r * Math.cos(-startAngle * rad),
x2 = cx + r * Math.cos(-endAngle * rad),
y1 = cy + r * Math.sin(-startAngle * rad),
y2 = cy + r * Math.sin(-endAngle * rad);
return paper.path(["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2, "z"]).attr(params);
}
so, a 50% slice would be
var fifty = sector(100,100,50,0,180,{"fill":"red"});
var twentyfive = sector(100,100,50,180,270,{"fill":"red"});
Of course, this is working with degrees - you may want to wrap it so that you can use percentages.
You have to use path() and specify it using SVG's path syntax. Here is an example of creating a closed quarter-circle (upper left quadrant):
var arcPath = paper2.path("M200,200 v-150 a150,150 0 0,0 -150,150 z");
arcPath.attr("fill", "red");
See this link for more on SVG Paths.

How to interpolate a color sequence?

I need to interpolate or change gradually a sequence of colors, so it goes from colorA to colorB to colorC to colorD and them back to colorA, this need to be based on time elapsed in milliseconds, any help will be much appreciated (algorithms, pseudo code will be great).
Note that I am working with RGB, it could be 0-255 or 0.0-1.0 range.
This is what I have so far, I need to change the colors on every "timePeriod", them I calculate the percentage of time elapsed and change the colors, the problem with this code is that there is a jump when it goes from A to B to B to C and so on
int millisNow = ofGetElapsedTimeMillis();
int millisSinceLastCheck = millisNow - lastTimeCheck;
if ( millisSinceLastCheck > timePeriod ) {
lastTimeCheck = millisNow;
millisSinceLastCheck = 0;
colorsIndex++;
if ( colorsIndex == colors.size()-1 ) colorsIndex = 0;
cout << "color indes: " << colorsIndex << endl;
cout << "color indes: " << colorsIndex + 1 << endl;
}
timeFraction = (float)(millisSinceLastCheck) / (float)(timePeriod);
float p = timeFraction;
colorT.r = colors[colorsIndex].r * p + ( colors[colorsIndex+1].r * ( 1.0 - p ) );
colorT.g = colors[colorsIndex].g * p + ( colors[colorsIndex+1].g * ( 1.0 - p ) );
colorT.b = colors[colorsIndex].b * p + ( colors[colorsIndex+1].b * ( 1.0 - p ) );
colorT.normalize();
Thanks in advance
Your code is mostly correct, but you are doing the interpolation backwards: i.e. you are interpolating B->A, then C->B, then D->C, etc. This causes the discontinuity when switching colors.
You should replace this:
colorT.r = colors[colorsIndex].r * p + ( colors[colorsIndex+1].r * ( 1.0 - p ) );
with:
colorT.r = colors[colorsIndex].r * (1.0 - p) + ( colors[colorsIndex+1].r * p );
and the same for the other lines.
Also, as others have said, using a different color space than RGB can provide better looking results.
There are two ways to handle interpolating colors. One is fast and easy (what you're doing), the other is slightly slower but can look better in some circumstances.
The first is the obvious, simple method of (x * s) + (y * (1-s)), which is pure linear interpolation and does what the name suggests. However, on certain color pairs (say green and orange), you get some nasty colors in the middle (a dirty brown). That's because you're lerping each component (R, G and B) and there are points where the combination is unpleasant. If you just need the most basic lerp, then this is the method you want, and your code is about right.
If you want a better-looking but slightly slower effect, you'll want to interpolate in HSL colorspace. Since the hue, saturation and lum are each interpolated, you get what color you would expect between them and can avoid a majority of the ugly ones. Since colors are typically drawn in some sort of wheel, this method is aware of that (where as basic RGB lerp acts like it's working with 3 discrete lines).
To use an HSL lerp, you need to convert the RGB values, lerp between the results, and convert back. This page has some formulas that may be useful for that, and this one has PHP code to handle it.
Interpolating the R, G, and B components will produce working code. The one shortcoming is that the steps you produce won't necessarily appear the same, even though they're mathematically equal.
If that bothers you, you could convert values from RGB to something like L*a*b* (which is designed to correspond more closely to human perception), do your interpolation on those values, and then convert each interpolated value back to RGB for display.
What you've got already looks very good, but I'd simplify the math a little bit:
int millisNow = ofGetElapsedTimeMillis();
int millisSinceLastCheck = millisNow % timerPeriod;
int colorsIndex = (millisNow / timerPerod) % (colors.size() - 1);
float p = (float)(millisSinceLastCheck) / (float)(timePeriod);
colorT.r = colors[colorsIndex+1].r * p + ( colors[colorsIndex].r * ( 1.0 - p ) );
colorT.g = colors[colorsIndex+1].g * p + ( colors[colorsIndex].g * ( 1.0 - p ) );
colorT.b = colors[colorsIndex+1].b * p + ( colors[colorsIndex].b * ( 1.0 - p ) );
colorT.normalize();
We're doing this on a project I'm currently working on. We just treat the R, G, B values independently and transition from color1 to color2 based on how many "steps" there are in between. We have discrete values so we have a look-up table approach, but you could do the same thing with floating point and just calculate the RGB values dynamically.
If you still have questions, I could post some Java code.
Separate the three components (RBG) and interpolate each
separately, using the classical interpolation algorithm.

Why is iplRotate() not giving me correct results?

sigh I'm sorry to say that I'm using Intel IPL (Image Processing Library) in some image processing code I'm working on. This is the tale of my struggle with getting my images to rotate correctly.
I have a source image. It has a size (w, h) which is not necessarily square.
It is going to be rotated by angle theta.
I've calculated the output size required to fit an image of size (w, h) rotated by angle theta. This size is (dw, dh). I've allocated a destination buffer with that size.
I want to rotate the source image by angle theta about the source image's center (w/2, h/2) and have that rotated image be centered in my destination buffer.
iplRotate() takes 2 shift parameters, xShift and yShift, which indicate the distance the image should be shifted along the x and y axis after the rotate is performed.
The problem is I cannot get iplRotate to center the rotated image in the destination image. It's always off center.
My best guess for what xShift and yShift should be is the following:
xShift = dw - w
yShift = dh - h
But this doesn't work, and I'm not sure what else to do to calculate xShift and yShift. Does anyone have any suggestions for how to use iplRotate to do what I want?
One last bit of info:
I've attempted to use iplGetRotateShift() to calculate xShift and yShift, again, to no avail. I would imagine that this would work:
iplGetRotateShift(dw / 2.0, dh / 2.0, theta, &xShift, &yShift);
But it does not.
Edit:
I rewrote the code using Intel IPP 6.0 instead of IPL and I'm seeing identical wrong results. I can't imagine that Intel got rotation wrong in 2 different libraries, so I must be doing something wrong.
Edit:
I tried the following (IPP) code that Dani van der Meer suggested:
xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;
ippiAddRotateShift(w / 2.0, h / 2.0, angle, &xShift, &yShift);
Unfortunately, still no luck. That does not work either.
When using iplGetRotateShift you need to specify the center of rotation in the source image. This will work well if the size of the source and destination image is the same.
In your case you want an extra shift to center the image in your destination image:
xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;
To combine the two shift you need to use ippiAddRotateShift instead of ippiGetRotateShift.
Note: These functions refer to the IPP library version 5.3 (the version I have). I am not sure that AddRotateShift is available in IPL. But you mentioned in the question that you tried the same using IPP, so hopefully you can use IPP instead of IPL.
You get something like this
xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;
ippiAddRotateShift(w / 2.0, h / 2.0, angle, &xShift, &yShift);
If you use these shifts in the call to ippiRotate the image should be centered in the destination image.
I hope this helps.
EDIT:
Here is the code I used to test (the change from w to dw and h to dh and the rotation angle are just random):
//Ipp8u* dst_p; Initialized somewhere else in the code
//Ipp8u* src_p; Initialized somewhere else in the code
int w = 1032;
int h = 778;
int dw = w - 40; // -40 is just a random change
int dh = h + 200; // 200 is just a random change
int src_step = w * 3;
int dst_step = dw * 3;
IppiSize src_size = { w, h };
IppiRect src_roi = { 0, 0, w, h };
IppiRect dst_rect = { 0, 0, dw, dh };
double xShift = ((double)dw - (double)w) / 2.0;
double yShift = ((double)dh - (double)h) / 2.0;
ippiAddRotateShift((double)w / 2, (double)h / 2, 37.0, &xShift, &yShift);
ippiRotate_8u_C3R(src_p, src_size, src_step, src_roi,
dst_p, dst_step, dst_rect, 37.0, xShift, yShift, IPPI_INTER_NN);
I've never used (or heard of) IPL before, so I'm just merely guessing what the API does. But if iplRotate rotates about (0, 0) and if iplGetRotateShift does similarly, why not try rotating the other 3 corners of your original "box" (ignoring (0, 0) since that stays put): (w, 0), (0, h), and (w, h).
Your result will be a new box with some negative values. You want to "shift back" so whatever negative values you have will become zero, if you get what I mean.
Based on my reading of the documentation I think you're using iplGetRotateShift wrong. In particular, I think you need to specify the center of rotation in the source image, not the destination image, thus:
iplGetRotateShift( w / 2.0, h / 2.0, angle, &xShift, &yShift );
If it's still not working for you then can we confirm that the assumptions are valid? In particular point 3. where you calculate dw and dh.
Mathematically
dw = w * |cos(theta)| + h * |sin(theta)|
dh = h * |cos(theta)| + w * |sin(theta)|
so if theta = pi/6 say, then if w = 100 and h = 150 then presumably dw = 162?
Does the incorrect position you're getting vary with theta? Presumably it works with theta=0? What about theta=pi/2 and theta=pi/4?