de.pixida.logtest.designer.automaton.LineIntersector.java Source code

Java tutorial

Introduction

Here is the source code for de.pixida.logtest.designer.automaton.LineIntersector.java

Source

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 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/.
 *
 * Copyright (c) 2016 Pixida GmbH
 */

package de.pixida.logtest.designer.automaton;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.Validate;

import javafx.geometry.Point2D;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;

/** I wonder why I have to implement it by myself - isn't there a library for that!? */
abstract class LineIntersector {
    private static final double EPSILON = 10E-5;
    private static final Rotate ROATE_90_DEGREES_COUNTERCLOCKWISE = new Rotate(-90.0);

    static class Intersection {
        private final Point2D intersection;
        private final Line line;
        private final double distance;

        Intersection(final Point2D aIntersection, final Line aLine, final double aDistance) {
            Validate.notNull(aIntersection);
            Validate.notNull(aLine);
            Validate.isTrue(aDistance >= 0d);
            this.intersection = aIntersection;
            this.line = aLine;
            this.distance = aDistance;
        }

        Point2D getIntersection() {
            return this.intersection;
        }

        Line getLine() {
            return this.line;
        }

        double getDistance() {
            return this.distance;
        }
    }

    enum PointPosition {
        LEFT_OF_THE_LINE, RIGHT_OF_THE_LINE, ON_SAME_LINE
    }

    static List<Intersection> calculateIntersections(final Point2D point, final Point2D vec,
            final List<Line> lines) {
        Validate.notNull(point);
        Validate.notNull(vec);
        Validate.notNull(lines);

        final List<Intersection> results = new ArrayList<>();
        for (final Line line : lines) {
            final Point2D intersection = calculateIntersection(point, vec, line);
            if (intersection == null) {
                continue;
            }

            if (!checkIfPointIsOnTheLine(intersection, line)) {
                continue;
            }

            results.add(new Intersection(intersection, line, point.distance(intersection)));
        }

        Collections.sort(results, (r0, r1) -> Double.compare(r0.getDistance(), r1.getDistance()));

        return results;
    }

    static boolean checkIfPointIsOnTheLine(final Point2D point, final Line line) {
        final Point2D lineStart = new Point2D(line.getStartX(), line.getStartY());
        final Point2D lineEnd = new Point2D(line.getEndX(), line.getEndY());
        final Point2D vecEndToStart = lineEnd.subtract(lineStart);
        final Point2D vecStartToEnd = lineStart.subtract(lineEnd);
        final Point2D vecEndToStartRotated = ROATE_90_DEGREES_COUNTERCLOCKWISE.transform(vecEndToStart);
        final Point2D vecStartToEndRotated = ROATE_90_DEGREES_COUNTERCLOCKWISE.transform(vecStartToEnd);
        if (getPointSideOfLine(point, lineEnd,
                lineEnd.add(vecEndToStartRotated)) == PointPosition.LEFT_OF_THE_LINE) {
            return false;
        }
        if (getPointSideOfLine(point, lineStart,
                lineStart.add(vecStartToEndRotated)) == PointPosition.LEFT_OF_THE_LINE) {
            return false;
        }
        return true;
    }

    // Reference: http://stackoverflow.com/questions/22668659/calculate-on-which-side-of-a-line-a-point-is
    static PointPosition getPointSideOfLine(final Point2D point, final Point2D lineStart, final Point2D lineEnd) {
        final double value = (lineEnd.getX() - lineStart.getX()) * (point.getY() - lineStart.getY())
                - (point.getX() - lineStart.getX()) * (lineEnd.getY() - point.getY());
        if (Math.abs(value) < EPSILON) {
            return PointPosition.ON_SAME_LINE;
        }
        if (value < 0.0) {
            return PointPosition.RIGHT_OF_THE_LINE;
        }
        return PointPosition.LEFT_OF_THE_LINE;
    }

    static Point2D calculateIntersection(final Point2D point, final Point2D vec, final Line line) {
        final Point2D q = new Point2D(line.getStartX(), line.getStartY());
        final Point2D w = new Point2D(line.getEndX(), line.getEndY()).subtract(q);

        // q + t1 * w = point + t2 * vec => q - point = (vec w) (t2 -t1)^T
        final double det = det2x2LineWiseDefined(vec.getX(), w.getX(), vec.getY(), w.getY());
        final double epsilon = 1E-5;
        if (Math.abs(det) < epsilon) {
            return null;
        }
        final double detInv = 1.0 / det;
        final double t2 = det2x2LineWiseDefined(q.getX() - point.getX(), w.getX(), q.getY() - point.getY(),
                w.getY()) * detInv;

        final Point2D intersection = vec.multiply(t2).add(point);
        return intersection;
    }

    private static double det2x2LineWiseDefined(final double a, final double b, final double c, final double d) {
        return a * d - b * c;
    }
}