use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method updateSubdivisionMesh.
/**
* Updates a subdivision mesh.
*
* @param mesh
* Must be a mesh generated by calling getSubdivisionMesh on this mesh.
*/
public void updateSubdivisionMesh(PolygonalMesh mesh) {
if (mesh != null) {
TrianglePatch patch = null;
Face lastFace = null;
Vector3d[] normals = new Vector3d[myVertices.size()];
for (int v = 0; v < normals.length; v++) {
((Vertex3d) myVertices.get(v)).computeNormal(normals[v] = new Vector3d());
}
for (Object vertexobject : mesh.myVertices) {
SubdivisionVertex3d vertex = (SubdivisionVertex3d) vertexobject;
double w = 1.0 - vertex.u - vertex.v;
HalfEdge he = vertex.f.he0;
Vertex3d v0 = he.head;
he = he.next;
Vertex3d v1 = he.head;
Vertex3d v2 = he.next.head;
Vector3d n0 = normals[v0.idx], n1 = normals[v1.idx], n2 = normals[v2.idx];
if (vertex.f != lastFace)
patch = new TrianglePatch(v0.pnt, n0, v1.pnt, n1, v2.pnt, n2);
lastFace = vertex.f;
vertex.normal.scale(vertex.u, n0);
vertex.normal.scaledAdd(vertex.v, n1, vertex.normal);
vertex.normal.scaledAdd(w, n2, vertex.normal);
vertex.normal.normalize();
vertex.pnt.scale(vertex.u, v0.pnt);
vertex.pnt.scaledAdd(vertex.v, v1.pnt, vertex.pnt);
vertex.pnt.scaledAdd(w, v2.pnt, vertex.pnt);
patch.interpolate(vertex.pnt, vertex.u, vertex.v, w);
}
}
}
use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method checkForDegenerateFaces.
public void checkForDegenerateFaces() {
for (Face face : 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.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method computeVolumeIntegrals.
/**
* Computes the volume integrals of this mesh, on the assumption that it is
* manifold and closed. The code for this was taken from vclip, by Brian
* Mirtich. See "Fast and Accurate Computation of Polyhedral Mass
* Properties," Brian Mirtich, journal of graphics tools, volume 1, number 2,
* 1996.
*
* @param mov1
* if non-null, returns the first moment of volume
* @param mov2
* if non-null, returns the second moment of volume
* @param pov
* if non-null, returns the product of volume
* @return closed volume of the mesh
*/
public double computeVolumeIntegrals(Vector3d mov1, Vector3d mov2, Vector3d pov) {
int a, b, c;
// Edge e;
// Face f;
double a0, a1, da;
// al
double b0, b1, db;
double a0_2, a0_3, a0_4, b0_2, b0_3, b0_4;
double a1_2, a1_3, b1_2, b1_3;
double d, na, nb, nc, inv;
double I, Ia, Ib, Iaa, Iab, Ibb, Iaaa, Iaab, Iabb, Ibbb;
double Icc, Iccc, Ibbc, Icca;
double C0, Ca, Caa, Caaa, Cb, Cbb, Cbbb;
double Cab, Kab, Caab, Kaab, Cabb, Kabb;
// h, w;
Vector3d v;
if (mov1 != null) {
mov1.setZero();
}
if (mov2 != null) {
mov2.setZero();
}
if (pov != null) {
pov.setZero();
}
// double rad_ = 0;
double vol_ = 0.0;
for (int i = 0; i < myFaces.size(); i++) {
Face f = myFaces.get(i);
// compute projection direction
Vector3d nrml = f.getNormal();
if (nrml.containsNaN()) {
// sanity check for badly formed meshes
continue;
}
v = new Vector3d();
v.set(Math.abs(nrml.x), Math.abs(nrml.y), Math.abs(nrml.z));
c = (v.x >= v.y) ? ((v.x >= v.z) ? 0 : 2) : ((v.y >= v.z) ? 1 : 2);
a = (c + 1) % 3;
b = (c + 2) % 3;
I = Ia = Ib = Iaa = Iab = Ibb = Iaaa = Iaab = Iabb = Ibbb = 0.0;
// walk around face
HalfEdge he0 = f.firstHalfEdge();
HalfEdge he = he0;
do {
a0 = he.getTail().pnt.get(a);
b0 = he.getTail().pnt.get(b);
a1 = he.getHead().pnt.get(a);
b1 = he.getHead().pnt.get(b);
da = a1 - a0;
db = b1 - b0;
a0_2 = a0 * a0;
a0_3 = a0_2 * a0;
a0_4 = a0_3 * a0;
b0_2 = b0 * b0;
b0_3 = b0_2 * b0;
b0_4 = b0_3 * b0;
a1_2 = a1 * a1;
a1_3 = a1_2 * a1;
b1_2 = b1 * b1;
b1_3 = b1_2 * b1;
C0 = a1 + a0;
Ca = a1 * C0 + a0_2;
Caa = a1 * Ca + a0_3;
Caaa = a1 * Caa + a0_4;
Cb = b1 * (b1 + b0) + b0_2;
Cbb = b1 * Cb + b0_3;
Cbbb = b1 * Cbb + b0_4;
Cab = 3 * a1_2 + 2 * a1 * a0 + a0_2;
Kab = a1_2 + 2 * a1 * a0 + 3 * a0_2;
Caab = a0 * Cab + 4 * a1_3;
Kaab = a1 * Kab + 4 * a0_3;
Cabb = 4 * b1_3 + 3 * b1_2 * b0 + 2 * b1 * b0_2 + b0_3;
Kabb = b1_3 + 2 * b1_2 * b0 + 3 * b1 * b0_2 + 4 * b0_3;
I += db * C0;
Ia += db * Ca;
Iaa += db * Caa;
Iaaa += db * Caaa;
Ib += da * Cb;
Ibb += da * Cbb;
Ibbb += da * Cbbb;
Iab += db * (b1 * Cab + b0 * Kab);
Iaab += db * (b1 * Caab + b0 * Kaab);
Iabb += da * (a1 * Cabb + a0 * Kabb);
he = he.getNext();
} while (he != he0);
I /= 2.0;
Ia /= 6.0;
Iaa /= 12.0;
Iaaa /= 20.0;
Ib /= -6.0;
Ibb /= -12.0;
Ibbb /= -20.0;
Iab /= 24.0;
Iaab /= 60.0;
Iabb /= -60.0;
d = -nrml.dot(f.firstHalfEdge().getHead().pnt);
na = nrml.get(a);
nb = nrml.get(b);
nc = nrml.get(c);
inv = 1.0 / nc;
if (a == 0) {
vol_ += inv * na * Ia;
} else if (b == 0) {
vol_ += inv * nb * Ib;
} else {
vol_ -= ((d * I + na * Ia + nb * Ib) / nc);
}
if (vol_ != vol_) {
throw new NumericalException("nrml=" + nrml + ", face " + i);
}
Icc = (SQR(na) * Iaa + 2 * na * nb * Iab + SQR(nb) * Ibb + d * (2 * (na * Ia + nb * Ib) + d * I)) * SQR(inv);
if (mov1 != null) {
mov1.set(a, mov1.get(a) + inv * na * Iaa);
mov1.set(b, mov1.get(b) + inv * nb * Ibb);
mov1.set(c, mov1.get(c) + Icc);
}
Iccc = -(CUBE(na) * Iaaa + 3 * SQR(na) * nb * Iaab + 3 * na * SQR(nb) * Iabb + CUBE(nb) * Ibbb + 3 * (SQR(na) * Iaa + 2 * na * nb * Iab + SQR(nb) * Ibb) * d + d * d * (3 * (na * Ia + nb * Ib) + d * I)) * CUBE(inv);
if (mov2 != null) {
mov2.set(a, mov2.get(a) + inv * na * Iaaa);
mov2.set(b, mov2.get(b) + inv * nb * Ibbb);
mov2.set(c, mov2.get(c) + Iccc);
}
Ibbc = -(d * Ibb + na * Iabb + nb * Ibbb) * inv;
Icca = (SQR(na) * Iaaa + 2 * na * nb * Iaab + SQR(nb) * Iabb + d * (2 * (na * Iaa + nb * Iab) + d * Ia)) * SQR(inv);
if (pov != null) {
pov.set(c, pov.get(c) + inv * na * Iaab);
pov.set(a, pov.get(a) + inv * nb * Ibbc);
pov.set(b, pov.get(b) + Icca);
}
}
if (mov1 != null) {
mov1.scale(0.5);
}
if (mov2 != null) {
mov2.scale(1.0 / 3.0);
}
if (pov != null) {
pov.scale(0.5);
}
return vol_;
}
use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method computeVertexNormals.
/**
* Computes a set of vertex normals for this mesh, using an
* angle-weighted average of the normals formed by the edges incident on
* each vertex. If the angle-weighted average would result in a zero normal
* (e.g. vertices on a straight line), then the adjacent face normals
* are used. If <code>multiNormals</code> is <code>true</code>, then
* multiple normals may be computed for each vertex, with different normals
* being computed for edge regions that are separated by open or hard
* edges. Otherwise, only one normal is computed per vertex.
*
* <p>If <code>normals</code> is passed in with zero size, then the normals
* are computed and returned in new <code>Vector3d</code> objects that are
* and added to it. Also, the method returns a set of computed normal
* indices. This option is used for the initial creation of normals.
*
* <p>If <code>normals</code> is passed in with non-zero size, then it is
* assumed to contain enough <code>Vector3d</code> objects to store all the
* computed normals, and the method returns <code>null</code>. This option
* is used for updating normals.
*
* @param normals returns the computed normals
* @param multiNormals if <code>true</code>, then multiple normals
* may be computed for each vertex
* @return normals indices, if <code>normals</code> has zero size,
* otherwise <code>null</code>.
*/
public int[] computeVertexNormals(ArrayList<Vector3d> normals, boolean multiNormals) {
boolean creatingNormals = (normals.size() == 0);
if (multiNormals) {
// make sure hard edges are properly set
updateHardEdgeCount();
}
HashMap<HalfEdge, Integer> normalIndexMap = null;
if (creatingNormals) {
// Each half edge will be associated with a normal for its head vertex.
normalIndexMap = new HashMap<HalfEdge, Integer>();
}
// Start by allocating normals and determining the normal index
// associated with each half-face
int idx = 0;
for (Vertex3d vtx : myVertices) {
HalfEdgeNode node = vtx.getIncidentHedges();
Vector3d nrm;
while (node != null) {
if (creatingNormals) {
// create a new vector to store the normal
nrm = new Vector3d();
normals.add(nrm);
} else {
// use the existing normal vector
nrm = normals.get(idx);
nrm.setZero();
}
// reach a normal boundary.
do {
HalfEdge he = node.he;
nrm.angleWeightedCrossAdd(he.tail.pnt, he.head.pnt, he.next.head.pnt);
if (creatingNormals) {
normalIndexMap.put(node.he, idx);
}
node = node.next;
} while (node != null && (!multiNormals || !vtx.isNormalBoundary(node.he)));
double n2 = nrm.normSquared();
if (n2 == 0) {
// backup, just in case angle weighted normals fails
vtx.computeAreaWeightedNormal(nrm);
// nmag = nrm.norm();
}
nrm.normalize();
// if (nmag > 0) {
// nrm.scale(1.0/nmag);
// }
idx++;
}
}
if (creatingNormals) {
// Now assign the normal indices for each face. These are the indices of
// the normals associated with each of the face's half edges.
int[] indexOffs = getFeatureIndexOffsets();
int[] indices = new int[indexOffs[indexOffs.length - 1]];
int k = 0;
for (Face face : myFaces) {
HalfEdge he0 = face.firstHalfEdge();
HalfEdge he = he0;
do {
Integer id = normalIndexMap.get(he);
if (id == null) {
throw new InternalErrorException("Normal not computed for halfEge on face " + face.getIndex());
}
indices[k++] = id;
he = he.getNext();
} while (he != he0);
}
return indices;
} else {
return null;
}
}
use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMeshRenderer method addFaceNormals.
protected void addFaceNormals(RenderObject r, PolygonalMesh mesh) {
boolean useRenderData = mesh.isRenderBuffered() && !mesh.isFixed();
updateFaceNormals(mesh);
ArrayList<Face> faces = mesh.getFaces();
for (int i = 0; i < faces.size(); i++) {
Vector3d nrm;
if (useRenderData) {
nrm = faces.get(i).getRenderNormal();
} else {
nrm = faces.get(i).getNormal();
}
r.addNormal((float) nrm.x, (float) nrm.y, (float) nrm.z);
}
}
Aggregations