tipos sistema representacion recta norte mapas longitud latitud google georreferenciación georeferenciación geograficas este ejemplo earth diedrico coordenadas c# wpf math 3d

c# - norte - representacion de la recta en el sistema diedrico



Proyección de un punto 3D a una coordenada de pantalla 2D (6)

Como las coordenadas de Windows son z en la pantalla (x cruz y), usaría algo como

screenY = viewPort.ActualHeight * (1 - screenY);

en lugar de

screenY = screenY * viewPort.ActualHeight;

para corregir screenY para acomodar Windows.

Alternativamente, puede usar OpenGL. Cuando establece el rango de ventana gráfica x / y / z, puede dejarlo en unidades "nativas" y dejar que OpenGL convierta a coordenadas de pantalla.

Editar: Dado que tu origen es el centro. lo intentaré

screenX = viewPort.ActualWidth * (screenX + 1.0) / 2.0 screenY = viewPort.ActualHeight * (1.0 - ((screenY + 1.0) / 2.0))

La pantalla + 1.0 se convierte de [-1.0, 1.0] a [0.0, 2.0]. En ese momento, se divide por 2.0 para obtener [0.0, 1.0] para la multiplicación. Para tener en cuenta Windows y ser volteado de cartesiano y, se convierte de [1.0, 0.0] (superior izquierdo a inferior izquierdo), a [0.0, 1.0] (superior a inferior) al restar la pantalla anterior de 1.0. Luego, puedes escalar a la Altura real.

Basado en la información del Capítulo 7 de Programación 3D para Windows (Charles Petzold) , he intentado escribir como función auxiliar que proyecta un Point3D a un Punto 2D estándar que contiene las coordenadas de pantalla correspondientes (x, y):

