/** * */ package cz.cuni.mff.peckam.java.origamist.modelstate; import static cz.cuni.mff.peckam.java.origamist.math.MathHelper.EPSILON; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.vecmath.Point2d; import javax.vecmath.Point3d; import cz.cuni.mff.peckam.java.origamist.math.IntersectionWithTriangle; import cz.cuni.mff.peckam.java.origamist.math.Line3d; import cz.cuni.mff.peckam.java.origamist.math.Polygon3d; import cz.cuni.mff.peckam.java.origamist.math.Segment2d; import cz.cuni.mff.peckam.java.origamist.math.Segment3d; import cz.cuni.mff.peckam.java.origamist.math.Stripe3d; /** * A layer of the paper - a planar part of the paper that is surrouned by paper boundaries and triangles with a * non-parallel normal. * * @author Martin Pecka */ public class Layer extends Polygon3d<ModelTriangle> { /** * Create a new layer consisting of the given triangles. * * @param triangles The triangles the layer consists of. The list can be modified by this function. * @throws IllegalStateException If the resulting layer either wouldn't be connected or one of the triangles * doesn't lie in the same plane as the first triangle does. In the case this exception is thrown, the * layers's state will remain the same as before calling this function (eg. this will not try to add * all "valid" triangles from the given list, but it either accepts all or none of them). */ public Layer(List<ModelTriangle> triangles) throws IllegalStateException { super(triangles); } /** * Create a new layer consisting of the given triangles. * * @param triangles The triangles the layer consists of. The list can be modified by this function. * @throws IllegalStateException If the resulting layer either wouldn't be connected or one of the triangles * doesn't lie in the same plane as the first triangle does. In the case this exception is thrown, the * layers's state will remain the same as before calling this function (eg. this will not try to add * all "valid" triangles from the given list, but it either accepts all or none of them). */ public Layer(ModelTriangle... triangles) throws IllegalStateException { super(triangles); } /** * Create a new layer consisting of the given triangles. * * @param triangles The triangles the layer consists of. The list can be modified by this function. * @throws IllegalStateException If the resulting layer either wouldn't be connected or one of the triangles * doesn't lie in the same plane as the first triangle does. In the case this exception is thrown, the * layers's state will remain the same as before calling this function (eg. this will not try to add * all "valid" triangles from the given list, but it either accepts all or none of them). */ public Layer(Set<ModelTriangle> triangles) throws IllegalStateException { super(triangles); } /** * Create a new layer out of the given polygon. * * @param polygon The polygon to create the layer from. */ public Layer(Polygon3d<ModelTriangle> polygon) { this(new HashSet<ModelTriangle>(polygon.getTriangles())); } @Override protected boolean additionalAddTrianglesCheck(Set<ModelTriangle> triangles) { // check if every two triangles neighboring in 3D are also neighbors on the paper for (ModelTriangle t : triangles) { List<ModelTriangle> neighbors = getNeighbors(t); for (ModelTriangle n : neighbors) { if (!t.originalPosition.hasCommonEdge(n.originalPosition, false)) return false; } } return true; } @Override protected boolean additionalRemoveTrianglesCheck(Set<ModelTriangle> triangles) { // check if every two triangles neighboring in 3D are also neighbors on the paper for (ModelTriangle t : this.triangles) { List<ModelTriangle> neighbors = getNeighbors(t); for (ModelTriangle n : neighbors) { if (!t.originalPosition.hasCommonEdge(n.originalPosition, false)) return false; } } return true; } @Override public List<? extends ModelSegment> getIntersections(Line3d line) { // connect all segments that can be connected into one new segment List<IntersectionWithTriangle<ModelTriangle>> intersections = getIntersectionsWithTriangles(line); return joinNeighboringSegments(intersections); } @Override public List<? extends ModelSegment> joinNeighboringSegments(List<IntersectionWithTriangle<ModelTriangle>> segments) { LinkedList<ModelSegment> result = new LinkedList<ModelSegment>(); for (IntersectionWithTriangle<ModelTriangle> s : segments) { ModelSegment newSeg = new ModelSegment(s, null, 0); if (result.size() == 0 || !result.getLast().getP2().epsilonEquals(s.getP1(), EPSILON)) { result.add(newSeg); } else { ModelSegment last = result.getLast(); last = new ModelSegment(new Segment3d(last.getP1(), s.getP2()), new Segment2d(last.getOriginal() .getP1(), newSeg.getOriginal().getP2()), null, 0); result.removeLast(); result.add(last); } } return result; } /** * Tell whether this polygon contains the given point both in 3D and 2D. * * @param point The point to check. * @return <code>true</code> if this polygon contains the given point in both 3D and 2D. */ public boolean contains(ModelPoint point) { if (!plane.contains(point)) return false; for (ModelTriangle t : triangles) { if (t.contains(point) && t.getOriginalPosition().contains(point.getOriginal())) return true; } return false; } /** * Tell whether this polygon's 2D triangles contain the given 2D point. * * @param point The point to check. * @return <code>true</code> if this polygon contains the given point in 2D. */ public boolean contains(Point2d point) { for (ModelTriangle t : triangles) { if (t.getOriginalPosition().contains(point)) return true; } return false; } /** * Return the single segment defining the intersection of the given stripe with this polygon (this segment joins the * first and last segment returned by {@link Polygon3d#getIntersections(Stripe3d)}). * * @param stripe The stripe to find the intersection with. * @return The intersection of the given stripe and this polygon. <code>null</code> if the stripe is parallel to * this polygon (and if it lies in the same plane as the polygon) or if the stripe doesn't intersect with * it. */ public ModelSegment getIntersectionSegment(Stripe3d stripe) { @SuppressWarnings("unchecked") List<? extends ModelSegment> ints = (List<? extends ModelSegment>) getIntersections(stripe); if (ints == null || ints.size() == 0) return null; Point3d int1 = ints.get(0).getP1(); Point3d int2 = ints.get(ints.size() - 1).getP2(); Point2d int1_2 = ints.get(0).getOriginal().getP1(); Point2d int2_2 = ints.get(ints.size() - 1).getOriginal().getP2(); return new ModelSegment(new Segment3d(int1, int2), new Segment2d(int1_2, int2_2), null, -1); } /** * Return the single segment defining the intersection of the given line with this polygon (this segment joins the * first and last segment returned by {@link Polygon3d#getIntersections(Line3d)}). * * @param line The line to find the intersection with. * @return The intersection of the given line and this polygon. <code>null</code> if the line doesn't intersect. */ public ModelSegment getIntersectionSegment(Line3d line) { List<? extends ModelSegment> ints = (List<? extends ModelSegment>) getIntersections(line); if (ints == null || ints.size() == 0) return null; Point3d int1 = ints.get(0).getP1(); Point3d int2 = ints.get(ints.size() - 1).getP2(); Point2d int1_2 = ints.get(0).getOriginal().getP1(); Point2d int2_2 = ints.get(ints.size() - 1).getOriginal().getP2(); return new ModelSegment(new Segment3d(int1, int2), new Segment2d(int1_2, int2_2), null, -1); } }