Java 如何扰动多边形,使其两条边不在同一条线上?

Java 如何扰动多边形,使其两条边不在同一条线上?,java,polygon,computational-geometry,floating-point-precision,Java,Polygon,Computational Geometry,Floating Point Precision,您将获得一个由R2中的点定义的简单多边形。您可以将点沿x轴和y轴移动一些小ε(例如1e-4)。移动点以确保多边形的两条边不完全位于同一条线上的算法是什么 “在同一直线上”通常被定义为两条线的角度之间有足够小的差异,但是为了这个特定的问题,我只考虑段在它们的角度或直线方程中有0的差异,或者定义它们。 编辑: 这里有一些代码。它只解决了轴平行边的问题 package org.tendiwa.geometry; import com.google.common.collect.ImmutableSe

您将获得一个由R2中的点定义的简单多边形。您可以将点沿x轴和y轴移动一些小ε(例如1e-4)。移动点以确保多边形的两条边不完全位于同一条线上的算法是什么

“在同一直线上”通常被定义为两条线的角度之间有足够小的差异,但是为了这个特定的问题,我只考虑段在它们的角度或直线方程中有0的差异,或者定义它们。 编辑:

这里有一些代码。它只解决了轴平行边的问题

package org.tendiwa.geometry;

import com.google.common.collect.ImmutableSet;
import org.jgrapht.UndirectedGraph;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Set;

public final class SameLineGraphEdgesPerturbations {
    private static Comparator<Segment2D> HORIZONTAL_COMPARATOR = (a, b) -> {
        assert a.start.y == a.end.y && b.start.y == b.end.y;
        double d = a.start.y - b.start.y;
        if (d < 0) {
            return -1;
        }
        if (d > 0) {
            return 1;
        }
        return 0;
    };
    private static Comparator<Segment2D> VERTICAL_COMPARATOR = (a, b) -> {
        assert a.start.x == a.end.x && b.start.x == b.end.x;
        double d = a.start.x - b.start.x;
        if (d < 0) {
            return -1;
        }
        if (d > 0) {
            return 1;
        }
        return 0;
    };

    /**
     * Checks if some of graph's edges are segments of the same line, and perturbs vertices and edges of this graph
     * so it contains no such segments.
     * <p>
     * This class is designed to work with graphs that represent simple polygons. You can use it with other classes
     * of graphs, but that probably won't be useful.
     * 
     *
     * @param graph
     *  A planar graph to be mutated.
     */
    public static void perturbIfHasSameLineEdges(UndirectedGraph<Point2D, Segment2D> graph, double magnitude) {
        ArrayList<Segment2D> verticalEdges = new ArrayList<>(graph.edgeSet().size());
        ArrayList<Segment2D> horizontalEdges = new ArrayList<>(graph.edgeSet().size());
        for (Segment2D edge : graph.edgeSet()) {
            if (edge.start.x == edge.end.x) {
                verticalEdges.add(edge);
            } else if (edge.start.y == edge.end.y) {
                horizontalEdges.add(edge);
            }
        }
        verticalEdges.sort(VERTICAL_COMPARATOR);
        horizontalEdges.sort(HORIZONTAL_COMPARATOR);
        /*
         The algorithm is the following:
         For each axis-parallel edge in a list of edges sorted by static coordinate,
         perturb its start if the next edge in list has the same static coordinate (i.e., lies on the same line).
         That way if we have N same line axis-parallel edges (placed consecutively in an array because it is sorted),
         N-1 of those will be perturbed, except for the last one (because there is no next edge for the last one).
         Perturbing the last one is not necessary because bu perturbing other ones the last one becomes non-parallel
         to each of them.
          */
        int size = verticalEdges.size() - 1;
        for (int i = 0; i < size; i++) {
            Point2D vertex = verticalEdges.get(i).start; // .end would be fine too
            if (vertex.x == verticalEdges.get(i + 1).start.x) {
                perturbVertexAndItsEdges(vertex, graph, magnitude);
            }
        }
        size = horizontalEdges.size() - 1;
        for (int i = 0; i < size; i++) {
            Point2D vertex = horizontalEdges.get(i).start; // .end would be fine too
            if (vertex.y == horizontalEdges.get(i + 1).start.y) {
                if (!graph.containsVertex(vertex)) {
                    // Same edge could already be perturbed in a loop over vertical edges.
                    continue;
                }
                perturbVertexAndItsEdges(vertex, graph, magnitude);
            }
        }
    }

