2016-04-07 42 views
0

我正面临着一个任务,我必须使用多边形绘制多段线。 作为输入参数,我有一个点和厚度值的数组。见下图。 enter image description here多义线轮廓构建/绘制粗多段线

我有点形成黑色折线和厚度,例如, 10px的。现在我需要计算点并构建一条蓝色多段线以形成多边形,然后再渲染它。

有与此相关的一些文章:

但我觉得他们有点复杂,难以理解。 没有任何现有的库或更简单的算法来实现这一点。不需要倒圆角。我正在使用java和libGDX。

+0

难道你不能简单地这样做:对于每一个黑点:首先,创建一个伪法线,这是点的法线的法线的平均值。其次,将伪法线归一化并乘以厚度。第三,将它添加到黑点以获得相应的蓝点。 – Aziuth

+0

蓝线与黑线的关系是什么? – gpasch

+0

@gpasch我使用的颜色只是为了显示给出的黑点阵列,并基于它们和厚度我需要确定蓝点的阵列以形成一个多边形 –

回答

1

的算法如下(例如因为不同的角度):

for each line: 
    find the parallel line upwards: 
    find the perpendicular: has a slope m2 in approximate 
    check which side is right (compare angles) 
    find the two points of the parallel line by solving a small equation problem (A, B, C) 
    if this line is the first one keep it (l1) 
    else find the intersection with the previous line (l1, l2): this will give the next articulation point 

黄线是你想要的;红线是一般的平行线。 关节点呈绿色。您可以在某些组件中打印此bufferedimage。

注意:多边形的宽度无法像您意识到的那样固定,因为在关节点处距离会更大。保证的是线段之间的距离是恒定的。

int[] approximate(int[] p, int[] p2, double dr, int l) { // l is the distance, dr is 0 for the beginning of the segment and 1 for the end 
      double d=Math.sqrt(Math.pow(p[0]-p2[0], 2)+Math.pow(p[1]-p2[1], 2)); 
      double ix=p[0]+dr*(p2[0]-p[0]), iy=p[1]+dr*(p2[1]-p[1]); 
      double x1=0, x2=0, y1=0, y2=0; 
      if(p2[0]==p[0]) { 
      x1=ix+l; x2=ix-l; y1=iy; y2=iy; 
      } 
      else { 
      double m=1.0*(p2[1]-p[1])/(p2[0]-p[0]); 
      if(Math.abs(m)==0) { 
      x1=ix; x2=ix; y1=iy+l; y2=iy-l; 
      } 
      else { 
      double m2=-1/m; 
      double c=iy-m2*ix; 
      double A=1+m2*m2, B=-2*(ix-m2*c+m2*iy), C=ix*ix+iy*iy+c*c-2*c*iy-l*l; 
      x1=(-B+Math.sqrt(B*B-4*A*C))/(2*A); x2=(-B-Math.sqrt(B*B-4*A*C))/(2*A); y1=m2*x1+c; y2=m2*x2+c; 
      } 
      } 
      int[] cp1={p2[0]-p[0], p2[1]-p[1]}, cp2={(int)x1-p[0], (int)y1-p[1]}, xy=new int[2]; 
      int cpp=compareAngles(cp1, cp2); 
      if(cpp>0) { xy[0]=(int)x1; xy[1]=(int)y1; } else { xy[0]=(int)x2; xy[1]=(int)y2; } 
      return xy; 
    } 

    void poly() { 
    int[][] p={{100, 400}, {110, 440}, {250, 300}, {350, 400}, {300, 310}}; 
    BufferedImage bim=new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB); 
    Graphics2D g=(Graphics2D)bim.getGraphics(); 
    g.setColor(Color.white); 
    g.fillRect(0, 0, 500, 500); 
    g.setStroke(new BasicStroke(5f)); 
    g.setColor(Color.black); 
    Line2D.Double l1=new Line2D.Double(), l2=new Line2D.Double(); 
    int[] currentp=new int[2], lastp=new int[2]; 
    for(int i=0; i<p.length-1; i++) { 
     g.setColor(Color.black); 
     g.drawLine(p[i][0], p[i][1], p[i+1][0], p[i+1][1]); 
     int[] p1=approximate(p[i], p[i+1], 0, 10), p2=approximate(p[i], p[i+1], 1, 10); 
     g.setColor(Color.red); 
     g.drawLine(p1[0], p1[1], p2[0], p2[1]); 
     if(i==0) { l1=new Line2D.Double(p1[0], p1[1], p2[0], p2[1]); currentp[0]=p1[0]; currentp[1]=p1[1]; } 
     else { 
     l2=new Line2D.Double(p1[0], p1[1], p2[0], p2[1]); 
     int[] pi=intersectionPoint(l1, l2); 
     g.setColor(Color.green); 
     g.fillOval(pi[0], pi[1], 5, 5); 
     g.setColor(Color.yellow); 
     g.drawLine(currentp[0], currentp[1], pi[0], pi[1]); 
     currentp[0]=pi[0]; currentp[1]=pi[1]; 
     l1.setLine(l2); 
     } 
     if(i==p.length-2) { lastp[0]=p2[0]; lastp[1]=p2[1]; } 
    } 
    g.setColor(Color.yellow); 
    g.drawLine(currentp[0], currentp[1], lastp[0], lastp[1]); 
    } 

    public int[] intersectionPoint(Line2D.Double l1, Line2D.Double l2) { 
    return intersectionPoint((int)l1.getX1(), (int)l1.getY1(), (int)l1.getX2(), (int)l1.getY2(), (int)l2.getX1(), (int)l2.getY1(), (int)l2.getX2(), (int)l2.getY2()); 
    } 

    public int[] intersectionPoint(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { 
    int[] xy={(int)(1.0*((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))), 
       (int)(1.0*((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)))}; 
    return xy; 
    } 


    public int compareAngles(int[] a, int[] b) { 
    int cp=a[0]*b[1]-a[1]*b[0]; 
    return -cp; 
    } 
+0

太棒了!那是我需要的。感谢您的时间! –

0

我真的不知道你为什么要实施框架一些先进的图形alghoritms它首先的责任是很容易的事情渲染:)

Libgdx具有内置ShapeRenderer,使您可以绘制简单的图形。您只需计算基于thickness的新顶点并将它们传递给ShapeRenderer以绘制连接这些圆的圆和线。

为了使超级容易,你甚至可以使用

rectLine(float x1, float y1, float x2, float y2, float width) 

方法,它允许您绘制一定厚度的线路。因此,只有你需要做的是遍历点,像画中所有的行这个伪代码:

for point in points: 
     if thereIsANextPoint(): 
      next = getNextPoint() 

      sr.rectLine(point.x, point.y, next.x, next .y, thickness) 

如何使用ShapeRenderer的很好描述包括在reference我上面


我想可以有一个小问题与点之间joinings我认为,渲染高于这个圈子加入将是很好的workarround :)

+0

由于线段关节的问题,我不能使用ShapeRenderer.rectLine(),因为我需要使用渐变为顶点着色并应用纹理到它。所以我决定使用Mesh,现在我正在寻找一种算法来计算这些点以形成一个多边形。 –