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