diff --git a/SqlServerSpatial.Toolkit/Viewers/GDI/SpatialViewer_GDI.cs b/SqlServerSpatial.Toolkit/Viewers/GDI/SpatialViewer_GDI.cs index a0d2d29..7221523 100644 --- a/SqlServerSpatial.Toolkit/Viewers/GDI/SpatialViewer_GDI.cs +++ b/SqlServerSpatial.Toolkit/Viewers/GDI/SpatialViewer_GDI.cs @@ -24,7 +24,8 @@ namespace SqlServerSpatial.Toolkit.Viewers Dictionary> _fills; Matrix _mouseTranslate; Matrix _mouseScale; - Matrix _prevMatrix; + Matrix _previousMatrix; + Vector _unitVectorAtGeometryScale; bool _readyToDraw = false; public bool AutoViewPort { get; set; } @@ -61,7 +62,7 @@ protected override void Dispose(bool disposing) DisposeGraphicsPaths(); _mouseTranslate.Dispose(); _mouseScale.Dispose(); - if (_prevMatrix != null) _prevMatrix.Dispose(); + if (_previousMatrix != null) _previousMatrix.Dispose(); this.MouseWheel -= SpatialViewer_GDI_MouseWheel; if (disposing && (components != null)) @@ -99,7 +100,7 @@ private void DisposeGraphicsPaths() #endregion - + protected override void OnPaint(PaintEventArgs pe) { @@ -190,9 +191,9 @@ public void SetGeometry(IEnumerable geometries) Matrix GenerateGeometryTransformViewMatrix() { - if (AutoViewPort == false && _prevMatrix != null) + if (AutoViewPort == false && _previousMatrix != null) { - return _prevMatrix.Clone(); + return _previousMatrix.Clone(); } else { @@ -201,28 +202,47 @@ Matrix GenerateGeometryTransformViewMatrix() Matrix m = new Matrix(); - m.Translate((float)-_geomBBox.XMin, (float)-_geomBBox.yMin); - - - m.Translate((float)-_geomBBox.Width / 2f, (float)-_geomBBox.Height / 2f); - + // Center matrix origin + m.Translate((float)(-_geomBBox.XMin - _geomBBox.Width / 2d), (float)(-_geomBBox.yMin - _geomBBox.Height / 2d)); - double scale = Math.Min(width / _geomBBox.Width - , height / _geomBBox.Height); + // Scale and invert Y as Y raises downwards + double scale = Math.Min(width / _geomBBox.Width, height / _geomBBox.Height); m.Scale((float)scale, -(float)scale, MatrixOrder.Append); + // translate to map center BoundingBox bboxTrans = _geomBBox.Transform(m); - m.Translate((float)bboxTrans.Width / 2f, -(float)bboxTrans.Height / 2f, MatrixOrder.Append); + m.Translate(width / 2, -(float)bboxTrans.Height / 2f, MatrixOrder.Append); - if (_prevMatrix != null) + if (_previousMatrix != null) { - _prevMatrix.Dispose(); + _previousMatrix.Dispose(); } - _prevMatrix = m.Clone(); + _previousMatrix = m.Clone(); + CalculateUnitVector(m, width, height); return m; } } + void CalculateUnitVector(Matrix mat, float mapWidth, float mapHeight) + { + using (Matrix matrix = mat.Clone()) + { + if (matrix.IsInvertible) + { + matrix.Invert(); + double width = mapWidth, height = mapHeight; + double scale = Math.Min(width / _geomBBox.Width + , height / _geomBBox.Height); + PointF vector1px = new PointF((float)(1d / scale), 0); + _unitVectorAtGeometryScale = new Vector(vector1px.X, vector1px.Y); + } + else + { + _unitVectorAtGeometryScale = new Vector(1, 1); + } + } + } + private void Internal_SetGeometry(IEnumerable geometries) { try @@ -255,12 +275,12 @@ private void Internal_SetGeometry(IEnumerable geometries) if (geometry.STIsValid().IsFalse) geometry = geometry.MakeValid(); - + // Envelope of Union of envelopes => global BBox envelope = envelope.STUnion(geometry.STEnvelope()).STEnvelope(); GraphicsPath stroke = new GraphicsPath(); GraphicsPath fill = new GraphicsPath(); - SqlGeometryGDISink.ConvertSqlGeometry(geometry, ref stroke, ref fill); + SqlGeometryGDISink.ConvertSqlGeometry(geometry, _unitVectorAtGeometryScale, ref stroke, ref fill); AppendFilledPath(geomStyled.Style, fill); AppendStrokePath(geomStyled.Style, stroke); @@ -339,7 +359,7 @@ internal void ResetView(bool fullReset) { if (fullReset) { - _prevMatrix = null; + _previousMatrix = null; _mouseTranslate = new Matrix(); _mouseScale = new Matrix(); _currentFactorMouseWheel = 1f; diff --git a/SqlServerSpatial.Toolkit/Viewers/GDI/SqlGeometryGDISink.cs b/SqlServerSpatial.Toolkit/Viewers/GDI/SqlGeometryGDISink.cs index 14cb478..b5f0a40 100644 --- a/SqlServerSpatial.Toolkit/Viewers/GDI/SqlGeometryGDISink.cs +++ b/SqlServerSpatial.Toolkit/Viewers/GDI/SqlGeometryGDISink.cs @@ -4,29 +4,50 @@ using System.Drawing.Drawing2D; using System.Linq; using System.Text; +using System.Windows; using Microsoft.SqlServer.Types; namespace SqlServerSpatial.Toolkit.Viewers { + /// + /// Sinks that fills two graphics paths : one for the filled geometries and one other for the outlines + /// internal class SqlGeometryGDISink : IGeometrySink110 { GraphicsPath _gpStroke; GraphicsPath _gpFill; List _currentLine; + Vector _unitVector; - private SqlGeometryGDISink(GraphicsPath gpStroke, GraphicsPath gpFill) + public static void ConvertSqlGeometry(SqlGeometry geom, Vector unitVector, ref GraphicsPath stroke, ref GraphicsPath fill) + { + SqlGeometryGDISink sink = new SqlGeometryGDISink(stroke, fill, unitVector); + geom.Populate(sink); + } + + private SqlGeometryGDISink(GraphicsPath gpStroke, GraphicsPath gpFill, Vector unitVector) { _gpStroke = gpStroke; _gpFill = gpFill; _currentLine = new List(); + _unitVector = unitVector; } public void BeginFigure(double x, double y, double? z, double? m) { - _gpStroke.StartFigure(); + if (_curType == OpenGisGeometryType.Point) + { + // for a point, we draw an ellipse with the provider unit vector + _gpFill.AddEllipse((float)x, (float)y, (float)(_unitVector.Length * 2d), (float)(_unitVector.Length * 2d)); + _gpStroke.AddEllipse((float)x, (float)y, (float)(_unitVector.Length * 2d), (float)(_unitVector.Length * 2d)); + } + else + { + _gpStroke.StartFigure(); - _currentLine.Clear(); - _currentLine.Add(new PointF((float)x, (float)y)); + _currentLine.Clear(); + _currentLine.Add(new PointF((float)x, (float)y)); + } } public void AddLine(double x, double y, double? z, double? m) { @@ -34,14 +55,17 @@ public void AddLine(double x, double y, double? z, double? m) } public void EndFigure() { - _gpStroke.CloseFigure(); + if (_curType != OpenGisGeometryType.Point) + { + _gpStroke.CloseFigure(); - PointF[] coords = _currentLine.ToArray(); - _gpStroke.AddLines(coords); + PointF[] coords = _currentLine.ToArray(); + _gpStroke.AddLines(coords); - if (_curType == OpenGisGeometryType.Polygon) - { - _gpFill.AddPolygon(coords); + if (_curType == OpenGisGeometryType.Polygon) + { + _gpFill.AddPolygon(coords); + } } } @@ -49,7 +73,6 @@ public void EndFigure() public void BeginGeometry(OpenGisGeometryType type) { _curType = type; - } public void EndGeometry() @@ -61,15 +84,10 @@ public void SetSrid(int srid) } - public static void ConvertSqlGeometry(SqlGeometry geom, ref GraphicsPath stroke, ref GraphicsPath fill) + + public void AddCircularArc(double x1, double y1, double? z1, double? m1, double x2, double y2, double? z2, double? m2) { - SqlGeometryGDISink sink = new SqlGeometryGDISink(stroke, fill); - geom.Populate(sink); + throw new NotImplementedException(); } - - public void AddCircularArc(double x1, double y1, double? z1, double? m1, double x2, double y2, double? z2, double? m2) - { - throw new NotImplementedException(); - } - } + } }