2009-11-19 13 views
7

Ich versuche, ein Pinsel-Werkzeug in AS3 (rein, nicht Flex) zu machen, das Handschrift simuliert, so dass Striche glatt statt eckig werden. Dann muss die Kurve auf kubische Bezierkurven reduziert werden, die gezogen und verformt werden können, was sich auf den zuvor gezeichneten Pfad auswirkt (wie das Stiftwerkzeug des Illustrators).Einen glatten Pfad aus einer unregelmäßigen Anzahl von x, y-Punkten erstellen, um Handschrift zu simulieren

Ich verfolge die Mausbewegung, um eine Reihe von Punkten zu erhalten, um den Pfad zu zeichnen. Soweit ich weiß, muss ich einen B-Spline-Pfad mit dieser Menge von Punkten machen. Dann sollte ich es auf kubische Bezierkurven reduzieren (indem ich dem Pfad die Funktion "Stiftwerkzeug" hinzufüge).

Ich habe das Stiftwerkzeug bereits entwickelt, indem ich einen Algorithmus verwende, der kubische Beziers auf Quadratische Beziers reduziert (und dann die Funktion Flash curveTo verwendet). Aber ich habe keine Ahnung, wie man ein B-Spline (oder eine andere Vereinfachung) erstellt, und dann auf Bezier-Kurven reduziert.

Kennen Sie einen Weg, dies zu erreichen?

+0

Ich bin auf der Suche nach der gleichen Sache, aber Javascript, kennen Sie irgendwelche? – igor

Antwort

7

Die jhotdraw ist ein Open Source-Projekt in Java zum Zeichnen. Es wandelt Freihandzeichnungen in kubische Bezierkurven um. Die Quelle ist verfügbar - herunterladen und übersetzen. Lassen Sie sich nicht Angst an der Größe des Projekts: Sie haben nur ein paar Klassen müssen nämlich:

org.jhotdraw.geom.Bezier 
org.jhotdraw.geom.BezierPath 
org.jhotdraw.geom.Geom 

Während Anfang der Übersetzung durch alle Sammlung Erklärungen zu Arrays zu ändern (Verwendung Vektoren, wenn Sie zielen nur FP10-Benutzer) . Ich habe einige Regexes, die Sie bei der Konvertierung nützlich finden könnten - ich kann sie bei Bedarf veröffentlichen.


Hier ist eine Liste von Regexes, die Sie nützlich finden könnten. Fügen Sie in jedem Paar das erste in den Suchtextbereich und das zweite in den Ersetzungsbereich ein, aktivieren Sie das Kontrollkästchen Regex und verwenden Sie die Schaltflächen Suchen und Ersetzen. Verwenden Sie nichtReplace All- keine von diesen sind garantiert idiotensicher.

Ersetzen alle int/double name Erklärungen mit var name:Number

\b(double|int)\s+(\w+)\b 

var $2:Number 

Ersetzen alle Point2D.Double name Erklärungen mit var name:Point

\bPoint2D\.Double\s+(\w+)\b 

var $1:Point 

Ersetzen alle int/double name Deklarationen in Funktionssignaturen mit name:Number

\(([^)]*)\b(?:double|int)\s+(\w+)\b([^)]*?)\) 

($1$2:Number$3) 

Ersetzen Sie alle Point2D.Double name Erklärungen in Funktionssignaturen mit name:Point

\(([^)]*)\b(?:Point2D\.Double)\s+(\w+)\b([^)]*?)\) 

($1$2:Point$3) 

Bevor Signaturen Methode zu ändern, stellen Sie sicher, dass alle Methoden statisch sind:

(public|private)\s+(?!static) 

Methode Signaturen ersetzen AS Format

(public|private)\s+static\s+(\w+)\s+(\w+)\s*\(([^)]*)\) 

$1 static function $3($4):$2 

Ersetzen Sie ArrayList.get (index) durch array [index] // Warnung: schlägt fehl für list.get (list.size() - 1)

(\w+)\.get\(([^)]+)\) 

$1[$2] 

//avoid the() failure 

(\w+)\.get\(([^)]*(?:\([^)]*\))[^)]*)\) 

