/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * logisim-evolution is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.draw.shapes; import com.cburch.logisim.data.Location; public class LineUtil { public static double distance(double x0, double y0, double x1, double y1) { return Math.sqrt(distanceSquared(x0, y0, x1, y1)); } public static double distanceSquared(double x0, double y0, double x1, double y1) { double dx = x1 - x0; double dy = y1 - y0; return dx * dx + dy * dy; } private static double[] nearestPoint(double xq, double yq, double x0, double y0, double x1, double y1, boolean isSegment) { double dx = x1 - x0; double dy = y1 - y0; double len2 = dx * dx + dy * dy; if (len2 < zeroMax * zeroMax) { // the "line" is essentially a point - return that return new double[] { (x0 + x1) / 2, (y0 + y1) / 2 }; } double num = (xq - x0) * dx + (yq - y0) * dy; double u; if (isSegment) { if (num < 0) u = 0; else if (num < len2) u = num / len2; else u = 1; } else { u = num / len2; } return new double[] { x0 + u * dx, y0 + u * dy }; } public static double[] nearestPointInfinite(double xq, double yq, double x0, double y0, double x1, double y1) { return nearestPoint(xq, yq, x0, y0, x1, y1, false); } public static double[] nearestPointSegment(double xq, double yq, double x0, double y0, double x1, double y1) { return nearestPoint(xq, yq, x0, y0, x1, y1, true); } public static double ptDistSqSegment(double x0, double y0, double x1, double y1, double xq, double yq) { double dx = x1 - x0; double dy = y1 - y0; double len2 = dx * dx + dy * dy; if (len2 < zeroMax * zeroMax) { // the "segment" is essentially a point return distanceSquared(xq, yq, (x0 + x1) / 2, (y0 + y1) / 2); } double u = ((xq - x0) * dx + (yq - y0) * dy) / len2; if (u <= 0) return distanceSquared(xq, yq, x0, y0); if (u >= 1) return distanceSquared(xq, yq, x1, y1); return distanceSquared(xq, yq, x0 + u * dx, y0 + u * dy); } public static Location snapTo8Cardinals(Location from, int mx, int my) { int px = from.getX(); int py = from.getY(); if (mx != px && my != py) { double ang = Math.atan2(my - py, mx - px); int d45 = (Math.abs(mx - px) + Math.abs(my - py)) / 2; int d = (int) (4 * ang / Math.PI + 4.5); switch (d) { case 0: case 8: // going west case 4: // going east return Location.create(mx, py); case 2: // going north case 6: // going south return Location.create(px, my); case 1: // going northwest return Location.create(px - d45, py - d45); case 3: // going northeast return Location.create(px + d45, py - d45); case 5: // going southeast return Location.create(px + d45, py + d45); case 7: // going southwest return Location.create(px - d45, py + d45); default: break; } } return Location.create(mx, my); // should never happen } // a value we consider "small enough" to equal it to zero: // (this is used for double solutions in 2nd or 3d degree equation) private static final double zeroMax = 0.0000001; private LineUtil() { } }