how to scale a Bezier curve (using HTML5 canvas)? - math

I have a Bezier path stored as an array of several points, which is each an array of coordinates in the form [cp1x,cp1y,cp2x,cp2y,x,y].
I'd like to be able to scale this path up and down to adjust its size, but I don't know the math to do that. I tried applying a coefficient to each of the coordinate values, but that didn't seem to work.
Does anybody know how to achieve this?

In the standard representation, the points P, represent actual points in space, so you'd move them around like any other points. That is to scale them, just multiple everything by you scaling factor: say it's a, so that would be [a*cp1x,a*cp1y,a*cp2x,a*cp2y,a*x,a*y], or if you want to scale x and y separately, you can use different factors for the x and y components.
Note also that this will scale things relative to the origin (x=0, y=0), so if you don't have any curves at the origin, it can look like a shift. If you want to negate the effect of this shift you can subtract Px and Py from the x and y values respectively, where Px and Py is the point you want to not move when scaled, before you do the scaling (and then add it back after you multiple, if you want to). But if what you want to do is scale an entire canvas, like going from 5x5 inch to 7x7, you'd want to do the multiplication without any shifts (and in this case, by 7./5).

Related

Moving an object diagonally inside a square

I am stuck on a particular problem. I am learning on how to create a very basic game, where a ball will travel diagonally from either top left corner of a square or a rectangular down to the bottom right corner in a straight line (As shown in Fig 1 & 2). Now I know that the ball x and y position will both need to be changed frame by frame but I am unsure on how to go about this.
enter image description here
Math is not my strong point and I am unsure how do I calculate the exact route, especially since both the square and rectangle will have a different angles. Are there any math formulas I can use to calculate the diagonal line and by how much each of the x and y coordinates of the ball will need to be adjusted frame by frame.
From the research that I have done I think that I will most likely need to calculate the angle using the sin or cos functions but I am not sure how everything fits together. Have been using https://www.mathsisfun.com/sine-cosine-tangent.html to try and learn more.
I am planning on starting to code this but would really appreciate answers to these basic questions. I am trying to learn both the programming and the mathematical aspect at the same time and I feel that this approach would be the best fit.
Many Thanks for any suggestions/help, I would really appreciate it.
Since it's rectangular, just calculate the slope: rise (Y) / run (X). That will give you how much to increase the object's location in each direction per frame. Depending on how fast or slow you want the object to move, you'll need to apply some modifier to that (e.g., if you want the object to move twice as fast, you'll need to multiple 2 by the change in a particular direction before you actually change the object's location.
For square :
If you are using Frame or JFrame, you have coordinate with you.
You can move ball from left top to right down as follow ->
Suppose ur top left corner is at (0,0), add 1in both coordinate until you reach right bottom corner.
U can do this using for loop
You don't technically need the angle for this mapping. You know that the formula for a line is "y = m * x + b." I presume that you can calculate m,b. If not, let me know.
Given that - you can simply increment x based on anything you like (timer, event, etc. ). You can place your incremented x into the equation above to get your respective y.
Now, that won't be quite enough as you are dealing with pixels instead of actual numbers. For example, lest assume that in your game x/y are in feet. You will need to know how many pixels represent a foot. Then when you draw to the screen you adjust your coordinates by dividing by pixels per foot.
So...
1. Calculate your m and b for your path.
2. Use a timer. At each tick, adjust your x value
3. Use your x value to calculate your y value
4. Divide x and y by a scaling number
5. Use the new scaled x and y to plot your object
Now...There are all kinds of tricks you can play with the math, but that should get you started.
Let's left bottom corner of rectangle (or square) has coordinates (x0, y0), and right top corner (x1, y1). Then diagonal has equation
X(t) = x0 + t * (x1 - x0)
Y(t) = y0 + t * (y1 - y0)
where t is parameter in range 0..1. Point at t=0 corresponds to (x0, y0), at t=1 to (x1, y1), and at t=0.5 - to the center of rectangle. So all you need is vary parameter t and calculate position.
When your object will move with constant absolute speed in arbitrary direction, use horizontal and vertical components of velocity vx and vy. At every moment get coordinates as x_new = x_old + delta_time * vx. Note that reflection from vertical edge just changes horizontal component of velocity 'vx = - vx' and so on.

