2015-01-09 82 views
1

我正在開發一個應用程序,用於解析來自TrueType字體的字形數據,並將其轉換爲使用OpenGL ES 2.0進行渲染的多邊形。Java如何對Path2D進行三角化?

我已經成功的字形數據轉換成離散的指令,例如MOVE_TOLINE_TOQUAD_TOCLOSE,類似於Java的Path2D類。我然後triangulate這些路徑進行渲染。

我遇到的問題是我似乎在以非標準方式處理這些指令,因爲我可以有效地呈現某些字體,但無法呈現其他字體,如下所示。經過一些測試,似乎是在LINE_TOBEZIER_TO指令之間移動時我使用的決策邏輯,但是我找不到與這兩種字體兼容的序列。

有沒有關於Java的Path2D數據是如何三角化的在線文檔?

1.正確渲染的字形('c')。

A correctly rendered character.

2.一種呈現不正確的字形,從不同的字體( 'C')。

An incorrectly rendered character.

在下面的代碼片段,我選擇的點繪製的三角測量。無論我們處於曲線的內部還是外部,我們都繪製了貝塞爾曲線或貝塞爾控制點的終點。貝塞爾曲線分別正確呈現給這個代碼。

switch(lVectorPathComponent) { 
     case MOVE_TO : 
      /* Append the current vertex to PolygonPoints. */ 
      if((lLastPathComponent == EVectorPathComponent.BEZIER_TO || lLastPathComponent == EVectorPathComponent.MOVE_TO)) { 
       lPolygonPoints.add(new PolygonPoint(pVectorPath.getPathData()[i + 1], pVectorPath.getPathData()[i + 2])); 
      } 
      /* Initialize the start location of the path. */ 
      lStartX = pVectorPath.getPathData()[i + 1]; 
      lStartY = pVectorPath.getPathData()[i + 2]; 
     break; 
     case LINE_TO : 
      if(lLastPathComponent != EVectorPathComponent.MOVE_TO) { 
       lPolygonPoints.add(new PolygonPoint(pVectorPath.getPathData()[i + 1], pVectorPath.getPathData()[i + 2])); 
      } 
      else { 
       if((lNextPathComponent == EVectorPathComponent.LINE_TO || lNextPathComponent == EVectorPathComponent.BEZIER_TO)) { 
        lPolygonPoints.add(new PolygonPoint(pVectorPath.getPathData()[i + 1], pVectorPath.getPathData()[i + 2])); 
       } 
      } 
     break; 
     case BEZIER_TO : 
      if(VectorPathGlobal.onCalculateBezierDirection(pVectorPath, i) == pVectorPath.getWindingOrder()) { 
       if(!(lLastPathComponent == EVectorPathComponent.LINE_TO && lNextPathComponent == EVectorPathComponent.BEZIER_TO)) { 
        lPolygonPoints.add(new PolygonPoint(pVectorPath.getPathData()[i - 2], pVectorPath.getPathData()[i - 1])); /* Last X, Y */ 
        lPolygonPoints.add(new PolygonPoint(pVectorPath.getPathData()[i + 1], pVectorPath.getPathData()[i + 2])); /* Control Point */ 
        lPolygonPoints.add(new PolygonPoint(pVectorPath.getPathData()[i + 3], pVectorPath.getPathData()[i + 4])); /* Bezier end X, Y */ 
       } 
      } 
      else { 
       lPolygonPoints.add(new PolygonPoint(pVectorPath.getPathData()[i + 3], pVectorPath.getPathData()[i + 4])); 
      } 
     break; 
     case CLOSE  : 
      lPolygonPoints.add(new PolygonPoint(lStartX, lStartY)); 
     break; 
    } 
} 

的正確呈現曲線包括這些命令:

