c# - importar - ¿Cómo funciona la simplificación de la polilínea en Adobe Illustrator?
importar archivos de autocad a illustrator (1)
Estoy trabajando en una aplicación que registra trazos, que pinta con un dispositivo señalador.
En la imagen de arriba, dibujé un solo trazo, que contiene 453 puntos de datos. Mi objetivo sería reducir drásticamente la cantidad de puntos de datos mientras se mantiene la forma del trazo original.
Para aquellos interesados, las coordenadas para el trazo ilustrado arriba están disponibles como una esencia en GitHub .
De hecho, Adobe Illustrator tiene una gran implementación de lo que estoy tratando de lograr. Si dibujo un trazo similar (con un pincel caligráfico) en Illustrator, la forma resultante se simplificará a lo que vemos a continuación. Al dibujar el trazo, se verá muy similar al de mi aplicación. Una vez que suelte el botón del mouse, la curva se simplificará a lo que vemos aquí:
Como podemos ver, el trazo solo tiene 14 puntos de datos. Aunque hay puntos de control adicionales que definen la inclinación de la spline bezier (o cualquier spline que estén usando). Aquí podemos ver algunos de esos puntos de control:
He observado algoritmos como el algoritmo de Ramer-Douglas-Peucker , pero parece que solo eliminan puntos del conjunto de entrada. Si no me equivoco, el enfoque que estoy buscando también tendría que introducir nuevos puntos en el conjunto para lograr la curva deseada.
Me he encontrado con preguntas como el algoritmo de dibujo de bocetos suave de iPhone que parecen estar relacionados Pero esos parecen centrarse en crear una curva suave a partir de un pequeño conjunto de puntos de entrada. Siento que tengo el caso opuesto.
Encontré la pregunta Alisando una curva dibujada a mano (de la que esta pregunta podría ser una trampa), que tiene una respuesta que propone utilizar Ramer-Douglas-Peucker y luego aplicar el ajuste de curvas según el here .
Una rápida adaptación del código de ejemplo proporcionado a mis métodos de dibujo da como resultado la siguiente curva:
Los datos de entrada de la pregunta se han reducido a 28 puntos (que se dibujan utilizando splines Bezier).
No estoy seguro de qué enfoque utiliza exactamente Adobe, pero este me sirve extremadamente bien hasta ahora.
Adaptación
Entonces, el código proporcionado por Kris está escrito para WPF y hace algunas suposiciones al respecto. Para trabajar en mi caso (y porque no quería ajustar su código), escribí el siguiente fragmento de código:
private List<Point> OptimizeCurve( List<Point> curve ) {
const float tolerance = 1.5f;
const double error = 100.0;
// Remember the first point in the series.
Point startPoint = curve.First();
// Simplify the input curve.
List<Point> simplified = Douglas.DouglasPeuckerReduction( curve, tolerance ).ToList();
// Create a new curve from the simplified one.
List<System.Windows.Point> fitted = FitCurves.FitCurve( simplified.Select( p => new System.Windows.Point( p.X, p.Y ) ).ToArray(), error );
// Convert the points back to our desired type.
List<Point> fittedPoints = fitted.Select( p => new Point( (int)p.X, (int)p.Y ) ).ToList();
// Add back our first point.
fittedPoints.Insert( 0, startPoint );
return fittedPoints;
}
La lista resultante estará en el formato Punto de inicio , Punto de control 1 , Punto de control 2 , Punto final .