use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method extendOpenEdges.
/**
* Extends the first open edge loop found.
*
* @param amount
* The amount to extend it by.
*/
public void extendOpenEdges(double amount) {
// Vertex3d v0;
HalfEdge he0 = null;
boolean found = false;
for (Object fo : myFaces) {
Face f = (Face) fo;
he0 = f.he0;
do {
if (isOpen(he0)) {
found = true;
break;
}
he0 = he0.next;
} while (he0 != f.he0);
if (found)
break;
}
Vector3d i = new Vector3d(), j = new Vector3d();
HalfEdge he = he0;
ArrayList<Vertex3d> iverts = new ArrayList<Vertex3d>(), overts = new ArrayList<Vertex3d>();
do {
HalfEdgeNode hen = he.tail.getIncidentHedges();
while (hen != null) {
if (isOpen(hen.he)) {
break;
}
hen = hen.next;
}
he.computeUnitVec(i);
hen.he.computeUnitVec(j);
double angleFactor = 1.0 - i.angle(j) / Math.PI;
i.add(j);
i.cross(he.face.getNormal());
i.normalize();
Point3d p = new Point3d();
p.scaledAdd(amount * angleFactor, i, he.tail.pnt);
iverts.add(he.tail);
overts.add(addVertex(p));
he = hen.he;
} while (he != he0);
Vertex3d lastiv = iverts.get(iverts.size() - 1), lastov = overts.get(overts.size() - 1);
for (int v = 0; v < iverts.size(); v++) {
Vertex3d iv = iverts.get(v), ov = overts.get(v);
addFace(new int[] { lastiv.idx, iv.idx, ov.idx });
addFace(new int[] { ov.idx, lastov.idx, lastiv.idx });
lastiv = iv;
lastov = ov;
}
}
use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method computePrincipalAxes.
public static RigidTransform3d computePrincipalAxes(PolygonalMesh mesh) {
Vector3d mov1 = new Vector3d();
Vector3d mov2 = new Vector3d();
Vector3d pov = new Vector3d();
double vol = mesh.computeVolumeIntegrals(mov1, mov2, pov);
double mass = vol;
Point3d cov = new Point3d();
// center of volume
cov.scale(1.0 / vol, mov1);
// [c], skew symmetric
Matrix3d covMatrix = new Matrix3d(0, -cov.z, cov.y, cov.z, 0, -cov.x, -cov.y, cov.x, 0);
// J
Matrix3d J = new Matrix3d((mov2.y + mov2.z), -pov.z, -pov.y, -pov.z, (mov2.x + mov2.z), -pov.x, -pov.y, -pov.x, (mov2.x + mov2.y));
// Jc = J + m[c][c]
Matrix3d Jc = new Matrix3d();
Jc.mul(covMatrix, covMatrix);
Jc.scale(mass);
Jc.add(J);
// Compute eigenvectors and eigenvlaues of Jc
SymmetricMatrix3d JcSymmetric = new SymmetricMatrix3d(Jc);
Vector3d lambda = new Vector3d();
Matrix3d U = new Matrix3d();
JcSymmetric.getEigenValues(lambda, U);
// Construct the rotation matrix
RotationMatrix3d R = new RotationMatrix3d();
R.set(U);
lambda.absolute();
if (lambda.x > lambda.y && lambda.z > lambda.y) {
R.rotateZDirection(new Vector3d(R.m01, R.m11, R.m21));
} else if (lambda.x > lambda.z && lambda.y > lambda.z) {
R.rotateZDirection(new Vector3d(R.m00, R.m10, R.m20));
}
return (new RigidTransform3d(cov, R));
}
use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method computeCentreOfVolume.
/**
* Computes the centre of volume of the mesh
*/
public double computeCentreOfVolume(Vector3d c) {
Vector3d mov1 = new Vector3d();
Vector3d mov2 = new Vector3d();
Vector3d pov = new Vector3d();
double vol = computeVolumeIntegrals(mov1, mov2, pov);
// center of volume
c.scale(1.0 / vol, mov1);
return vol;
}
use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method interpolate.
/**
* Smoothly interpolate a face using barycentric coordinates.
*
* @param f
* The face to interpolate.
* @param u
* The weighting of the first vertice.
* @param v
* The weighting of the second vertice.
*/
public void interpolate(Point3d p, Face f, double u, double v) {
HalfEdge he = f.he0;
Vertex3d v0 = he.head;
he = he.next;
Vertex3d v1 = he.head;
Vertex3d v2 = he.next.head;
Vector3d n0tmp = new Vector3d(), n1tmp = new Vector3d(), n2tmp = new Vector3d();
v0.computeNormal(n0tmp);
v1.computeNormal(n1tmp);
v2.computeNormal(n2tmp);
TrianglePatch patch = new TrianglePatch(v0.pnt, n0tmp, v1.pnt, n1tmp, v2.pnt, n2tmp);
patch.interpolate(p, u, v, (1.0 - u - v));
}
use of maspack.matrix.Vector3d in project artisynth_core by artisynth.
the class PolygonalMesh method mergeCoplanarFaces.
/**
* Merges adjacent faces whose normals satisfy n1.dot(n2) {@code >} cosLimit
*
* @param cosLimit limit above which faces should be merged
* @return true if modified, false otherwise
*/
public boolean mergeCoplanarFaces(double cosLimit) {
HashSet<HalfEdge> toMerge = new HashSet<>();
for (Face f : myFaces) {
HalfEdge he0 = f.he0;
HalfEdge he = he0;
do {
if (he.isPrimary() && he.opposite != null) {
if (he.getFace().getNormal().dot(he.opposite.getFace().getNormal()) > cosLimit) {
toMerge.add(he);
}
}
he = he.next;
} while (he != he0);
}
// go through and merge faces
boolean modified = false;
HashSet<Face> toUpdateFace = new HashSet<>();
HashSet<Face> toRemoveFace = new HashSet<>();
HashSet<Vertex3d> toRemoveVertex = new HashSet<>();
if (toMerge.size() > 0) {
for (HalfEdge he : toMerge) {
Face f1 = he.getFace();
Face f2 = he.getOppositeFace();
if (f1 == f2) {
// edge jutting out into nowhere
if (he.next == he.opposite) {
HalfEdge heopp = he.opposite;
he.head.removeIncidentHalfEdge(he);
heopp.head.removeIncidentHalfEdge(heopp);
// replace first half-edge on face
if (f1.he0 == he || f1.he0 == heopp) {
f1.he0 = heopp.next;
}
// find previous half-edge
HalfEdge hprev = heopp.next;
while (hprev.next != he) {
hprev = hprev.next;
}
hprev.next = heopp.next;
// form a loop
heopp.next = he;
// remove if vertex no longer attached to anything
if (he.head.numIncidentHalfEdges() == 0) {
toRemoveVertex.add(he.head);
}
} else if (he.opposite.next == he) {
HalfEdge heopp = he.opposite;
he.head.removeIncidentHalfEdge(he);
heopp.head.removeIncidentHalfEdge(heopp);
// replace first half-edge on face
if (f1.he0 == he || f1.he0 == heopp) {
f1.he0 = he.next;
}
// find previous half-edge
HalfEdge hprev = he.next;
while (hprev.next != heopp) {
hprev = hprev.next;
}
hprev.next = he.next;
// form a loop
he.next = heopp;
// remove if vertex no longer attached to anything
if (heopp.head.numIncidentHalfEdges() == 0) {
toRemoveVertex.add(heopp.head);
}
}
} else {
// replace first half-edge on face
if (f1.he0 == he) {
f1.he0 = he.next;
}
if (f2.he0 == he.opposite) {
f2.he0 = he.opposite.next;
}
// find previous half-edges
HalfEdge hprev = he.next;
while (hprev.next != he) {
hprev = hprev.next;
}
HalfEdge ohprev = he.opposite.next;
while (ohprev.next != he.opposite) {
ohprev = ohprev.next;
}
// adjust face on half-edges
HalfEdge hh = he.opposite.next;
do {
hh.face = f1;
hh = hh.next;
} while (hh != he.opposite);
// remove half-edge by connecting around it
he.head.removeIncidentHalfEdge(he);
he.opposite.head.removeIncidentHalfEdge(he.opposite);
hprev.next = he.opposite.next;
ohprev.next = he.next;
he.face = f2;
he.next = he.opposite;
he.opposite.face = f2;
he.opposite.next = he;
f2.he0 = he;
toRemoveFace.add(f2);
toUpdateFace.add(f1);
}
}
modified = true;
}
// remove vertices from straight lines
if (modified) {
for (Vertex3d vtx : myVertices) {
Vector3d v1 = new Vector3d();
Vector3d v2 = new Vector3d();
int nhe = vtx.numIncidentHalfEdges();
if (nhe == 0) {
toRemoveVertex.add(vtx);
} else if (nhe == 1) {
// check if straight boundary edge
HalfEdge he = vtx.firstIncidentHalfEdge();
v1.sub(he.head.pnt, he.tail.pnt);
v1.normalize();
v2.sub(he.next.head.pnt, he.next.tail.pnt);
v2.normalize();
if (v1.dot(v2) > cosLimit) {
// remove vtx and he
vtx.removeIncidentHalfEdge(he);
HalfEdge hprev = he.next;
while (hprev.next != he) {
hprev = hprev.next;
}
// connect he.next to hprev
hprev.next = he.next;
he.next.tail = hprev.head;
// maybe replace first half-edge on face
Face f = he.getFace();
if (f.he0 == he) {
f.he0 = he.next;
}
// create loop of one for removed half-edge
he.next = he;
toRemoveVertex.add(vtx);
}
} else if (nhe == 2) {
HalfEdge he = vtx.firstIncidentHalfEdge();
// check of consistent line on both sides of vertex
if (he.next.opposite != null && he.next.opposite.next == he.opposite) {
// check if closed straight edge
v1.sub(he.head.pnt, he.tail.pnt);
v1.normalize();
v2.sub(he.next.head.pnt, he.next.tail.pnt);
v2.normalize();
if (v1.dot(v2) > cosLimit) {
HalfEdge he2 = he.next.opposite;
// remove vtx and he
vtx.removeIncidentHalfEdge(he);
vtx.removeIncidentHalfEdge(he2);
HalfEdge hprev = he.next;
while (hprev.next != he) {
hprev = hprev.next;
}
// connect he.next to hprev
hprev.next = he.next;
he.next.tail = hprev.head;
HalfEdge hprev2 = he2.next;
while (hprev2.next != he2) {
hprev2 = hprev2.next;
}
// connect he2.next to hprev2
hprev2.next = he2.next;
he2.next.tail = hprev2.head;
// align new opposites
he.next.opposite = he2.next;
he2.next.opposite = he.next;
// maybe replace first half-edge on face
Face f = he.getFace();
if (f.he0 == he) {
f.he0 = he.next;
}
Face f2 = he2.getFace();
if (f2.he0 == he2) {
f2.he0 = he2.next;
}
// create loop of one for removed half-edge
he.next = he;
he2.next = he2;
toRemoveVertex.add(vtx);
}
}
}
}
}
if (modified) {
// remove faces and vertices
removeVertices(toRemoveVertex);
removeFaces(toRemoveFace);
// XXX for now just clear attributes. If we were diligent, we could re-adjust.
clearAttributes();
myTriQuadCountsValid = false;
notifyStructureChanged();
}
return modified;
}
Aggregations