/* file : PolyOrientedCurve2D.java
 * 
 * Project : geometry
 *
 * ===========================================
 * 
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. if not, write to :
 * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 * 
 * Created on 1 mai 2006
 *
 */

package math.geom2d.domain;

// Imports
import java.util.Collection;

import math.geom2d.AffineTransform2D;
import math.geom2d.Angle2D;
import math.geom2d.Box2D;
import math.geom2d.Point2D;
import math.geom2d.Vector2D;
import math.geom2d.curve.ContinuousCurve2D;
import math.geom2d.curve.Curve2D;
import math.geom2d.curve.Curves2D;
import math.geom2d.curve.CurveArray2D;
import math.geom2d.curve.CurveSet2D;
import math.geom2d.curve.PolyCurve2D;
import math.geom2d.curve.SmoothCurve2D;
import math.geom2d.line.StraightLine2D;

import static java.lang.Math.*;


/**
 * A PolyOrientedCurve2D is a set of piecewise smooth curve arcs, such that the
 * end of a curve is the beginning of the next curve, and such that they do not
 * intersect nor self-intersect.
 * 

* * @author dlegland */ public class PolyOrientedCurve2D extends PolyCurve2D implements ContinuousOrientedCurve2D { // =================================================================== // static constructors /** * Static factory for creating a new PolyOrientedCurve2D from a collection of * curves. * @since 0.8.1 */ /* public static PolyOrientedCurve2D create(Collection curves) { return new PolyOrientedCurve2D(curves); } */ /** * Static factory for creating a new PolyOrientedCurve2D from an array of * curves. * @since 0.8.1 */ public static PolyOrientedCurve2D create(T... curves) { return new PolyOrientedCurve2D(curves); } /** * Static factory for creating a new PolyOrientedCurve2D from an array of * curves. * @since 0.8.1 */ public static PolyOrientedCurve2D createClosed(T... curves) { return new PolyOrientedCurve2D(curves, true); } /** * Static factory for creating a new PolyOrientedCurve2D from a collection of * curves and a flag indicating if the curve is closed or not. * @since 0.9.0 */ /* public static PolyOrientedCurve2D create(Collection curves, boolean closed) { return new PolyOrientedCurve2D(curves, closed); } */ /** * Static factory for creating a new PolyOrientedCurve2D from an array of * curves and a flag indicating if the curve is closed or not. * @since 0.9.0 */ public static PolyOrientedCurve2D create(T[] curves, boolean closed) { return new PolyOrientedCurve2D(curves, closed); } // =================================================================== // Constructors public PolyOrientedCurve2D() { super(); } public PolyOrientedCurve2D(int size) { super(size); } public PolyOrientedCurve2D(T... curves) { super(curves); } public PolyOrientedCurve2D(T[] curves, boolean closed) { super(curves, closed); } public PolyOrientedCurve2D(Collection curves) { super(curves); } public PolyOrientedCurve2D(Collection curves, boolean closed) { super(curves, closed); } // =================================================================== // Methods specific to PolyOrientedCurve2D public double windingAngle(Point2D point) { double angle = 0; for (OrientedCurve2D curve : this.curves) angle += curve.windingAngle(point); return angle; } public double signedDistance(Point2D p) { return signedDistance(p.x(), p.y()); } /* * (non-Javadoc) * * @see math.geom2d.Shape2D#signedDistance(math.geom2d.Point2D) */ public double signedDistance(double x, double y) { double dist = this.distance(x, y); if (this.isInside(new Point2D(x, y))) dist = -dist; return dist; } /** * Determines if the given point lies within the domain bounded by this * curve. */ public boolean isInside(Point2D point) { double pos = this.project(point); if (!this.isSingular(pos)) { // Simply call the method isInside on the child curve return this.childCurve(pos).isInside(point); } // number of curves int n = this.size(); // vertex index and position int i = this.curveIndex(pos); if (pos / 2 - i > .25) i++; // Test case of point equal to last position if (round(pos) == 2 * n - 1) { pos = 0; i = 0; } Point2D vertex = this.point(pos); // indices of previous and next curves int iPrev = i > 0 ? i - 1 : n - 1; int iNext = i; // previous and next curves T prev = this.curves.get(iPrev); T next = this.curves.get(iNext); // tangent vectors of the 2 neighbor curves Vector2D v1 = computeTangent(prev, prev.t1()); Vector2D v2 = computeTangent(next, next.t0()); // compute on which side of each ray the test point lies boolean in1 = new StraightLine2D(vertex, v1).isInside(point); boolean in2 = new StraightLine2D(vertex, v2).isInside(point); // check if angle between vectors is acute or obtuse double diff = Angle2D.angle(v1, v2); double eps = 1e-12; if (diff < PI - eps) { // Acute angle return in1 && in2; } if (diff > PI + eps) { // obtuse angle return in1 || in2; } // Extract curvatures of both curves around singular point SmoothCurve2D smoothPrev = Curves2D.getLastSmoothCurve(prev); SmoothCurve2D smoothNext = Curves2D.getFirstSmoothCurve(next); double kappaPrev = smoothPrev.curvature(smoothPrev.t1()); double kappaNext = smoothNext.curvature(smoothNext.t0()); // get curvature signs double sp = Math.signum(kappaPrev); double sn = Math.signum(kappaNext); // Both curvatures have same sign // -> point is inside if both curvature are positive if (sn * sp > 0) { return kappaPrev > 0 && kappaNext > 0; } // One of the curvature is zero (straight curve) if (sn * sp == 0) { if (sn == 0 && sp == 0) { throw new IllegalArgumentException("colinear lines..."); } if (sp == 0) return kappaNext > 0; else return kappaPrev > 0; } // if curvatures have opposite signs, curves point in the same // direction but with opposite direction. if (kappaPrev > 0 && kappaNext < 0) { return Math.abs(kappaPrev) > Math.abs(kappaNext); } else { return Math.abs(kappaPrev) < Math.abs(kappaNext); } } /** * Computes the tangent of the curve at the given position. */ private static Vector2D computeTangent(ContinuousCurve2D curve, double pos) { // For smooth curves, simply call the getTangent() method if (curve instanceof SmoothCurve2D) return ((SmoothCurve2D) curve).tangent(pos); // Extract sub curve and recursively call this method on the sub curve if (curve instanceof CurveSet2D) { CurveSet2D curveSet = (CurveSet2D) curve; double pos2 = curveSet.localPosition(pos); Curve2D subCurve = curveSet.childCurve(pos); return computeTangent((ContinuousCurve2D) subCurve, pos2); } throw new IllegalArgumentException( "Unknown type of curve: should be either continuous or curveset"); } @Override public PolyOrientedCurve2D reverse() { ContinuousOrientedCurve2D[] curves2 = new ContinuousOrientedCurve2D[curves.size()]; int n = curves.size(); for (int i = 0; i < n; i++) curves2[i] = curves.get(n-1-i).reverse(); return new PolyOrientedCurve2D(curves2); } /** * Returns a portion of this curve as an instance of PolyOrientedCurve2D. */ @Override public PolyOrientedCurve2D subCurve( double t0, double t1) { PolyCurve2D set = super.subCurve(t0, t1); PolyOrientedCurve2D subCurve = new PolyOrientedCurve2D(); subCurve.setClosed(false); // convert to PolySmoothCurve by adding curves. for (Curve2D curve : set.curves()) subCurve.add((ContinuousOrientedCurve2D) curve); return subCurve; } /** * Clips the PolyCurve2D by a box. * The result is an instance of CurveSet2D, * which contains only instances of ContinuousOrientedCurve2D. If the * PolyCurve2D is not clipped, the result is an instance of * CurveSet2D which contains 0 curves. */ @Override public CurveSet2D clip(Box2D box) { // Clip the curve CurveSet2D set = Curves2D.clipCurve(this, box); // Stores the result in appropriate structure int n = set.size(); CurveArray2D result = new CurveArray2D(n); // convert the result for (Curve2D curve : set.curves()) { if (curve instanceof ContinuousOrientedCurve2D) result.add((ContinuousOrientedCurve2D) curve); } return result; } @Override public PolyOrientedCurve2D transform(AffineTransform2D trans) { PolyOrientedCurve2D result = new PolyOrientedCurve2D(); for (ContinuousOrientedCurve2D curve : curves) result.add(curve.transform(trans)); return result; } @Override public boolean equals(Object obj) { // check class if (!(obj instanceof CurveSet2D)) return false; // call superclass method return super.equals(obj); } }

Ads help maintain this website.