【问题标题】:Calculate the outer vertices for a border of uniform thickness x drawn around a polygon计算围绕多边形绘制的均匀厚度 x 边界的外部顶点
【发布时间】:2016-04-19 15:25:57
【问题描述】:

我有一个由中心点 C 和外部顶点数组(V0、V1、..、Vn sub>) 按 CCW 顺序输入。对于每个顶点 Vi,我知道顶点 V(i-1)%n、Vi 和 V(i+1)%n,我可以将向量从 C 归一化为 Vi。我也可以通过任何给定的向量来翻译一个顶点。我的多边形的外顶点可以作为我边界的内顶点,所以我只需要知道如何计算边界的外顶点。

这是我尝试过的:

public static Vertex[] calculateOuterVerticesForBorder(Polygon polygon, float borderThickness) {

  int outerVertexCount = polygon.outerVertexCount;

  Vertex[] bOuterVertices = new Vertex[outerVertexCount];

  for (int i = 0; i < outerVertexCount; i++) {
    Vertex pOuterVertex = polygon.outerVertices[i];
    float pOuterVertexAngle = polygon.outerVertexAngles[i];
    Vector pVectorNorm = new Vector(polygon.center, pOuterVertex).toLength(borderThickness);
    //Here I should probably make some adjustment to pVectorNorm based on the 
    //outer vertex angle, or perhaps the angle from C to Vi to V(i+1)
    Vertex bOuterVertex = new Translation(vectorNorm).transform(pOuterVertex);
    bOuterVertices[i] = bOuterVertex;
  }

  return bOuterVertices;
}

问题是,此计算导致边框厚度不均匀,如下图所示:

Image of non-uniform border drawn around some of my polygons

【问题讨论】:

  • 您是否尝试过使用着色器构建边框而不是在客户端计算?
  • 不,我认为在客户端计算边界顶点会更有效,这样我就可以将结果保存在我的数据库中以供重复使用。
  • 我还需要能够访问边界顶点的 contains(vertex) 方法,该方法用于检查点是否位于边界内。

标签: android opengl-es border polygon vertex


【解决方案1】:

您需要做的是计算在顶点连接的两条线之间的中间角。然后沿着该角度向量扩展边界borderThickness 距离,然后将该点添加到包含“边界”多边形的列表中。

我建议的代码有点像这样:

//This math is weird, but it basically just returns a boolean value: 
//are these three points convex or concave, using counterclockwise ordering?
boolean isConvex(Vertex previousVertex, Vertex currentVertex, Vertex nextVertex) {
    return
        (
        previousVertex.x * (nextVertex.y - currentVertex.y) +
        currentVertex.x * (previousVertex.y - nextVertex.y) +
        nextVertex.x * (currentVertex.y - previousVertex.y)
        ) < 0;
}

Vertex getBorderVertex(Vertex previousVertex, Vertex currentVertex, Vertex nextVertex, float borderDistance) {
    //I'm using the word "vector" here to distinguish numbers which are directions, 
    //whereas "vertex" refers to a point. Mathematically, there's no difference.
    Vector line1 = Vector(currentVertex.x - previousVertex.x, currentVertex.y - previousVertex.y);
    //normalize == make the length equal to 1
    line1 = normalize(line1);
    Vector line2 = Vector(currentVertex.x - nextVertex.x, currentVertex.y - nextVertex.y);
    line2 = normalize(line2);

    //We really shouldn't have joints that are just straight lines 
    //(especially because floating point numbers are imprecise), 
    //but we want the formula to be generic enough to handle this edge case (pun intended)

    //The Dot Product is the same as the dot product algorithm you learned in primary school geometry.
    float dotProduct = line1.dot(line2);
    if(dotProduct == 1 || dotProduct == -1) {
        Vector normalVector = Vector(line1.y, -line1.x);
        normalVector = normalVector.multiply(borderDistance);
        return Vertex(currentVertex.x + normalVector.x, currentVertex.y + normalVector.y);
    }
    Vector halfwayLine = line1.plus(line2);

    //We want the algorithm to work correctly regardless of whether it's a concave joint 
    //or a convex joint. If it's concave, we need to reverse the direction.
    if(!isConvex(previousVertex, currentVertex, nextVertex)) 
        halfwayLine = halfwayLine.multiply(-1);

    halfwayLine = normalize(halfwayLine);
    halfwayLine = halfwayLine.multiply(borderDistance);
    return Vertex(currentVertex.x + halfwayLine.x, currentVertex.y, halfwayLine.y);
}

然后您的程序可以调用所有这些代码,如下所示:

for(int vertexIndex = 0; vertexIndex < outerVertexCount; vertexIndex++) {
    //The weird math here is only because modulos of negative values can 
    //return negative numbers in some programming languages. If you know for certain 
    //that the modulo function will only return positive numbers, then you can remove 
    //the addition of outerVertexCount to the previousVertex index.
    Vertex previousVertex = polygon.outerVertices[(vertexIndex + outerVertexCount - 1) % outerVertexCount];
    Vertex currentVertex = polygon.outerVertices[vertexIndex];
    Vertex nextVertex = polygon.outerVertices[(vertexIndex + 1) % outerVertexCount];

    bOuterVertices[vertexIndex] = getBorderVertex(previousVertex, currentVertex, nextVertex, borderThickness);
}

【讨论】:

  • 谢谢。我能够使用您关于在顶点处连接两条线的想法找到解决方案,但是您的代码开箱即用不适用于我。你真的打算做 Vector(currentVertex.y - previousVertex.y, currentVertex.x - previousVertex.x) 而不是 Vector(currentVertex.x - previousVertex.x, currentVertex.y - previousVertex.y)?我假设向量构造函数是 Vector(x,y)。
  • @William 我没有。接得好。我创建的法线向量 is 应该是这个顺序。这两个线向量不是。
猜你喜欢
  • 1970-01-01
  • 2011-08-11
  • 2013-11-10
  • 1970-01-01
  • 2013-09-06
  • 2011-01-05
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多