So the first problem will be explaining what I am after clearly.
I have two non-rational 3D b-splines. The first b-spline it the guiding spline. The second b-spline is a reference and it is essentially 'inside' of the first spline. ( the splines were generated in Solidworks )
Imagine a circular playground slide. The first spline is the center line of the slide. The second spline is the inside edge of the slide.
The inside spline will tend to be shorter than the center spline. The inside will also tend to have more curvature at any given point than the center.
The path of the slide is not perfectly circular. But the inside spline is always 'parallel' to the outside. ( very liberal use of the word parallel here )
What I am after:
Given a point along the center curve, I would like to find the point on the inside curve that is on the plane that is defined by the normal to the tangent of the center spline at that point.
Where I am at:
I am using the geomdl library in python to manipulate the splines.
I can choose a distance along the center spline and from geomdl I get the 3D point and the tangent vector (A,B,C) of that point and therefore the plane at that point that is normal to the spline at that point.
What I am doing:
From the tangent vector and the point I compute the equation of the plane in the form of:
Ax + By + Cz = D.
From there I guess at the point at the same distance on the inside spline and plug it into the equation for the plane that I already have. I use the error in D to guess at which way I should bump my guess on where the point on the inside curve might really be.
[ I understand that over the entire length of the two splines there may be more than one solution. i.e. if the curve wraps more than 180° there would be more than one point on the inside curve that lands on the plane defined by the center curve. In the local area that i am interested in this will not be a problem. Any second point would also be a long ways away from the center line. i.e. the correct point will be no more than 25 mm from the center point. A non-local point will be at least 3000 mm away. ]
This mostly works. But from time to time it fails. i.e. if D is very near 0 my guesses will diverge from the answer.
Currently I make 10 guesses, each guess having a smaller delta guess than the last.
I have a great number of these points to evaluate. My solution requires 10 X the number of calculations so it is not terribly efficient.
From my Google searches I believe that using the error in D in the equation of a plane may not be correct. I 'think' that D is the distance of the plane to the origin.(yes /no?) Therefore I am really comparing the distance of the two planes from the origin and not really from each other. If my guess happens to be on the "other side" of the origin then the distance's may be the same but opposite.
My Question:
What is the correct way to go about this?
Is my assumption that D is the distance from the plane to the origin?
Is driving the error in D between the two points valid?
What is the correct way to do this?
Restate my question in different terms
Given a plane (Ax + By + Cz = D) how do I find the point on a given b-spline that pierces ( or is coincident to ) that plane (using geomdl.bcurve)?
( I am very much in over my head here so please forgive if this does not make sense )
Say I want to construct a 3D cubic Bézier curve, and I already have both end-points, and the direction (normal vector) for both control points. How can I choose the distance of both control points to their respective end-points in order to make the curve as 'nicely rounded' as possible?
To formalize 'nicely rounded': I think that means maximizing the smallest angle between any two segments in the curve. For example, having end-points (10, 0, 0) and (0, 10, 0) with respective normal vectors (0, 1, 0) and (1, 0, 0) should result in a 90° circular arc. For the specific case of 2D circular arcs, I've found articles like this one. But I haven't been able to find anything for my more general case.
(Note that these images are just to illustrate the 'roundness' concept. My curves are not guaranteed to be plane-aligned. I may replace the images later to better illustrate that point.)
This is a question of aesthetics, and if the real solution is unknown or too complicated, I would be happy with a reasonable approximation. My current approximation is too simplistic: choosing half the distance between the two end-points for both control point distances. Someone more familiar with the math will probably be able to come up with something better.
(PS: This is for open-source software, and I would be happy to give credit on GitHub.)
Edit: Here are some other images to illustrate a 3D case (jsfiddle):
Edit 2: Here's a screenshot of an unstable version of ApiNATOMY to give you an idea of what I'm trying to do. I'm creating 3D tubes to represent blood-vessels, connecting different parts of an anatomical schematic:
(They won't let me put in a jsfiddle link if I don't include code...)
What you are basically asking is to have curvature over the spline as constant as possible.
A curve with constant curvature is just a circular arc, so it makes sense to try to fit such an arc to your input parameters. In 2D, this is easy: construct the line which goes through your starting point and is orthogonal to the desired direction vector. Do the same for the ending point. Now intersect these two lines: the result is the center of the circle which passes through the two points with the desired direction vectors.
In your example, this intersection point would just be (0,0), and the desired circular arc lies on the unit circle.
So this gives you a circular arc, which you can either use directly or use the approximation algorithm which you have already cited.
This breaks down when the two direction vectors are collinear, so you'd have to fudge it a bit if this ever comes up. If they point at each other, you can simply use a straight line.
In 3D, the same construction gives you two planes passing through the end points. Intersect these, and you get a line; on this line, choose the point which minimizes the sum of squared distances to the two points. This gives you the center of a sphere which touches both end points, and now you can simply work in the plane spanned by these three points and proceed as in 2D.
For the special case where your two end points and the two known normal vector for the control points happen to make the Bezier curve a planar one, then basically you are looking for a cubic Bezier curve that can well approximate a circular arc. For this special case, you can set the distance (denoted as L) between the control point and their respective end point as L = (4/3)*tan(A/4) where A is the angle of the circular arc.
For the general 3D case, perhaps you can apply the same formula as:
compute the angle between the two normal vectors.
use L=(4/3)*tan(A/4) to decide the location of your control points.
if your normals are aligned in a plane
What you're basically doing here is creating an elliptical arc, in 3D, where the "it's in 3D" part is completely irrelevant, since it's just a 2D curve, rotated/translated to sit in your 3D space. So let's just solve the 2D case, and then the RT is entirely up to you.
Creating the "perfect" cubic Bezier between two points on an arc comes with limitations. You basically can't create good looking arcs that span more than a quarter circle. So, with that said: your start and end point normals give you a 2D angle between your normal vectors, which is the same angle as between your start and end tangents (since normals are perpendicular to tangents). So, let's:
align our curve so that the tangent at the start is 0
plug the angle between tangents into the formula given in the section on Circle approximation in the Primer on Bezier curves. This is basically just dumb "implementing the formula for c1x/c1y/c2x/c2y as a function that takes an angle as argument, and spits out four values as c1(x,y) and c2(x,y) coordinats".
There is no step 3, we're done.
After step 2, you have your control points in 2D to create the most circular arc between a start and end point. Now you just need to scale/rotate/translate it in 3D so that it lines up with where you needed your start and end point to begin with.
if your normals are not aligned in a plane
Now we have a problem, although one that we can deal with by treating the dimensions as separate things entirely. Instead of creating a single 2D curve, we're going to create three: one that's the X/Y projection, one that's the X/Z projection, and one that's the Y/Z projection. For all three of these, we're going to abstract the control points in exactly the same way as before, and then we simply take the projective control points (three for each control point), and then go "okay, we now have X, Y, and Z projective coordinates. That means we have (X,Y,Z) coordinates", and done again.
I'm making a program in which many weird shapes are drawn onto a canvas. Right now i'm trying to implement the last, and possebly hardest, one.
In this particular shape i need a way to find the location (on a 2d canvas) where the line hits the shape. The following image is an example of what i have right now.
The black dots are the points that a known to me (i also have the location of the center of the three open circles and the radius of these circles). Each of the three outer lines needs a line towards the center dot, ending at the point that it hits the circle. This shape can be turned 90, 180 or 270 degrees.
The shape should look something like the following:
If you need any other information, please ask me in the comments. I'm not very good at math so please be gentle, thanks!
If A and B are points forming a line, then you can describe any point on that line using coordinates:
x = t·Ax + (1−t)·Bx
y = t·Ay + (1−t)·By
0 ≤ t ≤ 1
You can also describe the circle with center M and radius r as
(x − Mx)2 + (y − My)2 = r2
So take the x and y from the equations of the line, and plug them into the equation of the circle. You obtain a quadratic equation in t. Its two solutions describe the two points of intersection between the line and circle. In your example, only one of them lies on the line segment, i.e. satisfies 0 ≤ t ≤ 1. The other describes a point on the extension of the segment past its endpoint. Take the correct value for t back to the equations of the line, and you obtain the x and y coordinates of the point of intersection.
If you don't know up front which circle you want to intersect with a given line, then intersect all three and choose the most appropriate point afterwards. Probably that is the point closest to the outside starting point of the line segment. The same goes in cases where both points of intersection lie on the segment.
I'm trying to figure out the most efficient/fast way to add a large number of convex quads (four given x,y points) into an array/list and then to check against those quads if a point is within or on the border of those quads.
I originally tried using ray casting but thought that it was a little overkill since I know that all my polygons will be quads and that they are also all convex.
currently, I am splitting each quad into two triangles that share an edge and then checking if the point is on or in each of those two triangles using their areas.
for example
Triangle ABC and test point P.
if (areaPAB + areaPAC + areaPBC == areaABC) { return true; }
This seems like it may run a little slow since I need to calculate the area of 4 different triangles to run the check and if the first triangle of the quad returns false, I have to get 4 more areas. (I include a bit of an epsilon in the check to make up for floating point errors)
I'm hoping that there is an even faster way that might involve a single check of a point against a quad rather than splitting it into two triangles.
I've attempted to reduce the number of checks by putting the polygon's into an array[,]. When adding a polygon, it checks the minimum and maximum x and y values and then using those, places the same poly into the proper array positions. When checking a point against the available polygons, it retrieves the proper list from the array of lists.
I've been searching through similar questions and I think what I'm using now may be the fastest way to figure out if a point is in a triangle, but I'm hoping that there's a better method to test against a quad that is always convex. Every polygon test I've looked up seems to be testing against a polygon that has many sides or is an irregular shape.
Thanks for taking the time to read my long winded question to what's prolly a simple problem.
I believe that fastest methods are:
1: Find mutual orientation of all vector pairs (DirectedEdge-CheckedPoint) through cross product signs. If all four signs are the same, then point is inside
Addition: for every edge
EV[i] = V[i+1] - V[i], where V[] - vertices in order
PV[i] = P - V[i]
Cross[i] = CrossProduct(EV[i], PV[i]) = EV[i].X * PV[i].Y - EV[i].Y * PV[i].X
Cross[i] value is positive, if point P lies in left semi-plane relatively to i-th edge (V[i] - V[i+1]), and negative otherwise. If all the Cross[] values are positive, then point p is inside the quad, vertices are in counter-clockwise order. f all the Cross[] values are negative, then point p is inside the quad, vertices are in clockwise order. If values have different signs, then point is outside the quad.
If quad set is the same for many point queries, then dmuir suggests to precalculate uniform line equation for every edge. Uniform line equation is a * x + b * y + c = 0. (a, b) is normal vector to edge. This equation has important property: sign of expression
(a * P.x + b * Y + c) determines semi-plane, where point P lies (as for crossproducts)
2: Split quad to 2 triangles and use vector method for each: express CheckedPoint vector in terms of basis vectors.
P = a*V1+b*V2
point is inside when a,b>=0 and their sum <=1
Both methods require about 10-15 additions, 6-10 multiplications and 2-7 comparisons (I don't consider floating point error compensation)
If you could afford to store, with each quad, the equation of each of its edges then you could save a little time over MBo's answer.
For example if you have an inward pointing normal vector N for each edge of the quad, and a constant d (which is N.p for one of the vertcies p on the edge) then a point x is in the quad if and only if N.x >= d for each edge. So thats 2 multiplications, one addition and one comparison per edge, and you'll need to perform up to 4 tests per point.This technique works for any convex polygon.
My question is fairly simple. I have two tetrahedra, each with a current position, a linear speed in space, an angular velocity and a center of mass (center of rotation, actually).
Having this data, I am trying to find a (fast) algorithm which would precisely determine (1) whether they would collide at some point in time, and if it is the case, (2) after how much time they collided and (3) the point of collision.
Most people would solve this by doing triangle-triangle collision detection, but this would waste a few CPU cycles on redundant operations such as checking the same edge of one tetrahedron against the same edge of the other tetrahedron upon checking up different triangles. This only means I'll optimize things a bit. Nothing to worry about.
The problem is that I am not aware of any public CCD (continuous collision detection) triangle-triangle algorithm which takes self-rotation in account.
Therefore, I need an algorithm which would be inputted the following data:
vertex data for three triangles
position and center of rotation/mass
linear velocity and angular velocity
And would output the following:
Whether there is a collision
After how much time the collision occurred
In which point in space the collision occurred
Thanks in advance for your help.
The commonly used discrete collision detection would check the triangles of each shape for collision, over successive discrete points in time. While straightforward to compute, it could miss a fast moving object hitting another one, due to the collision happening between discrete points in time tested.
Continuous collision detection would first compute the volumes traced by each triangle over an infinity of time. For a triangle moving at constant speed and without rotation, this volume could look like a triangular prism. CCD would then check for collision between the volumes, and finally trace back if and at what time the triangles actually shared the same space.
When angular velocity is introduced, the volume traced by each triangle no longer looks like a prism. It might look more like the shape of a screw, like a strand of DNA, or some other non-trivial shapes you might get by rotating a triangle around some arbitrary axis while dragging it linearly. Computing the shape of such volume is no easy feat.
One approach might first compute the sphere that contains an entire tetrahedron when it is rotating at the given angular velocity vector, if it was not moving linearly. You can compute a rotation circle for each vertex, and derive the sphere from that. Given a sphere, we can now approximate the extruded CCD volume as a cylinder with the radius of the sphere and progressing along the linear velocity vector. Finding collisions of such cylinders gets us a first approximation for an area to search for collisions in.
A second, complementary approach might attempt to approximate the actual volume traced by each triangle by breaking it down into small, almost-prismatic sub-volumes. It would take the triangle positions at two increments of time, and add surfaces generated by tracing the triangle vertices at those moments. It's an approximation because it connects a straight line rather than an actual curve. For the approximation to avoid gross errors, the duration between each successive moments needs to be short enough such that the triangle only completes a small fraction of a rotation. The duration can be derived from the angular velocity.
The second approach creates many more polygons! You can use the first approach to limit the search volume, and then use the second to get higher precision.
If you're solving this for a game engine, you might find the precision of above sufficient (I would still shudder at the computational cost). If, rather, you're writing a CAD program or working on your thesis, you might find it less than satisfying. In the latter case, you might want to refine the second approach, perhaps by a better geometric description of the volume occupied by a turning, moving triangle -- when limited to a small turn angle.
I have spent quite a lot of time wondering about geometry problems like this one, and it seems like accurate solutions, despite their simple statements, are way too complicated to be practical, even for analogous 2D cases.
But intuitively I see that such solutions do exist when you consider linear translation velocities and linear angular velocities. Don't think you'll find the answer on the web or in any book because what we're talking about here are special, yet complex, cases. An iterative solution is probably what you want anyway -- the rest of the world is satisfied with those, so why shouldn't you be?
If you were trying to collide non-rotating tetrahedra, I'd suggest a taking the Minkowski sum and performing a ray check, but that won't work with rotation.
The best I can come up with is to perform swept-sphere collision using their bounding spheres to give you a range of times to check using bisection or what-have-you.
Here's an outline of a closed-form mathematical approach. Each element of this will be easy to express individually, and the final combination of these would be a closed form expression if one could ever write it out:
1) The equation of motion for each point of the tetrahedra is fairly simple in it's own coordinate system. The motion of the center of mass (CM) will just move smoothly along a straight line and the corner points will rotate around an axis through the CM, assumed to be the z-axis here, so the equation for each corner point (parameterized by time, t) is p = vt + x + r(sin(wt+s)i + cos(wt + s)j ), where v is the vector velocity of the center of mass; r is the radius of the projection onto the x-y plane; i, j, and k are the x, y and z unit vectors; and x and s account for the starting position and phase of rotation at t=0.
2) Note that each object has it's own coordinate system to easily represent the motion, but to compare them you'll need to rotate each into a common coordinate system, which may as well be the coordinate system of the screen. (Note though that the different coordinate systems are fixed in space and not traveling with the tetrahedra.) So determine the rotation matrices and apply them to each trajectory (i.e. the points and CM of each of the tetrahedra).
3) Now you have an equation for each trajectory all within the same coordinate system and you need to find the times of the intersections. This can be found by testing whether any of the line segments from the points to the CM of a tetrahedron intersects the any of the triangles of another. This also has a closed-form expression, as can be found here.
Layering these steps will make for terribly ugly equations, but it wouldn't be hard to solve them computationally (although with the rotation of the tetrahedra you need to be sure not to get stuck in a local minimum). Another option might be to plug it into something like Mathematica to do the cranking for you. (Not all problems have easy answers.)
Sorry I'm not a math boff and have no idea what the correct terminology is. Hope my poor terms don't hide my meaning too much.
Pick some arbitrary timestep.
Compute the bounds of each shape in two dimensions perpendicular to the axis it is moving on for the timestep.
For a timestep:
If the shaft of those bounds for any two objects intersect, half timestep and start recurse in.
A kind of binary search of increasingly fine precision to discover the point at which a finite intersection occurs.
Your problem can be cast into a linear programming problem and solved exactly.
First, suppose (p0,p1,p2,p3) are the vertexes at time t0, and (q0,q1,q2,q3) are the vertexes at time t1 for the first tetrahedron, then in 4d space-time, they fill the following 4d closed volume
V = { (r,t) | (r,t) = a0 (p0,t0) + … + a3 (p3,t0) + b0 (q0,t1) + … + b3 (q3,t1) }
Here the a0...a3 and b0…b3 parameters are in the interval [0,1] and sum to 1:
a0+a1+a2+a3+b0+b1+b2+b3=1
The second tetrahedron is similarly a convex polygon (add a ‘ to everything above to define V’ the 4d volume for that moving tetrahedron.
Now the intersection of two convex polygon is a convex polygon. The first time this happens would satisfy the following linear programming problem:
If (p0,p1,p2,p3) moves to (q0,q1,q2,q3)
and (p0’,p1’,p2’,p3’) moves to (q0’,q1’,q2’,q3’)
then the first time of intersection happens at points/times (r,t):
Minimize t0*(a0+a1+a2+a3)+t1*(b0+b1+b2+b3) subject to
0 <= ak <=1, 0<=bk <=1, 0 <= ak’ <=1, 0<=bk’ <=1, k=0..4
a0*(p0,t0) + … + a3*(p3,t0) + b0*(q0,t1) + … + b3*(q3,t1)
= a0’*(p0’,t0) + … + a3’*(p3’,t0) + b0’*(q0’,t1) + … + b3’*(q3’,t1)
The last is actually 4 equations, one for each dimension of (r,t).
This is a total of 20 linear constraints of the 16 values ak,bk,ak', and bk'.
If there is a solution, then
(r,t)= a0*(p0,t0) + … + a3*(p3,t0) + b0*(q0,t1) + … + b3*(q3,t1)
Is a point of first intersection. Otherwise they do not intersect.
Thought about this in the past but lost interest... The best way to go about solving it would be to abstract out one object.
Make a coordinate system where the first tetrahedron is the center (barycentric coords or a skewed system with one point as the origin) and abstract out the rotation by making the other tetrahedron rotate around the center. This should give you parametric equations if you make the rotation times time.
Add the movement of the center of mass towards the first and its spin and you have a set of equations for movement relative to the first (distance).
Solve for t where the distance equals zero.
Obviously with this method the more effects you add (like wind resistance) the messier the equations get buts its still probably the simplest (almost every other collision technique uses this method of abstraction). The biggest problem is if you add any effects that have feedback with no analytical solution the whole equation becomes unsolvable.
Note: If you go the route of of a skewed system watch out for pitfalls with distance. You must be in the right octant! This method favors vectors and quaternions though, while the barycentric coords favors matrices. So pick whichever your system uses most effectively.