Skip to content

Commit

Permalink
Point geometry OK. Used resource bitmap to render. Issue #8
Browse files Browse the repository at this point in the history
  • Loading branch information
xfischer committed Nov 13, 2015
1 parent 178130d commit 20cdf04
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 42 deletions.
46 changes: 46 additions & 0 deletions SqlServerSpatial.Toolkit.Test/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,50 @@ static void Main(string[] args)

//TestTrace();
TestCentroid();
TestVariousGeometries();
}

private static void TestVariousGeometries()
{
SqlGeometry simplePoint = SqlGeometry.Point(1, 47, 4326);
SqlGeometry multiPoint = SqlGeometry.Parse(new SqlString("MULTIPOINT((1 47),(1 46),(0 46),(0 47),(1 47))")); multiPoint.STSrid = 4326;
SqlGeometry lineString = SqlGeometry.Parse(new SqlString("LINESTRING(1 47,1 46,0 46,0 47,1 47)")); lineString.STSrid = 4326;
SqlGeometry multiLineString = SqlGeometry.Parse(new SqlString("MULTILINESTRING((0.516357421875 47.6415668949958,0.516357421875 47.34463879017405,0.977783203125 47.22539733216678,1.175537109375 47.463611506072866,0.516357421875 47.6415668949958),(0.764923095703125 47.86549372980948,0.951690673828125 47.82309640371982,1.220855712890625 47.79911736820551,1.089019775390625 47.69015026565801,1.256561279296875 47.656860648589))"));
multiLineString.STSrid = 4326;
SqlGeometry simplePoly = SqlGeometry.Parse(new SqlString("POLYGON((1 47,1 46,0 46,0 47,1 47))")); simplePoly.STSrid = 4326;
SqlGeometry polyWithHole = SqlGeometry.Parse(new SqlString(@"
POLYGON(
(0.516357421875 47.6415668949958,0.516357421875 47.34463879017405,0.977783203125 47.22539733216678,1.175537109375 47.463611506072866,0.516357421875 47.6415668949958),
(0.630340576171875 47.54944962456812,0.630340576171875 47.49380564962583,0.729217529296875 47.482669772098674,0.731964111328125 47.53276262898896,0.630340576171875 47.54944962456812)
)")); polyWithHole.STSrid = 4326;
SqlGeometry multiPolygon = SqlGeometry.Parse(new SqlString(@"
MULTIPOLYGON (
((40 40, 20 45, 45 30, 40 40)),
((20 35, 45 20, 30 5, 10 10, 10 30, 20 35), (30 20, 20 25, 20 15, 30 20)),
((0.516357421875 47.6415668949958,0.516357421875 47.34463879017405,0.977783203125 47.22539733216678,1.175537109375 47.463611506072866,0.516357421875 47.6415668949958),(0.630340576171875 47.54944962456812,0.630340576171875 47.49380564962583,0.729217529296875 47.482669772098674,0.731964111328125 47.53276262898896,0.630340576171875 47.54944962456812))
)")); multiPolygon.STSrid = 4326;

SqlGeometry geomCol = SqlGeometry.Parse(new SqlString(@"
GEOMETRYCOLLECTION (
POLYGON((0.516357421875 47.6415668949958,0.516357421875 47.34463879017405,0.977783203125 47.22539733216678,1.175537109375 47.463611506072866,0.516357421875 47.6415668949958),(0.630340576171875 47.54944962456812,0.630340576171875 47.49380564962583,0.729217529296875 47.482669772098674,0.731964111328125 47.53276262898896,0.630340576171875 47.54944962456812)),
LINESTRING(0.764923095703125 47.86549372980948,0.951690673828125 47.82309640371982,1.220855712890625 47.79911736820551,1.089019775390625 47.69015026565801,1.256561279296875 47.656860648589),
POINT(0.767669677734375 47.817563762851776)
)")); geomCol.STSrid = 4326;

SpatialTrace.Enable();
SpatialTrace.SetFillColor(Color.FromArgb(128, 0, 0, 255)); // Fill with blue
SpatialTrace.TraceGeometry(simplePoint,"simplePoint");
SpatialTrace.SetFillColor(Color.FromArgb(128, 255, 0, 0)); // Fill with red
SpatialTrace.TraceGeometry(multiPoint, "multiPoint");
SpatialTrace.ResetStyle();
SpatialTrace.TraceGeometry(lineString, "lineString");
SpatialTrace.TraceGeometry(multiLineString, "multiLineString");
SpatialTrace.TraceGeometry(simplePoly, "simplePoly");
SpatialTrace.TraceGeometry(polyWithHole, "polyWithHole");
SpatialTrace.TraceGeometry(multiPolygon, "multiPolygon");
SpatialTrace.TraceGeometry(geomCol, "geomCol");
SpatialTrace.ShowDialog();
SpatialTrace.Clear();
}

private static void TestTrace()
Expand Down Expand Up @@ -48,6 +92,7 @@ private static void TestTrace()
SpatialTrace.Unindent();
SpatialTrace.Unindent();
SpatialTrace.ShowDialog();
SpatialTrace.Clear();
}

static void TestCentroid()
Expand All @@ -59,6 +104,7 @@ static void TestCentroid()
SpatialTrace.SetFillColor(Colors.Red);
SpatialTrace.TraceGeometry(centroid, "Centroid");
SpatialTrace.ShowDialog();
SpatialTrace.Clear();
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion SqlServerSpatial.Toolkit/Extensions/ColorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static System.Windows.Media.Color ToWpf(this System.Drawing.Color gdiColo
/// </summary>
/// <param name="gdiColor"></param>
/// <returns></returns>
public static System.Drawing.Color ToWpf(this System.Windows.Media.Color gdiColor)
public static System.Drawing.Color ToGDI(this System.Windows.Media.Color gdiColor)
{
return System.Drawing.Color.FromArgb(gdiColor.A, gdiColor.R, gdiColor.G, gdiColor.B);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="SqlServerTypes\readme.htm" />
<EmbeddedResource Include="Viewers\GDI\point.png" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
139 changes: 109 additions & 30 deletions SqlServerSpatial.Toolkit/Viewers/GDI/SpatialViewer_GDI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Forms;
Expand All @@ -19,17 +22,26 @@ namespace SqlServerSpatial.Toolkit.Viewers
/// </summary>
public partial class SpatialViewer_GDI : Control, ISpatialViewer, IDisposable //, IMessageFilter // for mousewheel
{
// geometry bounding box
BoundingBox _geomBBox;
Dictionary<GeometryStyle, List<GraphicsPath>> _strokes;
Dictionary<GeometryStyle, List<GraphicsPath>> _fills;

bool _readyToDraw = false;

// Viewport variables
float _currentFactorMouseWheel = 1f;
float _scale = 1f;
float _scaleX = 1f;
float _scaleY = 1f;
Matrix _mouseTranslate;
Matrix _mouseScale;
Matrix _previousMatrix;
Vector _unitVectorAtGeometryScale;
bool _readyToDraw = false;
public bool AutoViewPort { get; set; }

float _currentFactorMouseWheel = 1f;
// GDI+ geometries
Dictionary<GeometryStyle, List<GraphicsPath>> _strokes;
Dictionary<GeometryStyle, List<GraphicsPath>> _fills;
Dictionary<GeometryStyle, List<PointF>> _points;
Bitmap _pointBmp;

public SpatialViewer_GDI()
{
Expand All @@ -38,12 +50,20 @@ public SpatialViewer_GDI()
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
_strokes = new Dictionary<GeometryStyle, List<GraphicsPath>>();
_fills = new Dictionary<GeometryStyle, List<GraphicsPath>>();
_points = new Dictionary<GeometryStyle, List<PointF>>();

_mouseTranslate = new Matrix();
_mouseScale = new Matrix();
//System.Windows.Forms.Application.AddMessageFilter(this);
System.Windows.Forms.Application.AddMessageFilter(new MouseWheelMessageFilter());
this.MouseWheel += SpatialViewer_GDI_MouseWheel;

// Load point icon
Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
using (Stream file = assembly.GetManifestResourceStream("SqlServerSpatial.Toolkit.Viewers.GDI.point.png"))
{
_pointBmp = (Bitmap)Image.FromStream(file);
}
}

#region Dispose and Finalize
Expand All @@ -59,6 +79,10 @@ public SpatialViewer_GDI()
protected override void Dispose(bool disposing)
{
//clean up unmanaged here

if (_pointBmp != null)
_pointBmp.Dispose();

DisposeGraphicsPaths();
_mouseTranslate.Dispose();
_mouseScale.Dispose();
Expand Down Expand Up @@ -121,6 +145,7 @@ protected override void OnPaint(PaintEventArgs pe)
}
pe.Graphics.SmoothingMode = SmoothingMode.HighQuality;

// Shapes
foreach (var kvpFill in _fills)
{
using (Brush fillBrush = FromGeomStyleToBrush(kvpFill.Key))
Expand All @@ -135,6 +160,7 @@ protected override void OnPaint(PaintEventArgs pe)
}
}
}
// Outlines
foreach (var kvpStroke in _strokes)
{
using (Pen strokePen = FromGeomStyleToPen(kvpStroke.Key))
Expand All @@ -149,6 +175,23 @@ protected override void OnPaint(PaintEventArgs pe)
}
}
}

// Points
foreach (var kvpPoint in _points)
{
using (Bitmap bmp = FromGeomStyleToPoint(_pointBmp, kvpPoint.Key))
{
PointF[] points = kvpPoint.Value.ToArray();
if (points.Any())
{
mat.TransformPoints(points);
foreach (PointF point in points)
{
pe.Graphics.DrawImageUnscaled(bmp, (int)point.X - _pointBmp.Width / 2, (int)point.Y - _pointBmp.Height / 2);
}
}
}
}
}

sw.Stop();
Expand All @@ -157,6 +200,8 @@ protected override void OnPaint(PaintEventArgs pe)
}
}



#region GDI Helpers
private Pen FromGeomStyleToPen(GeometryStyle geometryStyle)
{
Expand All @@ -168,6 +213,10 @@ private Brush FromGeomStyleToBrush(GeometryStyle geometryStyle)
System.Windows.Media.Color c = geometryStyle.FillColor;
return new SolidBrush(Color.FromArgb(c.A, c.R, c.G, c.B));
}
private Bitmap FromGeomStyleToPoint(Bitmap sourceBitmap, GeometryStyle geometryStyle)
{
return TintBitmap(sourceBitmap, geometryStyle.FillColor.ToGDI(), 1f);
}
private void AppendStrokePath(GeometryStyle style, GraphicsPath stroke)
{
if (_strokes.ContainsKey(style) == false)
Expand All @@ -182,6 +231,43 @@ private void AppendFilledPath(GeometryStyle style, GraphicsPath path)

_fills[style].Add(path);
}
private void AppendPoints(GeometryStyle style, List<PointF> points)
{
if (_points.ContainsKey(style) == false)
_points[style] = new List<PointF>();

_points[style].AddRange(points);
}
/// <summary>
/// Tints a bitmap using the specified color and intensity.
/// </summary>
/// <param name="bitmap">Bitmap to be tinted</param>
/// <param name="color">Color to use for tint</param>
/// <param name="intensity">Intensity of the tint. Good ranges are .25 to .75, depending on your preference. Most images will white out around 2.0. 0 will not tint the image at all</param>
/// <returns>A bitmap with the requested Tint</returns>
/// <remarks>http://stackoverflow.com/questions/9356694/tint-property-when-drawing-image-with-vb-net</remarks>
Bitmap TintBitmap(Bitmap bitmap, Color color, float intensity)
{
Bitmap outBmp = new Bitmap(bitmap.Width, bitmap.Height, bitmap.PixelFormat);

using (ImageAttributes ia = new ImageAttributes())
{

ColorMatrix m = new ColorMatrix(new float[][]
{new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {color.R/255*intensity, color.G/255*intensity, color.B/255*intensity, 0, 1}});

ia.SetColorMatrix(m);
using (Graphics g = Graphics.FromImage(outBmp))
g.DrawImage(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, ia);
}

return outBmp;
}

#endregion

public void SetGeometry(IEnumerable<SqlGeometryStyled> geometries)
Expand All @@ -197,17 +283,20 @@ Matrix GenerateGeometryTransformViewMatrix()
}
else
{
float width = this.ClientRectangle.Width;
float height = this.ClientRectangle.Height;
int margin = 20;
float width = this.ClientRectangle.Width - margin;
float height = this.ClientRectangle.Height - margin;

Matrix m = new Matrix();

// Center matrix origin
m.Translate((float)(-_geomBBox.XMin - _geomBBox.Width / 2d), (float)(-_geomBBox.yMin - _geomBBox.Height / 2d));

// 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);
_scaleX = (float)(width / _geomBBox.Width);
_scaleY = (float)(height / _geomBBox.Height);
_scale = (float)Math.Min(_scaleX, _scaleY);
m.Scale(_scale, -_scale, MatrixOrder.Append);

// translate to map center
BoundingBox bboxTrans = _geomBBox.Transform(m);
Expand All @@ -218,30 +307,16 @@ Matrix GenerateGeometryTransformViewMatrix()
_previousMatrix.Dispose();
}
_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);
}
}
}
//void CalculateUnitVector()
//{
// // geom units * scale = pixels
// // To get in units what is a pixel, we do W * scale = 1 => W = 1 / scale;
// _unitVectorAtGeometryScale = new Vector(1d / (_currentFactorMouseWheel * _scaleX) * 2, 1d / (_currentFactorMouseWheel * _scaleY) * 2);
//}

