View Javadoc

1   /* File CircleInversion2D.java 
2    *
3    * Project : Java Geometry Library
4    *
5    * ===========================================
6    * 
7    * This library is free software; you can redistribute it and/or modify it 
8    * under the terms of the GNU Lesser General Public License as published by
9    * the Free Software Foundation, either version 2.1 of the License, or (at
10   * your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful, but 
13   * WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
14   * or FITNESS FOR A PARTICULAR PURPOSE.
15   *
16   * See the GNU Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public License
19   * along with this library. if not, write to :
20   * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21   * Boston, MA 02111-1307, USA.
22   */
23  
24  // package
25  
26  package math.geom2d.transform;
27  
28  import java.util.*;
29  import math.geom2d.conic.Circle2D;
30  import math.geom2d.conic.CircleArc2D;
31  import math.geom2d.curve.PolyCurve2D;
32  import math.geom2d.domain.BoundaryPolyCurve2D;
33  import math.geom2d.domain.BoundarySet2D;
34  import math.geom2d.line.LineSegment2D;
35  import math.geom2d.line.LinearShape2D;
36  import math.geom2d.line.StraightLine2D;
37  import math.geom2d.polygon.Polygon2D;
38  import math.geom2d.polygon.Polyline2D;
39  import math.geom2d.polygon.LinearRing2D;
40  import math.geom2d.Angle2D;
41  import math.geom2d.Point2D;
42  import math.geom2d.Shape2D;
43  
44  // Imports
45  
46  /**
47   * circle inversion : performs a bijection between points outside the circle and
48   * points inside the circle.
49   */
50  public class CircleInversion2D implements Transform2D {
51  
52      // ===================================================================
53      // constants
54  
55      // ===================================================================
56      // class variables
57      protected Circle2D circle = new Circle2D();
58  
59      // ===================================================================
60      // constructors
61  
62      /**
63       * Construct a new circle inversion based on the unit circle centered on the
64       * origin.
65       */
66      public CircleInversion2D() {
67          this.circle = new Circle2D(0, 0, 1);
68      }
69  
70      public CircleInversion2D(Circle2D circle) {
71          this.circle = circle;
72      }
73  
74      // ===================================================================
75      // accessors
76  
77      public Point2D getCenter() {
78      	return circle.getCenter();
79      }
80      
81      public double getRadius() {
82      	return circle.getRadius();
83      }
84      
85      public void setCircle(double xc, double yc, double r) {
86          this.circle = new Circle2D(xc, yc, r);
87      }
88  
89      public void setCircle(Circle2D circle) {
90          this.circle = new Circle2D(circle.getCenter(), circle.getRadius());
91      }
92  
93      // ===================================================================
94      // modifiers
95  
96      // ===================================================================
97      // general methods
98  
99      /**
100      * Transforms a general shape, and return the transformed shape.
101      * <p>
102      * Transformed shape can be computed for different cases:
103      * <ul>
104      * <li>Point2D is transformed into another Point2D</li>
105      * <li>LinearShape2D is transformed into a CircleArc2D or a Circle2D</li>
106      * <li>Circle2D is transformed into another Circle2D</li>
107      * <li>Polyline2D is transformed into a continuous set of circle arcs</li>
108      * </ul>
109      */
110     public Shape2D transformShape(Shape2D shape) {
111 
112         if (shape instanceof Point2D) {
113             double xc = circle.getCenter().getX();
114             double yc = circle.getCenter().getY();
115             double r = circle.getRadius();
116             Point2D pt = (Point2D) shape;
117 
118             double d = r*r/pt.getDistance(xc, yc);
119             double theta = Math.atan2(pt.getY()-yc, pt.getX()-xc);
120             return Point2D.createPolar(circle.getCenter(), d, theta);
121         } else if (shape instanceof LinearShape2D) {
122             Point2D center = circle.getCenter();
123             double r = circle.getRadius();
124             LinearShape2D line = (LinearShape2D) shape;
125 
126             Point2D po = line.getSupportingLine().getProjectedPoint(center);
127             double d = center.getDistance(po);
128 
129             // Degenerate case of a point belonging to the line :
130             // the transform is the line itself.
131             if (Math.abs(d)<Shape2D.ACCURACY)
132                 return new StraightLine2D(line);
133 
134             // angle from center to line
135             double angle = Angle2D.getHorizontalAngle(center, po);
136 
137             // center of transformed circle
138             double r2 = r*r/d/2;
139             Point2D c2 = Point2D.createPolar(center, r2, angle);
140 
141             // case of straight line -> create a full circle
142             if (line instanceof StraightLine2D)
143                 return new Circle2D(c2, r2);
144 
145             // case of line segment -> create a circle arc
146             if (line instanceof LineSegment2D) {
147                 LineSegment2D segment = (LineSegment2D) line;
148 
149                 // transform limits of edges, to obtain limits of arc
150                 Point2D p1 = segment.getFirstPoint();
151                 Point2D p2 = segment.getLastPoint();
152                 p1 = this.transformPoint(p1);
153                 p2 = this.transformPoint(p2);
154 
155                 // compute start and end angles of arc
156                 double theta1 = Angle2D.getHorizontalAngle(c2, p1);
157                 double theta2 = Angle2D.getHorizontalAngle(c2, p2);
158 
159                 boolean direct = new StraightLine2D(segment).isInside(center);
160 
161                 return new CircleArc2D(c2, r2, theta1, theta2, direct);
162             }
163         } else if (shape instanceof Circle2D) {
164             Point2D center = circle.getCenter();
165             Circle2D circle = (Circle2D) shape;
166 
167             Point2D c1 = circle.getCenter();
168             StraightLine2D line = new StraightLine2D(center, c1);
169 
170             // transform the two extreme points of the circle
171             Collection<Point2D> points = circle.getIntersections(line);
172             Iterator<Point2D> iter = points.iterator();
173             Point2D p1 = this.transformPoint(iter.next());
174             Point2D p2 = this.transformPoint(iter.next());
175 
176             // get center and diameter of transformed circle
177             double d = p1.getDistance(p2);
178             c1 = Point2D.midPoint(p1, p2);
179 
180             return new Circle2D(c1, d/2);
181         } else if (shape instanceof Polyline2D) {
182             // get all edges of polyline
183             Collection<LineSegment2D> edges = ((Polyline2D) shape).getEdges();
184 
185             // transform each edge into a circle arc
186             ArrayList<CircleArc2D> arcs = new ArrayList<CircleArc2D>();
187             for (LineSegment2D edge : edges)
188                 arcs.add((CircleArc2D) this.transformShape(edge));
189 
190             // create new shape by putting all arcs together
191             return new PolyCurve2D<CircleArc2D>(arcs);
192         } else if (shape instanceof Polygon2D) {
193             // get all rings of polygon
194             Collection<? extends LinearRing2D> rings = ((Polygon2D) shape).getRings();
195 
196             // for each ring, create a curve formed by several circle arcs
197             ArrayList<BoundaryPolyCurve2D<CircleArc2D>> curves = 
198                 new ArrayList<BoundaryPolyCurve2D<CircleArc2D>>(rings.size());    
199             for (LinearRing2D ring : rings)
200                 curves.add(this.transformRing(ring));
201 
202             // create new shape by putting all boundaries together
203             return new BoundarySet2D<BoundaryPolyCurve2D<CircleArc2D>>(curves);
204         }
205 
206         return null;
207     }
208 
209     
210      /**
211       * @deprecated use transformShape() instead (0.7.0)
212       */
213     @Deprecated
214     public Shape2D transform(Shape2D shape) {
215         return this.transformShape(shape);
216     }
217 
218     
219     public Point2D transformPoint(java.awt.geom.Point2D pt) {
220         Point2D center = circle.getCenter();
221         double r = circle.getRadius();
222 
223         double d = r*r/Point2D.getDistance(pt, center);
224         double theta = Angle2D.getHorizontalAngle(center, pt);
225         return Point2D.createPolar(center, d, theta);
226     }
227 
228     public BoundaryPolyCurve2D<CircleArc2D> transformRing(LinearRing2D ring) {    
229         // get all edges of the ring
230         Collection<LineSegment2D> edges = ring.getEdges();
231 
232         // transform each edge into a circle arc
233         ArrayList<CircleArc2D> arcs = new ArrayList<CircleArc2D>();
234         for (LineSegment2D edge : edges)
235             arcs.add((CircleArc2D) this.transformShape(edge));
236 
237         // create new shape by putting all arcs together
238         return new BoundaryPolyCurve2D<CircleArc2D>(arcs);
239     }
240     
241     public Point2D transform(java.awt.geom.Point2D pt) {
242         Point2D center = circle.getCenter();
243         double r = circle.getRadius();
244 
245         double d = r*r/Point2D.getDistance(pt, center);
246         double theta = Angle2D.getHorizontalAngle(center, pt);
247         return Point2D.createPolar(center, d, theta);
248     }
249 
250     /** Transforms an array of points, and returns the transformed points. */
251     public Point2D[] transform(java.awt.geom.Point2D[] src, Point2D[] dst) {
252 
253         double d, theta;
254         double xc, yc, r;
255 
256         // create the array if necessary
257         if (dst==null)
258             dst = new Point2D[src.length];
259 
260         // create instances of Points if necessary
261         if (dst[0]==null)
262             for (int i = 0; i<dst.length; i++)
263                 dst[i] = new Point2D();
264 
265         xc = circle.getCenter().getX();
266         yc = circle.getCenter().getY();
267         r = circle.getRadius();
268 
269         // transform each point
270         for (int i = 0; i<src.length; i++) {
271             d = java.awt.geom.Point2D.distance(src[i].getX(), src[i].getY(), xc, yc);
272             d = r*r/d;
273             theta = Math.atan2(src[i].getY()-yc, src[i].getX()-xc);
274             dst[i].setLocation(d*Math.cos(theta), d*Math.sin(theta));
275         }
276 
277         return dst;
278     }
279 
280 }