var x = Cx + a * Math.cos(ang);
var y = Cy + b * Math.sin(ang);
Cx, Cy are cords of center. ang is angle in radians. a is half of width, b is half of height.
If I change values of ang, I get different points on circumference of ellipse. Below is the path, which I get with above equation.
But instead of this elliptical shape, I want something like half ellipse, something like concave mirror. Even if we stretch both of its end to infinity, they should not form elliptical shape.
Can somebody provide me polar equations for second curve. I am very bad at digital drawing, but you can imagine that as concave mirror.
The parametric equations for a parabola with focus at (Fx, Fy) and focal parameter 2a, in terms of angle, would be:
x = Fx + (2*a*cos(ang))/(1 + cos(ang))
y = Fy + (2*a*sin(ang))/(1 + cos(ang))
Not too bad. :) You can adjust a as needed. You can actually modify it a bit by adjusting the ratio of the distances from the focus to the plot, versus the plot to the directrix:
x = Fx + (2*a*cos(ang))/(1 + cos(ang))
y = Fy + (2*b*sin(ang))/(1 + cos(ang))
Here the ratio will be b/a. So you can have the same distance from the origin to the vertex (2a) and make b larger to "flatten" the parabola.
Related
How can I create a polygon(square) with only knowing coordinate of single point with distance of each side (3km) and angle which is 90 degree using javascript. if I will have the coordinate of all 4 point then i can draw a rectangle.. Any suggestion will be of great help.
Mathematically, you cannot draw a square on a sphere, but we'll assume that:
the distance is small enough compared to the Earth that it doesn't matter and we can approximate a flat surface
it's not in the polar regions, as that messes with the maths.
From what I understood of your question, your start with Point 1 and the angle alpha which is the direction to the north (heading). If you define your angle differently, you'll have to adapt.
So we start with the following (I put the angle at 30 so it's more visible):
The first point is defined by lat1,lng1
var alpha = 30;
var dist=3;
var Rearth=6371.0
let cosa=Math.cos(alpha* Math.PI/180);
let sina=Math.sin(alpha* Math.PI/180);
let dlng=Rearth*Math.cos(lat1* Math.PI/180)
(dlng is the correction factor as the longitude dimensions gets smaller as the latitude goes from the equator to the poles. As the square is small, we can assume that the difference of latitude between the sides of the square doesn't really matter)
and to get to point 2 (as the angle between the centre of the earth and the side of the square is very small, there's no need to add a asin() function, as beta ~ sin(beta) in radians )
let lat2 = lat1 + (dist*cosa/Rearth*180/Math.PI);
let lng2 = lng1 + (dist*sina/(dlng)*180/Math.PI);
then we can find points 3 and 4 in a similar way:
let lat3 = lat2 - (dist*sina/Rearth*180/Math.PI);
let lng3 = lng2 + (dist*cosa/(dlng)*180/Math.PI);
let lat4=lat1 - dist*sina/Rearth*180/Math.PI;
let lng4=lng1 + dist*cosa /(dlng)*180/Math.PI;
and then you can use the lat,lng pairs to create a polygon:
var latlngs = [[lat1, lng1],[lat2, lng2],[lat3,lng3],[lat43,lng43],[lat4,lng4]];
L.polygon(latlngs, {color: 'blue'}).addTo(map);
For example, with dist=16km and alpha=45, you can draw a square that fits over the boundaries of Washington DC:
I'm working on a p5js project, and drawing radial lines with different lengths. I'm using this snippet in a loop to map and draw the lines:
var x1 = (this.mapR1)*Math.cos(i*2*Math.PI/this.numberLines);
var y1 = (this.mapR1)*Math.sin(i*2*Math.PI/this.numberLines);
var x2 = (this.mapR1 + this.mapRMinLen + (plot*this.mapRMaxLen*shift))*Math.cos(i*2*Math.PI/this.numberLines + skew);
var y2 = (this.mapR1 + this.mapRMinLen + (plot*this.mapRMaxLen*shift))*Math.sin(i*2*Math.PI/this.numberLines + skew)
p5.line(this.lines[i].x1, this.lines[i].y1, this.lines[i].x2, this.lines[i].y2);;
Plot is a simple bell curve distribution (between 0 and 1) to make the lines smoothly change length and shift is a randomly generated number to randomly scatter the second radius and change the length.
Skew is where things go awry. With skew I'm angling the lines from the center. Without shift, skew works great, but once I scatter the length of the lines, the math to calculate the position of the outer radius gets... well, skewed (image attached).
Here's a link to a codepen where you can see what I mean: https://codepen.io/chazthetic/pen/KKQNKaM. Is there a better way to calculate the second point position where the lines will be lined up?
One idea is to base the calculation of x2 and y2 on x1 and y1; sort of use them as the jumping off point for the calculating the end of the line segment.
Meaning:
var x2 = x1 + (rMinLen + (plot*rMaxLen*shift))*Math.cos(theta + skew);
var y2 = y1 + (rMinLen + (plot*rMaxLen*shift))*Math.sin(theta + skew);
https://codepen.io/lecrte/pen/JjpbwOV
Here's an image to demonstrate the question:
Let's say I have Point A at [0,0], and Point B at [50, 30]. I want to find the coordinates of Point X, along a circle of radius 15, with an origin at Point A, which is also on a line between Point A and Point B.
Pointers on the best method to do this?
Since this has been tagged JavaScript, here's a simple implementation:
// disclaimer: code written in browser
function Point2D(x, y) {
this.x = x;
this.y = y;
}
function findCircleInteresction(center, radius, target) {
var vector = new Point2D(target.x - center.x, target.y - target.y);
var length = Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2));
var normal = new Point2D(vector.x / length, vector.y / length);
var result = new Point2D(center.x + (normal.x * radius), center.y + (normal.y * radius));
return result;
}
findCircleInteresction(new Point2D(0, 0), 15, new Point2D(50, 30));
Point2D is just a class to make objects with x and y properties.
findCircleInteresction takes three parameters:
- center the center of the circle
- radius the radius of the circle
- target a point outside the circle
In findCircleInteresction:
- calculate the vector between the center and the target
- get the length of the resulting vector
- compute the normal (normalized) of the vector
- find the point where the vector intersects with the circle by adding the center of the circle plus the normalized vector components multiplied by the radius of the circle
This code could be heavily optimized and it's untested but I think it illustrated the idea.
You would want to think of this as two overlapping triangles, one with sides Bx-Ax and By-Ay. What you want is to find the coordinates of X, which would specifically be a triangle with sides Xx-Ax and Xy-Ay but with known hypotenuse R, which is your radius of the circle. Notice that the angle for both triangles are equal in respect to the x-coordinates-axis.
So to get the angle of the triangle, take the arctan(By-Ay/Bx-Ax) Now with that angle, call it T, you can solve for the smaller legs with your know radius R.
To get the x coordinate you would take Rcos(T)
To get the y coordinate you would take Rsin(T)
Bringing it all together you have that Xx = Rcos(T) and Xy = Rsin(T)
If you are not willing to use a Math library, which this method would use, you can use ratio's (as Pointy commented)
I have Google Maps icons which I need to rotate by certain angles before drawing on the map using MarkerImage. I do the rotation on-the-fly in Python using PIL, and the resulting image is of the same size as the original - 32x32. For example, with the following default Google Maps marker:
, a 30 degrees conter-clockwise rotation is achieved using the following python code:
# full_src is a variable holding the full path to image
# rotated is a variable holding the full path to where the rotated image is saved
image = Image.open(full_src)
png_info = image.info
image = image.copy()
image = image.rotate(30, resample=Image.BICUBIC)
image.save(rotated, **png_info)
The resulting image is
The tricky bit is getting the new anchor point to use when creating the MarkerImage using the new rotated image. This needs to be the pointy end of the icon. By default, the anchor point is the bottom middle [defined as (16,32) in x,y coordinates where (0,0) is the top left corner]. Can someone please explain to me how I can easily go about this in JavaScript?
Thanks.
Update 22 Jun 2011:
Had posted the wrong rotated image (original one was for 330 degrees counter-clockwise). I've corrected that. Also added resampling (Image.BICUBIC) which makes the rotated icon clearer.
To calculate the position of a rotated point you can use a rotation matrix.
Converted into JavaScript, this calculates the rotated point:
function rotate(x, y, xm, ym, a) {
var cos = Math.cos,
sin = Math.sin,
a = a * Math.PI / 180, // Convert to radians because that is what
// JavaScript likes
// Subtract midpoints, so that midpoint is translated to origin
// and add it in the end again
xr = (x - xm) * cos(a) - (y - ym) * sin(a) + xm,
yr = (x - xm) * sin(a) + (y - ym) * cos(a) + ym;
return [xr, yr];
}
rotate(16, 32, 16, 16, 30); // [8, 29.856...]
The formula for rotations about 0,0 is:
x1 = cos(theta) x0 - sin(theta) y0
y1 = sin(theta) x0 + cos(theta) y0
But that's for regular axes, and rotation about 0,0. The PIL rotation is clockwise with "graphics" axes. Plus, it's around the center of the image. The final confusing thing is that the size of the image can change, which needs to be accounted for in the final result.
Procedure: take original point, subtract off center of image, apply "graphics axes" corrected rotation, find new size of image, add back center position of new image.
Rotation using graphics axes is:
x1 = cos(theta) x0 + sin(theta) y0
y1 = -sin(theta) x0 + cos(theta) y0
16,32 - 16,16 is 0, 16. Rotate 30 degrees clockwise rotation (based on your images) gives a point cos(-30)*0+sin(-30)*16, -sin(-30)*0+cos(-30)*16 = -8, 13.86. The final step is adding back the center position of the rotated position.
In an image, downwards is positive Y and rightwards is positive X. However, to apply the rotation formula, we need upwards as positive Y. Therefore, step 1 would be to apply f(x,y) = f(x,h-y), where 'h' is the height of the image.
Let's say the image is rotated with respect to x0,y0. You'd then need to transform your origin to this point. Therefore, step 2 would be f(x,y) = f(x-x0,y-y0). At this stage (i.e. after the two steps), your new co-ordinates would be x-x0, h-y-y0. You're now ready to apply the rotation formula
x1 = x*cos(theta) - y*sin(theta)
y1 = xsin(theta) + ycos(theta)
Use the values of x and y obtained after step two.
You'd get
x1 = (x-x0)*cos(theta) - (h-y-y0)*sin(theta)
y1 = (x-x0)*sin(theta) + (h-y-y0)*cos(theta)
Now, undo transformations done in step 2 and step 1 (in that order).
After undoing step2: xNew = x1 + x0 and yNew = y1 + y0
After undoing step1: xNew = x1 + x0 and yNew = h - (y1 + y0)
This gives you:
xNew = (x-x0)*cos(theta) - (h-y-y0)*sin(theta) + x0
yNew = -(x-x0)*sin(theta) - (h-y-y0)*cos(theta) + (h-y0)
Over the last two days I've effectively figured out how NOT to rotate Raphael Elements.
Basically I am trying to implement a multiple pivot points on element to rotate it by mouse.
When a user enters rotation mode 5 pivots are created. One for each corner of the bounding box and one in the center of the box.
When the mouse is down and moving it is simple enough to rotate around the pivot using Raphael elements.rotate(degrees, x, y) and calculating the degrees based on the mouse positions and atan2 to the pivot point.
The problem arises after I've rotated the element, bbox, and the other pivots. There x,y position in the same only there viewport is different.
In an SVG enabled browser I can create new pivot points based on matrixTransformation and getCTM. However after creating the first set of new pivots, every rotation after the pivots get further away from the transformed bbox due to rounding errors.
The above is not even an option in IE since in is VML based and cannot account for transformation.
Is the only effective way to implement
element rotation is by using rotate
absolute or rotating around the center
of the bounding box?
Is it possible at all the create multi
pivot points for an object and update
them after mouseup to remain in the
corners and center of the transformed
bbox?
UPDATE:
I've attempted to use jQuery offset to find the pivot after it's been rotated, and to use that offset location as the pivot point.
Demo site ...
http://weather.speedfetishperformance.com/dev/raphael/rotation.html
The best cross-browser way I can think of to do what you want is to implement the rotation yourself rather than let SVG do it. Rotating x,y coordinates is fairly simple and I've been using this (tcl) code whenever I need to do 2D rotation: Canvas Rotation.
The upside to this is you have maximum control of the rotation since you're doing it manually. This solves the problems you're having trying to guess the final coordinates after rotation. Also, this should be cross browser compatible.
The downside is you have to use paths. So no rects (though it should be easy to convert them to paths) or ellipses (a little bit harder to convert to path but doable). Also, since you're doing it manually, it should be slower than letting SVG do it for you.
Here's a partial implementation of that Tcl code in javascript:
first we need a regexp to tokenize SVG paths:
var svg_path_regexp = (function(){
var number = '-?[0-9.]+';
var comma = '\s*[, \t]\s*';
var space = '\s+';
var xy = number + comma + number;
var standard_paths = '[mlcsqt]';
var horiz_vert = '[hv]\s*' + number;
var arc = 'a\s*' + xy + space + number + space + xy + space + xy;
var OR = '\s*|';
return new RegExp(
standard_paths +OR+
xy +OR+
horiz_vert +OR+
arc,
'ig'
);
})();
now we can implement the rotate function:
function rotate_SVG_path (path, Ox, Oy, angle) {
angle = angle * Math.atan(1) * 4 / 180.0; // degrees to radians
var tokens = path.match(svg_path_regexp);
for (var i=0; i<tokens.length; i++) {
var token = tokens[i].replace(/^\s+|\s+$/g,''); // trim string
if (token.match(/\d/)) { // assume it's a coordinate
var xy = token.split(/[, \t]+/);
var x = parseFloat(xy[0]);
var y = parseFloat(xy[1]);
x = x - Ox; // Shift to origin
y = y - Oy;
var xx = x * Math.cos(angle) - y * Math.sin(angle); // Rotate
var yy = x * Math.sin(angle) + y * Math.cos(angle);
x = xx + Ox; // Shift back
y = yy + Oy;
token = x + ',' + y;
}
else if (token.match(/^[hv]/)) {
// handle horizontal/vertical line here
}
else if (token.match(/^a/)) {
// handle arcs here
}
tokens[i] = token;
}
return tokens.join('');
}
The above rotate function implements everything except horizontal/vertical lines (you need to keep track of previous xy value) and arcs. Neither should be too hard to implement.