Compute the intersection between two line segments, or two lines of infinite length. - Android java.lang

Android examples for java.lang:Math Geometry

Description

Compute the intersection between two line segments, or two lines of infinite length.

Demo Code

/*******************************************************************************
 * Copyright (c) 2011 MadRobot.//from  w  w w.  ja  v a  2 s . com
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *  Elton Kent - initial API and implementation
 ******************************************************************************/
//package com.java2s;

import android.graphics.PointF;

public class Main {
    /**
     * Compute the intersection between two line segments, or two lines
     * of infinite length.
     * 
     * @param x0
     *            X coordinate first end point first line segment.
     * @param y0
     *            Y coordinate first end point first line segment.
     * @param x1
     *            X coordinate second end point first line segment.
     * @param y1
     *            Y coordinate second end point first line segment.
     * @param x2
     *            X coordinate first end point second line segment.
     * @param y2
     *            Y coordinate first end point second line segment.
     * @param x3
     *            X coordinate second end point second line segment.
     * @param y3
     *            Y coordinate second end point second line segment.
     * @param intersection
     *            [2] Preallocated by caller to double[2]
     * @return -1 if lines are parallel (x,y unset),
     *         -2 if lines are parallel and overlapping (x, y center)
     *         0 if intesrection outside segments (x,y set)
     *         +1 if segments intersect (x,y set)
     */
    public static int findLineSegmentIntersection(float x0, float y0,
            float x1, float y1, float x2, float y2, float x3, float y3,
            float[] intersection) {
        // TODO: Make limit depend on input domain
        final float LIMIT = 1e-5f;
        final float INFINITY = 1e10f;

        float x, y;

        //
        // Convert the lines to the form y = ax + b
        //

        // Slope of the two lines
        float a0 = equals(x0, x1, LIMIT) ? INFINITY : (y0 - y1) / (x0 - x1);
        float a1 = equals(x2, x3, LIMIT) ? INFINITY : (y2 - y3) / (x2 - x3);

        float b0 = y0 - a0 * x0;
        float b1 = y2 - a1 * x2;

        // Check if lines are parallel
        if (equals(a0, a1)) {
            if (!equals(b0, b1)) {
                return -1; // Parallell non-overlapping
            } else {
                if (equals(x0, x1)) {
                    if ((Math.min(y0, y1) < Math.max(y2, y3))
                            || (Math.max(y0, y1) > Math.min(y2, y3))) {
                        float twoMiddle = y0 + y1 + y2 + y3
                                - min(y0, y1, y2, y3) - max(y0, y1, y2, y3);
                        y = (twoMiddle) / 2.0f;
                        x = (y - b0) / a0;
                    } else {
                        return -1; // Parallell non-overlapping
                    }
                } else {
                    if ((Math.min(x0, x1) < Math.max(x2, x3))
                            || (Math.max(x0, x1) > Math.min(x2, x3))) {
                        float twoMiddle = x0 + x1 + x2 + x3
                                - min(x0, x1, x2, x3) - max(x0, x1, x2, x3);
                        x = (twoMiddle) / 2.0f;
                        y = a0 * x + b0;
                    } else {
                        return -1;
                    }
                }

                intersection[0] = x;
                intersection[1] = y;
                return -2;
            }
        }

        // Find correct intersection point
        if (equals(a0, INFINITY)) {
            x = x0;
            y = a1 * x + b1;
        } else if (equals(a1, INFINITY)) {
            x = x2;
            y = a0 * x + b0;
        } else {
            x = -(b0 - b1) / (a0 - a1);
            y = a0 * x + b0;
        }

        intersection[0] = x;
        intersection[1] = y;

        // Then check if intersection is within line segments
        float distanceFrom1;
        if (equals(x0, x1)) {
            if (y0 < y1) {
                distanceFrom1 = y < y0 ? length(new PointF(x, y),
                        new PointF(x0, y0)) : y > y1 ? length(new PointF(x,
                        y), new PointF(x1, y1)) : 0.0f;
            } else {
                distanceFrom1 = y < y1 ? length(new PointF(x, y),
                        new PointF(x1, y1)) : y > y0 ? length(new PointF(x,
                        y), new PointF(x0, y0)) : 0.0f;
            }
        } else {
            if (x0 < x1) {
                distanceFrom1 = x < x0 ? length(new PointF(x, y),
                        new PointF(x0, y0)) : x > x1 ? length(new PointF(x,
                        y), new PointF(x1, y1)) : 0.0f;
            } else {
                distanceFrom1 = x < x1 ? length(new PointF(x, y),
                        new PointF(x1, y1)) : x > x0 ? length(new PointF(x,
                        y), new PointF(x0, y0)) : 0.0f;
            }
        }

        float distanceFrom2;
        if (equals(x2, x3)) {
            if (y2 < y3) {
                distanceFrom2 = y < y2 ? length(new PointF(x, y),
                        new PointF(x2, y2)) : y > y3 ? length(new PointF(x,
                        y), new PointF(x3, y3)) : 0.0f;
            } else {
                distanceFrom2 = y < y3 ? length(new PointF(x, y),
                        new PointF(x3, y3)) : y > y2 ? length(new PointF(x,
                        y), new PointF(x2, y2)) : 0.0f;
            }
        } else {
            if (x2 < x3) {
                distanceFrom2 = x < x2 ? length(new PointF(x, y),
                        new PointF(x2, y2)) : x > x3 ? length(new PointF(x,
                        y), new PointF(x3, y3)) : 0.0f;
            } else {
                distanceFrom2 = x < x3 ? length(new PointF(x, y),
                        new PointF(x3, y3)) : x > x2 ? length(new PointF(x,
                        y), new PointF(x2, y2)) : 0.0f;
            }
        }

        return equals(distanceFrom1, 0.0f) && equals(distanceFrom2, 0.0f) ? 1
                : 0;
    }

