Finding Faces of Mesh Subparts - algorithm

Description:
I have a mesh and its all vertex-face information (vertex indices, vertex position, face indices, etc.) and I want to render sub-parts of this mesh. For example, if I have a hand mesh, I want to only render one of the fingers.
I have the information of related vertices for each sub-part which means I know vertex indices, vertex positions, etc. for the finger I want to render. However, I do not know which faces are associated with the finger. So, I need to find associated face indices to render the sub-part.
Question:
How I can find associated indices for sub-parts in the whole face indices set? I can use an exhaustive search algorithm but, I hope that there is a better approach, a known algorithm to do that.
More Information:
class Vertex
{
Vertex(float _x, float _y, float _z)
{
x = _x; y = _y; z = _z;
}
float x, y, z; // Positions
};
class Face
{
Face(int _v1, int _v2, int _v3)
{
vertIndex1 = _v1; vertIndex2 = _v2; vertIndex3 = _v3;
}
int vertIndex1, vertIndex2, vertIndex3; // Vertex indices
};
Example usage for a triangulated square mesh:
some vector such as std::vector<Vertex> verts and std::vector<Face> faces. I have Vertex v1(0,0,0), v2(1,0,0), v3(0,1,0), and v4(1,1,0). So corresponding Face objects are f1(0, 1, 2) and f2(0, 3, 4) where 0, 1, 2, and 4 are indices of Vertex objects in verts vector. As you can see, a vertex can be in different Faces.
Now, let's say I have a hand mesh where verts.size() is 6000 and faces.size() is 12000. However, instead of whole hand mesh, I want to render only pinky finger and I only have a set of vertex indices of pinky finger such as (345, 369, 541, ...).
So, I know which vertices I need to use, I know whole face information, and I want to find the face indices only for these given vertices.

If the simple O(m+n)-time, O(n)-space algorithm I described in a comment is too slow, there are a variety of things you can do, but I suggest the following easy trick that will quickly find all relevant faces whenever (a) the width or the height or the depth of the bounding box containing all sub-part vertices is "small", and (b) most faces are not "too wide":
Precompute 6 lists of faces, 2 for each dimension (x, y, z): one sorted by increasing minimum vertex co-ord in that dimension, the other sorted by increasing maximum vertex co-ord in that direction. From the given list of sub-part vertices, find the minimum and maximum position in each of the 3 dimensions (so 6 numbers, mx, my, mz, Mx, My, Mz). Binary-search in the list of faces sorted by minimum vertex x co-ord for mx, and then again for Mx, giving positions within the list i and j, respectively. We need only actually test the faces in the range i .. j, since every other face by definition has at least one vertex with x co-ord outside the range mx .. Mx (if its minimum x co-ord is < mx, it has at least 1 vertex outside the range; if its minimum x vertex is > Mx then all 3 vertices are outside the range). Remember j-i, and do similarly for the other 5 sorted lists, keeping track of the one with the smallest value of j-i. Finally, test all faces in that smallest possible list "the hard way".

Related

How to find the "interior boundary" / "interior convex hull" for a list of 3D points?

