Java Geometry Algorithm curvedLineHit(Point point, Point startPoint, Point endPoint, Point controlPoint1, Point controlPoint2, float padding)

Here you can find the source of curvedLineHit(Point point, Point startPoint, Point endPoint, Point controlPoint1, Point controlPoint2, float padding)

Description

Find the square of the distance between the point and a point on the curve (u).

License

Open Source License

Parameter

Parameter Description
point the Point on the line
startPoint the Start Point
endPoint the End Point
controlPoint1 the First Control Point
controlPoint2 the Second Control Point
padding the area surrounding the curve

Return

TRUE point is on the curve, FALSE otherwise

Declaration

public static boolean curvedLineHit(Point point, Point startPoint, Point endPoint, Point controlPoint1,
        Point controlPoint2, float padding) 

Method Source Code


//package com.java2s;
/*//from www.j a v a  2s  .c o m
 * Twirl Editor - Petri-Net Editor
 * 
 * Copyright (C) 2009 Neil Brittliff
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

import java.awt.Point;

public class Main {
    /**
     * Find the square of the distance between the point and a point on the
     * curve (u). use newtons method to approach the minumum u.
     * 
     * @param point
     *            the Point on the line
     * @param startPoint
     *            the Start Point
     * @param endPoint
     *            the End Point
     * @param controlPoint1
     *            the First Control Point
     * @param controlPoint2
     *            the Second Control Point
     * @param padding
     *            the area surrounding the curve
     * 
     * @return TRUE point is on the curve, FALSE otherwise
     * 
     */
    public static boolean curvedLineHit(Point point, Point startPoint, Point endPoint, Point controlPoint1,
            Point controlPoint2, float padding) {
        Point a[] = new Point[4]; // our regular coefficients
        double c[] = new double[7]; // a cubic squared gives us 7 coefficients
        double u;

        double tolerance = padding + 1 / 2;
        double delta;
        double minDelta;
        int i;

        tolerance *= tolerance;

        parameterizeCurve(a, startPoint, endPoint, controlPoint1, controlPoint2);

        delta = a[0].x - point.x;
        c[0] = delta * delta;
        delta = a[0].y - point.y;

        c[0] += delta * delta;
        c[1] = 2 * ((a[0].x - point.x) * a[1].x + (a[0].y - point.y) * a[1].y);
        c[2] = a[1].x * a[1].x + a[1].y * a[1].y + 2 * (a[2].x * (a[0].x - point.x) + a[2].y * (a[0].y - point.y));
        c[3] = 2 * (a[1].x * a[2].x + (a[0].x - point.x) * a[3].x + a[1].y * a[2].y + (a[0].y - point.y) * a[3].y);
        c[4] = a[2].x * a[2].x + a[2].y * a[2].y + 2 * (a[1].x * a[3].x + a[1].y * a[3].y);
        c[5] = 2.0 * (a[2].x * a[3].x + a[2].y * a[3].y);
        c[6] = a[3].x * a[3].x + a[3].y * a[3].y;

        // Estimate a starting U

        if (endPoint.x < startPoint.x) {
            u = point.x - endPoint.x;
        } else {
            u = point.x - startPoint.x;
            delta = endPoint.x - startPoint.x;
        }

        delta = Math.abs(startPoint.x - point.x) + Math.abs(endPoint.x - point.x);
        delta += Math.abs(startPoint.y - point.y) + Math.abs(endPoint.y - point.y);

        if (endPoint.y < startPoint.y) {
            u += point.y - endPoint.y;
            delta += startPoint.y - endPoint.y;
        } else {
            u += point.y - startPoint.y;
            delta += endPoint.y - startPoint.y;
        }

        u /= delta;

        u = (u < 0) ? 0 : (u > 1) ? 1 : u;

        // Iterate while adjust U with our error function

        // NOTE: Sadly, Newton's method becomes unstable as we approach the
        // solution. Also, the farther away from the curve, the wider the
        // oscillation will be.
        // To get around this, we're keeping track of our best result, adding a
        // few more iterations, and damping our approach.

        minDelta = 100000;

        for (i = 0; i < 12; i++) {

            delta = (((((c[6] * u + c[5]) * u + c[4]) * u + c[3]) * u + c[2]) * u + c[1]) * u + c[0];

            if (delta < minDelta) {
                minDelta = delta;
            }

            if (i == 11 && minDelta <= tolerance) {
                return true;
            } else {
                double slope = (((((6 * c[6] * u + 5 * c[5]) * u + 4 * c[4]) * u + 3 * c[3]) * u + 2 * c[2]) * u
                        + c[1]);
                double deltaU = delta / slope;

                if ((u == 0 && delta > 0) || (u == 1 && delta < 0)) {
                    return minDelta <= tolerance;
                }

                u -= 0.75 * deltaU; // Used to be just deltaU, but we're damping
                // it a bit
                u = u < 0.0 ? 0.0 : u > 1.0 ? 1.0 : u;

            }

        }

        return false;

    }

    /**
     * Given a curveto's endpoints and control points, compute the coefficients
     * to trace out the curve as p(t) = c[0] + c[1]*t + c[2]*t^2 + c[3]*t^3
     * 
     * @param coefficients
     *            the Coefficients
     * @param startPoint
     *            the Start Point
     * @param endPoint
     *            the End Point
     * @param controlPoint1
     *            the First Control Point
     * @param controlPoint2
     *            the Second Control Point
     * @param padding
     *            the area surrounding the curve
     * 
     */
    static void parameterizeCurve(Point[] coefficients, Point startPoint, Point endPoint, Point controlPoint1,
            Point controlPoint2) {
        Point tangent2 = new Point();

        tangent2.x = (int) (3.0 * (endPoint.x - controlPoint2.x));
        tangent2.y = (int) (3.0 * (endPoint.y - controlPoint2.y));

        coefficients[0] = startPoint;
        coefficients[1] = new Point((int) (3.0 * (controlPoint1.x - startPoint.x)),
                (int) (3.0 * (controlPoint1.y - startPoint.y)));
        // tangent
        coefficients[2] = new Point(
                (int) (3.0 * (endPoint.x - startPoint.x) - 2.0 * coefficients[1].x - tangent2.x),
                (int) (3.0 * (endPoint.y - startPoint.y) - 2.0 * coefficients[1].y - tangent2.y));
        coefficients[3] = new Point((int) (2.0 * (startPoint.x - endPoint.x) + coefficients[1].x + tangent2.x),
                (int) (2.0 * (startPoint.y - endPoint.y) + coefficients[1].y + tangent2.y));

    }
}

Related

  1. computeBarycenter(Map values)
  2. computeEuclideanDistance(Point2D point1, Point2D point2)
  3. computePolygonArea(Point2D[] pts)
  4. coordinateSplit(Point2D.Double[] aPoints, double[] aX, double[] aY)
  5. cornersToWorldFile(Point2D[] esq, Dimension size)
  6. derivativeOfCubicBezier(Point2D p0, Point2D p1, Point2D p2, Point2D p3, double t)
  7. deriveLocation(Point origin, double radius)
  8. determineConnectionPoint(Point wayPoint, Polygon polygon)
  9. directVincenty(Point2D.Double point, double brng, double distance)