    /**
     * Check if two double precision numbers are "equal", i.e. close enough
     * to a prespecified limit.
     * 
     * @param a
     *            First number to check
     * @param b
     *            Second number to check
     * @return True if the twho numbers are "equal", false otherwise
     */
    private static boolean equals(float a, float b) {
        return equals(a, b, 1.0e-5f);
    }

    /**
     * Check if two double precision numbers are "equal", i.e. close enough
     * to a given limit.
     * 
     * @param a
     *            First number to check
     * @param b
     *            Second number to check
     * @param limit
     *            The definition of "equal".
     * @return True if the twho numbers are "equal", false otherwise
     */
    private static boolean equals(float a, float b, float limit) {
        return Math.abs(a - b) < limit;
    }

    /**
     * Return smallest of four numbers.
     * 
     * @param a
     *            First number to find smallest among.
     * @param b
     *            Second number to find smallest among.
     * @param c
     *            Third number to find smallest among.
     * @param d
     *            Fourth number to find smallest among.
     * @return Smallest of a, b, c and d.
     */
    private static float min(float a, float b, float c, float d) {
        return Math.min(Math.min(a, b), Math.min(c, d));
    }

    /**
     * Return largest of four numbers.
     * 
     * @param a
     *            First number to find largest among.
     * @param b
     *            Second number to find largest among.
     * @param c
     *            Third number to find largest among.
     * @param d
     *            Fourth number to find largest among.
     * @return Largest of a, b, c and d.
     */
    private static float max(float a, float b, float c, float d) {
        return Math.max(Math.max(a, b), Math.max(c, d));
    }

    public static float length(float ax, float ay) {
        return (float) Math.sqrt(ax * ax + ay * ay);
    }

    public static float length(float ax, float ay, float bx, float by) {
        PointF v = createVector(ax, ay, bx, by);
        return length(v);
    }

    /**
     * Return the length of a vector.
     * 
     * @param v
     *            Vector Point
     * @return Length of vector.
     */
    public static float length(PointF v) {
        return length(v.x, v.y);
    }

    /**
     * Compute distance between two points.
     * 
     * @param p0
     *            starting point
     * @param p1
     *            ending point
     * 
     * @return Distance between points.
     */
    public static float length(PointF p0, PointF p1) {
        PointF v = createVector(p0, p1);
        return length(v);
    }

    public static PointF createVector(float ax, float ay, float bx, float by) {
        PointF point = new PointF();
        point.x = bx - ax;
        point.y = by - ay;
        return point;
    }

    /**
     * Construct the vector specified by two points.
     * 
     * @param lineStart
     *            The coordinate of the line starting point
     * @param lineEnd
     *            The coordinate of the line ending point
     * 
     * @return The Vector point
     */
    public static PointF createVector(PointF lineStart, PointF lineEnd) {
        return createVector(lineStart.x, lineStart.y, lineEnd.x, lineEnd.y);
    }
}

Related Tutorials