1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.geometry.hull.euclidean.twod;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23
24 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
25 import org.apache.commons.geometry.euclidean.twod.ConvexArea;
26 import org.apache.commons.geometry.euclidean.twod.Vector2D;
27 import org.apache.commons.geometry.euclidean.twod.path.LinePath;
28 import org.apache.commons.geometry.hull.ConvexHull;
29
30 /**
31 * This class represents a convex hull in two-dimensional Euclidean space.
32 */
33 public final class ConvexHull2D implements ConvexHull<Vector2D> {
34
35 /** Vertices for the convex hull, in order. */
36 private final List<Vector2D> vertices;
37
38 /** Polyline path for the convex hull. */
39 private final LinePath path;
40
41 /** Simple constructor; no validation is performed.
42 * @param vertices the vertices of the convex hull; callers are responsible for ensuring that
43 * the given vertices are in order, unique, and define a convex hull.
44 * @param precision precision context used to compare floating point numbers
45 */
46 ConvexHull2D(final Collection<Vector2D> vertices, final DoublePrecisionContext precision) {
47 this.vertices = Collections.unmodifiableList(new ArrayList<>(vertices));
48 this.path = buildHullPath(vertices, precision);
49 }
50
51 /** {@inheritDoc} */
52 @Override
53 public List<Vector2D> getVertices() {
54 return vertices;
55 }
56
57 /** Get a path defining the convex hull. The path will contain
58 * <ul>
59 * <li>zero segments if the hull consists of only a single point,</li>
60 * <li>one segment if the hull consists of two points,</li>
61 * <li>three or more segments defining a closed loop if the hull consists of more than
62 * two non-collinear points.</li>
63 * </ul>
64 * @return polyline path defining the convex hull
65 */
66 public LinePath getPath() {
67 return path;
68 }
69
70 /** {@inheritDoc} */
71 @Override
72 public ConvexArea getRegion() {
73 return path.isClosed() ?
74 ConvexArea.convexPolygonFromPath(path) :
75 null;
76 }
77
78 /** {@inheritDoc} */
79 @Override
80 public String toString() {
81 final StringBuilder sb = new StringBuilder();
82 sb.append(getClass().getSimpleName())
83 .append("[vertices= ")
84 .append(getVertices())
85 .append(']');
86
87 return sb.toString();
88 }
89
90 /** Build a polyline representing the path for a convex hull.
91 * @param vertices convex hull vertices
92 * @param precision precision context used to compare floating point values
93 * @return path for the convex hull defined by the given vertices
94 */
95 private static LinePath buildHullPath(final Collection<Vector2D> vertices, final DoublePrecisionContext precision) {
96 if (vertices.size() < 2) {
97 return LinePath.empty();
98 }
99
100 final boolean closeLoop = vertices.size() > 2;
101
102 return LinePath.builder(precision)
103 .appendVertices(vertices)
104 .build(closeLoop);
105 }
106 }