I need some help with writing this algorithm.
For a given set of lines in space, I am trying to find the accessible volume when the origin (reference point) is 0.5,0.5,0.5. Currently, I do the following:
For each line, calculate the distance to the origin (0.5,0.5,0.5). Then, gather all these perpendicular distance points on all the lines into a list.
Now, I would like to calculate the "interior" (neither the boundary nor the convhull), because I want to evaluate the accessible volume for a ball centered at (0.5,0.5,0.5).
For example I would like to compute with my algorithm the green (internal line) in this simple example:
The configuration:
The closest points from the origin (0.5,0.5,0.5) to the lines
Only the points for whom I want the "internal boundary" be computed. Meaning the shape that bounds all the point either outside of the interior or on its boundary.
Here is the code for which I want something else rather than convhull:
close all
N=30;
S1 = cell(1, N);
for k = 1:N, S1{k} = rand(1, 3); end
S2 = cell(1, N);
for k = 1:N, S2{k} = rand(1, 3); end
M1 = cat(3, S1{:});
M2 = cat(3, S2{:});
M = permute(cat(1, M1, M2), [1, 3, 2]);
figure
plot3(M(:, :, 1), M(:, :, 2), M(:, :, 3))
hold on
[x,y,z] = sphere;
x=x/100;y=y/100;z=z/100;
plot3(x+0.5,y+0.5,z+0.5)
figure
hold on
NearestIntersectionPoints = cell(1,N);
for k = 1:N
tmp1 = M(1,k,:); tmp2 = M(2,k,:);
v1=tmp1(1,:); v2=tmp2(1,:);
[d, intersection] = point_to_line([0.5,0.5,0.5], v1, v2);
[x,y,z] = sphere;
x=x/500;y=y/500;z=z/500;
plot3(x+intersection(1),y+intersection(2),z+intersection(3))
NearestIntersectionPoints{k} = intersection;
end
MHull = cat(3,NearestIntersectionPoints{:});
X=MHull(:,1,:); Y=MHull(:,2,:); Z=MHull(:,3,:);
X=X(:); Y=Y(:); Z=Z(:);
k = boundary(X,Y,Z);
hold on
plot3(X(k),Y(k),Z(k), 'r-*')
function [d,intersection] = point_to_line(pt, v1, v2)
a = v1 - v2;
b = pt - v2;
d = norm(cross(a,b)) / norm(a);
theta = asin(norm(cross(a,b))/(norm(a)*norm(b)));
intersection = v2 + a * cos(theta);
end
I would do it like this:
tetrahedronize your pointcloud
so create a mesh consisting of tetrahedrons where no tetrahedron intersect any other or contain any point in it. I do it like this:
structures
you need list of points,triangles and tetrahedrons. Each triangle need one counter which will tell you if it is used once or twice.
create first tetrahedron
by 4 nested loops through all points and check if formed tetrahedron does not contain any point inside. If not stop as you found your first tetrahedron. This is O(n^5) but as there are a lot of valid tetrahedrons it will never reach such high runtime... Now just add this tetrahedron to triangle and tetrahedron lists.
find next tetrahedron
now loop through all triangles that has been used once. for each form tetrahedron by using those 3 points used by it and find 4th point the same way as in #2. Valid tetrahedron must not contain any points in it and also must not intersect any existing tetrahedron in the list.
To ensure whole volume will be filled without holes you need to prioritize the process by preferring tetrahedrons with more triangles already in list. So first search 4 triangles if no found than 3 etc ...
For each found valid tetrahedron add it to the lists and look again until no valid tetrahedron can be formed ... The whole process is around O(n^2) so be careful with too many points in pointcloud. Also having normals for triangles stored can speed the tests a lot ...
outer boundary
outer boundary consist of triangles in list which have been used just once
interior boundary
interior gap tetrahedrons should be larger than all the others. So check their size against average size and if bigger they are most likely a gap. So group them together to lists. Each gap have only large tetrahedrons and all of them must share at least one face (triangle). Now just count the triangle usage for each group alone and all the triangles used just once will form your gap/hole/interior boundary/mesh.
If your point density is uniform you can adapt this:
Finding holes in 2d point sets?
And create a voxel map of point density... voxels with no density are either gap or outer space. This can be used for faster and better selection of interior tetrahedrons.
If I understand well your question, you want the largest volume inside another volume, without points in common between the two volumes.
The outer volume is built from a subset of the set of points. The obvious solution is to build the inner volume with the rest of points.
A volume from a set of points can be made in several ways. If the volume is not convex, then you need some more info (e.g. minimum angle between faces) because you get starred polytopo or cuasi-convex, or some other shape.
For convex volume I recomend the 3D Delaunay construction, with tetrahedra. The boundary is defined by the faces of "tets" that are not shared with other "tets".
Remove from the full set of points those belonging to the boundary: Each tet in boundary has a fourth point that does not lie on the boundary.
The inner volume is another Delaunay construction. Perhaps you only need the fourth points from the previous boundary-tets.

Dodecahedron (or any platonic solids) uniform rotations, so that the vertices do not overlap any of the previous rotations