Trying to calculate the slope of a plane from a normal

I have a set of 3D normal vectors for points on a 3D mesh, and I need to calculate the slope of the area below each of them. I have no idea how to do this. I don't need X or Y slope, I just need the total incline of the point in question (although to be fair, I don't know how to derive total slope from X and Y slope individually, which is part of my problem). I did see This article, but I couldn't really make heads or tails of it... The vectors are outward-facing. If anyone can explain this one to me, I'd be really grateful.
If you already have the normal vector, you're almost there. What you now need is the angle (look for dot product) between the normal and a vertical line (what exactly vertical means depends on your application).
If your normal vectors are actually normalized (have length 1) and the vertical is (0 0 1), the cosine of the slope angle is simply the z coordinate of the normal vector.
To demonstrate this: Take a pen and let it stand on your table. This is your table's normal vector. The angle between this vector and a vertical line is zero, as your table has no slope at all. If you tilt your table by a certain amount, the angle between the normal and a vertical line will increase by the same amount.

Scaling an object with a local scale and a rotation

I have an object which has a position, a rotation angle and a scale (x and y). The overall transform matrix is as follows :
QTransform xform;
xform.translate(instance.definition.position.x, instance.definition.position.y);
xform.rotateRadians(instance.definition.rotation);
xform.scale(instance.definition.scale.x, instance.definition.scale.y);
I need to scale this object using a global scale which then modifies the local scale of the object. For example, the object is rotated by 45 degrees, I apply a scale of 1,2, I need to know how this affects the local scale as it should affect both local scale axes.
Thanks.
PS : maybe this is impossible due to being a non affine transformation, I don't know, I didn't find much on Google about this particular problem
UPDATE : I think I need to have at least a 3 col by 2 rows matrix transform to keep enough information, I tried some things in SVG which uses this kind of matrix transform and it seems to work, I will need to update this matrix according to the position and rotation though.
Either scale the object first
or calculate the inverse matrix, apply it to object (that undoes the translation/rotation), scale it and apply the first matrix again.
If you take, say, a rectangle, rotate it so that its edges are no longer parallel to the coordinate axes, then apply a scaling factor to, say, X, it will no longer be a rectangle. It will be a parallelogram, and your data structures will have to accommodate more information than they do now.

Scalling connected lines

I have some kind of a shape consisting of vertical, horizontal and diagonal lines. I have starting X,Y and ending X,Y (this is my input - just 2 points defining a line) of each line and I would like to make the whole shape scalable (just by changing the value of a scale ratio variable), so that I can still preserve the proper connection of the lines and the proportions as well. Just for getting a better idea of what I mean: it'd be as if I had the same lines in a vector editor.
Would that be possible with an algorithm, and could you please, give me another possible solution if there is no such algorithm ?
Thank you very much in advance!
what point do you want it to scale about? You could scale relative to the first point, the center, or some other arbitrary location. Typically, you subtract out an offset (for instance the first point in your input), multiply by a scale factor, and then add back the offset.
A more systematic approach in computer graphics would be to use a transformation matrix... although thats probably overkill in your case.

Polygon math

