tutorial que ejemplos custom control c# wpf xaml wpf-controls

c# - que - Cambiar el sistema de coordenadas de un lienzo en WPF



wpf c# tutorial (8)

Estoy bastante seguro de que no puedes hacer eso exactamente, pero sería bastante trivial tener un método que se traduzca de latitud / longitud a coordenadas de Lienzo.

Point ToCanvas(double lat, double lon) { double x = ((lon * myCanvas.ActualWidth) / 360.0) - 180.0; double y = ((lat * myCanvas.ActualHeight) / 180.0) - 90.0; return new Point(x,y); }

(O algo por el estilo)

Estoy escribiendo una aplicación de mapas que usa un lienzo para posicionar elementos. Para cada elemento, tengo que convertir programáticamente Lat / Long del elemento a la coordenada canvas, luego establezco las propiedades Canvas.Top y Canvas.Left.

Si tuviera un lienzo de 360x180, ¿puedo convertir las coordenadas en el lienzo para ir de -180 a 180 en lugar de 0 a 360 en el eje X y de 90 a -90 en lugar de 0 a 180 en el eje Y?

Requisitos de escala:

  • El lienzo puede ser de cualquier tamaño, por lo que debería funcionar si es 360x180 o 5000x100.
  • El área Lat / Long puede no ser siempre (-90, -180) x (90,180), podría ser cualquier cosa (es decir, (5, -175) x (89, -174)).
  • Elementos como PathGeometry que son base de punto, en lugar de base de Canvas.Top/Left necesitan funcionar.

Pude lograrlo creando mi propio lienzo personalizado y anulando la función ArrangeOverride de la siguiente manera:

public class CustomCanvas : Canvas { protected override Size ArrangeOverride(Size arrangeSize) { foreach (UIElement child in InternalChildren) { double left = Canvas.GetLeft(child); double top = Canvas.GetTop(child); Point canvasPoint = ToCanvas(top, left); child.Arrange(new Rect(canvasPoint, child.DesiredSize)); } return arrangeSize; } Point ToCanvas(double lat, double lon) { double x = this.Width / 360; x *= (lon - -180); double y = this.Height / 180; y *= -(lat + -90); return new Point(x, y); } }

Lo cual funciona para mi problema descrito, pero probablemente no funcionaría para otra necesidad que tengo, que es una PathGeometry. No funcionaría porque los puntos no están definidos como Superior e Izquierda, sino como puntos reales.


Supongo que otra opción sería extender el lienzo y anular la medida / disposición para que se comporte de la manera que desee.


Aquí hay una solución completamente XAML. Bueno, principalmente XAML, porque tienes que tener el IValueConverter en el código. Entonces: cree un nuevo proyecto WPF y agregue una clase a él. La clase es MultiplyConverter:

namespace YourProject { public class MultiplyConverter : System.Windows.Data.IValueConverter { public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { return AsDouble(value)* AsDouble(parameter); } double AsDouble(object value) { var valueText = value as string; if (valueText != null) return double.Parse(valueText); else return (double)value; } public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new System.NotSupportedException(); } } }

Luego usa este XAML para tu ventana. Ahora debería ver los resultados en la ventana de vista previa de XAML.

EDITAR : Puede solucionar el problema de fondo colocando su lienzo dentro de otro lienzo. Es un poco raro, pero funciona. Además, he agregado una ScaleTransform que voltea el eje Y para que Y positiva esté arriba y negativa. Observe cuidadosamente qué Nombres van donde:

<Canvas Name="canvas" Background="Moccasin"> <Canvas Name="innerCanvas"> <Canvas.RenderTransform> <TransformGroup> <TranslateTransform x:Name="translate"> <TranslateTransform.X> <Binding ElementName="canvas" Path="ActualWidth" Converter="{StaticResource multiplyConverter}" ConverterParameter="0.5" /> </TranslateTransform.X> <TranslateTransform.Y> <Binding ElementName="canvas" Path="ActualHeight" Converter="{StaticResource multiplyConverter}" ConverterParameter="0.5" /> </TranslateTransform.Y> </TranslateTransform> <ScaleTransform ScaleX="1" ScaleY="-1" CenterX="{Binding ElementName=translate,Path=X}" CenterY="{Binding ElementName=translate,Path=Y}" /> </TransformGroup> </Canvas.RenderTransform> <Rectangle Canvas.Top="-50" Canvas.Left="-50" Height="100" Width="200" Fill="Blue" /> <Rectangle Canvas.Top="0" Canvas.Left="0" Height="200" Width="100" Fill="Green" /> <Rectangle Canvas.Top="-25" Canvas.Left="-25" Height="50" Width="50" Fill="HotPink" /> </Canvas> </Canvas>

En cuanto a sus nuevos requisitos de que necesita varios rangos, un ValueConverter más complejo probablemente sea el truco.


Puede usar transform para traducir entre los sistemas de coordenadas, tal vez un TransformGroup con un TranslateTranform para mover (0,0) al centro del lienzo y un ScaleTransform para obtener las coordenadas al rango correcto.

Con el enlace de datos y tal vez un convertidor de valor o dos, puede hacer que las transformaciones se actualicen automáticamente en función del tamaño del lienzo.

La ventaja de esto es que funcionará para cualquier elemento (incluido PathGeometry), una posible desventaja es que escalará todo y no solo los puntos, por lo que cambiará el tamaño de los iconos y el texto en el mapa.


Otra posible solución:

Incruste un lienzo personalizado (el lienzo para dibujar) en otro lienzo (el lienzo de fondo) y configure el lienzo para dibujar para que sea transparente y no se recorte a los límites. Transforme el lienzo de dibujar con una matriz que hace y flip (M22 = -1) y traduce / escala el lienzo dentro del lienzo principal para ver la extensión del mundo que está mirando.

En efecto, si dibuja en -115, 42 en el lienzo de atracción, el elemento que está dibujando está "desactivado" en el lienzo, pero se muestra de todos modos porque el lienzo no está recortando los límites. A continuación, transforma el lienzo de dibujar para que el punto aparezca en el lugar correcto en el lienzo de fondo.

Esto es algo que intentaré pronto. Espero eso ayude.



Aquí hay una respuesta que describe un método de extensión de Canvas que le permite aplicar un sistema de coordenadas cartesianas. Es decir:

canvas.SetCoordinateSystem(-10, 10, -10, 10)

configurará el sistema de coordenadas del canvas modo que x vaya de -10 a 10 y vaya de -10 a 10.