$1[$2] 

ArrayList.set(index, element) Ersetzen mit array[index] = element // Achtung: nicht für list.set (i, list.size())

(\w+)\.set\(([^,]+)\s*,\s*([^)]+)\) 

$1[$2] = $3 


/*the above regex successfully made the following replacement*/ 

cleaned.set(cleaned.size() - 1, digitizedPoints[digitizedPoints.size() - 1]) 

cleaned[cleaned.size() - 1] = digitizedPoints[digitizedPoints.size() - 1] 

arraylist.add(object) mit array.push(object) ersetzen

//would fail if object contains ')' 
//add(index, object) should be done with splice 

(\w+)\.add\(([^)]+)\) 

$1.push($2) 

//too many failures - fail safe version - 
//still fails for nested parenthesis list.add(new Point(a.first(), a.last())) 
//- only three such cases - the effort to match parenthesis wouldn't be worth it 
//works for list.add(new Point(3, 4)) - there were many similar cases 

(\w+)\.add\(([^)]*(?:\([^)]*\))[^)]*)\) 

$1.push($2) 

Ersetzen Sie Methodensignaturen im AS-Format (nicht statische Methoden)

(public|private)\s+(?!function)(\w+)\s+(\w+)\s*\(([^)]*)\) 

$1 function $3($4):$2 

Ersetzen alle int/double/point/boolean name Deklarationen in Funktionssignaturen mit name:type

\(([^)]*)\b(\w+)\s+(\w+)\b([^)]*?)\) 

($1$3:$2$4) 

Ersetzen aller Variablendeklarationen in einer eigenen Zeile mit einem Format = AS

^(\s+)(\w+)\s+(\w+)\s*=\s*(.+?)\s*;(\s*)$ 

$1var $3:$2 = $4;$5 

Änderung Platzierung von Zahnspangen.

^(\t)(\s*)([^\n]+)\{\s*(\n)\s+ 

$1$2$3$4$1$2{$4$1$2 

Änderung in } else} \n else

^([ \t]+)}[ \t]*else\b([^\n]*)(\n) 

$1}$3$1else$2$3 

Ersetzen 4 Variablendeklarationen in einer einzigen Zeile zu AS in unterschiedlichen Linien

^(\t+)(\w+)\s+(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*;[ \t]*(\n) 

$1var $3:$2;$7$1var $4:$2;$7$1var $5:$2;$7$1var $6:$2;$7 

Ersetzen Array Erklärungen

^(\s+)\w+\[\]\s*(\w+)\b 

$1 var $2:Array 

Remove() Gießen - AS Compiler mag sie max nicht

(?:\(\w+\)\s*)([^ ,*+;/)><=\-]) 

$1 

Ersetzen usw. in Math.max - AS nicht statisch Importe

