Facendo un percorso agevole da un numero irregolare di x, y punti per simulare grafia
-
21-09-2019 - |
Domanda
Sto cercando di fare uno strumento 'pennello' in AS3 (puro, non Flex) che simula scrittura a mano, facendo colpi per essere liscia, invece di spalle al muro. Poi, la traccia deve essere ridotta alle curve di Bezier cubiche che possono essere trascinati e deformate, influenzare il percorso precedentemente disegnato (come strumento penna dell'illustratore).
Sono monitoraggio del movimento del mouse per ottenere un insieme di punti per disegnare il percorso. Per quanto ne so, ho bisogno di fare un percorso B-Spline utilizzando tale insieme di punti. Poi ho dovuto ridurlo a curve di Bezier cubi (aggiungendo la funzionalità 'strumento penna' al percorso).
ho già sviluppato lo strumento penna, utilizzando un algoritmo che riduce Beziers cubi a quadratica Beziers (e quindi usando la funzione Flash curveTo). Ma non ho idea di come creare una B-Spline (o un altro la semplificazione), uno poi ridurlo a curve di Bezier.
Conoscete qualche modo per ottenere questo?
Soluzione
Il jhotdraw è un progetto opensource in Java per il disegno. Converte disegni a mano libera in curve di Bezier cubiche. La sorgente è disponibile - scaricare e tradurre. Non avere paura alla dimensione del progetto: è necessario solo un paio di classi e cioè:
org.jhotdraw.geom.Bezier
org.jhotdraw.geom.BezierPath
org.jhotdraw.geom.Geom
Durante la traduzione di avvio modificando tutte le dichiarazioni di raccolta per array (vettori di uso se si stanno prendendo di mira solo gli utenti FP10). Ho alcune espressioni regolari che potreste trovare utili nella conversione - posso postare se vuoi
. Ecco un elenco di espressioni regolari che potreste trovare utile. In ogni coppia, incollare la prima nella ricerca di testo e la seconda in sostituzione zona, selezionare la casella di controllo regex e utilizzare Trova e sostituisci pulsanti. Non utilizzare Replace All
-. Nessuno di questi sono garantiti per essere a prova di errore
Sostituire tutte le dichiarazioni int/double name
con var name:Number
\b(double|int)\s+(\w+)\b
var $2:Number
Sostituire tutte le dichiarazioni Point2D.Double name
con var name:Point
\bPoint2D\.Double\s+(\w+)\b
var $1:Point
Sostituire tutte le dichiarazioni int/double name
nelle firme di funzione con name:Number
\(([^)]*)\b(?:double|int)\s+(\w+)\b([^)]*?)\)
($1$2:Number$3)
Sostituire tutte le dichiarazioni Point2D.Double name
nelle firme di funzione con name:Point
\(([^)]*)\b(?:Point2D\.Double)\s+(\w+)\b([^)]*?)\)
($1$2:Point$3)
Prima di cambiare metodo di firme, assicurarsi che tutti i metodi sono statici:
(public|private)\s+(?!static)
Sostituire metodo firme per AS formato
(public|private)\s+static\s+(\w+)\s+(\w+)\s*\(([^)]*)\)
$1 static function $3($4):$2
Sostituire ArrayList.get (indice) con array [index] // Attenzione: non riesce per list.get (list.size () - 1)
(\w+)\.get\(([^)]+)\)
$1[$2]
//avoid the () failure
(\w+)\.get\(([^)]*(?:\([^)]*\))[^)]*)\)
$1[$2]
Sostituire ArrayList.set(index, element)
con array[index] = element
// Attenzione: non riesce per 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]
Sostituire arraylist.add(object)
con array.push(object)
//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)
Sostituire metodo firme per il formato (i metodi non statici)
(public|private)\s+(?!function)(\w+)\s+(\w+)\s*\(([^)]*)\)
$1 function $3($4):$2
Sostituire tutte le dichiarazioni int/double/point/boolean name
nelle firme di funzione con name:type
\(([^)]*)\b(\w+)\s+(\w+)\b([^)]*?)\)
($1$3:$2$4)
Sostituire tutte le dichiarazioni di variabili in una propria linea con = per AS formato
^(\s+)(\w+)\s+(\w+)\s*=\s*(.+?)\s*;(\s*)$
$1var $3:$2 = $4;$5
cambiamento immissione di parentesi graffe.
^(\t)(\s*)([^\n]+)\{\s*(\n)\s+
$1$2$3$4$1$2{$4$1$2
cambiamento } else
in } \n else
^([ \t]+)}[ \t]*else\b([^\n]*)(\n)
$1}$3$1else$2$3
Sostituire 4 dichiarazioni di variabili in una singola linea di AS in linee differenti
^(\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
Sostituire le dichiarazioni di matrice
^(\s+)\w+\[\]\s*(\w+)\b
$1 var $2:Array
Rimuovi () casting - AS compilatore non piacciono
(?:\(\w+\)\s*)([^ ,*+;/)><=\-])
$1
Sostituire max ecc in Math.max - AS non ha le importazioni statiche
(?<!Math\.)\b(max|min|abs|sqrt|PI|cos|sin|atan2)\(
Math.$1(
Altri suggerimenti
Ho usato questa funzione una sola volta.
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]);
}
}
C'è un algoritmo in una libreria C che fa quello che si sta chiedendo: http://tog.acm.org/resources/GraphicsGems/gems/FitCurves.c
Questo è un algoritmo piuttosto complesso che semplifica la geometria convertendo un elenco di molti punti in una lista di alcuni stretti curve di Bezier montaggio, essenzialmente trasformando scarabocchi in curve molto morbide. Ha una quantità regolabile di allentamento, e opere di trovare il minor numero di curve di Bezier che misura il vostro insieme di punti entro un certo allentamento. Così il più alto si imposta il gioco dell'algoritmo, il più agevole (ma potenzialmente meno preciso) la tua scrittura diventa.
Non è sicuro se si specificamente bisogno di Beziers, ma questo strumento spline Catmull-ROM è abbastanza grande: http://www.motiondraw.com/md/as_samples/t/ CatmullRomSpline / tween.html