Interconnected curved lines - javascript

Given a series of JSON co-ordinates typically in the format:
{from: {x:0, y:0}, to: {x:0, y:10}, ...}
I would like to draw a series of straight dotted paths which are connected with simple, fixed radius rounded corners. I have been looking at Slope Intercept Form to calculate the points along the straight line but I am a little perplexed as to the approach for calcualting the points along the (Bezier?) curves.
e.g. I want to draw curves between p1 and p2 and p3 and p4. Despite what the poor mockup might imply I am happy for the corners to be a fixed radius e.g. 10px
I would like to abstract out the drawing logic and therefore am seeking a generalised approach to returning a JavaScript point array which I can then render in a number of ways (hence I am avoiding using any inbuilt functions provided by SVG, Canvas etc).

What you want is a cubic bezier curve.
http://www.blackpawn.com/texts/splines/
Look at the first applet on this page. If A is p1, D is p2, the direction A-B is line 1's angle and the direction C-D is line 2's angle you can see how this gives you the properties you need - it starts at angle 1 and ends at angle 2 and is flush with the points.
So, to get your points C and D, one way to do this would be to take the line segment 1, copy it, place it starting at p1 - and say where the new line ends is B, and similar with line segment 2 and p2 for D. (And you could do things like have a factor that multiplies into the copied line segments' distance to make the curves stick out more or less... etc)
Then just do the math :)
http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves
And once you have your equation for the curve, step through it with a delta t of the desired precision (e.g. every 0.1 of t, every 0.01...) and spit out every pair of points on the curve as a line segment.

Related

How can I make squares?