Given a list of points that form a simple 2d polygon oriented in 3d space and a normal for that polygon, what is a good way to determine which points are specific 'corner' points?
For example, which point is at the lower left, or the lower right, or the top most point? The polygon may be oriented in any 3d orientation, so I'm pretty sure I need to do something with the normal, but I'm having trouble getting the math right.
Thanks!
You would need more information in order to make that decision. A set of (co-planar) points and a normal is not enough to give you a concept of "lower left" or "top right" or any such relative identification.
Viewing the polygon from the direction of the normal (so that it appears as a simple 2D shape) is a good start, but that shape could be rotated to any arbitrary angle.
Is there some other information in the 3D world that you can use to obtain a coordinate-system reference?
What are you trying to accomplish by knowing the extreme corners of the shape?
Are you looking for a bounding box?
I'm not sure the normal has anything to do with what you are asking.
To get a Bounding box, keep 4 variables: MinX, MaxX, MinY, MaxY
Then loop through all of your points, checking the X values against MaxX and MinX, and your Y values against MaxY and MinY, updating them as needed.
When looping is complete, your box is defined as MinX,MinY as the upper left, MinX, MaxY as upper right, and so on...
Response to your comment:
If you want your box after a projection, what you need is to get the "transformed" points. Then apply bounding box loop as stated above.
Transformed usually implies 2D screen coordinates after a projection(scene render) but it could also mean the 2D points on any plane that you projected on to.
A possible algorithm would be
Find the normal, which you can do by using the cross product of vectors connecting two pairs of different corners
Create a transformation matrix to rotate the polygon so that it is planer in XY space (i.e. normal alligned along the Z axis)
Calculate the coordinates of the bounding box or whatever other definition of corners you are using (as the polygon is now aligned in 2D space this is a considerably simpler problem)
Apply the inverse of the transformation matrix used in step 2 to transform these coordinates back to 3D space.
I believe that your question requires some additional information - namely the coordinate system with respect to which any point could be considered "topmost", or "leftmost".
Don't forget that whilst the normal tells you which way the polygon is facing, it doesn't on its own tell you which way is "up". It's possible to rotate (or "roll") around the normal vector and still be facing in the same direction.
This is why most 3D rendering systems have a camera which contains not only a "view" vector, but also "up" and "right" vectors. Changes to the latter two achieve the effect of the camera "rolling" around the view vector.
Project it onto a plane and get the bounding box.
I have a silly idea, but at the risk of gaining a negative a point, I'll give it a try:
Get the minimum/maximum value from
each three-dimensional axis of each
point on your 2d polygon. A single pass with a loop/iterator over the list of values for every point will suffice, simply replacing the minimum and maximum values as you go. The end result is a list that has the "lowest" X, Y, Z coordinates and "highest" X, Y, Z coordinates.
Iterate through this list of min/max
values to create each point
("corner") of a "bounding box"
around the object. The result
should be a box that always contains
the object regardless of axis
examined or orientation (no point on
the polygon will ever exceed the
maximum or minimums you collect).
Then get the distance of each "2d
polygon" point to each corner
location on the "bounding box"; the
shorter the distance between points,
the "closer" it is to that "corner".
Far from optimal, certainly crummy, but certainly quick. You could probably post-capture this during the object's rotation, by simply looking for the min/max of each rotated x/y/z value, and retaining a list of those values ahead of time.
If you can assume that there is some constraints regarding the shapes, then you might be able to get away with knowing less information. For example, if your shape was the composition of a small square with a long thin triangle on one side (i.e. a simple symmetrical geometry), then you could compare the distance from each list point to the "center of mass." The largest distance would identify the tip of the cone, the second largest would be the two points farthest from the tip of the cone, etc... If there was some order to the list, like points are entered in counter clockwise order (about the normal), you could identify all the points. This sounds like a bit of computation, so it might be reasonable to try to include some extra info with your shapes, like the "center of mass" and a reference point that is located "up" above the COM (but not along the normal). This will give you an "up" vector that you can cross with the normal to define some body coordinates, for example. Also, the normal can be defined by an ordering of the point list. If you can't assume anything about the shapes (or even if the shapes were symmetrical, for example), then you will need more data. It depends on your constraints.
If you know that the polygon in 3D is "flat" you can use the normal to transform all 3D-points of the vertices to a 2D-representation (of the points with respect to the plan in which the polygon is located) - but this still leaves you with defining the origin of this coordinate-system (but this don't really matter for your problem) and with the orientation of at least one of the axes (if you want orthogonal axes you can still rotate them around your choosen origin) - and this is where the trouble starts.
I would recommend using the Y-axis of your 3D-coordinate system, project this on your plane and use the resulting direction as "up" - but then you are in trouble in case your plan is orthogonal to the Y-axis (now you might want to use the projected Z-Axis as "up").
The math is rather simple (you can use the inner product (a.k.a. scalar product) for projection to your plane and some matrix stuff to convert to the 2D-coordinate system - you can get all of it by googling for raytracer algorithms for polygons.

Resources