001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2016, by Object Refinery Limited. All rights reserved. 006 * 007 * http://www.object-refinery.com/orsoncharts/index.html 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * Orson Charts home page: 028 * 029 * http://www.object-refinery.com/orsoncharts/index.html 030 * 031 */ 032 033package com.orsoncharts.graphics3d; 034 035import java.awt.Dimension; 036import java.awt.geom.Line2D; 037import java.awt.geom.Point2D; 038 039/** 040 * A collection of utility methods for 2D geometry. 041 */ 042public class Utils2D { 043 044 private Utils2D() { 045 // no need to instantiate 046 } 047 048 /** 049 * Returns {@code true} if the specified value is spanned by the 050 * two bounds, and {@code false} otherwise. 051 * 052 * @param value the value. 053 * @param bound1 the first boundary. 054 * @param bound2 the second boundary. 055 * 056 * @return A boolean. 057 */ 058 public static boolean spans(double value, double bound1, double bound2) { 059 return (bound1 < value && bound2 > value) 060 || (bound1 > value && bound2 < value); 061 } 062 063 /** 064 * Calculates twice the area of a triangle for points specified in 065 * counter-clockwise order (if the points are specified in clockwise order 066 * the result will be negative). 067 * 068 * @param a the first point ({@code null} not permitted). 069 * @param b the second point ({@code null} not permitted). 070 * @param c the third point ({@code null} not permitted). 071 * 072 * @return The area x 2. 073 */ 074 public static double area2(Point2D a, Point2D b, Point2D c) { 075 double ax = a.getX(); 076 double ay = a.getY(); 077 double bx = b.getX(); 078 double by = b.getY(); 079 double cx = c.getX(); 080 double cy = c.getY(); 081 return (ax - cx) * (by - cy) - (ay - cy) * (bx - cx); 082 } 083 084 /** 085 * Returns the point in the center of the four supplied points. 086 * 087 * @param pt0 point 0 ({@code null} not permitted). 088 * @param pt1 point 1 ({@code null} not permitted). 089 * @param pt2 point 2 ({@code null} not permitted). 090 * @param pt3 point 3 ({@code null} not permitted). 091 * 092 * @return The center point (never {@code null}). 093 */ 094 public static Point2D centerPoint(Point2D pt0, Point2D pt1, Point2D pt2, 095 Point2D pt3) { 096 float x = (float) ((pt0.getX() + pt1.getX() + pt2.getX() + pt3.getX()) 097 / 4.0); 098 float y = (float) ((pt0.getY() + pt1.getY() + pt2.getY() + pt3.getY()) 099 / 4.0); 100 return new Point2D.Float(x, y); 101 } 102 103 /** 104 * Returns the dimensions of the smallest rectangle that could contain 105 * the supplied points. 106 * 107 * @param pts an array of points ({@code null} not permitted). 108 * 109 * @return The dimensions. 110 */ 111 public static Dimension findDimension(Point2D[] pts) { 112 double minx = Double.POSITIVE_INFINITY; 113 double maxx = Double.NEGATIVE_INFINITY; 114 double miny = Double.POSITIVE_INFINITY; 115 double maxy = Double.NEGATIVE_INFINITY; 116 for (Point2D pt : pts) { 117 minx = Math.min(minx, pt.getX()); 118 maxx = Math.max(maxx, pt.getX()); 119 miny = Math.min(miny, pt.getY()); 120 maxy = Math.max(maxy, pt.getY()); 121 } 122 return new Dimension((int) (maxx - minx), (int) (maxy - miny)); 123 } 124 125 /** 126 * Creates and returns a line that is perpendicular to the specified line. 127 * 128 * @param line the reference line ({@code null} not permitted). 129 * @param b the base point, expressed as a percentage along the length of 130 * the reference line. 131 * @param size the size or length of the perpendicular line. 132 * @param opposingPoint an opposing point, to define which side of the 133 * reference line the perpendicular line will extend ({@code null} 134 * not permitted). 135 * 136 * @return The perpendicular line. 137 */ 138 public static Line2D createPerpendicularLine(Line2D line, double b, 139 double size, Point2D opposingPoint) { 140 double dx = line.getX2() - line.getX1(); 141 double dy = line.getY2() - line.getY1(); 142 double length = Math.sqrt(dx * dx + dy * dy); 143 double pdx = dy / length; 144 double pdy = -dx / length; 145 int ccw = line.relativeCCW(opposingPoint); 146 Point2D pt1 = new Point2D.Double(line.getX1() + b * dx, 147 line.getY1() + b * dy); 148 Point2D pt2 = new Point2D.Double(pt1.getX() - ccw * size * pdx, 149 pt1.getY() - ccw * size * pdy); 150 return new Line2D.Double(pt1, pt2); 151 } 152 153 /** 154 * Creates and returns a line that is perpendicular to the specified 155 * line. 156 * 157 * @param line the reference line ({@code null} not permitted). 158 * @param pt1 a point on the reference line ({@code null} not 159 * permitted). 160 * @param size the length of the new line. 161 * @param opposingPoint an opposing point, to define which side of the 162 * reference line the perpendicular line will extend ({@code null} 163 * not permitted). 164 * 165 * @return The perpendicular line. 166 */ 167 public static Line2D createPerpendicularLine(Line2D line, Point2D pt1, 168 double size, Point2D opposingPoint) { 169 double dx = line.getX2() - line.getX1(); 170 double dy = line.getY2() - line.getY1(); 171 double length = Math.sqrt(dx * dx + dy * dy); 172 double pdx = dy / length; 173 double pdy = -dx / length; 174 int ccw = line.relativeCCW(opposingPoint); 175 Point2D pt2 = new Point2D.Double(pt1.getX() - ccw * size * pdx, 176 pt1.getY() - ccw * size * pdy); 177 return new Line2D.Double(pt1, pt2); 178 } 179 180 /** 181 * Returns the angle of rotation (in radians) for the specified line. 182 * 183 * @param line the line ({@code null} not permitted). 184 * 185 * @return The angle of rotation (in radians). 186 */ 187 public static double calculateTheta(Line2D line) { 188 double dx = line.getX2() - line.getX1(); 189 double dy = line.getY2() - line.getY1(); 190 return Math.atan2(dy, dx); 191 } 192 193 /** 194 * Returns the length of the line. 195 * 196 * @param line the line ({@code null} not permitted). 197 * 198 * @return The length of the line. 199 */ 200 public static double length(Line2D line) { 201 double dx = line.getX2() - line.getX1(); 202 double dy = line.getY2() - line.getY1(); 203 return Math.sqrt(dx * dx + dy * dy); 204 } 205 206}