    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}