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 * https://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
18 /*
19 * This is not the original file distributed by the Apache Software Foundation
20 * It has been modified by the Hipparchus project
21 */
22 package org.hipparchus.geometry.euclidean.twod;
23
24 import org.hipparchus.util.FastMath;
25
26 /** Simple container for a two-points segment.
27 */
28 public class Segment {
29
30 /** Start point of the segment. */
31 private final Vector2D start;
32
33 /** End point of the segment. */
34 private final Vector2D end;
35
36 /** Line containing the segment. */
37 private final Line line;
38
39 /** Build a segment.
40 * @param start start point of the segment
41 * @param end end point of the segment
42 * @param tolerance of the line.
43 */
44 public Segment(final Vector2D start, final Vector2D end, final double tolerance) {
45 this(start, end, new Line(start, end, tolerance));
46 }
47
48 /** Build a segment.
49 * @param start start point of the segment
50 * @param end end point of the segment
51 * @param line line containing the segment
52 */
53 public Segment(final Vector2D start, final Vector2D end, final Line line) {
54 this.start = start;
55 this.end = end;
56 this.line = line;
57 }
58
59 /** Get the start point of the segment.
60 * @return start point of the segment
61 */
62 public Vector2D getStart() {
63 return start;
64 }
65
66 /** Get the end point of the segment.
67 * @return end point of the segment
68 */
69 public Vector2D getEnd() {
70 return end;
71 }
72
73 /** Get the line containing the segment.
74 * @return line containing the segment
75 */
76 public Line getLine() {
77 return line;
78 }
79
80 /**
81 * Get the length of the line segment.
82 *
83 * @return line segment length.
84 */
85 public double getLength() {
86 return getEnd().distance(getStart());
87 }
88
89 /** Calculates the shortest distance from a point to this line segment.
90 * <p>
91 * If the perpendicular extension from the point to the line does not
92 * cross in the bounds of the line segment, the shortest distance to
93 * the two end points will be returned.
94 * </p>
95 *
96 * Algorithm adapted from:
97 * <a href="http://www.codeguru.com/forum/printthread.php?s=cc8cf0596231f9a7dba4da6e77c29db3&t=194400&pp=15&page=1">
98 * Thread @ Codeguru</a>
99 *
100 * @param p to check
101 * @return distance between the instance and the point
102 */
103 public double distance(final Vector2D p) {
104 final double deltaX = end.getX() - start.getX();
105 final double deltaY = end.getY() - start.getY();
106
107 final double r = ((p.getX() - start.getX()) * deltaX + (p.getY() - start.getY()) * deltaY) /
108 (deltaX * deltaX + deltaY * deltaY);
109
110 // r == 0 => P = startPt
111 // r == 1 => P = endPt
112 // r < 0 => P is on the backward extension of the segment
113 // r > 1 => P is on the forward extension of the segment
114 // 0 < r < 1 => P is on the segment
115
116 // if point isn't on the line segment, just return the shortest distance to the end points
117 if (r < 0 || r > 1) {
118 final double dist1 = getStart().distance(p);
119 final double dist2 = getEnd().distance(p);
120
121 return FastMath.min(dist1, dist2);
122 }
123 else {
124 // find point on the line and see if it is in the line segment
125 final double px = start.getX() + r * deltaX;
126 final double py = start.getY() + r * deltaY;
127
128 final Vector2D interPt = new Vector2D(px, py);
129 return interPt.distance(p);
130 }
131 }
132 }