Get coordinates of line-surrounding box - javascript

I've been working in JavaScript to code a line drawing system. I'd like the lines drawn to be selectable, so I've been attempting to implement line-highlighting. As you can see in the image below, I have a line (in black) with known coordinates and an equation in slope-intercept (y=mx+b). How can I calculate the corners' (circled in green) coordinates, knowing the box's radius?

This is easiest to think of in terms of vectors.
Start off by defining the point at the end of the line as A, and the other end as B
var A = new Vector(1, 1)
var B = new Vector(5, 3)
Now find the unit direction vector of the line (a vector of length 1 pointing from A to B), and its perpendicular:
var dir = B.minus(A).normalize();
var dir_perp = new Vector(dir.y, -dir.x)
And extend them to be of length thickness:
dir = dir.times(thickness);
dir_perp = dir_perp.times(thickness)
The four corners are then:
[
A.minus(dir).plus(dir_perp),
A.minus(dir).minus(dir_perp),
B.plus(dir).minus(dir_perp),
B.plus(dir).plus(dir_perp)
]
This obviously assumes you have some sort of vector math library. Here's one I made earlier

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]))
]);`

In PaperJS is it possible to set the length of a straight line path explicitly?

From what I can see it looks like the only way to change the length of a single Path is to path.scale(x) it. However I want to make the line's length oscillate slightly around its original length, which is difficult to do with scale, because if you feed it random values you will in effect end up with its length taking a random walk, potentially ending up far away from its original length.
is it possible to set the length of a line path explicitly, something like path.length = 10? According to the documentation it doesn't seem like this is possible. Why not?? And what would be the best way to achieve my desired outcome?
You can do this by noting that paths in paperjs are not geometric shapes though they may have been specified as one. They are arrays of segment points; that's why setting the length of a line directly is not possible. A line has two segment points - one for the start and one for the end of the line. By manipulating the second segment point you can adjust the length of the line. This sketch (the following code) illustrates how to do so. To adjust the length of the original line uncomment the last line of code.
line = new Path.Line([100,100], [200, 300]);
line.strokeColor = 'black';
line.strokeWidth = 5;
// paths in paper are arrays of segments, not instances of
// circle or line or rectangle. so find the vector that
// represents the delta between the first point and the
// second point.
vector = line.segments[0].point - line.segments[1].point;
// adjustment for the line - this would vary in your case
factor = 0.9;
// I'm drawing a new line here to make it easy to see
p0 = line.segments[0].point;
p1 = p0 - vector * factor;
newline = new Path.Line(p0, p1);
newline.strokeColor = 'red';
newline.strokeWidth = 2;
// but to adjust your original line just use the following
//line.segments[1].point = p1;
You can store the original vector, if you choose to do so, in the property line.data which is an empty object that paper creates for whatever the user wishes. So line.data.vector = vector; would allow you to keep each line's original vector. And you can set the length of a line to a specific length with the following:
var v = line.data.vector.clone();
v.length = 10; // specific length
line.segments[1].point = p0 - v;

How to render a sphere with triangle strips

I'm currently going through this tutorial on rendering shapes WebGL (specifically a sphere in this case) and I understand the math behind the generation of each point on the sphere. In the tutorial though, the author defines one method to find all of the vertices and another to generate all of the squares that will comprise the sphere.
A couple of things are unclear from what is done in the tutorial. First, how exactly are the vertices generated by the parametric equation being connected to the squares (triangle strips) being generated? I've made a bare bones program in plain javascript and HTML5 before doing the same thing just using the vertices generated so I'm not seeing how and why they have to be used in conjunction with the triangle strips. The other point of confusion is specifically regarding the function that generates the squares:
var indexData = [];
for (var latNumber = 0; latNumber < latitudeBands; latNumber++) {
for (var longNumber = 0; longNumber < longitudeBands; longNumber++) {
var first = (latNumber * (longitudeBands + 1)) + longNumber;
var second = first + longitudeBands + 1;
indexData.push(first);
indexData.push(second);
indexData.push(first + 1);
indexData.push(second);
indexData.push(second + 1);
indexData.push(first + 1);
}
}
To generate the first point of each square (point on the top left corner) the following is done: var first = (latNumber * (longitudeBands + 1)) + longNumber;
I'm not sure why the number of the lattitude line needs to be multiplied by the total number of longitude lines (plus 1 to fully wrap around) at each step.
The code for both functions is toward the bottom of the tutorial. A general explanation of the use of triangle strips in a case like this could also be helpful, thanks.
how exactly are the vertices generated by the parametric equation being connected to the squares (triangle strips) being generated?
A: Vertices are basically points. So its basically generating points using math. Quote from tutorial :
"for a sphere of radius r, with m latitude bands and n longitude bands, we can generate values for x, y, and z by taking a range of values for θ by splitting the range 0 to π up into m parts, and taking a range of values for φ by splitting the range 0 to 2π into n parts, and then just calculating:
x = r sinθ cosφ
y = r cosθ
z = r sinθ sinφ"
how and why they have to be used in conjunction with the triangle strips
A: they are not triangle STRIPS as in the primitive type gl.TRIANGLE_STRIP, but merely regular triangles defined with 3 points.
regarding the function that generates the squares
A: They are not generation squares per se, but using the points generated from the parametric equation to create triangles for the GPU to render. The code you shown in the OP basically divides a square into 2 triangles.

measuring angles on HTML 5 canvas element?

I am confused when implementing (measure) angles in an HTML5 canvas especially after rotating objects
Let's assume I have drawn a shape like this
ctx.moveTo(100,100)//center of canvas
ctx.lineTo(0,200)//left bottom
ctx.lineTo(200,200)//right bottom
We know it is a 45 degrees or pi*2/4 angle.
But how do I figure it out using Math functions to see if the shape was rotated or not?
And how to re-measure it after changing the x and y of the shape(first point) ?
First things first, you will need to make sure the points are stored in some sort of data structure, as it won't be easy to pull the points from the canvas itself. Something like an array of arrays:
var angle = [[100,100], [0,200], [200,200]];
Now, you need to convert your lines to vectors:
var AB = [angle[1][0]-angle[0][0], angle[1][1]-angle[0][1]];
var BC = [angle[2][0]-angle[1][0], angle[2][1]-angle[1][1]];
Now find the dot-product of the two:
var dot_product = (AB[0]*BC[0]) + (AB[1]*BC[1]);//not dot-product
Now you need to find the length (magnitude) of the vectors:
var ABmagnitude = Math.sqrt(Math.pow(AB[0],2) + Math.pow(AB[1],2));
var BCmagnitude = Math.sqrt(Math.pow(BC[0],2) + Math.pow(BC[1],2));
Now you put it all together by dividing the dot product by the product of the two magnitudes and getting the arcosine:
var theta = Math.acos(dot_product/(ABmagnitude*BCmagnitude));
You mentioned rotation, but unless you are only rotating one line, the angle will stay the same.

How to Draw line in 3D rectangle based on x,y and z?

I would like draw 3D points represented in image to 3D rectangle. Any idea how could I represent these in x,y and z axis
Here projection type is orthographic.
Thanks
Okay. Let's look at a simple example of what you are trying to accomplish it, and why this is such a complicated problem.
First, lets look a some projection functions. You need a way to mathematically describe how to transform a 3D (or higher dimensional) point into a 2D space (your monitor), or a projection.
The simpiest to understand is a very simple dimetric projection. Something like:
x' = x + z/2;
y' = y + z/4;
What does this mean? Well, x' is you x coordinate 2D projection: for every unit you move backwards in space, the projection will move that point half that many units to the right. And y' represents that same projection for your y coordinate: for every unit you move backwards in space, the projection will move that point a quarter unit up.
So a point at [0,0,0] will get projected to a 2d point of [0,0]. A point at [0,0,4] will get projected to a 2d point of [2,1].
Implemented in JavaScript, it would look something like this:
// Dimetric projection functions
var dimetricTx = function(x,y,z) { return x + z/2; };
var dimetricTy = function(x,y,z) { return y + z/4; };
Once you have these projection functions -- or ways to translate from 3D space into 2D space -- you can use them to start draw your image. A simple example of that using js canvas. First, some context stuff:
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
Now, lets make a little helper to draw a 3D point:
var drawPoint = (function(ctx,tx,ty, size) {
return function(p) {
size = size || 3;
// Draw "point"
ctx.save();
ctx.fillStyle="#f00";
ctx.translate(tx.apply(undefined, p), ty.apply(undefined,p));
ctx.beginPath();
ctx.arc(0,0,size,0,Math.PI*2);
ctx.fill();
ctx.restore();
};
})(ctx,dimetricTx,dimetricTy);
This is pretty simple function, we are injecting the canvas context as ctx, as well as our tx and ty functions, which in this case our the dimetric functions we saw earlier.
And now a polygon drawer:
var drawPoly = (function(ctx,tx,ty) {
return function() {
var args = Array.prototype.slice.call(arguments, 0);
// Begin the path
ctx.beginPath();
// Move to the first point
var p = args.pop();
if(p) {
ctx.moveTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
// Draw to the next point
while((p = args.pop()) !== undefined) {
ctx.lineTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
ctx.closePath();
ctx.stroke();
};
})(ctx, dimetricTx, dimetricTy);
With those two functions, you could effectively draw the kind of graph you are looking for. For example:
// The array of points
var points = [
// [x,y,z]
[20,30,40],
[100,70,110],
[30,30,75]
];
(function(width, height, depth, points) {
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
// Set some context
ctx.save();
ctx.scale(1,-1);
ctx.translate(0,-c.height);
ctx.save();
// Move our graph
ctx.translate(100,20);
// Draw the "container"
ctx.strokeStyle="#999";
drawPoly([0,0,depth],[0,height,depth],[width,height,depth],[width,0,depth]);
drawPoly([0,0,0],[0,0,depth],[0,height,depth],[0,height,0]);
drawPoly([width,0,0],[width,0,depth],[width,height,depth],[width,height,0]);
drawPoly([0,0,0],[0,height,0],[width,height,0],[width,0,0]);
ctx.stroke();
// Draw the points
for(var i=0;i<points.length;i++) {
drawPoint(points[i]);
}
})(150,100,150,points);
However, you should now be able to start to see some of the complexity of your actual question emerge. Namely, you asked about rotation, in this example we are using an extremely simple projection (our dimetric projection) which doesn't take much other than an oversimplified relationship between depth and its influences on x,y position. As the projections become more complex, you need to know more about your relationship/orientation in 3D space in order to create a reasonable 2D projection.
A working example of the above code can be found here. The example also includes isometric projection functions that can be swapped out for the dimetric ones to see how that changes the way the graph looks. It also does some different visualization stuff that I didn't include here, like drawing "shadows" to help "visualize" the actual orientation -- the limitations of 3D to 2D projections.
It's complicated, and even a superficial discussion is kind of beyond the scope of this stackoverflow. I recommend you read more into the mathematics behind 3D, there are plenty of resources, both online and in print form. Once you have a more solid understanding of the basics of how the math works then return here if you have a specific implementation question about it.
What you want to do is impossible to do using the method you've stated - this is because a box - when rotated in 3 dimensions won't look anything like that diagram of yours. It will also vary based on the type of projection you need. You can, however get started using three.js which is a 3D drawing library for Javascript.
Hope this helps.
How to Draw 3D Rectangle?
posted in: Parallelogram | updated on: 14 Sep, 2012
To sketch 3 - Dimensional Rectangle means we are dealing with the figures which are different from 2 – D figures, which would need 3 axes to represent them. So, how to draw 3D rectangle?
To start with, first make two lines, one vertical and another horizontal in the middle of the paper such that they represent a “t” letter of English. This is what we need to draw for temporary use and will be removed later after the construction of the 3 – D rectangle is complete. Next we draw a Square whose measure of each side is 1 inch. Square must be perfect in Geometry so that 90 degree angles that are formed at respective corners are exact in measure. Now starting from upper right corner of the square we draw a line segment that will be stretched to a measure of 2 inches in the direction at an angle of 45 degrees. Similarly, we repeat the procedure by drawing another Line Segment from the upper left corner of the square and stretching it to 2 inches length in the direction at an angle of 45 degrees. These 2 line segments are considered to be the diagonals with respect to the horizontal line that we drew temporarily in starting. Also these lines will be parallel to each other. Next we draw a line that joins the end Point of these two diagonals.
Next starting from the very right of the 2 inch diagonal end point, draw a line of measure 1 inch that is supposed to be perpendicular to the temporary horizontal line. Next we need to join the lower left corner of the square with end point of the last 1’’ line we drew in 4th step and finally we get our 3 - D rectangular. Now we can erase our initial “t”. This 3- D rectangle resembles a Cuboid.

Categories