I have a square (100px x 100px) with origin at 0,0 (upper left).
When I move the mouse, lets say 10 pixel x and y, I move the origin according to displacement and then origin becomes 10,10, simple. Works fine!
When I rotate the square, my rotation function rotates it fine, but then, after the square is rotated, lets say 10 degrees, the origin point should be move accordingly to the rotation. And now, I have no idea of the formula I have to apply to make it append!
I wikipedia, but I tink it's too complicated.
http://en.wikipedia.org/wiki/Angular_displacement
and
http://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine.2C_and_tangent
Example: After a 90 deg rotation to the left, the origin is now at : lower left, now when I move the mouse to to right, the picture go UP!!!!
If I understand your problem correctly, you are applying an offset to the rectangle points based on your mouse position, then rotating the resulting points about the origin.
Instead, try applying your mouse offset after you do your rotation, not before.
Suppose you have a figure and you want to rotate it by angle alpha and translate it so that point (cx, cy) of the figure gets to point (sx, sy) after the transformation.
The transformation is
transformed_x = x*cos(alpha) - y*sin(alpha) + offset_x
transformed_y = x*sin(alpha) + y*cos(alpha) + offset_y
to compute desired offset_x and offset_y values you just need to put your requirement about (cx, cy) and (sx, sy) into the above equations:
sx = cx*cos(alpha) - cy*sin(alpha) + offset_x
sy = cx*sin(alpha) + cy*cos(alpha) + offset_y
and now you can easily extract the offset values from that:
offset_x = sx - cx*cos(alpha) + cy*sin(alpha)
offset_y = sy - cx*sin(alpha) - cy*cos(alpha)
To set up canvas transform for it you need just to call
context.translate(sx - cx*Math.cos(alpha) + cy*Math.sin(alpha),
sy - cx*Math.sin(alpha) - cy*Math.cos(alpha));
context.rotate(alpha);
You can see a little demo of this formula following this link.
Related
So to give further context lets say I have an image that is 200px by 200px with a rectangle on it, its red below:
I know the height and width of the image, the coordinates of the rectangle and also the height and width of the red rectangle.
So what I need to know is if I flip this whole image (including the rectangle) is there a way to work out what the new coordinates are of the red rectangle? I'd imagine there must be some kind of formula or algorithm I can apply to get these new coordinates.
This was already answered over here. The below is the function that worked best for my use case which is very similar to yours.
def rotate(point, origin, degrees):
radians = np.deg2rad(degrees)
x,y = point
offset_x, offset_y = origin
adjusted_x = (x - offset_x)
adjusted_y = (y - offset_y)
cos_rad = np.cos(radians)
sin_rad = np.sin(radians)
qx = offset_x + cos_rad * adjusted_x + sin_rad * adjusted_y
qy = offset_y + -sin_rad * adjusted_x + cos_rad * adjusted_y
return int(qx), int(qy)
In addition to this sometimes when you rotate the points you get negative values(depending on degrees of rotation), in cases like these you need to add the height and or width of the image you are rotating to the value. In my case below the images were of fixed size (416x416)
def cord_checker(pt1):
for item in pt1:
if item<0:
pt1[pt1.index(item)]=416+item
else: pass
return pt1
finally to get the coordinates of the rotated point
pt1=tuple(cord_checker(list(rotate((xmi,ymi),origin=(0,0),degrees*=))))
*degrees can be 90,180 etc
If the image is centered around the origin (0,0), you can just flip the signs of the x-coordinates to do a horizontal flip or the y-coordinates to do a vertical flip while preserving the origin as your center.
You can also flip an arbitrary image by flipping the signs:
# Horizontal flip
new_x = -x
new_y = y
# Vertical flip
new_x = x
new_y = -y
but the center coordinates will not be the same. If you want the same center coordinates, you'd have to shift it back.
I am trying to make a function that if a point is outside a certain circle, the point move to the point where the line passing by the center of the circle and the point collide. the code:
def inside_circle(self, pos):
if ((pos[0]-self.pos[0])**2 + (pos[1]-self.pos[1])**2) <= teleport_range**2:
return "inside"#pos
else:
pente = (pos[1]-self.pos[1])/(pos[0]-self.pos[0])
origine = pos[1]-pente*pos[0]
A = pente**2 + 1
B = 2 * -self.pos[0] + (origine+self.pos[1])*pente*2
C = self.pos[0]**2 + (origine+self.pos[1])**2 - teleport_range**2
if pos[0] > self.pos[0]:
X = (-B + math.sqrt(B**2 - 4*A*C))/(2*A)
Y = pente * X + origine
return "outside bot"#(X,Y)
elif pos[0] < self.pos[0]:
X = (-B - math.sqrt(B**2 - 4*A*C))/(2*A)
Y = pente * X + origine
return "outside top"#(X,Y)
self.pos is the center of the circle, pos is where the point I wanna check is, both are tuple
pente is the tilt of the line (its in french sorry)
origine is the Y origin of the line (french also)
teleport_range is the radius, being a constant 300
the actual return I want are commented for testing purposes
When I run it, if it is inside the circle, everythings fine but if it is outside, an error show up because it is trying to square root a negative
X = (-B + math.sqrt(B**2 - 4*A*C))/(2*A)
ValueError: math domain error
the square root in the quadratic equation is only negative when there is no collide point between the line and the circle, however, the line pass by the center of the circle and a point, so there should be two collide point.
I know there can be only one collide point when the line is a constant but I will fix that when I understand why (B**2 - 4*A*C) is negative when it shouldnt
I am not good in math, if someone could help me please, also dont hesitate to tell me if the code could be simplified without loosing clarity
thanks :)
Here is an easier, shorter, clearer way to get your desired point on the circle.
theta = math.atan2(pos[0] - self.pos[0], pos[1] - self.pos[1])
X = self.pos[0] + teleport_range * math.cos(theta)
Y = self.pos[1] + teleport_range * math.sin(theta)
This code first finds the angle of inclination of the ray from the circle's center to the point. It then uses that angle to find a point on the circle with the same angle.
Note that this code even works for points inside the circle: it finds the point on the circle with the same angle from the center. If the point is the circle's center, the desired point is ambiguous but the code returns one particular point.
How can one calculate the camera distance from an object in 3D space (an image in this case) such that the image is at its original pixel width.
Am I right in assuming that this is possible given the aspect ratio of the camera, fov, and the original width/height of the image in pixels?
(In case it is relevant, I am using THREE.js in this particular instance).
Thanks to anyone who can help or lead me in the right direction!
Thanks everyone for all the input!
After doing some digging and then working out how this all fits into the exact problem I was trying to solve with THREE.js, this was the answer I came up with in JavaScript as the target Z distance for displaying things at their original scale:
var vFOV = this.camera.fov * (Math.PI / 180), // convert VERTICAL fov to radians
var targetZ = window.innerHeight / (2 * Math.tan(vFOV / 2) );
I was trying to figure out which one to mark as the answer but I kind of combined all of them into this solution.
Trigonometrically:
A line segment of length l at a right angle to the view plane and at a distance of n perpendicular to it will subtend arctan(l/n) degrees on the camera. You can arrive at that result by simple trigonometry.
Hence if your field of view in direction of the line is q, amounting to p pixels, you'll end up occupying p*arctan(l/n)/q pixels.
So, using y as the output number of pixels:
y = p*arctan(l/n)/q
y*q/p = arctan(l/n)
l/tan(y*q/p) = n
Linear algebra:
In a camera with a field-of-view of 90 degrees and a viewport of 2w pixels wide, the projection into screen space is equivalent to:
x' = w - w*x/z
When perpendicular, the length of a line on screen is the difference between two such xs so by normal associativity and commutivity rules:
l' = w - w*l/z
Hence:
w - l' = w*l/z
z = (w - l') / (w*l)
If your field of view is actually q degrees rather than 90 then you can use the cotangent to scale appropriately.
In your original question you said that you're using css3D. I suggest that you do the following:
Set up an orthographic camera with fov = 1..179 degrees, where left = screenWidth / 2, right = screenWidth / - 2, top = screenHeight / 2, bottom = screenHeight / - 2. Near and far planes do not affect CSS3D rendering as far as I can tell from experience.
camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
camera.fov = 75;
now you need to calculate the distance between the camera and object in such way that when the object is projected using the camera with settings above, the object has 1:1 coordinate correspondence on screen. This can be done in following way:
var camscale = Math.tan(( camera.fov / 2 ) / 180 * Math.PI);
var camfix = screenHeight / 2 / camscale;
place your div to position: x, y, z
set the camera's position to 0, 0, z + camfix
This should give you 1:1 coordinate correspondence with rendered result and your pixel values in css / div styles. Remember that the origin is in center and the object's position is the center of the object so you need to do adjustments in order to achieve coordinate specs from top-left corner for example
object.x = ( screenWidth - objectWidth ) / 2 + positionLeft
object.y = ( screenHeight - objectHeight ) / 2 + positionTop
object.z = 0
I hope this helps, I was struggling with same thing (exact control of the css3d scene) but managed to figure out that the Orthographic camera + viewport size adjusted distance from object did the trick. Don't alter the camera rotation or its x and y coordinates, just fiddle with the z and you're safe.
i have an object that is doing a circular motion in a 3d space, the center or the circle is at x:0,y:0,z:0 the radius is a variable. i know where the object is on the circle (by its angle [lets call that ar] or by the distance it has moved). the circle can be tilted in all 3 directions, so i got three variables for angles, lets call them ax,ay and az. now i need to calculate where exactly the object is in space. i need its x,y and z coordinates.
float radius = someValue;
float ax = someValue;
float ay = someValue;
float az = someValue;
float ar = someValue; //this is representing the angle of the object on circle
//what i need to know
object.x = ?;
object.y = ?;
object.z = ?;
You need to provide more information to get the exact formula. The answer depends on which order you apply your rotations, which direction you are rotating in, and what the starting orientation of your circle is. Also, it will be much easier to calculate the position of the object considering one rotation at a time.
So, where is your object if all rotations are 0?
Let's assume it's at (r,0,0).
The pseudo-code will be something like:
pos0 = (r,0,0)
pos1 = pos0, rotated around Z-axis by ar (may not be Z-axis!)
pos2 = pos1, rotated around Z-axis by az
pos3 = pos2, rotated around Y-axis by ay
pos4 = pos3, rotated around X-axis by ax
pos4 will be the position of your object, if everything is set up right. If you have trouble setting it up, try keeping ax=ay=az=0 and worry about just ar, until your get that right. Then, start setting the other angles one at a time and updating your formula.
Each rotation can be performed with
x' = x * cos(angle) - y * sin(angle)
y' = y * cos(angle) + x * sin(angle)
This is rotation on the Z-axis. To rotate on the Y-axis, use z and x instead of x and y, etc. Also, note that angle is in radians here. You may need to make angle negative for some of the rotations (depending which direction ar, ax, ay, az are).
You can also accomplish this rotation with matrix multiplication, like Marcelo said, but that may be overkill for your project.
Use a rotation matrix. Make sure you use a unit vector.
I'm writing a script where icons rotate around a given pivot (or origin). I've been able to make this work for rotating the icons around an ellipse but I also want to have them move around the perimeter of a rectangle of a certain width, height and origin.
I'm doing it this way because my current code stores all the coords in an array with each angle integer as the key, and reusing this code would be much easier to work with.
If someone could give me an example of a 100x150 rectangle, that would be great.
EDIT: to clarify, by rotating around I mean moving around the perimeter (or orbiting) of a shape.
You know the size of the rectangle and you need to split up the whole angle interval into four different, so you know if a ray from the center of the rectangle intersects right, top, left or bottom of the rectangle.
If the angle is: -atan(d/w) < alfa < atan(d/w) the ray intersects the right side of the rectangle. Then since you know that the x-displacement from the center of the rectangle to the right side is d/2, the displacement dy divided by d/2 is tan(alfa), so
dy = d/2 * tan(alfa)
You would handle this similarily with the other three angle intervals.
Ok, here goes. You have a rect with width w and depth d. In the middle you have the center point, cp. I assume you want to calculate P, for different values of the angle alfa.
I divided the rectangle in four different areas, or angle intervals (1 to 4). The interval I mentioned above is the first one to the right. I hope this makes sense to you.
First you need to calculate the angle intervals, these are determined completely by w and d. Depending on what value alfa has, calculate P accordingly, i.e. if the "ray" from CP to P intersects the upper, lower, right or left sides of the rectangle.
Cheers
This was made for and verified to work on the Pebble smartwatch, but modified to be pseudocode:
struct GPoint {
int x;
int y;
}
// Return point on rectangle edge. Rectangle is centered on (0,0) and has a width of w and height of h
GPoint getPointOnRect(int angle, int w, int h) {
var sine = sin(angle), cosine = cos(angle); // Calculate once and store, to make quicker and cleaner
var dy = sin>0 ? h/2 : h/-2; // Distance to top or bottom edge (from center)
var dx = cos>0 ? w/2 : w/-2; // Distance to left or right edge (from center)
if(abs(dx*sine) < abs(dy*cosine)) { // if (distance to vertical line) < (distance to horizontal line)
dy = (dx * sine) / cosine; // calculate distance to vertical line
} else { // else: (distance to top or bottom edge) < (distance to left or right edge)
dx = (dy * cosine) / sine; // move to top or bottom line
}
return GPoint(dx, dy); // Return point on rectangle edge
}
Use:
rectangle_width = 100;
rectangle_height = 150;
rectangle_center_x = 300;
rectangle_center_y = 300;
draw_rect(rectangle_center_x - (rectangle_width/2), rectangle_center_y - (rectangle_center_h/2), rectangle_width, rectangle_height);
GPoint point = getPointOnRect(angle, rectangle_width, rectangle_height);
point.x += rectangle_center_x;
point.y += rectangle_center_y;
draw_line(rectangle_center_x, rectangle_center_y, point.x, point.y);
One simple way to do this using an angle as a parameter is to simply clip the X and Y values using the bounds of the rectangle. In other words, calculate position as though the icon will rotate around a circular or elliptical path, then apply this:
(Assuming axis-aligned rectangle centered at (0,0), with X-axis length of XAxis and Y-axis length of YAxis):
if (X > XAxis/2)
X = XAxis/2;
if (X < 0 - XAxis/2)
X = 0 - XAxis/2;
if (Y > YAxis/2)
Y = YAxis/2;
if (Y < 0 - YAxis/2)
Y = 0 - YAxis/2;
The problem with this approach is that the angle will not be entirely accurate and the speed along the perimeter of the rectangle will not be constant. Modelling an ellipse that osculates the rectangle at its corners can minimize the effect, but if you are looking for a smooth, constant-speed "orbit," this method will not be adequate.
If think you mean rotate like the earth rotates around the sun (not the self-rotation... so your question is about how to slide along the edges of a rectangle?)
If so, you can give this a try:
# pseudo coode
for i = 0 to 499
if i < 100: x++
else if i < 250: y--
else if i < 350: x--
else y++
drawTheIcon(x, y)
Update: (please see comment below)
to use an angle, one line will be
y / x = tan(th) # th is the angle
the other lines are simple since they are just horizontal or vertical. so for example, it is x = 50 and you can put that into the line above to get the y. do that for the intersection of the horizontal line and vertical line (for example, angle is 60 degree and it shoot "NorthEast"... now you have two points. Then the point that is closest to the origin is the one that hits the rectangle first).
Use a 2D transformation matrix. Many languages (e.g. Java) support this natively (look up AffineTransformation); otherwise, write out a routine to do rotation yourself, once, debug it well, and use it forever. I must have five of them written in different languages.
Once you can do the rotation simply, find the location on the rectangle by doing line-line intersection. Find the center of the orbited icon by intersecting two lines:
A ray from your center of rotation at the angle you desire
One of the four sides, bounded by what angle you want (the four quadrants).
Draw yourself a sketch on a piece of paper with a rectangle and a centre of rotation. First translate the rectangle to centre at the origin of your coordinate system (remember the translation parameters, you'll need to reverse the translation later). Rotate the rectangle so that its sides are parallel to the coordinate axes (same reason).
Now you have a triangle with known angle at the origin, the opposite side is of known length (half of the length of one side of the rectangle), and you can now:
-- solve the triangle
-- undo the rotation
-- undo the translation