Search in sources :

Example 1 with Vertex3d

use of maspack.geometry.Vertex3d in project artisynth_core by artisynth.

the class MeshThicken method applyGrowth.

public void applyGrowth(PolygonalMesh mesh, double dn) {
    mesh.autoGenerateNormals();
    for (int i = 0; i < mesh.numVertices(); i++) {
        Vertex3d v = mesh.getVertex(i);
        Vector3d n = mesh.getNormal(i);
        v.pnt.scaledAdd(dn, n);
    }
    myMesh.notifyVertexPositionsModified();
    viewer.rerender();
}
Also used : Vertex3d(maspack.geometry.Vertex3d) Vector3d(maspack.matrix.Vector3d)

Example 2 with Vertex3d

use of maspack.geometry.Vertex3d in project artisynth_core by artisynth.

the class MeshThicken method applyThickening.

public void applyThickening(Region region, MeshBase mesh, double thickening) {
    double margin = region.myMargin;
    Point3d pnt = new Point3d();
    Vector3d nrm = new Vector3d();
    Vector2d p2d = new Vector2d();
    ArrayList<Vertex3d> verts = myMesh.getVertices();
    ArrayList<Vector3d> nrmls = mesh.getNormals();
    if (nrmls == null) {
        System.out.println("Mesh does not have normals; thickening ignored");
    }
    int cnt = 0;
    Vector3d regionNrm = new Vector3d();
    // region normal in mesh coordinates
    region.myFrame.R.getColumn(2, regionNrm);
    for (int i = 0; i < verts.size(); i++) {
        Vertex3d v = verts.get(i);
        pnt.inverseTransform(region.myFrame, v.pnt);
        nrm.inverseTransform(region.myFrame, nrmls.get(i));
        if (pnt.z <= region.myHeight && pnt.z >= -region.myBackHeight) {
            // if (Math.abs(pnt.z) <= region.myHeight) {
            p2d.set(pnt.x, pnt.y);
            double d = region.myDist.computeInteriorDistance(/*near=*/
            null, p2d);
            if (d <= 0) {
                double dz = computeDeltaZ(-d, margin, thickening);
                if (region.myUseNormalZScalingP) {
                    if (adjacentFacesCrossNormal(v, regionNrm)) {
                        dz = 0;
                    } else {
                        dz *= nrm.z;
                    }
                } else {
                    dz = (nrm.z >= 0 ? dz : -dz);
                }
                if (nrm.z >= 0) {
                    pnt.z += dz;
                } else {
                    if (region.getThickenBackSide()) {
                        pnt.z += dz;
                    }
                }
                v.pnt.transform(region.myFrame, pnt);
                cnt++;
            }
        }
    }
    System.out.println("count=" + cnt);
    myMesh.notifyVertexPositionsModified();
    viewer.rerender();
}
Also used : Vertex3d(maspack.geometry.Vertex3d) Vector2d(maspack.matrix.Vector2d) Vector3d(maspack.matrix.Vector3d) Point3d(maspack.matrix.Point3d)

Example 3 with Vertex3d

use of maspack.geometry.Vertex3d 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());
            }
        }
    }
}
Also used : Vertex3d(maspack.geometry.Vertex3d) Vector3d(maspack.matrix.Vector3d) Face(maspack.geometry.Face) Point(java.awt.Point)

Example 4 with Vertex3d

use of maspack.geometry.Vertex3d 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);
        }
    }
}
Also used : Vertex3d(maspack.geometry.Vertex3d) LinkedHashSet(java.util.LinkedHashSet) RigidTransform3d(maspack.matrix.RigidTransform3d) TriTriIntersection(maspack.geometry.TriTriIntersection) BVFeatureQuery(maspack.geometry.BVFeatureQuery) AxisAngle(maspack.matrix.AxisAngle) Vector2d(maspack.matrix.Vector2d) Vector3d(maspack.matrix.Vector3d) Point3d(maspack.matrix.Point3d) Face(maspack.geometry.Face)

Example 5 with Vertex3d

use of maspack.geometry.Vertex3d in project artisynth_core by artisynth.

the class ContactPlane method normalContact.

/*
    * Handle the case where there are enough contact points in the contour to
    * define a plane.
    */
