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 }