MOVE_TO x:121.0 y:682.0 
BEZIER_TO cx:121.0 cy:840.0 x:164.0 y:969.0 
BEZIER_TO cx:208.0 cy:1098.0 x:289.0 y:1189.0 
BEZIER_TO cx:370.0 cy:1281.0 x:485.0 y:1330.0 
BEZIER_TO cx:601.0 cy:1380.0 x:746.0 y:1380.0 
BEZIER_TO cx:797.0 cy:1380.0 x:838.0 y:1374.0 
BEZIER_TO cx:880.0 cy:1369.0 x:914.0 y:1360.0 
BEZIER_TO cx:949.0 cy:1351.0 x:978.0 y:1339.0 
BEZIER_TO cx:1007.0 cy:1327.0 x:1033.0 y:1314.0 
LINE_TO x:978.0 y:1184.0 
BEZIER_TO cx:929.0 cy:1207.0 x:872.0 y:1220.0 
BEZIER_TO cx:816.0 cy:1234.0 x:746.0 y:1234.0 
BEZIER_TO cx:650.0 cy:1234.0 x:571.0 y:1202.0 
BEZIER_TO cx:492.0 cy:1170.0 x:435.0 y:1102.0 
BEZIER_TO cx:379.0 cy:1035.0 x:348.0 y:931.0 
BEZIER_TO cx:317.0 cy:827.0 x:317.0 y:682.0 
BEZIER_TO cx:317.0 cy:537.0 x:349.0 y:432.0 
BEZIER_TO cx:382.0 cy:327.0 x:441.0 y:259.0 
BEZIER_TO cx:500.0 cy:191.0 x:583.0 y:158.0 
BEZIER_TO cx:666.0 cy:126.0 x:768.0 y:126.0 
BEZIER_TO cx:811.0 cy:126.0 x:847.0 y:131.0 
BEZIER_TO cx:884.0 cy:137.0 x:915.0 y:146.0 
BEZIER_TO cx:946.0 cy:155.0 x:972.0 y:165.0 
BEZIER_TO cx:998.0 cy:176.0 x:1020.0 y:186.0 
LINE_TO x:1062.0 y:58.0 
BEZIER_TO cx:1009.0 cy:25.0 x:933.0 y:2.0 
BEZIER_TO cx:858.0 cy:-20.0 x:746.0 y:-20.0 
BEZIER_TO cx:601.0 cy:-20.0 x:485.0 y:30.0 
BEZIER_TO cx:370.0 cy:81.0 x:289.0 y:173.0 
BEZIER_TO cx:208.0 cy:265.0 x:164.0 y:394.0 
BEZIER_TO cx:121.0 cy:524.0 x:121.0 y:682.0 

的呈現不正確曲線使用這些:

MOVE_TO x:831.0 y:1391.0 
BEZIER_TO cx:556.0 cy:1391.0 x:398.0 y:1215.0 
BEZIER_TO cx:240.0 cy:1039.0 x:240.0 y:733.0 
BEZIER_TO cx:240.0 cy:420.0 x:389.0 y:247.0 
BEZIER_TO cx:538.0 cy:74.0 x:815.0 y:74.0 
BEZIER_TO cx:999.0 cy:74.0 x:1153.0 y:121.0 
LINE_TO x:1153.0 y:31.0 
BEZIER_TO cx:1008.0 cy:-20.0 x:791.0 y:-20.0 
BEZIER_TO cx:483.0 cy:-20.0 x:306.0 y:179.0 
BEZIER_TO cx:129.0 cy:378.0 x:129.0 y:735.0 
BEZIER_TO cx:129.0 cy:958.0 x:213.0 y:1128.0 
BEZIER_TO cx:298.0 cy:1298.0 x:456.0 y:1390.0 
BEZIER_TO cx:615.0 cy:1483.0 x:825.0 y:1483.0 
BEZIER_TO cx:1039.0 cy:1483.0 x:1208.0 y:1403.0 
LINE_TO x:1167.0 y:1311.0 
BEZIER_TO cx:1007.0 cy:1391.0 x:831.0 y:1391.0 
+0

考慮顯示您嘗試過的相關代碼片段。示例輸出也會有所幫助。 – usr2564301 2015-01-09 22:14:09

+0

@Jongware我已經添加了相關的代碼片段。希望這不會混淆事物! – 2015-01-09 22:30:38

+0

我總是發現它看起來像是這樣的輸出例程*認爲它正在做什麼的文本表示。你可以爲每個命令添加'print'行,並且可以爲好的和壞的解碼添加輸出嗎? – usr2564301 2015-01-09 22:32:57

回答

0

我發現,在LibTess2使用的鑲嵌方法是用Java的Path2D三角兼容。

在我原來的問題中,我遇到的問題是,我使用的頂點的三角剖分是Poly2Tri,它不支持位於多邊形邊上的頂點;由於這個問題,幾個奇怪的三角形正在產生,似乎漸漸降落到原點。 LibTess2還努力對非簡單的多邊形進行三角剖分,但是在檢測到衝突的頂點時,它允許用戶通過它的方法回調來提供解決衝突的方法。通過在衝突頂點之間進行平等,可以解決錯誤的細分問題,從而產生正確的三角化字形。 earcut-j也足夠強大以處理這些頂點。

1

是代碼是好的。下面的代碼使用標準的Path2D quadTo/curveTo。也許這與偶數纏繞規則等有關。

public class JavaGUI extends JPanel { 

