/* * Copyright ©1998-2020 by Richard A. Wilkes. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, version 2.0. If a copy of the MPL was not distributed with * this file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This Source Code Form is "Incompatible With Secondary Licenses", as * defined by the Mozilla Public License, version 2.0. */ package com.trollworks.gcs.utility; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Point2D; /** Provides geometry-related utilities. */ public class Geometry { private static final Point2D[] NO_LINE_INTERSECTION = new Point2D[0]; /** * Intersects two {@link Rectangle}s, producing a third. Unlike the {@link * Rectangle#intersection(Rectangle)} method, the resulting {@link Rectangle}'s width & height * will not be set to less than zero when there is no overlap. * * @param first The first {@link Rectangle}. * @param second The second {@link Rectangle}. * @return The intersection of the two {@link Rectangle}s. */ public static Rectangle intersection(Rectangle first, Rectangle second) { if (first.width < 1 || first.height < 1 || second.width < 1 || second.height < 1) { return new Rectangle(); } int x = Math.max(first.x, second.x); int y = Math.max(first.y, second.y); int w = Math.min(first.x + first.width, second.x + second.width) - x; int h = Math.min(first.y + first.height, second.y + second.height) - y; if (w < 0 || h < 0) { return new Rectangle(); } return new Rectangle(x, y, w, h); } /** * Unions two {@link Rectangle}s, producing a third. Unlike the {@link * Rectangle#union(Rectangle)} method, an empty {@link Rectangle} will not cause the {@link * Rectangle}'s boundary to extend to the 0,0 point. * * @param first The first {@link Rectangle}. * @param second The second {@link Rectangle}. * @return The resulting {@link Rectangle}. */ public static Rectangle union(Rectangle first, Rectangle second) { boolean firstEmpty = first.width < 1 || first.height < 1; boolean secondEmpty = second.width < 1 || second.height < 1; if (firstEmpty && secondEmpty) { return new Rectangle(); } if (firstEmpty) { return new Rectangle(second); } if (secondEmpty) { return new Rectangle(first); } return first.union(second); } /** * @param pt The {@link Point} to generate a string for. * @return The string form. */ public static final String toString(Point pt) { return pt.x + "," + pt.y; } /** * @param encoded A string previously generated by {@link #toString(Point)}. * @return A {@link Point} with the encoded string's contents. */ public static final Point toPoint(String encoded) throws NumberFormatException { if (encoded == null) { throw new NumberFormatException("Not a point"); } String[] parts = encoded.split(",", 2); if (parts.length != 2) { throw new NumberFormatException("Not a point"); } return new Point(Integer.parseInt(parts[0].trim()), Integer.parseInt(parts[1].trim())); } /** * @param rect The {@link Rectangle} to generate a string for. * @return The string form. */ public static final String toString(Rectangle rect) { if (rect.width != 1 || rect.height != 1) { return rect.x + "," + rect.y + "," + rect.width + "," + rect.height; } return rect.x + "," + rect.y; } /** * @param encoded A string previously generated by {@link #toString(Rectangle)}. * @return A {@link Rectangle} with the encoded string's contents. */ public static final Rectangle toRectangle(String encoded) throws NumberFormatException { if (encoded == null) { throw new NumberFormatException("Not a rectangle"); } String[] parts = encoded.split(",", 4); if (parts.length != 2 && parts.length != 4) { throw new NumberFormatException("Not a rectangle"); } return new Rectangle(Integer.parseInt(parts[0].trim()), Integer.parseInt(parts[1].trim()), parts.length > 2 ? Integer.parseInt(parts[2].trim()) : 1, parts.length > 2 ? Integer.parseInt(parts[3].trim()) : 1); } /** * @param amount The number of pixels to inset the {@link Rectangle}. * @param bounds The {@link Rectangle} to inset. * @return The {@link Rectangle} that was passed in. */ public static final Rectangle inset(int amount, Rectangle bounds) { bounds.x += amount; bounds.y += amount; bounds.width -= amount * 2; bounds.height -= amount * 2; if (bounds.width < 0) { bounds.width = 0; } if (bounds.height < 0) { bounds.height = 0; } return bounds; } }