private void Internal_SetGeometry(IEnumerable<SqlGeometryStyled> geometries)
{
Expand All @@ -266,6 +341,7 @@ private void Internal_SetGeometry(IEnumerable<SqlGeometryStyled> geometries)
{
System.Windows.Forms.MessageBox.Show("Some geometries are not valid. Will try to valid them.", "Invalid geometry", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}

foreach (SqlGeometryStyled geomStyled in geometries)
{

Expand All @@ -280,9 +356,11 @@ private void Internal_SetGeometry(IEnumerable<SqlGeometryStyled> geometries)
envelope = envelope.STUnion(geometry.STEnvelope()).STEnvelope();

GraphicsPath stroke = new GraphicsPath(); GraphicsPath fill = new GraphicsPath();
SqlGeometryGDISink.ConvertSqlGeometry(geometry, _unitVectorAtGeometryScale, ref stroke, ref fill);
List<PointF> points = new List<PointF>();
SqlGeometryGDISink.ConvertSqlGeometry(geometry, ref stroke, ref fill, ref points);
AppendFilledPath(geomStyled.Style, fill);
AppendStrokePath(geomStyled.Style, stroke);
AppendPoints(geomStyled.Style, points);

}
#region BBox
Expand Down Expand Up @@ -343,6 +421,7 @@ private void ClearGDI()
DisposeGraphicsPaths();
_strokes = new Dictionary<GeometryStyle, List<GraphicsPath>>();
_fills = new Dictionary<GeometryStyle, List<GraphicsPath>>();
_points = new Dictionary<GeometryStyle, List<PointF>>();

}
public void Clear()
Expand Down
14 changes: 6 additions & 8 deletions SqlServerSpatial.Toolkit/Viewers/GDI/SqlGeometryGDISink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,27 @@ internal class SqlGeometryGDISink : IGeometrySink110
GraphicsPath _gpStroke;
GraphicsPath _gpFill;
List<PointF> _currentLine;
Vector _unitVector;
List<PointF> _points;

public static void ConvertSqlGeometry(SqlGeometry geom, Vector unitVector, ref GraphicsPath stroke, ref GraphicsPath fill)
public static void ConvertSqlGeometry(SqlGeometry geom, ref GraphicsPath stroke, ref GraphicsPath fill, ref List<PointF> points)
{
SqlGeometryGDISink sink = new SqlGeometryGDISink(stroke, fill, unitVector);
SqlGeometryGDISink sink = new SqlGeometryGDISink(stroke, fill, points);
geom.Populate(sink);
}

private SqlGeometryGDISink(GraphicsPath gpStroke, GraphicsPath gpFill, Vector unitVector)
private SqlGeometryGDISink(GraphicsPath gpStroke, GraphicsPath gpFill, List<PointF> points)
{
_gpStroke = gpStroke;
_gpFill = gpFill;
_currentLine = new List<PointF>();
_unitVector = unitVector;
_points = points;
}

public void BeginFigure(double x, double y, double? z, double? m)
{
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));
_points.Add(new PointF((float)x, (float)y));
}
else
{
Expand Down
Binary file added SqlServerSpatial.Toolkit/Viewers/GDI/point.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 20cdf04

Please sign in to comment.