    public static void main(String[] args) { 
     final JFrame f = new JFrame("Glyphs"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(new JavaGUI()); 
     f.pack(); 
     f.setLocationRelativeTo(null); 

     EventQueue.invokeLater(() -> { 
      f.setVisible(true); 
     }); 
    } 

    public JavaGUI() { 
     setPreferredSize(new Dimension(600, 600)); 
     setBackground(new Color(0xDDEEFF)); 
    } 

    private double x0; 
    private double y0; 

    @Override 
    public void paintComponent(Graphics g) { 
     final String aString = "c"; 
     super.paintComponent(g); 

     Graphics2D g2d = (Graphics2D) g; 

     double scale = 0.25; 
     g2d.translate(100, 100); 
     g2d.scale(scale, scale); 

     Path2D.Double path = new Path2D.Double(); // May add rule and such. 

     moveTo(path, 121.0, 682.0); 
     bezierTo(path, 121.0, 840.0, 164.0, 969.0); 
     bezierTo(path, 208.0, 1098.0, 289.0, 1189.0); 
     bezierTo(path, 370.0, 1281.0, 485.0, 1330.0); 
     bezierTo(path, 601.0, 1380.0, 746.0, 1380.0); 
     bezierTo(path, 797.0, 1380.0, 838.0, 1374.0); 
     bezierTo(path, 880.0, 1369.0, 914.0, 1360.0); 
     bezierTo(path, 949.0, 1351.0, 978.0, 1339.0); 
     bezierTo(path, 1007.0, 1327.0, 1033.0, 1314.0); 
     lineTo(path, 978.0, 1184.0); 
     bezierTo(path, 929.0, 1207.0, 872.0, 1220.0); 
     bezierTo(path, 816.0, 1234.0, 746.0, 1234.0); 
     bezierTo(path, 650.0, 1234.0, 571.0, 1202.0); 
     bezierTo(path, 492.0, 1170.0, 435.0, 1102.0); 
     bezierTo(path, 379.0, 1035.0, 348.0, 931.0); 
     bezierTo(path, 317.0, 827.0, 317.0, 682.0); 
     bezierTo(path, 317.0, 537.0, 349.0, 432.0); 
     bezierTo(path, 382.0, 327.0, 441.0, 259.0); 
     bezierTo(path, 500.0, 191.0, 583.0, 158.0); 
     bezierTo(path, 666.0, 126.0, 768.0, 126.0); 
     bezierTo(path, 811.0, 126.0, 847.0, 131.0); 
     bezierTo(path, 884.0, 137.0, 915.0, 146.0); 
     bezierTo(path, 946.0, 155.0, 972.0, 165.0); 
     bezierTo(path, 998.0, 176.0, 1020.0, 186.0); 
     lineTo(path, 1062.0, 58.0); 
     bezierTo(path, 1009.0, 25.0, 933.0, 2.0); 
     bezierTo(path, 858.0, -20.0, 746.0, -20.0); 
     bezierTo(path, 601.0, -20.0, 485.0, 30.0); 
     bezierTo(path, 370.0, 81.0, 289.0, 173.0); 
     bezierTo(path, 208.0, 265.0, 164.0, 394.0); 
     bezierTo(path, 121.0, 524.0, 121.0, 682.0); 

     path.closePath(); 

     g2d.setColor(Color.RED); 
     g2d.fill(path); 

     // ------ 

     path = new Path2D.Double(); // May add rule and such. 

     moveTo(path, 831.0, 1391.0); 
     bezierTo(path, 556.0, 1391.0, 398.0, 1215.0); 
     bezierTo(path, 240.0, 1039.0, 240.0, 733.0); 
     bezierTo(path, 240.0, 420.0, 389.0, 247.0); 
     bezierTo(path, 538.0, 74.0, 815.0, 74.0); 
     bezierTo(path, 999.0, 74.0, 1153.0, 121.0); 
     lineTo(path, 1153.0, 31.0); 
     bezierTo(path, 1008.0, -20.0, 791.0, -20.0); 
     bezierTo(path, 483.0, -20.0, 306.0, 179.0); 
     bezierTo(path, 129.0, 378.0, 129.0, 735.0); 
     bezierTo(path, 129.0, 958.0, 213.0, 1128.0); 
     bezierTo(path, 298.0, 1298.0, 456.0, 1390.0); 
     bezierTo(path, 615.0, 1483.0, 825.0, 1483.0); 
     bezierTo(path, 1039.0, 1483.0, 1208.0, 1403.0); 
     lineTo(path, 1167.0, 1311.0); 
     bezierTo(path, 1007.0, 1391.0, 831.0, 1391.0  ); 

     path.closePath(); 

     g2d.setColor(new Color(0x8800CC00, true)); 
     g2d.fill(path); 

     g2d.scale(1/scale, 1/scale); 
    } 

    private void bezierTo(Path2D.Double path, double cx, double cy, 
      double x, double y) { 
     path.quadTo(cx, cy, x, y); 
     //path.curveTo(x0, y0, cx, cy, x, y); 
     x0 = x; 
     y0 = y; 
    } 

    private void moveTo(Path2D.Double path, double x, double y) { 
     path.moveTo(x, y); 
     x0 = x; 
     y0 = y; 
    } 

    private void lineTo(Path2D.Double path, double x, double y) { 
     path.lineTo(x, y); 
     x0 = x; 
     y0 = y; 
    } 
} 

Two glyphs of both a "c"

+0

我並不認爲這是一種調試方法,很好! – 2015-01-10 02:12:40