public Point Point3DToScreen2D(Point3D point3D,Viewport3D viewPort ) { double screenX = 0d, screenY = 0d; // Camera is defined in XAML as: // <Viewport3D.Camera> // <PerspectiveCamera Position="0,0,800" LookDirection="0,0,-1" /> // </Viewport3D.Camera> PerspectiveCamera cam = viewPort.Camera as PerspectiveCamera; // Translate input point using camera position double inputX = point3D.X - cam.Position.X; double inputY = point3D.Y - cam.Position.Y; double inputZ = point3D.Z - cam.Position.Z; double aspectRatio = viewPort.ActualWidth / viewPort.ActualHeight; // Apply projection to X and Y screenX = inputX / (-inputZ * Math.Tan(cam.FieldOfView / 2)); screenY = (inputY * aspectRatio) / (-inputZ * Math.Tan(cam.FieldOfView / 2)); // Convert to screen coordinates screenX = screenX * viewPort.ActualWidth; screenY = screenY * viewPort.ActualHeight; // Additional, currently unused, projection scaling factors /* double xScale = 1 / Math.Tan(Math.PI * cam.FieldOfView / 360); double yScale = aspectRatio * xScale; double zFar = cam.FarPlaneDistance; double zNear = cam.NearPlaneDistance; double zScale = zFar == Double.PositiveInfinity ? -1 : zFar / (zNear - zFar); double zOffset = zNear * zScale; */ return new Point(screenX, screenY); }

Sin embargo, al realizar la prueba, esta función devuelve coordenadas de pantalla incorrectas (verificadas al comparar las coordenadas del mouse 2D con una forma 3D simple). Debido a mi falta de experiencia en programación en 3D, estoy confundido sobre por qué.

La sección comentada del bloque contiene cálculos de escalado que pueden ser esenciales, sin embargo, no estoy seguro de cómo, y el libro continúa con MatrixCamera utilizando XAML. Inicialmente, solo quiero que funcione un cálculo básico, independientemente de cuán ineficiente sea en comparación con Matrices.

¿Alguien puede aconsejar qué se debe agregar o cambiar?


No veo una corrección por el hecho de que al dibujar usando la API de Windows, el origen está en la esquina superior izquierda de la pantalla. Estoy asumiendo que su sistema de coordenadas es

y | | +------x

Además, ¿su sistema de coordenadas asume el origen en el centro, según la pregunta de Scott, o está en la esquina inferior izquierda?

Pero, la API de pantalla de Windows es

+-------x | | | y

Necesitarías la transformación de coordenadas para pasar del clásico cartesiano a Windows.


screenX y screenY deberían ser calculados en relación con el centro de la pantalla ...


Creé y probé con éxito un método de trabajo al usar la biblioteca fuente 3Dpletil Codeplex.

El trabajo real se realiza en el método TryWorldToViewportTransform () de 3DUtils. Este método no funcionará sin él (ver el enlace de arriba).

También se encontró información muy útil en el artículo de Eric Sink: Auto-Zoom .

NÓTESE BIEN. Puede haber enfoques más confiables / eficientes, de ser así, agréguelos como respuesta. Mientras tanto, esto es lo suficientemente bueno para mis necesidades.

/// <summary> /// Takes a 3D point and returns the corresponding 2D point (X,Y) within the viewport. /// Requires the 3DUtils project available at http://www.codeplex.com/Wiki/View.aspx?ProjectName=3DTools /// </summary> /// <param name="point3D">A point in 3D space</param> /// <param name="viewPort">An instance of Viewport3D</param> /// <returns>The corresponding 2D point or null if it could not be calculated</returns> public Point? Point3DToScreen2D(Point3D point3D, Viewport3D viewPort) { bool bOK = false; // We need a Viewport3DVisual but we only have a Viewport3D. Viewport3DVisual vpv =VisualTreeHelper.GetParent(viewPort.Children[0]) as Viewport3DVisual; // Get the world to viewport transform matrix Matrix3D m = MathUtils.TryWorldToViewportTransform(vpv, out bOK); if (bOK) { // Transform the 3D point to 2D Point3D transformedPoint = m.Transform(point3D); Point screen2DPoint = new Point(transformedPoint.X, transformedPoint.Y); return new Nullable<Point>(screen2DPoint); } else { return null; } }


Esto no aborda el algoritmo en cuestión, pero puede ser útil para este tipo de preguntas (como yo lo hice).

En .NET 3.5 puede usar Visual3D.TransformToAncestor (Ancestro visual) . Lo utilizo para dibujar una malla en un lienzo sobre mi ventana 3D:

void CompositionTarget_Rendering(object sender, EventArgs e) { UpdateWireframe(); } void UpdateWireframe() { GeometryModel3D model = cube.Content as GeometryModel3D; canvas.Children.Clear(); if (model != null) { GeneralTransform3DTo2D transform = cube.TransformToAncestor(viewport); MeshGeometry3D geometry = model.Geometry as MeshGeometry3D; for (int i = 0; i < geometry.TriangleIndices.Count;) { Polygon p = new Polygon(); p.Stroke = Brushes.Blue; p.StrokeThickness = 0.25; p.Points.Add(transform.Transform(geometry.Positions[geometry.TriangleIndices[i++]])); p.Points.Add(transform.Transform(geometry.Positions[geometry.TriangleIndices[i++]])); p.Points.Add(transform.Transform(geometry.Positions[geometry.TriangleIndices[i++]])); canvas.Children.Add(p); } } }

Esto también toma en cuenta cualquier transformación en el modelo, etc.

Ver también: http://blogs.msdn.com/wpf3d/archive/2009/05/13/transforming-bounds.aspx


  1. No está claro lo que estás tratando de lograr con aspectRatio coeff. Si el punto está en el borde del campo de visión, entonces debe estar en el borde de la pantalla, pero si aspectRatio! = 1 no lo está. Intenta establecer aspectRatio = 1 y haz que la ventana sea cuadrada. ¿Las coordenadas siguen siendo incorrectas?

  2. ActualWidth y ActualHeight parecen ser realmente la mitad del tamaño de la ventana, por lo que screenX será [-ActualWidth; ActualWidth], pero no [0; ActualWidth]. ¿Es eso lo que quieres?