2009-04-07 13 views
21

Estamos utilizando wpf para desarrollar una aplicación tipo cad donde los dibujos se colocan en el lienzo utilizando el objeto Path. Me encontré con un pequeño problema que cuando escalo/zoom mi lienzo, todos los elementos en el lienzo se escalan y este es el comportamiento que quería, pero esto también aumenta el grosor del trazo de la ruta.Espesor de trazo invariable de Trayectoria independientemente de la escala

¿Hay alguna manera de aumentar/escalar/acercar los objetos pero aún así mantener el mismo grosor de trazo de la ruta.

Cualquier ayuda en este sentido será muy útil para mí.

Respuesta

6

Finalmente recibí la solución para la solución anterior. Lo hice estableciendo el StrokeThickness del Path relativo a la escala del Canvas.

De esta manera:

// scale = scaling factor applied to the canvas 
path.StrokeThickness = 1.0/scale; 

esto sólo funciona si ScaleX y ScaleY son uniformes.

+13

Esto está bien si sus escalas xey son uniformes, pero no funciona si las escalas no son las mismas. – Klay

13

Una mejor solución sería utilizar uno o más objetos System.Windows.Media.Geometry para almacenar sus caminos, puntos, etc.

Esta geometría se puede dibujar con una pluma, por lo que de hecho podría cambiar el trazo grosor al hacer zoom, pero más flexible es usar la propiedad Transformar.

Utilizando la transformación, puede "acercar" las coordenadas reales de la representación geométrica y no la visualización, de modo que cuando la dibuje, no tenga que manipular las transformaciones de representación.

Para calcular la transformada, utilizo el siguiente código como:

public static Matrix TransformShape(Rect fromPosition, Rect toPosition, bool flipVertical) { 
    Matrix translateThenScale = Matrix.Identity; 
    //we first translate to origin since that's just easier 
    translateThenScale.Translate(-fromPosition.X, -fromPosition.Y); 
    //now we scale the graph to the appropriate dimensions 
    translateThenScale.Scale(toPosition.Width/fromPosition.Width, toPosition.Height/fromPosition.Height); 
    //then we flip the graph vertically around the viewport middle since in our graph positive is up, not down. 
    if (flipVertical) 
     translateThenScale.ScaleAt(1.0, -1.0, 0.0, toPosition.Height/2.0); 
    //now we push the graph to the right spot, which will usually simply be 0,0. 
    translateThenScale.Translate(toPosition.X, toPosition.Y); 

    return translateThenScale; 
} 

donde el fromPosition Rect debe contener los límites no transformadas, y la toPosition Rect debe contener los límites transformadas. Esto también permite trivialmente escalar X e Y por separado, lo que a menudo es necesario para trazar.

Es fácil de calcular los límites de la geometría:

Geometry graphGeom; 
//[...] 
//the bounds are modified by the transform, so we want no transform!  
graphGeom.Transform = Transform.Identity; 
Rect graphBounds = graphGeom.Bounds; 
//then set the transform again 

//or, if the transform is axis-aligned, the following _should_ work: 
Rect graphBoundsAlt = graphGeom.Transform.Inverse.TransformBounds(graphGeom.Bounds); 

Y, por supuesto WPF se puede decir que limita lo que necesita para hacer entrar, si ello fuera necesario. Juntando todo, usted podría hacer algo como

public void RecomputeTransform(Rect targetRect, bool flipVertical) { 
    graphGeom.Transform = Transform.Identity; 
    Rect graphBounds = graphGeom.Bounds; 
    Matrix transMat = TransformShape(graphBounds,targetRect,flipVertical); 
    graphGeom.Transform = new MatrixTransform(transMat); 
} 

La ventaja de utilizar esta solución es que no es necesario meterse con RenderTransforms, usted es libre de utilizar transformaciones que X cizalla y/o la escala e Y de forma independiente sin obtener distorsiones extrañas en sus líneas, y puede tratar el Pen como un objeto opaco (es decir, más fácil de personalizar desde la UI; si selecciona el ancho del Pen o lo que sea, no es necesario realizar más correcciones).

+0

Supongo que el uso de esta solución requeriría que las partes del dibujo que no desea escalar estén separadas del lienzo principal que puede escalar. El ejemplo sería una aplicación de dibujo vectorial en la que el dibujo se escala, pero las imágenes visuales del punto de anclaje y tal escala de posición, pero no tan lejos como su espesor y tal. ¿Estoy en lo correcto en esta suposición? – jpierson

+0

Lo siento, no entiendo muy bien * su pregunta ... De hecho, esto es algo que haría en un escenario de dibujo vectorial en el que le interesan las líneas o los puntos idealizados y no su grosor. Este enfoque escalará (o transformará linealmente de otra manera) un dibujo lineal sin transformar los anchos de línea. Es decir, estás transformando la geometría idealizada y solo * luego * convirtiéndola en la forma "real" que por supuesto tiene líneas de ancho distinto de cero. Si tuvieras que transformar el 'Dibujo', también estarías transformando detalles como line withs y line joins, etc. ¿Eso lo aclara? –

+0

Creo que sí, mi suposición era que la aplicación de dibujo tendría algunas partes que escalarían todo, como los dibujos y algunas partes que son más como decoradores que no se escalan en términos de grosor, sino que se ubican en relación con el dibujo a escala. Tales como las aplicaciones de dibujo vectorial como Inkscape donde las líneas de dibujo se escalan en términos de grosor, pero los puntos de anclaje que se muestran para el objeto seleccionado no se escalan de la misma manera. Así que mi suposición es lograr esto en .NET aún necesitaría tener estas partes en dos paneles disjuntos que se escalan de forma independiente. – jpierson

0

He estado aquí varias veces, pero esta idea se me acaba de ocurrir, ¿qué le parece si la envolviera en una Viewbox?

Puede probar esto: jugar con la altura/ancho no debe cambiar la relación de grosor a tamaño. Tal vez haga otras cosas malas que aún no he descubierto ...

<Viewbox Height="50" Width="50"> 
    <Path Stroke="Black" Fill="Black" StrokeThickness="0.8" Stretch="Uniform" 
       Data="M0,0 20,20" /> 
</Viewbox> 
Cuestiones relacionadas