boolean normalContact(PenetrationRegion region0, PenetrationRegion region1, PolygonalMesh mesh0) {
    /*
       * Project each point into the plane. Calculate the radius of the
       * projected point from the centroid. Also calculate the maximum distance
       * of a mesh intersection point from either side of the plane. This
       * maximum depth includes all points, even concave ones which may later be
       * removed from the contour.
       */
    Point3d proj = new Point3d();
    for (IntersectionPoint mip : mPoints) {
        proj.sub(mip, centroid);
        // signed distance from plane to the mip
        double s = proj.dot(normal);
        // along normal
        if (s < minProjectedDistance) {
            minProjectedDistance = s;
        }
        if (s > maxProjectedDistance) {
            maxProjectedDistance = s;
        }
        proj.scaledAdd(-s, normal);
    // mip.radius = proj.norm();
    }
    /*
       * Distance between two planes parallel to the fitted plane which contain
       * all the intersection points between them.
       */
    depth = maxProjectedDistance - minProjectedDistance;
    /*
       * Remove concave points to make the points a convex hull. A point p1 is
       * concave with respect to the preceding and following points p0 and p2
       * if the point sequence p0, p1, p2 forms a right turn with respect to
       * the normal.
       */
    boolean removedPoint;
    Vector3d xprod = new Vector3d();
    do {
        removedPoint = false;
        IntersectionPoint p0;
        IntersectionPoint p1 = mPoints.get(0);
        IntersectionPoint p2 = mPoints.get(1);
        int i = 2;
        for (int k = 1; k <= mPoints.size(); k++) {
            p0 = p1;
            p1 = p2;
            p2 = mPoints.get(i % mPoints.size());
            if (turn(p0, p1, p2, normal) < 0) {
                mPoints.remove((i - 1) % mPoints.size());
                removedPoint = true;
                p1 = p0;
            } else {
                i++;
            }
        }
    } while (removedPoint);
    /*
       * Adjust depth so it is greater than or equal to the maximum distance
       * from a vertex of either region to the opposing face of that vertex.
       * 
       * Also try to figure out which way the normal should point. It's
       * required by RigidBodyContact to point in the direction of the force to
       * be applied to mesh0 to stop it from penetrating mesh1. For
       * pathological contours this may be ambiguous, but in the simple case
       * where the contour fits well to a plane, the ContactRegion normal
       * should point from the penetrating vertices of mesh0 to the opposing
       * faces of mesh1.
       * 
       * If the contour is too confusing to distinguish a direction then throw
       * an error.
       */
    if (region0.numVertices() + region1.numVertices() == 0) {
        checkNormalDirection(region0.getFaces(), region1.getFaces(), mesh0);
    } else {
        double dTotal = 0;
        BVFeatureQuery query = new BVFeatureQuery();
        Point3d wpnt = new Point3d();
        Point3d nearest = new Point3d();
        Vector2d coords = new Vector2d();
        Vector3d diff = new Vector3d();
        for (Vertex3d v : region0.myVertices) {
            v.getWorldPoint(wpnt);
            if (query.isInsideOrientedMesh(region1.myMesh, wpnt, 0)) {
                query.getFaceForInsideOrientedTest(nearest, coords);
                region1.myMesh.transformToWorld(nearest);
                diff.sub(wpnt, nearest);
                double d = diff.dot(normal);
                dTotal += d;
                if (d < 0) {
                    d = -d;
                }
                if (d > depth) {
                    depth = d;
                }
            }
        }
        for (Vertex3d v : region1.myVertices) {
            v.getWorldPoint(wpnt);
            if (query.isInsideOrientedMesh(region0.myMesh, wpnt, 0)) {
                query.getFaceForInsideOrientedTest(nearest, coords);
                region0.myMesh.transformToWorld(nearest);
                diff.sub(wpnt, nearest);
                double d = diff.dot(normal);
                dTotal -= d;
                if (d < 0) {
                    d = -d;
                }
                if (d > depth) {
                    depth = d;
                }
            }
        }
        if (dTotal > 0) {
            negateNormal();
        }
    }
    return true;
}
Also used : Vertex3d(maspack.geometry.Vertex3d) Vector3d(maspack.matrix.Vector3d)

Aggregations

Vertex3d (maspack.geometry.Vertex3d)81 Point3d (maspack.matrix.Point3d)35 Face (maspack.geometry.Face)30 PolygonalMesh (maspack.geometry.PolygonalMesh)24 Vector3d (maspack.matrix.Vector3d)23 ContactPoint (artisynth.core.mechmodels.ContactPoint)22 Point (artisynth.core.mechmodels.Point)22 ArrayList (java.util.ArrayList)19 PointParticleAttachment (artisynth.core.mechmodels.PointParticleAttachment)15 HalfEdge (maspack.geometry.HalfEdge)13 PointAttachment (artisynth.core.mechmodels.PointAttachment)10 HashMap (java.util.HashMap)10 Vector2d (maspack.matrix.Vector2d)8 VectorNd (maspack.matrix.VectorNd)8 BVFeatureQuery (maspack.geometry.BVFeatureQuery)7 RenderProps (maspack.render.RenderProps)6 PointFem3dAttachment (artisynth.core.femmodels.PointFem3dAttachment)5 Color (java.awt.Color)5 FemNode (artisynth.core.femmodels.FemNode)4 BufferedWriter (java.io.BufferedWriter)4