View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.util.geometry;
16  
17  /**
18   * Simple 2D line segment shape.
19   *
20   * @author Ronald Brill
21   */
22  public class Line2D implements Shape2D {
23  
24      private final double startX_;
25      private final double startY_;
26      private final double endX_;
27      private final double endY_;
28      private final boolean isVertical_;
29  
30      private final double slope_;
31      private final double yIntercept_;
32  
33      /**
34       * Creates a new line segment between the two given points.
35       *
36       * @param start the start point
37       * @param end the end point
38       */
39      public Line2D(final Point2D start, final Point2D end) {
40          this(start.getX(), start.getY(), end.getX(), end.getY());
41      }
42  
43      /**
44       * Creates a new line segment between the two given coordinates.
45       *
46       * @param x1 the x coordinate of the start point
47       * @param y1 the y coordinate of the start point
48       * @param x2 the x coordinate of the end point
49       * @param y2 the y coordinate of the end point
50       */
51      public Line2D(final double x1, final double y1, final double x2, final double y2) {
52          startX_ = x1;
53          startY_ = y1;
54          endX_ = x2;
55          endY_ = y2;
56  
57          isVertical_ = Math.abs(startX_ - endX_) < EPSILON;
58          if (isVertical_) {
59              slope_ = Double.NaN;
60              yIntercept_ = Double.NaN;
61          }
62          else {
63              // y = slope * x + b
64              slope_ = (endY_ - startY_) / (endX_ - startX_);
65              yIntercept_ = startY_ - slope_ * startX_;
66          }
67      }
68  
69      /**
70       * Returns the intersection point of this line with the given line,
71       * or {@code null} if the lines are parallel.
72       *
73       * @param line the line to intersect with
74       * @return the intersection point, or {@code null} if the lines are parallel
75       */
76      public Point2D intersect(final Line2D line) {
77          if (isVertical_ && line.isVertical_) {
78              return null;
79          }
80  
81          if (isVertical_ && !line.isVertical_) {
82              final double intersectY = line.slope_ * startX_ + line.yIntercept_;
83              return new Point2D(startX_, intersectY);
84          }
85  
86          if (!isVertical_ && line.isVertical_) {
87              final double intersectY = slope_ * line.startX_ + yIntercept_;
88              return new Point2D(line.startX_, intersectY);
89          }
90  
91          // parallel?
92          if (Math.abs(slope_ - line.slope_) < EPSILON) {
93              return null;
94          }
95  
96          // x = (n2-n1)/(m1-m2)
97          final double intersectX = (line.yIntercept_ - yIntercept_) / (slope_ - line.slope_);
98          // y = m2*x+n2
99          final double intersectY = slope_ * intersectX + yIntercept_;
100         return new Point2D(intersectX, intersectY);
101     }
102 
103     /**
104      * {@inheritDoc}
105      */
106     @Override
107     public boolean contains(final double x, final double y) {
108         if (isVertical_) {
109             if (Math.abs(startX_ - x) > EPSILON) {
110                 return false;
111             }
112         }
113         else {
114             final double testY = slope_ * x + yIntercept_;
115             if (Math.abs(y - testY) > EPSILON) {
116                 return false;
117             }
118 
119             if (x < startX_ && x < endX_
120                     || (x > startX_ && x > endX_)) {
121                 return false;
122             }
123         }
124 
125         if (y < startY_ && y < endY_
126                 || (y > startY_ && y > endY_)) {
127             return false;
128         }
129 
130         return true;
131     }
132 
133     /**
134      * {@inheritDoc}
135      */
136     @Override
137     public boolean isEmpty() {
138         return Math.abs(startX_ - endX_) < EPSILON && Math.abs(startY_ - endY_) < EPSILON;
139     }
140 
141     @Override
142     public String toString() {
143         return "Line2D [ (" + startX_ + ", " + startY_ + "), (" + endX_ + ", " + endY_
144                 + "), " + (isVertical_ ? "isVertical" : "y = " + slope_ + "*x + " + yIntercept_ + "]");
145     }
146 }