use of maspack.geometry.Face in project artisynth_core by artisynth.
the class MeshViewer method checkFaces.
private void checkFaces(PolygonalMesh mesh) {
for (Face face : mesh.getFaces()) {
Vector3d nrm = face.getNormal();
if (nrm.containsNaN()) {
System.out.println("face " + face.getIndex() + " badly formed");
for (int i = 0; i < 3; i++) {
Vertex3d v = face.getVertex(i);
System.out.println(" " + v + " " + v.pnt + " " + v.numIncidentHalfEdges());
}
}
}
}
use of maspack.geometry.Face in project artisynth_core by artisynth.
the class IntersectionContour method getFirstFaceEntryIndex.
// void setSegmentFaces (PolygonalMesh mesh0, PolygonalMesh mesh1) {
// for (int i=0; i<size(); i++) {
// IntersectionPoint p = get(i);
// p.myMesh0 = mesh0;
// p.myFace0 = findSegmentFace (i, mesh0);
// p.myFace1 = findSegmentFace (i, mesh1);
// }
// }
/**
* Returns the index of the point where the contour first enters the
* specified <code>face</code> on <code>mesh</code>. If the contour does not
* enter the face, or if it is entirely located on the face, the method
* returns <code>-1</code>.
*
* <p>If <code>face</code> is <code>null</code>, then the methods returns
* the first point where the contour first enters <i>any</i> face. For open
* contours, this is 0. If the contour is closed and entirely associated
* with one face, there is no entry index and the method returns -1.
*/
int getFirstFaceEntryIndex(PolygonalMesh mesh, Face face) {
Face lastFace = findSegmentFace(size() - 1, mesh);
for (int k = 0; k < size(); k++) {
Face segFace = findSegmentFace(k, mesh);
if (segFace == null) {
// occurs only we are at the end of an open contour
return -1;
}
if (segFace != lastFace) {
if (face == null || segFace == face) {
return k;
}
}
lastFace = segFace;
}
return -1;
}
use of maspack.geometry.Face in project artisynth_core by artisynth.
the class MeshCollider method getContactPlaneInfo.
/**
* Get information about a specific region of intersections.
*/
static void getContactPlaneInfo(ContactPlane region, PolygonalMesh mesh0, PolygonalMesh mesh1, double pointTol) {
Vector3d sectnormal = new Vector3d(), tmpnormal = new Vector3d();
BVFeatureQuery query = new BVFeatureQuery();
RigidTransform3d trans0 = mesh0.getMeshToWorld();
RigidTransform3d trans1 = mesh1.getMeshToWorld();
// calculate a weighted average of the face normals
for (TriTriIntersection isect : region.intersections) {
region.points = new ArrayList<Point3d>();
region.points.add(isect.points[0]);
region.points.add(isect.points[1]);
double length = isect.points[0].distance(isect.points[1]);
tmpnormal.transform(trans0, isect.face0.getNormal());
tmpnormal.negate();
sectnormal.scaledAdd(length, tmpnormal, sectnormal);
tmpnormal.transform(trans1, isect.face1.getNormal());
sectnormal.scaledAdd(length, tmpnormal, sectnormal);
}
// calculate the weighted intersection center
Point3d center = new Point3d();
double weight = 0;
for (TriTriIntersection isect : region.intersections) {
double length = isect.points[0].distance(isect.points[1]);
center.scaledAdd(length, isect.points[0], center);
center.scaledAdd(length, isect.points[1], center);
weight += 2 * length;
}
center.scale(1.0 / weight);
region.centroid = center;
// calculate the weighted normal
Vector3d cp0 = new Vector3d(), cp1 = new Vector3d();
region.normal.setZero();
for (TriTriIntersection isect : region.intersections) {
cp0.sub(isect.points[0], center);
cp1.sub(isect.points[1], center);
tmpnormal.cross(cp0, cp1);
if (tmpnormal.dot(sectnormal) < 0)
tmpnormal.negate();
region.normal.add(tmpnormal);
}
if (region.normal.dot(sectnormal) < 0)
region.normal.negate();
// handle degenerate cases
if (region.normal.containsNaN() || region.normal.norm() < EPS) {
region.normal.setZero();
Point3d p0 = new Point3d();
Point3d p1 = new Point3d();
Vector3d c0 = new Vector3d();
Vector3d c1 = new Vector3d();
for (TriTriIntersection isect : region.intersections) {
for (Point3d p : isect.points) {
p0.inverseTransform(trans0, p);
p1.inverseTransform(trans1, p);
Vertex3d u0 = isect.face0.getVertex(0);
Vertex3d u1 = isect.face0.getVertex(1);
Vertex3d u2 = isect.face0.getVertex(2);
Vertex3d v0 = isect.face1.getVertex(0);
Vertex3d v1 = isect.face1.getVertex(1);
Vertex3d v2 = isect.face1.getVertex(2);
getCoordinates(c0, u0.pnt, u1.pnt, u2.pnt, p0);
getCoordinates(c1, v0.pnt, v1.pnt, v2.pnt, p1);
int[] type0 = classifyPoint(c0);
int[] type1 = classifyPoint(c1);
if (type0[0] == 2) {
if (type1[0] == 2) {
// vertex,vertex
region.normal.add(vertexVertexNormal(trans0, trans1, isect.face0, isect.face1, type0[1], type1[1]));
} else if (type1[0] == 1) {
// vertex,edge
region.normal.add(vertexEdgeNormal(trans0, trans1, isect.face0, isect.face1, type0[1], type1[1]));
} else {
// vertex,face
region.normal.add(vertexFaceNormal(trans0, trans1, isect.face0, isect.face1, type0[1]));
}
} else if (type0[0] == 1) {
if (type1[0] == 2) {
// edge,vertex
region.normal.sub(vertexEdgeNormal(trans1, trans0, isect.face1, isect.face0, type1[1], type0[1]));
} else if (type1[0] == 1) {
// edge,edge
region.normal.add(edgeEdgeNormal(trans0, trans1, isect.face0, isect.face1, type0[1], type1[1]));
} else {
// edge,face
region.normal.add(edgeFaceNormal(trans0, trans1, isect.face0, isect.face1, type0[1]));
}
} else {
if (type1[0] == 2) {
// face,vertex
region.normal.sub(vertexFaceNormal(trans1, trans0, isect.face1, isect.face0, type1[1]));
} else if (type1[0] == 1) {
// face,edge
region.normal.sub(edgeFaceNormal(trans1, trans0, isect.face1, isect.face0, type1[1]));
} else {
// face,face
region.normal.add(faceFaceNormal(trans0, trans1, isect.face0, isect.face1));
}
}
}
}
}
region.normal.normalize();
// calculate the contact depth for the region
boolean foundPenetratingVertice = false;
Point3d p = new Point3d();
Point3d nearest = new Point3d();
Vector3d diff = new Vector3d();
Vector2d coords = new Vector2d();
Vertex3d v;
Face nf;
Point3d plocal = new Point3d();
LinkedHashSet<Vertex3d> regionvertices0 = new LinkedHashSet<Vertex3d>();
LinkedHashSet<Vertex3d> regionvertices1 = new LinkedHashSet<Vertex3d>();
region.depth = 0;
for (TriTriIntersection isect : region.intersections) {
for (int i = 0; i < 3; i++) {
// face0 vertex depths
v = isect.face0.getVertex(i);
p.transform(trans0, v.pnt);
plocal.inverseTransform(trans1, p);
plocal.sub(isect.face1.getVertex(0).pnt);
if (plocal.dot(isect.face1.getNormal()) <= 0) {
regionvertices0.add(v);
}
// face1 vertex depths
v = isect.face1.getVertex(i);
p.transform(trans1, v.pnt);
plocal.inverseTransform(trans0, p);
plocal.sub(isect.face0.getVertex(0).pnt);
if (plocal.dot(isect.face0.getNormal()) <= 0) {
regionvertices1.add(v);
}
}
}
for (Vertex3d v0 : regionvertices0) {
p.transform(trans0, v0.pnt);
// XXX Sanchez, Jun 22, 2014
// Changed to isInside. Sometimes a vertex is outside
// the mesh but determined to be "penetrating" due to
// normal (e.g. when nearest to an edge)
// nf = myQuery.nearestFaceToPoint (nearest, coords, mesh1, p);
boolean inside = query.isInsideOrientedMesh(mesh1, p, 0);
if (inside) {
query.getFaceForInsideOrientedTest(nearest, coords);
nearest.transform(trans1);
diff.sub(p, nearest);
diff.inverseTransform(trans1);
foundPenetratingVertice = true;
// -diff.dot (nf.getNormal());
double dist = diff.norm();
if (dist > region.depth)
region.depth = dist;
}
}
for (Vertex3d v1 : regionvertices1) {
p.transform(trans1, v1.pnt);
// nf = myQuery.nearestFaceToPoint (nearest, coords, mesh0, p);
boolean inside = query.isInsideOrientedMesh(mesh0, p, 0);
if (inside) {
query.getFaceForInsideOrientedTest(nearest, coords);
nearest.transform(trans0);
diff.sub(p, nearest);
diff.inverseTransform(trans0);
foundPenetratingVertice = true;
// -diff.dot (nf.getNormal());
double dist = diff.norm();
if (dist > region.depth)
region.depth = dist;
}
}
if (!foundPenetratingVertice) {
double min = Double.POSITIVE_INFINITY, max = Double.NEGATIVE_INFINITY;
for (int i = 0; i < region.points.size(); i++) {
double d = region.points.get(i).dot(region.normal);
if (d < min)
min = d;
if (d > max)
max = d;
}
region.depth = max - min;
}
// eliminate redundant points
// use point tolerance
region.points.clear();
for (TriTriIntersection isect : region.intersections) {
for (Point3d pcandidate : isect.points) {
boolean add = true;
for (Point3d other : region.points) if (pcandidate.epsilonEquals(other, pointTol)) {
add = false;
break;
}
if (add) {
region.points.add(pcandidate);
}
}
}
// take extrema along n axes
if (numextremaaxes > 0) {
// final ArrayList<Vector3d> axes = new ArrayList<Vector3d>();
Vector3d crosszup = new Vector3d(0, 0, 1);
crosszup.cross(region.normal, crosszup);
double crosszupnorm = crosszup.norm();
RigidTransform3d normtoworld;
if (crosszup.norm() > EPS) {
normtoworld = new RigidTransform3d(new Vector3d(), new AxisAngle(crosszup, Math.asin(crosszupnorm)));
} else {
normtoworld = new RigidTransform3d();
}
boolean[] keep = new boolean[region.points.size()];
for (int j = 0; j < region.points.size(); j++) keep[j] = false;
Vector3d offset = new Vector3d();
Vector3d axis = new Vector3d();
for (int i = 0; i < numextremaaxes; i++) {
double min = Double.POSITIVE_INFINITY, max = Double.NEGATIVE_INFINITY;
int mini = 0, maxi = 0;
double angle = Math.PI * i / numextremaaxes;
axis.set(Math.cos(angle), Math.sin(angle), 0);
axis.transform(normtoworld);
for (int j = 0; j < region.points.size(); j++) {
offset.sub(region.points.get(j), center);
double dot = offset.dot(axis);
if (dot < min) {
min = dot;
mini = j;
}
if (dot > max) {
max = dot;
maxi = j;
}
}
keep[mini] = true;
keep[maxi] = true;
}
for (int j = (region.points.size() - 1); j >= 0; j--) {
if (!keep[j])
region.points.remove(j);
}
}
}
use of maspack.geometry.Face in project artisynth_core by artisynth.
the class SDGridTest method build.
@Override
public void build(String[] args) throws IOException {
super.build(args);
PolygonalMesh mesh = new PolygonalMesh();
Vertex3d[] v = new Vertex3d[9 * 2 + 8];
Face[] f = new Face[8 * 6];
int idx = 0;
int fidx = 0;
double c = 64;
v[idx++] = mesh.addVertex(-c, -c, -c);
v[idx++] = mesh.addVertex(-c, -c, 0);
v[idx++] = mesh.addVertex(-c, -c, c);
v[idx++] = mesh.addVertex(-c, 0, -c);
v[idx++] = mesh.addVertex(-c, 0, 0);
v[idx++] = mesh.addVertex(-c, 0, c);
v[idx++] = mesh.addVertex(-c, c, -c);
v[idx++] = mesh.addVertex(-c, c, 0);
v[idx++] = mesh.addVertex(-c, c, c);
// left
f[fidx++] = mesh.addFace(v[0], v[1], v[4]);
f[fidx++] = mesh.addFace(v[1], v[2], v[4]);
f[fidx++] = mesh.addFace(v[2], v[5], v[4]);
f[fidx++] = mesh.addFace(v[5], v[8], v[4]);
f[fidx++] = mesh.addFace(v[8], v[7], v[4]);
f[fidx++] = mesh.addFace(v[7], v[6], v[4]);
f[fidx++] = mesh.addFace(v[6], v[3], v[4]);
f[fidx++] = mesh.addFace(v[3], v[0], v[4]);
v[idx++] = mesh.addVertex(0, -c, -c);
v[idx++] = mesh.addVertex(0, -c, 0);
v[idx++] = mesh.addVertex(0, -c, c);
v[idx++] = mesh.addVertex(0, 0, -c);
// test.addVertex( 0, 0, 0);
v[idx++] = mesh.addVertex(0, 0, c);
v[idx++] = mesh.addVertex(0, c, -c);
v[idx++] = mesh.addVertex(0, c, 0);
v[idx++] = mesh.addVertex(0, c, c);
// back
f[fidx++] = mesh.addFace(v[0], v[9], v[10]);
f[fidx++] = mesh.addFace(v[1], v[0], v[10]);
f[fidx++] = mesh.addFace(v[2], v[1], v[10]);
f[fidx++] = mesh.addFace(v[11], v[2], v[10]);
// top
f[fidx++] = mesh.addFace(v[2], v[11], v[13]);
f[fidx++] = mesh.addFace(v[5], v[2], v[13]);
f[fidx++] = mesh.addFace(v[8], v[5], v[13]);
f[fidx++] = mesh.addFace(v[16], v[8], v[13]);
// front
f[fidx++] = mesh.addFace(v[8], v[16], v[15]);
f[fidx++] = mesh.addFace(v[7], v[8], v[15]);
f[fidx++] = mesh.addFace(v[6], v[7], v[15]);
f[fidx++] = mesh.addFace(v[14], v[6], v[15]);
// bottom
f[fidx++] = mesh.addFace(v[3], v[6], v[12]);
f[fidx++] = mesh.addFace(v[6], v[14], v[12]);
f[fidx++] = mesh.addFace(v[0], v[3], v[12]);
f[fidx++] = mesh.addFace(v[9], v[0], v[12]);
v[idx++] = mesh.addVertex(c, -c, -c);
v[idx++] = mesh.addVertex(c, -c, 0);
v[idx++] = mesh.addVertex(c, -c, c);
v[idx++] = mesh.addVertex(c, 0, -c);
v[idx++] = mesh.addVertex(c, 0, 0);
v[idx++] = mesh.addVertex(c, 0, c);
v[idx++] = mesh.addVertex(c, c, -c);
v[idx++] = mesh.addVertex(c, c, 0);
v[idx++] = mesh.addVertex(c, c, c);
// bottom
f[fidx++] = mesh.addFace(v[17], v[9], v[12]);
f[fidx++] = mesh.addFace(v[20], v[17], v[12]);
f[fidx++] = mesh.addFace(v[23], v[20], v[12]);
f[fidx++] = mesh.addFace(v[14], v[23], v[12]);
f[fidx++] = mesh.addFace(v[9], v[17], v[10]);
f[fidx++] = mesh.addFace(v[17], v[18], v[10]);
f[fidx++] = mesh.addFace(v[18], v[19], v[10]);
f[fidx++] = mesh.addFace(v[19], v[11], v[10]);
f[fidx++] = mesh.addFace(v[11], v[19], v[13]);
f[fidx++] = mesh.addFace(v[19], v[22], v[13]);
f[fidx++] = mesh.addFace(v[22], v[25], v[13]);
f[fidx++] = mesh.addFace(v[25], v[16], v[13]);
f[fidx++] = mesh.addFace(v[16], v[25], v[15]);
f[fidx++] = mesh.addFace(v[25], v[24], v[15]);
f[fidx++] = mesh.addFace(v[24], v[23], v[15]);
f[fidx++] = mesh.addFace(v[23], v[14], v[15]);
f[fidx++] = mesh.addFace(v[25], v[22], v[21]);
f[fidx++] = mesh.addFace(v[22], v[19], v[21]);
f[fidx++] = mesh.addFace(v[19], v[18], v[21]);
f[fidx++] = mesh.addFace(v[18], v[17], v[21]);
f[fidx++] = mesh.addFace(v[17], v[20], v[21]);
f[fidx++] = mesh.addFace(v[20], v[23], v[21]);
f[fidx++] = mesh.addFace(v[23], v[24], v[21]);
f[fidx++] = mesh.addFace(v[24], v[25], v[21]);
// Move in some corner(s)
v[0].setPosition(new Point3d(0, 0, 0));
// v[25].setPosition(new Point3d(0,0,0));
int divisions = 3;
mesh = MeshFactory.subdivide(mesh, divisions);
// randomize vertex order and re-number (to test different chiralities)
ArrayList<Vertex3d> vertices = mesh.getVertices();
Collections.shuffle(vertices);
for (int i = 0; i < vertices.size(); ++i) {
vertices.get(i).setIndex(i);
}
FixedMeshBody fm = new FixedMeshBody("cube", mesh);
RenderProps.setFaceStyle(fm, FaceStyle.FRONT_AND_BACK);
addRenderable(fm);
int cells = 1 << (divisions + 2);
double margin = 1.0 / cells;
cells += 2;
sdgrid = new DistanceGrid(mesh.getFaces(), margin, cells, /*signed=*/
true);
// test a bunch of inside points
Vector3d norm = new Vector3d();
double dx = 2 * c / ((1 << (divisions + 1)));
for (double x = -c + dx; x < c; x += dx) {
for (double y = -c + dx; y < c; y += dx) {
for (double z = -c + dx; z < c; z += dx) {
double d = sdgrid.getLocalDistanceAndNormal(norm, x, y, z);
// check bottom corner
if ((x < 0 && y < 0 && z < 0)) {
// ||(x > 0 && y > 0 && z > 0)) {
if (d < 0) {
System.err.println("Point (" + x + "," + y + "," + z + ") incorrectly labelled as inside");
}
} else {
if (d > 0) {
System.err.println("Point (" + x + "," + y + "," + z + ") incorrectly labelled as outside");
}
}
}
}
}
RenderProps.setDrawEdges(fm, true);
}
use of maspack.geometry.Face in project artisynth_core by artisynth.
the class SurfaceMeshContourIxer method getOneContour.
/**
* From an non-empty list of MIPs, create a new MeshIntersectionContour and
* return it. It might be open or closed. MIPs are removed from mips as they
* are used.
*
* @param mips List of possible MeshIntersectionPoints to check. This method
* deletes MIPs in mips as it goes along.
* @return new MeshIntersectionContour, or <code>null</code>
* if <code>mips</code> is empty
*/
protected IntersectionContour getOneContour(ArrayList<IntersectionPoint> mips) throws DegenerateLoopCaseException {
if (mips.size() == 0) {
return null;
}
IntersectionContour contour = new IntersectionContour();
contour.setClosed(true);
IntersectionPoint firstMip = mips.get(0);
IntersectionPoint mip = firstMip;
IntersectionPoint nextMip = null;
// Start the contour
contour.add(mip);
Face fPrev = null;
while (nextMip != contour.get(0) || contour.size() < 2) {
nextMip = null;
// First search this edge's face's edges for intersection with mip.face
Face thisEdgesFace;
if (mip.edge.getFace() == fPrev) {
if (mip.edge.opposite == null) {
thisEdgesFace = null;
} else {
thisEdgesFace = mip.edge.opposite.getFace();
}
} else {
thisEdgesFace = mip.edge.getFace();
}
/*
* We have found the edge of an open mesh. This contour is
* definitely open. Continue from contour.get(0) and go in
* opposite direction. If we already did that, then we're finished.
*/
if (thisEdgesFace == null) {
if (!contour.isClosed()) {
// We're finished, since we already did this
break;
}
contour.setClosed(false);
nextMip = firstMip;
contour.reverse();
mip = nextMip;
mips.remove(mip);
// mip.edge.getFace was already checked in first pass,
// so we should use this as previous to switch directions.
fPrev = mip.edge.getFace();
continue;
}
/*
* Now the meat of the algorithm. Search this edge's faces edges
* for another match. If found, this is the next mip in the contour
*/
for (int i = 0; i < 3; i++) {
HalfEdge candEdge = thisEdgesFace.getEdge(i).getPrimary();
if (candEdge == mip.edge.getPrimary()) {
// We already know about this edge
continue;
}
EdgeFacePair testPair = new EdgeFacePair(candEdge, mip.face);
nextMip = mySavedEdgeFaceResults.get(testPair);
if (nextMip == null) {
continue;
} else {
fPrev = thisEdgesFace;
break;
}
}
/*
* if nextMip is still null, the next mip must be on the other mesh's face
*/
if (nextMip == null) {
for (int i = 0; i < 3; i++) {
HalfEdge candEdge = mip.face.getEdge(i).getPrimary();
EdgeFacePair testPair = new EdgeFacePair(candEdge, thisEdgesFace);
nextMip = mySavedEdgeFaceResults.get(testPair);
if (nextMip == null) {
continue;
} else {
fPrev = mip.face;
break;
}
}
}
/*
* If we still haven't found the next MIP at this point,
* we're basically screwed. We should probably give up or something
*/
if (nextMip == null) {
System.out.println("mips.size(): " + mips.size());
System.out.println("contour.size(): " + contour.size());
throw new DegenerateLoopCaseException("Couldn't find next intersection point!");
}
mip = nextMip;
contour.add(mip);
if (!mips.remove(mip)) {
// This shouldn't happen
System.out.println("mips.size(): " + mips.size());
System.out.println("contour.size(): " + contour.size());
if (!contour.isClosed()) {
System.out.println("Open contour");
}
throw new DegenerateLoopCaseException("Warning! nextMip wasn't in mips!!! aborting");
}
}
return contour;
}
Aggregations