001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ------------- 028 * GeomUtil.java 029 * ------------- 030 * (C) Copyright 2021-present, by Yuri Blankenstein and Contributors. 031 * 032 * Original Author: Yuri Blankenstein (for ESI TNO); 033 * 034 */ 035package org.jfree.chart.util; 036 037import java.awt.Shape; 038import java.awt.geom.AffineTransform; 039import java.awt.geom.Line2D; 040import java.awt.geom.PathIterator; 041import java.awt.geom.Point2D; 042import java.util.ArrayList; 043 044/** 045 * Some utility methods for working with geometry in Java2D. 046 */ 047public final class GeomUtil { 048 private GeomUtil() { 049 // Empty for utility classes 050 } 051 052 /** 053 * For each line in {@code lines}, calculates its intersection point with 054 * {@code lineA}, possibly no intersection point exists (i.e. parallel 055 * lines). 056 * 057 * @param lineA line to calculate the intersection point for. 058 * @param lines lines to calculate the intersection points with. 059 * @return all intersections points between {@code lineA} and {@code lines}. 060 * @see #calculateIntersectionPoint(Line2D, Line2D) 061 */ 062 public static Point2D[] calculateIntersectionPoints(Line2D lineA, 063 Line2D... lines) { 064 ArrayList<Point2D> intersectionPoints = new ArrayList<>( 065 lines.length); 066 for (Line2D lineB : lines) { 067 if (lineA.intersectsLine(lineB)) { 068 // Why does Java have the tester method, but not the method to 069 // get the point itself :S 070 intersectionPoints.add(calculateIntersectionPoint(lineA, lineB)); 071 } 072 } 073 return intersectionPoints.toArray(new Point2D[0]); 074 } 075 076 /** 077 * Calculates the intersection point of {@code lineA} with {@code lineB}, 078 * possibly {@code null} if no intersection point exists (i.e. parallel 079 * lines). 080 * 081 * @param lineA the first line for the calculation 082 * @param lineB the second line for the calculation 083 * @return the intersection point of {@code lineA} with {@code lineB}, 084 * possibly {@code null} if no intersection point exists 085 */ 086 public static Point2D calculateIntersectionPoint(Line2D lineA, 087 Line2D lineB) { 088 double x1 = lineA.getX1(); 089 double y1 = lineA.getY1(); 090 double x2 = lineA.getX2(); 091 double y2 = lineA.getY2(); 092 093 double x3 = lineB.getX1(); 094 double y3 = lineB.getY1(); 095 double x4 = lineB.getX2(); 096 double y4 = lineB.getY2(); 097 098 Point2D p = null; 099 100 double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); 101 if (d != 0) { 102 double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) 103 - (x1 - x2) * (x3 * y4 - y3 * x4)) / d; 104 double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) 105 - (y1 - y2) * (x3 * y4 - y3 * x4)) / d; 106 107 p = new Point2D.Double(xi, yi); 108 } 109 return p; 110 } 111 112 /** 113 * Returns all {@link PathIterator#SEG_LINETO line segments} building up a 114 * {@code shape}. 115 * 116 * @param shape a shape that is built up of {@link PathIterator#SEG_LINETO} 117 * elements. 118 * @param at an optional {@code AffineTransform} to be applied to the 119 * coordinates as they are returned in the iteration, or 120 * {@code null} if untransformed coordinates are desired 121 * @return all {@link PathIterator#SEG_LINETO line segments} building up the 122 * {@code shape} 123 * @throws IllegalArgumentException if {@code shape} contains non-straight 124 * line segments (i.e. 125 * {@link PathIterator#SEG_CUBICTO} or 126 * {@link PathIterator#SEG_QUADTO}) 127 */ 128 public static Line2D[] getLines(Shape shape, AffineTransform at) 129 throws IllegalArgumentException { 130 ArrayList<Line2D> lines = new ArrayList<>(); 131 Point2D first = null; 132 Point2D current = null; 133 double[] coords = new double[6]; 134 for (PathIterator pathIterator = shape.getPathIterator(at); 135 !pathIterator.isDone(); pathIterator.next()) { 136 switch (pathIterator.currentSegment(coords)) { 137 case PathIterator.SEG_MOVETO: 138 current = new Point2D.Double(coords[0], coords[1]); 139 break; 140 case PathIterator.SEG_LINETO: 141 Point2D to = new Point2D.Double(coords[0], coords[1]); 142 lines.add(new Line2D.Double(current, to)); 143 current = to; 144 break; 145 case PathIterator.SEG_CLOSE: 146 lines.add(new Line2D.Double(current, first)); 147 current = first; 148 break; 149 default: 150 throw new IllegalArgumentException( 151 "Shape contains non-straight line segments"); 152 } 153 if (null == first) 154 first = current; 155 } 156 return lines.toArray(new Line2D[0]); 157 } 158}