44
55/**
66 * Implementation of the Rotating Calipers algorithm for convex polygons.
7- *
7+ *
88 * The Rotating Calipers algorithm is used to compute various geometric properties
99 * of convex polygons efficiently, including:
1010 * - Diameter: the largest distance between any two points
1111 * - Width: the smallest distance between two parallel lines enclosing the polygon
1212 * - Minimum-area bounding rectangle: the rectangle with minimal area that encloses all points
13- *
13+ *
1414 * Time complexity: O(n) where n is the number of vertices in the convex polygon
15- *
15+ *
1616 * Reference: Shamos, M. I. (1978). Computational Geometry.
17- *
17+ *
1818 * @author TheAlgorithms
1919 */
2020public final class RotatingCalipers {
21-
21+
2222 private RotatingCalipers () {
2323 // Utility class
2424 }
25-
25+
2626 /**
2727 * Represents a pair of points.
2828 */
2929 public static final class PointPair {
3030 public final Point first ;
3131 public final Point second ;
3232 public final double distance ;
33-
33+
3434 public PointPair (Point first , Point second ) {
3535 this .first = first ;
3636 this .second = second ;
3737 this .distance = euclideanDistance (first , second );
3838 }
39-
39+
4040 @ Override
4141 public String toString () {
4242 return String .format ("PointPair{%s, %s, distance=%.2f}" , first , second , distance );
4343 }
4444 }
45-
45+
4646 /**
4747 * Represents a rectangle defined by four points.
4848 */
4949 public static final class Rectangle {
5050 public final Point [] vertices ;
5151 public final double area ;
52-
52+
5353 public Rectangle (Point [] vertices ) {
5454 this .vertices = vertices .clone ();
5555 this .area = calculateArea (vertices );
5656 }
57-
57+
5858 private static double calculateArea (Point [] vertices ) {
59- if (vertices .length != 4 ) return 0 ;
59+ if (vertices .length != 4 ) {
60+ return 0 ;
61+ }
6062 double width = euclideanDistance (vertices [0 ], vertices [1 ]);
6163 double height = euclideanDistance (vertices [1 ], vertices [2 ]);
6264 return width * height ;
6365 }
64-
66+
6567 @ Override
6668 public String toString () {
6769 return String .format ("Rectangle{area=%.2f}" , area );
@@ -71,7 +73,7 @@ public String toString() {
7173 /**
7274 * Computes the diameter of a convex polygon using rotating calipers.
7375 * The diameter is the maximum distance between any two vertices.
74- *
76+ *
7577 * @param convexHull List of points representing the convex hull in counter-clockwise order
7678 * @return PointPair containing the two points that form the diameter
7779 * @throws IllegalArgumentException if the hull has fewer than 2 points
@@ -80,14 +82,14 @@ public static PointPair diameter(List<Point> convexHull) {
8082 if (convexHull .size () < 2 ) {
8183 throw new IllegalArgumentException ("Convex hull must have at least 2 points" );
8284 }
83-
85+
8486 if (convexHull .size () == 2 ) {
8587 return new PointPair (convexHull .get (0 ), convexHull .get (1 ));
8688 }
87-
89+
8890 // Find maximum distance between all pairs of points
8991 PointPair maxPair = new PointPair (convexHull .get (0 ), convexHull .get (1 ));
90-
92+
9193 for (int i = 0 ; i < convexHull .size (); i ++) {
9294 for (int j = i + 1 ; j < convexHull .size (); j ++) {
9395 PointPair candidate = new PointPair (convexHull .get (i ), convexHull .get (j ));
@@ -96,14 +98,14 @@ public static PointPair diameter(List<Point> convexHull) {
9698 }
9799 }
98100 }
99-
101+
100102 return maxPair ;
101103 }
102104
103105 /**
104106 * Computes the width of a convex polygon using rotating calipers.
105107 * The width is the minimum distance between two parallel supporting lines.
106- *
108+ *
107109 * @param convexHull List of points representing the convex hull in counter-clockwise order
108110 * @return The minimum width of the polygon
109111 * @throws IllegalArgumentException if the hull has fewer than 3 points
@@ -112,15 +114,15 @@ public static double width(List<Point> convexHull) {
112114 if (convexHull .size () < 3 ) {
113115 throw new IllegalArgumentException ("Convex hull must have at least 3 points for width calculation" );
114116 }
115-
117+
116118 int n = convexHull .size ();
117119 double minWidth = Double .MAX_VALUE ;
118-
120+
119121 int j = 1 ;
120122 for (int i = 0 ; i < n ; i ++) {
121123 Point p1 = convexHull .get (i );
122124 Point p2 = convexHull .get ((i + 1 ) % n );
123-
125+
124126 // Find the farthest point from edge p1-p2
125127 while (true ) {
126128 int nextJ = (j + 1 ) % n ;
@@ -130,17 +132,17 @@ public static double width(List<Point> convexHull) {
130132 break ;
131133 }
132134 }
133-
135+
134136 double currentWidth = distanceToLine (p1 , p2 , convexHull .get (j ));
135137 minWidth = Math .min (minWidth , currentWidth );
136138 }
137-
139+
138140 return minWidth ;
139141 }
140142
141143 /**
142144 * Computes the minimum-area bounding rectangle of a convex polygon.
143- *
145+ *
144146 * @param convexHull List of points representing the convex hull in counter-clockwise order
145147 * @return Rectangle with minimum area that encloses all points
146148 * @throws IllegalArgumentException if the hull has fewer than 3 points
@@ -149,24 +151,24 @@ public static Rectangle minimumBoundingRectangle(List<Point> convexHull) {
149151 if (convexHull .size () < 3 ) {
150152 throw new IllegalArgumentException ("Convex hull must have at least 3 points" );
151153 }
152-
154+
153155 int n = convexHull .size ();
154156 Rectangle minRect = null ;
155157 double minArea = Double .MAX_VALUE ;
156-
158+
157159 for (int i = 0 ; i < n ; i ++) {
158160 Point p1 = convexHull .get (i );
159161 Point p2 = convexHull .get ((i + 1 ) % n );
160-
162+
161163 // Create rectangle aligned with edge p1-p2
162164 Rectangle rect = createAlignedRectangle (convexHull , p1 , p2 );
163-
165+
164166 if (rect .area < minArea ) {
165167 minArea = rect .area ;
166168 minRect = rect ;
167169 }
168170 }
169-
171+
170172 return minRect ;
171173 }
172174
@@ -178,40 +180,43 @@ private static Rectangle createAlignedRectangle(List<Point> points, Point p1, Po
178180 double dx = p2 .x () - p1 .x ();
179181 double dy = p2 .y () - p1 .y ();
180182 double length = Math .sqrt (dx * dx + dy * dy );
181-
183+
182184 if (length == 0 ) {
183185 // Degenerate case
184186 return new Rectangle (new Point []{p1 , p1 , p1 , p1 });
185187 }
186-
188+
187189 // Unit vectors
188190 double ux = dx / length ;
189191 double uy = dy / length ;
190192 double vx = -uy ; // Perpendicular vector
191193 double vy = ux ;
192-
193- double minU = 0 , maxU = 0 , minV = 0 , maxV = 0 ;
194-
194+
195+ double minU = 0 ;
196+ double maxU = 0 ;
197+ double minV = 0 ;
198+ double maxV = 0 ;
199+
195200 for (Point p : points ) {
196201 double u = (p .x () - p1 .x ()) * ux + (p .y () - p1 .y ()) * uy ;
197202 double v = (p .x () - p1 .x ()) * vx + (p .y () - p1 .y ()) * vy ;
198-
203+
199204 minU = Math .min (minU , u );
200205 maxU = Math .max (maxU , u );
201206 minV = Math .min (minV , v );
202207 maxV = Math .max (maxV , v );
203208 }
204-
209+
205210 // Calculate rectangle corners
206211 Point [] corners = new Point [4 ];
207212 corners [0 ] = new Point ((int ) Math .round (p1 .x () + minU * ux + minV * vx ), (int ) Math .round (p1 .y () + minU * uy + minV * vy ));
208213 corners [1 ] = new Point ((int ) Math .round (p1 .x () + maxU * ux + minV * vx ), (int ) Math .round (p1 .y () + maxU * uy + minV * vy ));
209214 corners [2 ] = new Point ((int ) Math .round (p1 .x () + maxU * ux + maxV * vx ), (int ) Math .round (p1 .y () + maxU * uy + maxV * vy ));
210215 corners [3 ] = new Point ((int ) Math .round (p1 .x () + minU * ux + maxV * vx ), (int ) Math .round (p1 .y () + minU * uy + maxV * vy ));
211-
216+
212217 return new Rectangle (corners );
213218 }
214-
219+
215220 /**
216221 * Calculates the Euclidean distance between two points.
217222 */
@@ -220,21 +225,21 @@ private static double euclideanDistance(Point p1, Point p2) {
220225 double dy = p1 .y () - p2 .y ();
221226 return Math .sqrt (dx * dx + dy * dy );
222227 }
223-
228+
224229 /**
225230 * Calculates the perpendicular distance from a point to a line defined by two points.
226231 */
227232 private static double distanceToLine (Point lineStart , Point lineEnd , Point point ) {
228233 double dx = lineEnd .x () - lineStart .x ();
229234 double dy = lineEnd .y () - lineStart .y ();
230-
235+
231236 if (dx == 0 && dy == 0 ) {
232237 return euclideanDistance (lineStart , point );
233238 }
234-
239+
235240 double numerator = Math .abs (dy * point .x () - dx * point .y () + lineEnd .x () * lineStart .y () - lineEnd .y () * lineStart .x ());
236241 double denominator = Math .sqrt (dx * dx + dy * dy );
237-
242+
238243 return numerator / denominator ;
239244 }
240- }
245+ }
0 commit comments