This question already has answers here:
Calculate depth of indentation in an model using three point system?
(2 answers)
Closed 4 years ago.
Via Raycasting one can select a point on an GameObjects Collider. In the short visual two points are represented with small spheres denoting user selection. The desire is to calculate the depth of any spot in an models indentation. Current thought is to use a system in which the user selects a point within the depth of the indentation and a point outside of it than calculating the depth using Vector math.
As of now, the information available to us is the two points (Vectors) in space and the distance between them. How do we use the aforementioned data to calculate a point perpendicular to the point in the depth? Thought being if this point is calculable than the depth would be the distance between those two points. How to go about this, and is it feasible?
Visual:
I don't think that 2 points are enough. You, seeing the whole scene, know the planes where both points lie so you can see the direction of the shortest distance (perpendicular) segment. But just for two points there are infinitely many other valid planes going through them. The only thing you can say is that the depth is bound by the distance between those two points.
Consider following example: one point A is (0,0,0) and B is (2,1,0). How deep is the indentation? The answer is: you don't know.
Assume first that the planes are (the plane a contains the point A and the plane b contains the point B):
a is X = 0 while b is X = 2. Then the indentation depth is clearly 2.
a is Y = 0 while b is Y = 1. Then the indentation depth is clearly 1.
finally if a is Z = 0 and b is Z = 0. Then the indentation depth is clearly 0.
Actually change the planes direction you can get any depth between 0 and the distance between A and B.
The only solution I see is to fix at least one of the two planes by selecting 3 points on that plane. And then the problem becomes trivial. Having 3 points you find the plane equation in a form of
a*x + b*y + c*z + d = 0
Then the distance from a point (x1,y1,z1) to that plane is
dist = (a*x1 + b*y1 + c*z1 + d)/sqrt(a^2+b^2+c^2)
Related
I have a polyline composed of multiple line segments. The line is very complex and squiggles all over the place in 3D, so for simplicity's sake let's say it looks something like this
I want to render it in 3D. Currently, I do a very simple process where I just generate a cylinder for each segment:
This is decent, but looks bad where the line changes direction. It is also wasteful - each of the direction changes requires twices as many vertices as is strictly necessary. I would be much happier with an approach that generated shapes like this:
At first I didn't think it would be too hard, but the more I've worked on it the more I've found it to be surprisingly nontrivial. I'm working in C#, and if this were in 2D I would just use Clipper, but I can't find any libraries or resources for how to solve this problem in 3D. It's okay if the solution isn't always perfect or sometimes leads to self-intersections or things of that nature. Anyone have any guidance?
So in a mathematical sense, the intersection of two cylinders is an ellipse. If I give you where the semi-major axis point on the ellipse is and the semi-minor axis you could calculate any number (like numsides) nodes on the ellipse.
Take the node connecting two segments located at a point p and define the two vectors of the ellipse as follows. a is the semi-major axis and b is the semi-minor axis
Each joining line segment has unit directions vectors e_1 and e_2 and the cylinder has radius R.
Then the intersection ellipse would be defined from the vectors a and b:
Then find a point c around the ellipse use the following parameterization with t = 0..1
Here is some C# code that calculates numsides points around the ellipse
// Vectors p, a, b defined
for(int i=0; i<numsides; i++)
{
double t = (1.0*i)/numsides
Vector c = p + a*Math.Cos(2*Math.PI*t) + b*Math.Sin(2*Math.PI*t)
// use/store c as needed for the mesh generation
}
I found this site which had an elegant solution. Starting with some points around the first line segment making up your polyline, you compute the intersection of the line parallel to the current segment that passes through each point and the plane formed by the intersection of the two current line segments.
If a circle is defined by the X, Y of it's center and a Radius, then how can I find a Circle that encompasses a given number of circles? A single circle that is the smallest possible circle to completely contain 2 or more circles of any size and location.
At first I tried just encompassing 2 circles by finding the midpoint of the centers and that being the midpoint of the new circle while the radius was equal to the half of the radius of the 2 initial circles and half the distance between their centers, but somehow it always turned out to be a little off. The problem always seemed to be a problem with finding the radius, but I have such a headache about this I can't make it work.
I don't necessarily need a method for finding a circle that encompasses 3 or more circles. I can find a circle that encompasses 2, take that circle and encompass it with another, and another, and the final circle should encompass all circles given throughout the steps.
Given two circles, with centers [x1,y1], [x2,y2], and radii R1 and R2. What is the center of the enclosing circle?
Assume that R1 is no larger than R2. If the second circle is the smaller, then just swap them.
Compute the distance between centers of the circles.
D = sqrt((x1-x2)^2 + (y1-y2)^2)
Does the first circle lie entirely inside the second circle? Thus if (D + R1) <= R2, then we are done. Return the larger circle as the enclosing circle, with a center of [x2,y2], with radius R2.
If (D+R1) > R2, then the enclosing circle has a radius of (D+R1+R2)/2
In this latter case, the center of the enclosing circle must lie along the line connecting the two centers. So we can write the new center as
center = (1-theta)*[x1,y1] + theta*[x2,y2]
where theta is given by
theta = 1/2 + (R2 - R1)/(2*D)
Note that theta will always be a positive number, since we have assured that (D+R1) > R2. Likewise, we should be able to ensure that theta is never larger than 1. These two conditions ensure that the enclosing center lies strictly between the two original circle centers.
There problem you have at hand is called Smallest enclosing sphere of spheres. I have written my thesis about it, see "Smallest enclosing ball of balls", ETH Zurich.
You can find a very efficient C++ implementation in the Computational Geometry Algorithms Library (CGAL) in package Bounding Volumes. (There is no need to use all of CGAL; just extract the required source and header files and you are up and running.)
Note: If you are looking for an algorithm to compute the smallest enclosing sphere of points only, there are other implementations out there, see this post.
Since my inexact solution was not liked. Heres a way to get the exact solution. But its slow ( O(N^4)? ) and computationally nasty. (Unlike the inexact method)
First you need to know that given three circles we can find a circle tangential to them all than contains all three. This is one of the circles of Apollonius. You can get the algorithm from mathworld.
Next you can show that the smallest enclosing circle for N circles is tangential to at least 3 of the N circles.
To find this circle we do the following
loop through all triples of circles - O(N^3)
find the enclosing Apollonius circle of those 3 circles - computationally nasty
if it encloses all the circles add it to a list of potentials - check is O(N)
Solution is potential with smallest radius
There may be some tricks to speed this up, but it should give you the exact solution.
Some of the "tricks" for getting Smallest Enclosing Circle algorithms to linear time may be applicable here, but I suspect they would not be trivial adaptions.
I'm going to recommend against this, now
See the discussion below.
Original thoughts
I would consider an iterative push-pull method.
Guess where to put the center (simplest would be the mean position of all centers)
Compute the vectors to the farthest point on each circle. These are always in the direction to the center of that circle and have length distance_to_center_of_circle[i]+radius_of_circle[i] and form the vector sum as you go. Also note that the necessary radius at the current location is the maximum of these lengths.
Propose a step of (say) 1/5 or 1/10 of the vector sum from 2, and redo the computations from 2 for the new point
If the new point needs a smaller circle than the old, make the new point the current point, otherwise, split the difference, reduce the size of the proposed step (say half it).
goto 3
You're done when it stops[+] converging.
Nikie poked at it until...
As requested clarifying step two. Call the position to be tested \vec{P} (a vector quantity).[++] Call the centers of each circle \vec{p}_i (also vector quantities) and the radius of each circle is r_i. Form the sum \sum_i=1^n \hat{p_i - P}*|(p_i-P)|+r_i).[+++] Each element of the sum points in the direction from the current evaluation point towards the center of the circle in question, but is longer by r_i. The sum itself it a vector quantity.
The radius R need to enclose all the circle from P is the max(|p_i-P|_r_i).
Pathological case
I don't think the particular case nikie's brought up is a problem, but it has put me onto a case where this algorithm fails. The failure is one of failing to improve a solution, rather than one of diverging, but still...
Consider four circles all of radius 1 positioned at
(-4, 1)
(-5, 0)
(-4, 1)
( 5, 0)
and a starting position of (-1, 0). Symmetric by design so that all distances lie along the x axis.
The correct solution is (0, 0) with radius 6, but the vector calculated in step 2 be about ::calculates furiously:: (-.63, 0), pointing in the wrong direction resulting in never finding the improvement towards the origin.
Now, the algorithm above would actual pick (-2, 0) for the starting point, which gives an initial vector sum of ::calculates furiously:: about +1.1. So, a bad choice of step size on (3) would result in a less than optimal solution. ::sigh::
Possible solution:
In (3) throw a random fraction between (say +1/5 and -1/5) possibly weighted towards the positive size.
In (4) if the step is rejected, simply return to step three without altering the step size limits.
However, at this point it is not much better than a pure random walk, and you don't have an easy condition for knowing when it has converged. Meh.
[+] Or slows to your satisfaction, of course.
[++] Using latex notation.
[+++] Here \hat{} means the normalized vector pointing in the same direction as the argument.
I've taken what some of you had to say and here's the solution I discovered:
public static Circle MinimalEnclosingCircle(Circle A, Circle B) {
double angle = Math.Atan2(B.Y - A.Y, B.X - A.X);
Point a = new Point((int)(B.X + Math.Cos(angle) * B.Radius), (int)(B.Y + Math.Sin(angle) * B.Radius));
angle += Math.PI;
Point b = new Point((int)(A.X + Math.Cos(angle) * A.Radius), (int)(A.Y + Math.Sin(angle) * A.Radius));
int rad = (int)Math.Sqrt(Math.Pow(a.X - b.X, 2) + Math.Pow(a.Y - b.Y, 2)) / 2;
if (rad < A.Radius) {
return A;
} else if (rad < B.Radius) {
return B;
} else {
return new Circle((int)((a.X + b.X) / 2), (int)((a.Y + b.Y) / 2), rad);
}
}
Circle is defined by the X, Y of it's center and a Radius, all are ints. There's a constructor that is Circle(int X, int Y, int Radius). After breaking out some old trig concepts, I figured the best way was to find the 2 points on the circles that are farthest apart. Once I have that, the midpoint would be the center and half the distance would be the radius and thus I have enough to define a new circle. If I want to encompass 3 or more circles, I first run this on 2 circles, then I run this on the resulting encompassing circle and another circle and so on until the last circle is encompassed. There may be a more efficient way to do this, but right now it works and I'm happy with that.
I feel weird answering my own question, but I could not have come to this solution without everybody's ideas and links. Thanks everybody.
So if you don't need the exact circle this approximation might do.
Take the average of all your centers of the circles call this
point X
Let R1 be the maximum distance from X to a circle center.
Let R2 be the maximum radius of the circles
The all the circles must fall inside the circle centered at X with radius R1+R2
This is not a trivial problem. I haven't read all the answers above, so if I repeat what someone has already said, the fault is mine.
Each circle c_i is defined by 3 parameters x_i,y_i,r_i
3 parameters need to be found x*,y*,r* for the optimal circle C*
C* is such that it contains c_i for all i
Let d_i = ||(x,y)-(x_i,y_i)|| + r_i
Then if r is radius of a circle that contains all c_i, then r >= d_i for all i
We want r to be as small as possible
So, r* = max(d_i)
Thus we want to minimize the max of d_i
So (x*,y*) are given by the arg min of max(d_i). And once (x*,y*) are found, r* can be readily computed and will equal max(d_i). This is a minimax problem.
To make things easier to understand consider just 2 circles, how can we find (x*,y*)?
(x*,y*) can be found by finding the (x,y) that minimize (d_1 - d_2)^2. In the general case
let e_ij = (d_i - d_j)^2
Then define e = \sum e_ij for i != j (there are n Choose 2 terms in this sum)
(x*,y*) = arg min of e
And this is what needs to be solved for.
Tip: if r_i = 0 for all i, then this reduces to the traditional minimum enclosing circle problem when the input is a bunch of points, and we want to find minimum circle that covers all of them.
Just understand the equations of the circle and derive an equation (or a series) for find the answer then start implementing. Perhaps we will be able to help you in that given you have done something.
Given a 3D solid model and an edge, I am testing whether that edge is concave or convex.
What is the best way to do this? I'd like to minimize the assumptions regarding the input geometry. My first pass at the problem takes the average of the vertices of the two adjacent faces to generate center points, offsets one of those points by the face normal at that point, and tests whether the offset point is closer or farther to the opposing face than the original. This works for pairs of simple faces, approximately the same size. It fails, for example, with small faces far from the center of larger faces.
I'm doing this in Revit, but I imagine the problem is the same in Rhino, Catia, any solid modeler. From the edge I can extract the adjacent faces. I know the faces are oriented correctly such that the normals point outward. I can project 3D points to the faces, calculate normals of the faces at those points, etc.
Here's the code for the naive version:
public static Boolean AreFacesConcave(Face face_0, Face face_1, Document doc)
{
UV uvMid_0 = VertexAverageUV( face_0 ); //3D average of the vertices
UV uvMid_1 = VertexAverageUV( face_1 ); // approximates the center of the face
XYZ pt_0 = face_0.Evaluate(uvMid_0);
XYZ pt_1 = face_1.Evaluate(uvMid_1);
// normals at those points
XYZ normal_0 = face_0.ComputeNormal(uvMid_0);
XYZ normal_1 = face_1.ComputeNormal(uvMid_1);
// third point, offset from face 2 by normal
XYZ pt_2 = pt_1.Add(normal_1.Normalize());
Double d0 = pt_0.DistanceTo(pt_1);
Double d1 = pt_0.DistanceTo(pt_2);
return (d1 < d0);
}
If you know that normal vectors always are outward, get two points A and B inside two adjacent faces (either mean of three non-collinear vertices or your 'center points').
Then check the sign of dot (scalar) product of vectors AB and nA (normal to the face containing point A).
Result = DotProduct(AB, nA)
Negative sign denotes 'convex' edge, positive - 'concave' one.
2D example: nA is outward normal, D-edge for CDF is concave, D-edge for CDE is convex
I suppose by distance I mean radius, so another way of phrasing it would be "how do I get random points on the circumference of a circle of a given radius, given also the circles centre point".
I don't understand the markdowns. This is a simple C# question that requires a simple C# answer as provided adequately by Daniel DiPaolo below.
Neither the markdowns nor the associated comments are helpful by way of improving the question or providing an answer.
If your center and radius are fixed, then really the only thing that's varying is the angle. So, just calculate some random angle between 0 and 360 degrees (or 0 and 2π radians) and use that to get the x-y coordinates using the polar conversion.
x = r × cos( θ )
y = r x sin( θ )
Add the x,y coords of your center as the offset and you have your coordinates.
Calculate a random angle and then use the angle and distance as a polar offset from the first point.
Have a look at Circle Point Tracking there's a few methods for picking points.
Algorithmic code
Given circle of {[0,0], 1} - {centre, radius}
x => Get random number x from [-1, 1]
y+ or y- => Randomly select either positive or negative y quarter (0 or 1 for example)
y => Get intersection of vertical line x=X1 (from step 1) and circle, select either positive or negative quarter (from step 2)
NB This is can be done simpler, faster, and more uniformly distributed by using angles, see other answers.
The problem with my algorithm, in case anyone would try to use it, is that because of the bending shape of a circle, points close to X=r+ and X=r- will be picked up less often than the one close to X=0. See comments by #Servy.
I am working on a C# 2d soft body physics engine and I need to assign masses to an object's vertices given: a list of vertices (x,y positions), the total mass for the object, and the center of mass.
The center of mass is given as:
where,
R = center of mass
M = total mass
mj = mass of vertex j
rj = position of vertex j
I need an algorithm that can approximate each mj given R, M, and rj.
edit: I just want to clarify that I am aware that there are an infinite set of solutions. I am looking for a quick algorithm that finds a set of mj's (such that they are each sufficiently close to mj = M/[number of vertices] and where "sufficiently" is defined as some small floating point threshold).
Also, each object will consist of about 5 to 35 points.
You can compute the CM of a uniformly dense polygon as follows: number the N vertices from 0..N-1, and treat them cyclicly, so that vertex N wraps to vertex 0:
total_area = sum[i=0..N-1]( X(p[i],p[i+1])/2 )
CM = sum[i=0..N-1]( (p[i]+p[i+1])*X(p[i],p[i+1])/6 ) / total_area
where X(p,q)= p.x*q.y - q.x*p.y [basically, a 2D cross product]
If the polygon is convex, the CM will be inside the polygon, so you can reasonably start out by slicing up the area in triangles like a pie, with the CM at the hub. You should be able to weight each vertex of a triangle with a third of its mass, without changing the CM -- however, this would still leave a third of the total mass at the CM of the entire polygon. Nonetheless, scaling the mass transfer by 3/2 should let you split the mass of each triangle between the two "external" vertices. As a result,
area[i] = X( (p[i]-CM), (p[i+1]-CM) ) / 2
(this is the area of the triangle between the CM and vertices i and i+1)
mass[i] = (total_mass/total_area) * (area[i-1] + area[i])/2
Note that this kind of mass transfer is profoundly "unphysical" -- if nothing else, if treated literally, it would screw up the moment of inertia something fierce. However, if you need to distribute the mass among the vertices (like for some kind of cheesy explosion), and you don't want to disrupt the CM in doing so, this should do the trick.
Finally, a couple of warnings:
if you don't use the actual CM for this, it won't work right
it is hazardous to use this on concave objects; you risk ending up with negative masses
The center of mass R will constantly be changing as the vertices move. So, if you have 10 vertices, store the values from 10 consecutive "frames" - this will give you 10 equations for your 10 unknowns (assuming that the masses don't change over time).
Count the degrees of freedom: for points in D dimensional space you have D+1 equations[+] and n unknowns for n separate particles. If n>D+1 you are sunk (unless you have more information than you have told us about: symmetry constraints, higher order moments, etc...).
edit: My earlier version assumed you had the m_is and were looking for the r_is. It is slightly better when you have the r_is and want the m_is.
[+] The one you list above (which is actual D separate equation) and M = \sum m_j
Arriu said:
Oh sorry I misunderstood your question. I thought you were asking if I was modeling objects such as a torus, doughnut, or ring (objects with cutouts...). I am modeling bodies with just outer shells (like balloons or bubbles). I don't require anything more complex than that.
Now we are getting somewhere. You do know something more.
You can approximate the surface area of the object by breaking it into triangles between adjacent points. This total area gives you mean mass density. Now find the DoF deficit, and assign that many r_is (drawn at random, I guess) an initial mass based on the mean density and 1/3 of the area of each triangle it is a party to. Then solve the remaining system analytically. If the problem is ill-conditioned you can either draw a new set of assigned points, or attempt a random walk on the masses that you have already guessed at.
I would flip the problem around. That is, given a density and the position of the object (which is of course naturally still the center of mass of the object and three vectors corresponding to the orientation of the object, see Euler's angles), at each vertex associate a volume with that element (which would change with resolution and could be fractional for positions at the edge of the object) and multiply the density (d_j) with the associated volume (v_j), m_j=v_j * d_j. This approach should naturally reproduce the center of the mass of the object again.
Perhaps I didn't understand your problem, but consider that this would ultimately yield the correct mass ( Mass = sum(m_j) = sum(v_j * d_j) ) and at worst this approach should yield a verification of your result.