(Follow-up of this question.)
Given a sequence of cubic Bézier curves, how can I modify them minimally to make them join in a C2-continuous way?
Input:
curve P with control points P0, P1, P2, P3
curve Q with control points Q0, Q1, Q2, Q3
if it helps, you can assume that they are already C1 continuous.
Constraints:
C0 continuity: P3 = Q0
C1 continuity: P2 - P3 = Q0 - Q1
C2 continuity: P1 - 2*P2 + P3 = Q0 - 2*Q1 + Q2
modified curves as close as possible to original curves P and Q
Getting the modified curves as close as possible to the originals can have multiple interpretations, but one could consider that keeping endpoints and tangents far from the joining points constant could fit. So the points P0, P1, P3 = Q0, Q2, Q3 are constant.
We can change the origin such that P3 = Q0 = 0, enforcing C2 continuity can then be expressed as:
P1 - 2*P2 = 2*Q1 + Q2
One can expressP2=a*e^i*r and Q1=b*e^i*r in complex representations (keeping the same angle enforces C2 continuity. Compute
(P1 - Q2)/2 = c*e^i*s
Enforcing C2 continuity should be choosing r=s, and finding a combination of a and b such that a+b =c. There are infinitely many solutions, but one might use heuristics such as changing a if it is the smallest (thus producing less sensible changes).
If that's not producing sufficiently small variations, try a two-step optimisation: first change P1 and Q2 to get s closer to r, then apply the steps above.
Related
My question is simple but i can't remember the "transformation" formula:
I have a surface S in a 3d world. I know the coordinate of all four corners (P1, P2, P3, P4) where P1 is (x1, y1, z1) ect.
Then a random rotation and translation yielding the same surface is applied.
I found the new coordinate of all four corners (Q1, Q2, Q3, Q4).
I already found the transfomation matrix for all this 4 point so (R1, T1), (R2, T2) ...
But, How can i found the universal transformation matrix for all points of S?
So, for example, i have coordinate of point P5 on our surface. How Can i found Q5?
Thanks
EDIT:
I found the answer, was really stupid sorry. The transformation matrix are different for each point because it is composed by Rmat x tvec . Rmat is equal for all point but tvec no, it change depending by where the rotation was applied. BUT yeah, all point are in relationship, I can use only the trasformation matrix of one of this point, P1 and apply this formula; Q2 = (R1,t1) x P1 + P2* where P2* is P2 coordinate respect P1 = P2 - P1
I have a room with four corners (c1, c2, c3, c4), for each of which I have coordinates.
A user takes a photosphere - a 360-degree image - in this room. (We do not have the coordinates of the photosphere's location.) They then identify the room corners by clicking on the image. This gives us four angles (a1, a2, a3, a4).
From this data, I would like to find the most likely location where the photosphere was taken, as xy coordinates. What's the best way to do this?
(Disclaimer: I'm a halfway competent programmer but not a great mathematician, so please excuse me if I need to follow up on any particular points of understanding. Thank you!)
Edit 1: I've been trying to get #meowgoesthedog's really helpful solution working. Here it is (in Ruby, but it'd be pretty much the same in any other language) with some sample data:
c1 = [70.38017162671083, 573.9210230366474]
c2 = [62.14926043346433, 573.9210230601221]
c3 = [62.170859502652874, 566.273256963365]
c4 = [70.41870117287603, 566.2827951694268]
a1 = 0.7162475014121918
a2 = 3.076344266497204
a3 = 4.964159781307695
a4 = 5.859686474799228
a = Math.sin(a1) +Math.sin(a2)
b =-Math.cos(a1) -Math.cos(a2)
c = Math.sin(a3) +Math.sin(a4)
d =-Math.cos(a3) -Math.cos(a4)
e = Math.sin(a1)*c1[0] + Math.sin(a2)*c2[0] - Math.cos(a1)*c1[1] - Math.cos(a2)*c2[1]
f = Math.sin(a3)*c3[0] + Math.sin(a4)*c4[0] - Math.cos(a3)*c3[1] - Math.cos(a4)*c4[1]
x = (d*e - b*f) / (a*d - b*c)
y = (a*f - c*e) / (a*d - b*c)
However, the results aren't what I'd expect: in this case, x is 77.29614012577807 and y is 551.2264007863547. Both of these are outside the bounding box of the room (roughly x 62-70, y 566-574) where the camera is placed.
Calculating the angle from x,y to the corners c1 c2 c3 c4, which should result in (roughly) a1 a2 a3 a4, comes up with very different results:
puts Math.atan2(c1[1]-y, c1[0]-x)
> 1.8665964276063274
Is there anything obvious you can see that I'm doing wrong? Thank you again!
I'm sure this is basic trigonometry, and I bet I covered at school many years ago, but I struggle knowing what function to apply to a real world situation. Anyway, rather than try and explain what I need help with, I've drawn a little diagram:
I know p1, p2, r1 and r2 but I can't remember (or know how to search for) how to work out what p3 and p4 are.
The basic application of this setup is I have 2 circles (red and blue) and I need them constantly connected as I drag them around the canvas. The pink link will connect them via their centre points but I don't want the line to penetrate the circle's circumferences.
Hope that makes sense? Thanks in advance.
this is simple vector math (no trigonometry needed)
create unit vector v with P1 to P2 direction
That is easy in vector form:
v=P2-P1; v/=|v|
And when put into 2D:
v.x=P2.x-P1.x;
v.y=P2.y-P1.y;
l=sqrt((v.x*v.x)+(v.y*v.y))
v.x/=l;
v.y/=l;
Now just translate from P1,P2by r1,r2
Vector form:
P3=P1+r1*v
P4=P2-r2*v
In 2D:
P3.x=P1.x+r1*v.x;
P3.y=P1.y+r1*v.y;
P4.x=P2.x-r2*v.x;
P4.y=P2.y-r2*v.y;
You have to solve the following equation system:
For p3 -->
(X-p1x)/(p1x-p2x)=(Y-p1y)/(p1y-p2y)
(X-p1x)^2 + (Y-p1y)^2 = r1^2
The same for p4 just change r1 for r2 and p1 for p4 in the second equation.
The first equation is the equation of a line given 2 points.
And the second equation is the equation of a circle given a center point and a radius.
The resulting X, Y values will be the values of p3, and then p4.
Let d be the distance between p1(x1, y1) and p2(x2,y2)
Thus
d = sqrt((x1-x2)^2 + (y1-y2)^2)
Now point p3(x3, y3) divides the line between p1 and p2 in the ratio of r1:(d-r1)
Thus
x3 = (r1*x2 + (d-r1)*x1)/d and
y3 = (r1*y2 + (d-r1)*y1)/d
Similarly for p4(x4, y4)
x4 = (r2*x1 + (d-r2)*x2)/d and
y4 = (r2*y1 + (d-r2)*y2)/d
What I am going to say is a little long. I will let you write your own code, however, of course will not help with that.
You know points P1, P2, and radius R1 and R2. Say suppose points P1 and P2 have coordinates (x1,y1) and (x2,y2) respectively.
The line connecting P1 and P2 is a straight line and hence you can calculate the slope of the line using the formula m=(y2-y1)/(x2-x1). Since you know the slope and know two coordinates, you can calculate the intercept c and construct a formula of the form y=mx+c.
Once the line formula is there, you can apply values for x and calculate y for point P3, lets say x3 and y3 since you have the radius R1. Similarly, calculate the coordinates for P4.
I need a help in writing the algorithm remove nodes Bezier curve. Using cubic Bezier curves, there are two curves (P0, P1, P2, P3 and Q0, Q1, Q2, Q3), which have a common point (P3=Q0). Need to get a single curve (P0, R1, R2, Q3), repeating the shape of two. How to find the coordinates of control points R1, R2?
Thank you!
In the general case, it's not possible to do what you're asking. You're asking to go from 7 degrees of freedom down to 4 but keep the same result. The representative power of the lower DOF system can't match that of the higher. The only time it would be possible is if the more complex curve still happened to lie in the simpler space. For example, if your two Bezier curves came from sub-dividing a single parent curve with points R0, R1, R2, R3. Using the de Casteljau algorithm, we can generate two new curves, P and Q, that lie on the same original curve and share a point that is t distance along the original curve (where t is in [0,1]).
P0 = R0
P1 = R0*(1-t) + R1*t
X = R1*(1-t) + R2*t
P2 = P1*(1-t) + X*t
Q3 = R3
Q2 = R2*(1-t) + R3*t
Q1 = X*(1-t) + Q2*t
Q0 = P3 = P2*(1-t) + Q1*t
If that relationship doesn't hold for your original points, then you'll have to craft an approximation. But you might get away with pretending that the relationship holds and just invert the equations:
R1 = (P1 - P0*(1-t))/t
R2 = (Q2 - Q3*t)/(1-t)
Where
t = (Q0 - P2)/(Q1 - P2)
This last equation is the problem because, unless P2, Q0, Q1 are co-linear it won't work exactly. t is a scalar, but Q1-P2 is normally an n-dimensional point. So you can solve it separately for each dimension and find the average, or be a bit more sophisticated and minimize the squared error.
I have a nice cubic spline code but it is for interpolation only. I need to extrapolate just a little into the future. Does anyone know of a good source of code, not a library, for doing this?
This is the code I wrote in basic (now ASM) for interpolation.
You don't need new code for that.
To extrapolate the spline you can extrapolate the parameters of the first and last spline.
Depending on your existing code/library that might not be possible without modifying the code. In that case just prepend/append two other points to the beginning/end of your list of points. You can get those two points by linearily interpolating between the first/last two points.
Be careful: Depending on the original meaning of the points that extrapolation might be completely inappropriate, especially when it comes to statistical data. In that case you should consider using regression analysis.
For simplicity, I'm going to represent a cubic Bezier curve
as 4 points (A, B, C, D),
where A and D are the endpoints of the curve,
and B and C are the "control handle points".
(The actual curve usually does not touch the control handle points).
See "Don Lancaster's Guru's Lair Cubic Spline Library"
for ways to convert this representation of a cubic Bezier curve
into other popular representations.
interpolation
Given one cubic Bezier curve (P0, P1, P2, P3),
we use De Casteljau's algorithm
to chop a Bezier curve into
a left half and a right half.
This is super-easy even on a microcontroller that doesn't have a "multiply" instruction,
because it only requires calculating a few averages until we get a midpoint:
P0
F0 := average(P0, P1)
P1 S0 := average(F0, F1)
F1 := average(P1, P2) Midpoint := average(S0, S1)
P2 S1 := average(F1, F2)
F2 := average(P2, P3)
P3
The entire Bezier curve is (P0, P1, P2, P3).
The left half of that entire Bezier curve is the Bezier curve (P0, F0, S0, M).
The right half of that entire Bezier curve is the Bezier curve (M, S1, F2, P3).
Many microcontrollers continue to divide each curve up
into smaller and smaller little curves
until each piece is small enough to approximate with
a straight line.
But we want to go the other way -- extrapolate out to a bigger curve.
extrapolation
Given either the left half or the right half,
we can run this in reverse to recover the original curve.
Let's imagine that we forgot the original points P1, P2, P3.
Given the left half of a Bezier curve (P0, F0, S0, M),
we can extrapolate to the right with:
S1 := M + (M - S0)
F1 := S0 + (S0 - F0)
P1 := F0 + (F0 - P0)
then use those values to calculate
F2 := S1 + (S1 - F1)
P2 := F1 + (F1 - P1)
and finally
P3 := F2 + (F2 - P2)
to extrapolate and recover the extrapolated Bazier curve (P0, P1, P2, P3).
details
The extrapolated curve (P0, P1, P2, P3)
passes through every point in the original curve
(P0, F0, S0, M) --
in particular, starting at P0 and passing through the midpoint M --
and keeps on going until it reaches P3.
We can always extrapolate from any 4 points (P0, F0, S0, M),
whether or not those 4 points were originally calculated
as the left half (or right half) of some larger Bezier spline.
I'm sure you already know this, but just for clarity:
Midpoint = average(F0, F1)
means "find the Midpoint exactly halfway between points F0 and F1",
or in other words,
Midpoint.x = (F0.x + F1.x)/2
Midpoint.y = (F0.y + F1.y)/2
Midpoint.z = (F0.z + F1.z)/2
The expression
S1 := M + (M - S0)
means "Given a line segment, with one end at S0, and the midpoint at M,
start at S0 and run in a straight line past M until you reach the other end at S1",
or in other words
(unless you have a decent vector library) 3 lines of code
S1.x := M.x + (M.x - S0.x)
S1.y := M.y + (M.y - S0.y)
S1.z := M.z + (M.z - S0.z)
.
(If you're doing 2D, skip all the "z" stuff -- it's always zero).
You'll really have to expand that question a little. Also, "cubic spline" is a very wide term.
If you're interested in splines, I can heartly reccomend Carl de Boors "A Practical Guide to Splines". It is however a little mathematically oriented, but it has code examples included (they can be downloaded from the author's home page). Googling and wikiing for "cubic spline" can bring up some examples, maybe even in particular languages - another thing to add to the question (if you're looking for code).
If you're interested in extrapolation and curve fitting, googling those could help. Matlab package has a very nice curve fitting toolbox. Wikipedia has some links to useful references
Really, it is too wide a question, to even start guessing an answer.
Also, could you explain what exactly are you trying to do ? What kind of data ? Anything ?
Edit1: Here, try this: you may find something useful in here - link
Generally for spline interpolation you use a variable t to interpolate over the line. As long as 0 <= t <= 1 you're interpolating. However, when t < 0 or t > 1 you're simply extrapolating the spline.
You need to write better requirements for requested code. Splines are usually used for interpolation of some unknown or complex function by using of some fixed data set. If you want to have an estimate of function's value outside of boundaries of this data set then you shouldn't use splines.
If your spline is function defined in the place where you really want to evaluate your value (cubic, but not piecewise-cubic) then you already can evaluate that value.
If you want to have ability to evaluate your spline outside of interpolation range, but leave it as piecewise-cubic function with the same values inside of interpolation range then you should extend spline range by some nodes, and add some logic of evaluation values at the new nodes (for example you want to have your spline be not only a continuous function, but also have some number of first derivatives be also continuous functions)
Really I suggest you to use some algorithm more suitable for extrapolation, like usage of Lagrange polynomial if everything you really need is single value not very far from points of original data set.