    private static void perturbVertexAndItsEdges(
        Point2D vertex,
        UndirectedGraph<Point2D, Segment2D> graph,
        double magnitude
    ) {
        Set<Segment2D> edges = ImmutableSet.copyOf(graph.edgesOf(vertex));
        assert edges.size() == 2 : edges.size();
        // We move by both axes so both vertical and
        // horizontal edges will become not on the same line
        // with those with which they were on the same line.
        Point2D newVertex = vertex.moveBy(magnitude, magnitude);
        graph.addVertex(newVertex);
        for (Segment2D edge : edges) {
            boolean removed = graph.removeEdge(edge);
            assert removed;
            // It should be .end, not .start, because in perturbIfHasSameLineEdges we used
            // vertex = edges.get(i).start
            if (edge.start == vertex) {
                graph.addEdge(newVertex, edge.end);
            } else {
                assert edge.end == vertex;
                graph.addEdge(newVertex, edge.start);
            }
        }
        assert graph.degreeOf(vertex) == 0 : graph.degreeOf(vertex);
        graph.removeVertex(vertex);
    }
}
package org.tendiwa.geometry;
导入com.google.common.collect.ImmutableSet;
导入org.jgrapht.UndirectedGraph;
导入java.util.ArrayList;
导入java.util.Comparator;
导入java.util.Set;
公共最后一堂课相同的摄影干扰{
专用静态比较器水平_比较器=(a,b)->{
断言a.start.y==a.end.y&&b.start.y==b.end.y;
双d=a.start.y-b.start.y;
if(d<0){
返回-1;
}
如果(d>0){
返回1;
}
返回0;
};
专用静态比较器垂直比较器=(a,b)->{
断言a.start.x==a.end.x&&b.start.x==b.end.x;
双d=a.start.x-b.start.x;
if(d<0){
返回-1;
}
如果(d>0){
返回1;
}
返回0;
};
/**
*检查图的某些边是否为同一直线的线段,并扰动该图的顶点和边
*所以它不包含这样的片段。
*
*此类设计用于处理表示简单多边形的图形。您可以将其用于其他类
*但这可能不会有用。
* 
*
*@param图
*要变异的平面图。
*/
公共静态空间扰动HassameLineEdge(无向图图形,双幅){
ArrayList verticalEdges=新的ArrayList(graph.edgeSet().size());
ArrayList HorizontalEdge=新的ArrayList(graph.edgeSet().size());
对于(分段2D边:graph.edgeSet()){
if(edge.start.x==edge.end.x){
垂直边。添加(边);
}else if(edge.start.y==edge.end.y){
水平边。添加(边);
}
}
垂直边。排序(垂直比较器);
水平边。排序(水平比较器);
/*
算法如下所示:
对于按静态坐标排序的边列表中的每个轴平行边,
如果列表中的下一条边具有相同的静态坐标(即位于同一条线上),则扰动其起点。
这样,如果我们有N条相同的线轴平行边(由于排序,所以连续放置在一个数组中),
除最后一条外,其中N-1条将受到扰动(因为最后一条没有下一条边)。
扰动最后一个是不必要的,因为扰动其他的最后一个变得不平行
给他们每个人。
*/
int size=verticalEdges.size()-1;
对于(int i=0;i
提示:

对于每条边,计算一些标量方向参数(例如角度,如您所建议的,可以是其他,但需要是标量)。这需要时间O(N)

在时间O(N Lg(N))内对如此获得的所有参数进行排序

在O(N)中查找列表中的重复值

对于每组相等的值,以确保不会产生新的巧合的方式引入扰动(找到最接近的相邻值,并使用间隙大小分数的不同倍数对每个相等值进行扰动;例如,0.1、0.2、0.2、0.2、0.4的重复值为0.2,最近的间隙为0.1;因此可以将扰动值设为0.1、0.2-0.001、0.2、0.2+0.001、0.4)。或者只是随机扰动

现在是一个非防弹步骤:bui