I'm trying to generate random, convex, non-self-intersecting polygons - quadrilaterals specifically.
I've gotten as far as:
function randquad(){
var bodyDef = new b2BodyDef,
fixDef = new b2FixtureDef,
x=0, y=0;
fixDef.density = Math.random();
fixDef.friction = Math.random();
fixDef.restitution = Math.random()*0.3;
bodyDef.type = b2Body.b2_dynamicBody;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsArray([
new b2Vec2(x, y),
new b2Vec2(x+=Math.random()*2, y+=Math.random()*2*(Math.random()<0.5?1:-1)),
new b2Vec2(x+=Math.random()*2*(Math.random()<0.5?1:-1), y+=Math.random()*2),
new b2Vec2(x-=Math.random()*2, y+=Math.random()*2*(Math.random()<0.5?1:-1))
]);
bodyDef.position.x = Math.random() * 10;
bodyDef.position.y = 0;
world.CreateBody(bodyDef).CreateFixture(fixDef);
}
I'm working with Box2D web; however, this question is not limited to it, or javascript - its a broader one that is more mathematical.
I want to get 4 points that, in a sequence, make the shape I'm looking for.
With the code I've written I often get the desired shape; however, I do still get self-intersecting shapes. At the moment I'm not too fussed about the shapes being convex.
The reason I need such shapes is because it seems they're the only ones box2d web likes.
Any 4 points can make a non-self-intersecting quadrilateral right?
Should I generate 4 initially, and sort them into a sequence that works?
Whats the best/most efficient manner in which to approach this?
-- Original Question Title: Random Quadrilateral Generation
You could start from the fact that if you take 3 random points, they will always form a convex, non-intersecting triangle (provided the points are all different). Then you can just pop out one of the edges by adding a fourth point a random distance along the last edge, and pushing it away from the center of the triangle by a random amount.
Start off by generating a random triangle by generating 3 random points: A, B, C
Choose a random number between 0 and 1, and use it to calculate a point D somewhere along the line between C and A
Calculate the centroid of the triangle by averaging A, B, C
Calculate another random number between 1 and n (say 2)
Calculate the vector from the centroid to D (subtract the centroid from D), and multiply it by this second random number, then add back to the centroid. This will produce your fourth point.
I'm not sure if you have any aesthetic requirements (e.g. no excessively pointy shapes) but you could play around with the random number generation a bit to get the results you like. For example in the second step you could choose a random number between 0.2 and 0.8, for example, so the points aren't too close together. You can also change the value of n in the fourth step.
Another issue is winding. With this method, half the quads will have a clockwise winding and have will be counter-clockwise. If you need a particular winding you can do a winding test (sign of dot product of BC with normal of AB), and if it's not the way you want then just reflect all the points on one axis.
If you take your points from the perimeter of a circle all the vertices will be convex.
Knowing this we can program a loop to branch out to a non-existant circle and generate corners that'll always produce a convex shape.
angles=[];
for (var i = 4; i--;) angles.push(Math.random()*2*Math.PI);
Now the angles need to be sorted so when the shape is created, clockwise, they're chosen in order of angle size.
This will stop points crossing / self intersection of the shape.
angles.sort()
Now you can create the shape using the triganometric functions cos and sin, these will convert the angle to actual co-ordinates.
polygon([
vector(Math.cos(angles[0]), Math.sin(angles[0])),
vector(Math.cos(angles[1]), Math.sin(angles[1])),
vector(Math.cos(angles[2]), Math.sin(angles[2])),
vector(Math.cos(angles[3]), Math.sin(angles[3]))
]);`

Geometry on Latitude/Longitude (Projection of point on arc)

I just want to check if there is a point (lat, long) of the projection intersecting with the arc giving by 2 points (lat, long) and if it does, I want to find that (lat, long).
Can (lat, long) be used as a 2D vector space to make this problem similar to the one in cartesian co-ordinates? How accurate would it be?
While the answer on Link helps with getting the distance to the arc, how can I know whether the point of intersection is between the points that were used to find the great circle? Also would it be possible to solve this without having to use switch to cartesian co-ordinates?
There are two ways to approach this.
The first assumes a straight line between the two points--although, in actuality, such a line would intersect with the earth.
The second actually determines the great-circle route between the two points, that is, the minimum-length arc that actually follows the earth's surface and joins the two points. To do this, you have to use coordinate transformations to generate vectors of direction cosines for the two superficial points. Call them A and B.
To determine whether C lies on that arc, you can't just do linear interpolation like you could if you cheated and used a line segment that passes through the earth. Instead, you need to calculate the direction cosines for C also. C lies true between A and B if angles AC, BC, and AB are all equal. Angles can be determined by calculating the dot products of the corresponding direction cosines and evaluating the inverse cosine thereof.

2d perspective skew in JS

I want to transform an image in 2 points perspective.
I guess I need to transfer to JS a formula from: http://web.iitd.ac.in/~hegde/cad/lecture/L9_persproj.pdf
But I'm humanities-minded person and I faint when I see matrices.
Here's what I need exactly:
I have a two vanishing points: X(X.x, X.y) and Z(Z.x, Z.y). And rectangle ABCD (A.x, A.y and so on)
(source: take.ms)
And I want to find new nA, nB, nC and nD points with which I can transform my rectangle like that (the points order doesn't really matter):
(source: take.ms)
Right now I'm doing weird approximate calculations: I'm looking for most distant point from X (1), then lay over an interval towards Z (2), than another interval towards X (3) and then again from Z (4):
(source: take.ms)
The result is a bit off but is alright for the precision I need, but this algorithm sometimes gives very weird results if I change vanishing points, so if there's a proper solution I'll gladly use it. Thanks!

Cubic Bezier Curve between two points on a sphere in three.js

I'm letting the user click on two points on a sphere and I would then like to draw a line between the two points along the surface of the sphere (basically on the great circle). I've been able to get the coordinates of the two selected points and draw a QuadraticBezierCurve3 between the points, but I need to be using CubicBezierCurve3. The problem is is that I have no clue how to find the two control points.
Part of the issue is everything I find is for circular arcs and only deals with [x,y] coordinates (whereas I'm working with [x,y,z]). I found this other question which I used to get a somewhat-working solution using QuadraticBezierCurve3. I've found numerous other pages with math/code like this, this, and this, but I really just don't know what to apply. Something else I came across mentioned the tangents (to the selected points), their intersection, and their midpoints. But again, I'm unsure of how to do that in 3D space (since the tangent can go in more than one direction, i.e. a plane).
An example of my code: http://jsfiddle.net/GhB82/
To draw the line, I'm using:
function drawLine(point) {
var middle = [(pointA['x'] + pointB['x']) / 2, (pointA['y'] + pointB['y']) / 2, (pointA['z'] + pointB['z']) / 2];
var curve = new THREE.QuadraticBezierCurve3(new THREE.Vector3(pointA['x'], pointA['y'], pointA['z']), new THREE.Vector3(middle[0], middle[1], middle[2]), new THREE.Vector3(pointB['x'], pointB['y'], pointB['z']));
var path = new THREE.CurvePath();
path.add(curve);
var curveMaterial = new THREE.LineBasicMaterial({
color: 0xFF0000
});
curvedLine = new THREE.Line(path.createPointsGeometry(20), curveMaterial);
scene.add(curvedLine);
}
Where pointA and pointB are arrays containing the [x,y,z] coordinates of the selected points on the sphere. I need to change the QuadraticBezierCurve3 to CubicBezierCurve3, but again, I'm really at a loss on finding those control points.
I have a description on how to fit cubic curves to circular arcs over at http://pomax.github.io/bezierinfo/#circles_cubic, the 3D case is essentially the same in that you need to find out the (great) circular cross-section your two points form on the sphere, and then build the cubic Bezier section along that circle.
Downside: Unless your arc is less than or equal to roughly a quarter circle, one curve is not going to be enough, you'll need two or more. You can't actually model true circular curves with Bezier curves, so using cubic instead of quadratic just means you can approximate a longer arc segment before it starts to look horribly off.
So on a completely different solution note: if you have an arc command available, much better to use that than to roll your own (and if three.js doesn't support them, definitely worth filing a feature request for, I'd think)

Gradient a Parallelogram

I'm working in JavaScript drawing on a canvas, and have four coordinates to draw a parallelogram, called A, B, C, and D starting from the top-left, top-right, bottom-left, and bottom right, respectively.
An example of some coordinates might be:
A: (3, 3)
B: (4, 3)
C: (1, 0)
D: (2, 0)
I can draw the parallelogram just fine, but I would like to fill it in with a gradient. I want the gradient to fill in from left to right, but matching the angle of the shape. The library I use (CAKE) requires a start and stop coordinate for the gradient. My stop and start would be somewhere half way between A and C, and end somewhere half way between B and D. Of course, it is not simply EXACTLY half way because the angles at A, B, C, and D are not right angles. So given this information (the coordinates), how to I find the point on the line A -> C to start, and the point on the line B -> D to stop?
Remember, I'm doing this in JavaScript, so I have some good Math tools at my disposal for calculation.
What you specified in your comment is doable with more information (e.g. you need to specify where the perpendicular line starts as that will affect your gradient a lot), but I don't think it will get you what you want.
Instead, take the following for example, which I think is closer to what you are striving for:
As you can see, to make the gradient for the above parallelogram we ignore the AC and BD sides and make the gradient relative to AB and CD. You can decide which pair of sides to use, but I would probably go by length so that the display is consistent across all your parallelograms (either you want the gradient relative to the pair of longer sides or the shorter ones, your choice, but personally I'd go with the longer sides).
Let's say you pick AB. The slope of the line perpendicular to AB is the inverse reciprocal of the slope of AB, which is (ax-bx)/(by-ay) (careful about the dividing by zero case here!).
Next, you have to find 2 gradient points, which will be two appropriate points on any line with that slope. One option is to pick the line going through A, use A as the starting point, and use the point where it intersects with CD as the ending point (you can use this page as a guide for figuring out the intersection point). Otherwise, keep the slope but tweak the points to your liking to get the gradient you want.
Once you have your points for your gradient, plug them in and it's a piece of CAKE!

Categories