001/******************************************************************************* 002 * This software is provided as a supplement to the authors' textbooks on digital 003 * image processing published by Springer-Verlag in various languages and editions. 004 * Permission to use and distribute this software is granted under the BSD 2-Clause 005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit https://imagingbook.com for additional details. 008 ******************************************************************************/ 009package imagingbook.common.geometry.delaunay.guibas; 010 011import imagingbook.common.geometry.basic.Pnt2d; 012 013import static imagingbook.common.math.Arithmetic.isZero; 014 015 016/** 017 * This class represents a 2D edge (line segment), specified by its two end-points. Instances of this class are 018 * immutable. 019 */ 020public class Edge2D { 021 022 protected final Pnt2d a, b; 023 024 /** 025 * Constructor of the 2D edge class used to create a new edge instance from two 2D vectors describing the edge's 026 * vertices. 027 * 028 * @param a first vertex of the edge 029 * @param b second vertex of the edge 030 */ 031 protected Edge2D(Pnt2d a, Pnt2d b) { 032 this.a = a; 033 this.b = b; 034 } 035 036 private double getMinDistance(Pnt2d point) { 037 //return getClosestPoint(point).minus(point).mag(); 038 return getClosestPoint(point).distance(point); 039 } 040 041 /** 042 * Calculates the point on this edge that is closest to the specified point. 043 * 044 * @param point the point whose distance is to be calculated 045 * @return the closest point on this edge 046 */ 047 private Pnt2d getClosestPoint(Pnt2d point) { 048 Pnt2d ab = b.minus(a); 049 double denom = ab.dot(ab); 050 if (isZero(denom)) { // avoid zero denominator (this should not happen ever) 051 throw new ArithmeticException("zero dot product ab . ab"); 052 } 053 double t = point.minus(a).dot(ab) / denom; 054 if (t < 0.0) { 055 t = 0.0; 056 } else if (t > 1.0) { 057 t = 1.0; 058 } 059 return a.plus(ab.mult(t)); 060 } 061 062 /** 063 * Creates and returns a new {@link Edge2D.Distance} object, representing the minimum distance between this edge and 064 * the specified point. 065 * 066 * @param point the point to calculate the distance for 067 * @return a new {@link Edge2D.Distance} instance 068 */ 069 protected Distance distanceFromPoint(Pnt2d point) { 070 return new Distance(point); 071 } 072 073 /** 074 * Non-static inner class representing the distance of a particular point to the associated (enclosing) 075 * {@link Edge2D} instance. 076 */ 077 public class Distance implements Comparable<Distance> { 078 079 private final double distance; 080 081 protected Distance(Pnt2d point) { 082 this(Edge2D.this.getMinDistance(point)); 083 } 084 085 protected Distance(double distance) { 086 this.distance = distance; 087 } 088 089 protected Edge2D getEdge() { 090 return Edge2D.this; 091 } 092 093 protected double getDistance() { 094 return this.distance; 095 } 096 097 @Override 098 public int compareTo(Distance o) { 099 return Double.compare(this.distance, o.distance); 100 } 101 } 102 103}