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.euclidean.threed.line;
18
19 import org.apache.commons.geometry.core.Transform;
20 import org.apache.commons.geometry.euclidean.threed.Bounds3D;
21 import org.apache.commons.geometry.euclidean.threed.Vector3D;
22 import org.apache.commons.numbers.core.Precision;
23
24 /** Class representing a line segment in 3D Euclidean space. A line segment is a portion of
25 * a line with finite start and end points.
26 *
27 * <p>Instances of this class are guaranteed to be immutable.</p>
28 * @see Lines3D
29 * @see <a href="https://en.wikipedia.org/wiki/Line_segment">Line Segment</a>
30 */
31 public final class Segment3D extends LineConvexSubset3D {
32
33 /** Start abscissa for the segment. */
34 private final double start;
35
36 /** End abscissa for the segment. */
37 private final double end;
38
39 /** Construct a new instance from a line and two points on the line. The points are projected onto
40 * the line and must be in order of increasing abscissa. No validation is performed.
41 * @param line line for the segment
42 * @param startPoint segment start point
43 * @param endPoint segment end point
44 */
45 Segment3D(final Line3D line, final Vector3D startPoint, final Vector3D endPoint) {
46 this(line, line.abscissa(startPoint), line.abscissa(endPoint));
47 }
48
49 /** Construct a new instance from a line and two abscissa locations on the line.
50 * The abscissa locations must be in increasing order. No validation is performed.
51 * @param line line for the segment
52 * @param start abscissa start location
53 * @param end abscissa end location
54 */
55 Segment3D(final Line3D line, final double start, final double end) {
56 super(line);
57
58 this.start = start;
59 this.end = end;
60 }
61
62 /** {@inheritDoc}
63 *
64 * <p>This method always returns {@code false}.</p>
65 */
66 @Override
67 public boolean isInfinite() {
68 return false;
69 }
70
71 /** {@inheritDoc}
72 *
73 * <p>This method always returns {@code true}.</p>
74 */
75 @Override
76 public boolean isFinite() {
77 return true;
78 }
79
80 /** {@inheritDoc} */
81 @Override
82 public Vector3D getStartPoint() {
83 return getLine().toSpace(start);
84 }
85
86 /** {@inheritDoc} */
87 @Override
88 public double getSubspaceStart() {
89 return start;
90 }
91
92 /** {@inheritDoc} */
93 @Override
94 public Vector3D getEndPoint() {
95 return getLine().toSpace(end);
96 }
97
98 /** {@inheritDoc} */
99 @Override
100 public double getSubspaceEnd() {
101 return end;
102 }
103
104 /** {@inheritDoc} */
105 @Override
106 public double getSize() {
107 return end - start;
108 }
109
110 /** {@inheritDoc} */
111 @Override
112 public Vector3D getCentroid() {
113 return getLine().toSpace((0.5 * (end - start)) + start);
114 }
115
116 /** {@inheritDoc} */
117 @Override
118 public Bounds3D getBounds() {
119 return Bounds3D.builder()
120 .add(getStartPoint())
121 .add(getEndPoint())
122 .build();
123 }
124
125 /** {@inheritDoc} */
126 @Override
127 public Segment3D transform(final Transform<Vector3D> transform) {
128 final Vector3D t1 = transform.apply(getStartPoint());
129 final Vector3D t2 = transform.apply(getEndPoint());
130
131 final Line3D tLine = getLine().transform(transform);
132
133 return new Segment3D(tLine, t1, t2);
134 }
135
136 /** {@inheritDoc} */
137 @Override
138 public String toString() {
139 final StringBuilder sb = new StringBuilder();
140 sb.append(getClass().getSimpleName())
141 .append("[startPoint= ")
142 .append(getStartPoint())
143 .append(", endPoint= ")
144 .append(getEndPoint())
145 .append(']');
146
147 return sb.toString();
148 }
149
150 /** {@inheritDoc} */
151 @Override
152 boolean containsAbscissa(final double abscissa) {
153 final Precision.DoubleEquivalence precision = getLine().getPrecision();
154 return precision.gte(abscissa, start) &&
155 precision.lte(abscissa, end);
156 }
157 }