How to rotate an object, so that its vertices never overlap with any of the other rotations? With a predefined number of rotations.
Idea:
It can be achieved with relaxation. (Idea comes from Greg Turk's paper: Generating Textures on Arbitrary Surfaces Using Reaction-Diffusion)
Steps:
Generate x dodecahedrons or any object symmetric to its centre
point.
These objects should be identical in position, orientation
and size. (so we can create an easy relation between vertices =>
ones that overlap at the beginning are related)
Create a function that calculates the distance between the related points.
Maximize the average distance between related points. (every point has x-1
related points)
Problems:
This is not a simple relaxation problem with points. Here, due to the dodecahedron constraint, I cannot just translate around. Rotation matrixes/quaternions are needed.
Possible solution with Brute force
Summary:Rotate randomly until desired average distance is achieved.
Explanation:Every dodecahedron is rotated until it's vertices do not overlap any vertices of the other dodecahedrons.
Then average distance is calculated and checked against the best (minimal) so far. Save all vertex positions, and the rotation quaternion, that will turn the base dodecahedron into the rotated one.
float minThreshold <- user defined
int iterationThreshold <- user defined
float minAveDistance = Infinity;
while (minAveDistance > minThreshold || maxIteration > iterationThreshold) {
Foreach (dodecahedron) { // except the first one, that can stay as is
// rotate randomly until there are no overlapping positions with the other dodecahedrons
while (checkOverlappingWithOtherDodecahedrons(dodecahedron)) {
rotateRandomly(dodecahedron);
}
}
float aveDistance = CalculateAverageDistanceBetweenAllPointsOfDodecahedrons();
if (aveDistance < minAveDistance) {
minAveDistance = aveDistance;
SaveAllPositions(); // e.g.: to a file
SaveAllRotationQuaternionsFromStartOrientation(); // e.g.: to a file
}
}

Merging two overlapping rectangles into the resulting polygon

I am looking for an algorithm that, given two rectangles that overlap partially or totally, finds the ordered list of vertexes that defines the polygon representing the sum of the two rectangles.
To be more specific:
I have as input two ordered list of points, representing the two rectangles
I know how to find the vertexes of the resulting polygon, which is formed by the vertexes of each rectangle which are outside the other rectangle, plus the intersection points between each edge of one rectangle with each edge of the other
I don't currently know how to order into an array the points, obtained as explained above, so that the element j and j+1 of the array represents the two vertexes of the same edge (this is what I mean by ordered list of vertexes).
Thanks in advance for any help
UPDATE :
I found a way to sort vertexes to obtain a polygon, as follows:
compute the vertexes centroid ( coords average )
sort the vertexes by the angle formed between the segment from the centroid and the vertex and any reference line passing by the centroid (e.g. the X axis ).
However, although I consistently obtain a polygon enclosing the two rectangles, without holes or intersecting edges, it is not always the polygon I want ( sometimes it includes extra area not belonging to one of the input rectangles ).
So I'm going back to the solution pointed in one of the comments, which is also described here:
polygon union without holes
Once you have the 4 vertices, you merely find the farther point using the distance formula (since it seems we can't make the assumption of a collinear or unrotated beginning rects)
So if you have points a = (xA, yA), b, c, d and you know these 4 points make a rectangle
float dist(Point a, Point b){
float dx = a.x - b.x;
float dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
//somewhere else, where u need it
//put point A into index 0
Point curFarthest = b;
float distance = dist(a, b);
if (dist(a, c) > distance){
curFarther = c;
distance = dist(a, c);
} else if (dist(a, d) > distance){
curFarther = d;
curFarthest = dist(a, d);
}
//store curFarthest into index 2
// store the rest (exculding points a and curFarthest)
// into index 1 and 3 in no particular order
I am working on the same problem but I use a different approach(work still in progress).
Find the intersection points.
Distance of each point(vertices) with its neighboring connected points.
Using Dinics Algorithm find the Maxmimum flow.
Note: there will be a few special cases. But then again my problems revolves around polygons having 1 common point(vertice).

Sort a set of 3-D points in clockwise/counter-clockwise order

In 3-D space I have an unordered set of, say, 6 points; something like this:
(A)*
(C)*
(E)*
(F)*
(B)*
(D)*
The points form a 3-D contour but they are unordered. For unordered I mean that they are stored in an
unorderedList = [A - B - C - D - E - F]
I just want to reorganize this list starting from an arbitrary location (let's say point A) and traversing the points clockwise or counter-clockwise. Something like this:
orderedList = [A - E - B - D - F - C]
or
orderedList = [A - C - F - D - B - E]
I'm trying to implement an algorithm as simple as possible, since the set of points in mention corresponds to a N-ring neighborhood of each vertex on a mesh of ~420000 points, and I have to do this for each point on the mesh.
Some time ago there was a similar discussion regarding points in 2-D, but for now it's not clear for me how to go from this approach to my 3-D scenario.
The notion of "clockwise" or "counterclockwise" is not well-defined without an axis and orientation! (proof: What if you looked at those points from the other side of your monitor screen, or flipped them, for example!)
You must define an axis and orientation, and specify it as an additional input. Ways to specify it include:
a line (1x=2y=3z), using the right-hand rule
a (unit) vector (A_x, A_y, A_z), using the right-hand rule; this is the preferred way to do so
In order to determine the orientation, you have to look deeper at your problem: You must define a "up" and "down" size of the mesh. Then for each set of points, you must take the centroid (or another "inside" point) and construct a unit vector pointing "up" which is normal to the surface. (One way to do this would be to find the least-squares-fit plane, then find the two perpendicular vectors through that point, picking the one in the "up" direction.)
You will need to use any of the above suggestions to determine your axis. This will allow you to reformulate your problem as follows:
Inputs:
the set of points {P_i}
an axis, which we shall call "the z-axis" and treat as a unit vector centered on the centroid (or somewhere "inside") of the points
an orientation (e.g. counterclockwise) chosen by one of the above methods
Setup:
For all points, pick two mutually-orthogonal unit vectors to the axis, which we shall call "the y-axis" and "the x-axis". (Just rotate the z-axis unit-vector 90 degrees in two directions, http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations )
Algorithm:
For each point P, project P onto the x-axis and y-axis (using the dot product), then use http://en.wikipedia.org/wiki/Atan2
Once you have the angles, you can just sort them.
I can't attest for the efficiency of this code, but it works, and you can optimize parts of it as needed, I'm just not good at it.
Code is in C#, using system collection classes, and linq.
Vector3 is a class with floats x, y, z, and static vector math functions.
Node is a class with Vector3 variable called pos
//Sort nodes with positions in 3d space.
//Assuming the points form a convex shape.
//Assuming points are on a single plain (or close to it).
public List<Node> sortVerticies( Vector3 normal, List<Node> nodes ) {
Vector3 first = nodes[0].pos;
//Sort by distance from random point to get 2 adjacent points.
List<Node> temp = nodes.OrderBy(n => Vector3.Distance(n.pos, first ) ).ToList();
//Create a vector from the 2 adjacent points,
//this will be used to sort all points, except the first, by the angle to this vector.
//Since the shape is convex, angle will not exceed 180 degrees, resulting in a proper sort.
Vector3 refrenceVec = (temp[1].pos - first);
//Sort by angle to reference, but we are still missing the first one.
List<Node> results = temp.Skip(1).OrderBy(n => Vector3.Angle(refrenceVec,n.pos - first)).ToList();
//insert the first one, at index 0.
results.Insert(0,nodes[0]);
//Now that it is sorted, we check if we got the direction right, if we didn't we reverse the list.
//We compare the given normal and the cross product of the first 3 point.
//If the magnitude of the sum of the normal and cross product is less than Sqrt(2) then then there is more than 90 between them.
if ( (Vector3.Cross( results[1].pos-results[0].pos, results[2].pos - results[0].pos ).normalized + normal.normalized).magnitude < 1.414f ) {
results.Reverse();
}
return results;
}

Count number of points inside a circle fast

Given a set of n points on plane, I want to preprocess these points somehow faster than O(n^2) (O(nlog(n)) preferably), and then be able to answer on queries of the following kind "How many of n points lie inside a circle with given center and radius?" faster than O(n) (O(log(n) preferably).
Can you suggest some data structure or algorithm I can use for this problem?
I know that such types of problems are often solved using Voronoi diagrams, but I don't know how to apply it here.
Build a spatial subdivision structure such as a quadtree or KD-tree of the points. At each node store the amount of points covered by that node. Then when you need to count the points covered by the lookup circle, traverse the tree and for each subdivision in a node check if it is fully outside the circle, then ignore it, if it is fully inside the circle then add its count to the total if it intersects with the circle, recurse, when you get to the leaf, check the point(s) inside the leaf for containment.
This is still O(n) worst case (for instance if all the points lie on the circle perimeter) but average case is O(log(n)).
Build a KD-tree of the points, this should give you much better complexity than O(n), on average O(log(n)) I think.
You can use a 2D tree since the points are constrained to a plane.
Assuming that we have transformed the problem into 2D, we'll have something like this for the points:
struct Node {
Pos2 point;
enum {
X,
Y
} splitaxis;
Node* greater;
Node* less;
};
greater and less contains points with greater and lesser coordinates respectively along the splitaxis.
void
findPoints(Node* node, std::vector<Pos2>& result, const Pos2& origin, float radius) {
if (squareDist(origin - node->point) < radius * radius) {
result.push_back(node->point);
}
if (!node->greater) { //No children
return;
}
if (node->splitaxis == X) {
if (node->point.x - origin.x > radius) {
findPoints(node->greater, result, origin radius);
return;
}
if (node->point.x - origin.x < -radius) {
findPoints(node->less, result, origin radius);
return;
}
findPoints(node->greater, result, origin radius);
findPoints(node->less, result, origin radius);
} else {
//Same for Y
}
}
Then you call this function with the root of the KD-tree
If my goal is speed, and the number of points weren't huge (millions,) I'd focus on memory footprint as much as algorithmic complexity.
An unbalanced k-d tree is best on paper, but it requires pointers, which can expand memory footprint by 3x+, so it is out.
A balanced k-d tree requires no storage, other than for an array with one scalar for each point. But it too has a flaw: the scalars can not be quantized - they must be the same 32 bit floats as in the original points. If they are quantized, it is no longer possible to guarantee that a point which appears earlier in the array is either on the splitting plane, or to its left AND that a point which appears later in the array is either on the splitting plane, or to its right.
There is a data structure I developed that addresses this problem. The Synergetics folks tell us that volume is experientially four-directional. Let's say that a plane is likewise experientially three-directional.
We're accustomed to traversing a plane by the four directions -x, +x, -y, and +y, but it's simpler to use the three directions a, b, and c, which point at the vertices of an equilateral triangle.
When building the balanced k-d tree, project each point onto the a, b, and c axes. Sort the points by increasing a. For the median point, round down, quantize and store a. Then, for the sub-arrays to the left and right of the median, sort by increasing b, and for the median points, round down, quantize, and store b. Recurse and repeat until each point has stored a value.
Then, when testing a circle (or whatever) against the structure, first calculate the maximum a, b, and c coordinates of the circle. This describes a triangle. In the data structure we made in the last paragraph, compare the median point's a coordinate to the circle's maximum a coordinate. If the point's a is larger than the circle's a, we can disqualify all points after the median. Then, for the sub-arrays to the left and right (if not disqualified) of the median, compare the circle's b to the median point's b coordinate. Recurse and repeat until there are no more points to visit.
This is similar in theme to the BIH data structure, but requires no intervals of -x and +x and -y and +y, because a, b, and c are just as good at traversing the plane, and require one fewer direction to do it.
Assuming you have a set of points S in a cartesian plane with coordinates (xi,yi), given an arbitrary circle with center (xc,yc) and radius r you want to find all the points contained within that circle.
I will also assume that the points and the circle may move so certain static structures that can speed this up won't necessarily be appropriate.
Three things spring to mind that can speed this up:
Firstly, you can check:
(xi-xc)^2 + (yi-yc)^2 <= r^2
instead of
sqrt((xi-xc)^2 + (yi-yc)^2) <= r
Secondly, you can cull the list of points somewhat by remembering that a point can only be within the circle if:
xi is in the range [xc-r,xc+r]; and
yi is in the range [yc-r,yc+r]; and
This is known as a bounding box. You can use it as either an approximation or to cut down your list of points to a smaller subset to check accurately with the first equation.
Lastly, sort your points in either x or y order and then you can do a bisection search to find the set of points that are possibly within your bounding box, further cutting down on unnecessary checks.
I used Andreas's code but it contains a bug. For example I had two points on the plane [13, 2], [13, -1] and my origin point was [0, 0] with a radius of 100. It finds only 1 point. This is my fix:
void findPoints(Node * root, vector<Node*> & result, Node * origin, double radius, int currAxis = 0) {
if (root) {
if (pow((root->coords[0] - origin->coords[0]), 2.0) + pow((root->coords[1] - origin->coords[1]), 2.0) < radius * radius) {
result.push_back(root);
}
if (root->coords[currAxis] - origin->coords[currAxis] > radius) {
findPoints(root->right, result, origin, radius, (currAxis + 1) % 2);
return;
}
if (origin->coords[currAxis] - root->coords[currAxis] > radius) {
findPoints(root->left, result, origin, radius, (currAxis + 1) % 2);
return;
}
findPoints(root->right, result, origin, radius, (currAxis + 1) % 2);
findPoints(root->left, result, origin, radius, (currAxis + 1) % 2);
}
}
The differnce is Andreas checked for now children with just if (!root->greater) which is not complete. I on the other hand don't do that check, I simply check if the root is valid.
Let me know if you find a bug.
depending on how much precomputing time you have, you could build a tree like this:
first node branches are x-values, below them are y-value nodes, and below them are radius value nodes. at each leaf is a hashset of points.
when you want to compute the points at x,y,r: go through your tree and go down the branch that matches your x,y values the closest. when you get down to the root level, you need to do a little match (constant time stuff), but you can find a radius such that all the points in that circle (defined by the path in the tree) are inside the circle specified by x,y,r, and another circle (same x_tree,y_tree in the tree as before, but different r_tree) such that all of the points in the original circle (specified by x,y,r) are in that circle.
from there, go through all the points in the larger of the two tree circles: if a point is in the smaller circle add it to the results, if not, run the distance check on it.
only problem is that it takes a very long time to precompute the tree. although, you can specify the amount of time you want to spend by changing how many x,y, and r branches you want to have in your tree.

Resources