(?<!Math\.)\b(max|min|abs|sqrt|PI|cos|sin|atan2)\(

Math.$1(
+0

Ich habe die Bibliothek überprüft und es sieht fantastisch aus. Die Beispielanwendung zum Zeichnen funktioniert genau so, wie ich es möchte. Danke für die Referenz. – yizzreel

+0

Hier sind die Regexes, von denen ich gesprochen habe. – Amarghosh

+0

Was für eine tolle Arbeit !! Ich habe bereits begonnen, den Java-Code auf AS3 zu portieren, es scheint keine schwierige Aufgabe zu sein, aber das wird den Prozess enorm beschleunigen. Danke vielmals. – yizzreel

1

ich diese Funktion einmal verwendet hat.

 

    public function multicurve(g: Graphics, args: Array, closed: Boolean): void {   
      var mid: Array = args.slice(); //make dublicate 
      var i: uint; 
      var point: Point; 
      var nextPoint: Point; 
      var numPoints: uint = mid.length; 

      if (numPoints == 2) { 
       g.moveTo(mid[0].x, mid[0].y); 
       g.lineTo(mid[1].x, mid[1].y); 
       return; 
      } 

      var Xpoint: Array = new Array(); 
      var Ypoint: Array = new Array(); 
      for (i = 1; i < numPoints - 2; i++) { 
       point = mid[i]; 
       nextPoint = mid[i+1]; 
       Xpoint[i] = 0.5*(nextPoint.x + point.x); 
       Ypoint[i] = 0.5*(nextPoint.y + point.y); 
      } 
      if (closed) { 
       Xpoint[0] = 0.5*(mid[1].x + mid[0].x); 
       Ypoint[0] = 0.5*(mid[1].y + mid[0].y); 
       Xpoint[i] = 0.5*(mid[i+1].x + mid[i].x); 
       Ypoint[i] = 0.5*(mid[i+1].y + mid[i].y); 
       Xpoint[i+1] = 0.5*(mid[i+1].x + mid[0].x); 
       Ypoint[i+1] = 0.5*(mid[i+1].y + mid[0].y); 
       mid.push(new Point(mid[0].x, mid[0].y)); 
       Xpoint[i+2] = Xpoint[0]; 
       Ypoint[i+2] = Ypoint[0]; 
      } else { 
       Xpoint[0] = mid[0].x; 
       Ypoint[0] = mid[0].y; 
       Xpoint[i] = mid[i+1].x; 
       Ypoint[i] = mid[i+1].y; 
       mid.pop(); 
       numPoints--; 
      } 
      g.moveTo(Xpoint[0], Ypoint[0]); 
      for (i = 1; i < numPoints; i++) { 
       point = mid[i]; 
       g.curveTo(point.x, point.y, Xpoint[i], Ypoint[i]); 
      } 
      if (closed) { 
       g.curveTo(mid[0].x, mid[0].y, Xpoint[i], Ypoint[i]); 
      } 
     } 

 
1

Es gibt einen Algorithmus in ac Bibliothek, das tut, was Sie fordern: http://tog.acm.org/resources/GraphicsGems/gems/FitCurves.c

Dies ist ein ziemlich komplexer Algorithmus, der Ihre Geometrie vereinfacht, indem er eine Liste mit vielen Punkten in eine Liste einiger eng anliegender Bezier-Kurven umwandelt, die Scribbles im Wesentlichen in sehr glatte Kurven verwandeln. Es hat eine einstellbare Menge an Durchhang und funktioniert, indem es die geringste Anzahl von Bezier-Kurven findet, die zu Ihrer Menge von Punkten innerhalb eines bestimmten Durchhangs passen. Je höher also der Algorithmus eingestellt ist, desto glatter (aber möglicherweise weniger genau) wird Ihr Schreiben.

+0

Hey! Vielen Dank! das sieht gut aus! Ich benutze bereits den jHotDraw-Algorithmus (vereinfacht), und es funktioniert so ziemlich wie der Code, den Sie mir verlinkt haben. Aber ich werde mir das auch genau ansehen. Und es scheint, es gibt mehr Quellen auf der Website, wo die Datei ist. Danke nochmal für die Referenz! – yizzreel

+0

Kurzes Update: Die FitCurves-Bibliothek funktionierte, aber wenn ich das Problem noch einmal lösen würde, würde ich es anders angehen. Zuallererst musste ich die Bibliothek optimieren, um schnelle Handschrift gut zu handhaben - schnelle Handschrift scheint ein guter Weg zu sein, einen solchen Algorithmus zu testen. Noch wichtiger ist jedoch, dass ich einen Echtzeitalgorithmus erstellen würde, der beim Zeichnen jeweils eine Kurve berechnet. Ich würde den Kern von FitCurves behalten, bei dem es sich um einen Algorithmus handelt, der eine einzelne Kurve zurückgibt, die am besten zu einer Reihe von Punkten passt, und den Rest anpasst. –

+0

Link jetzt tot. Archivierte hier: https://web.archive.org/web/20090805204502/http://tog.acm.org/resources/GraphicsGems/gems/FitCurves.c und das sieht aus wie der neue offizielle Link: https://github.com/erich666/GraphicsGems/blob/master/gems/FitCurves.c /* Ein Algorithmus zur automatischen Anpassung Digitalisierte Kurven von Philip J. Schneider von "Graphics Gems", Academic Press, 1990 * / – murkle

Verwandte Themen