ThinkGeo.com    |     Documentation    |     Premium Support

Draw curve/arc

 Hello,


I am part of a land administration project in wich we have to develop a tool to help cartographers easily modify different parcels on a map. Most of parcels have a simple polygon shape, but sometimes cartographers need to draw a curved line or arc (especially when dealing with buildings). I managed to extend TrackInteractiveOverlay and EditInteractiveOverlay to allow users to draw an arc by setting three points (this is similar to the arc functionality in AutoCAD). They can also modify the arc by modifying those three points. I used the DrawArc() function of the System.Drawing.Graphics class in .NET. However, this arc needs to be connected with another geometry which usually will be a polygon and thus resulting in a "curved polygon". This kind of geometries can be stored in spatial databases (at leaast in postgre with postgis and MS SQL 2008 R2) by using their WKT, but as I searched through the discussion forum, MapSuite doesn't support this geometries because it relies on the WKB and even ellipse and circle shape will be automatically converted to a polygon shape (when converted to a feature).


Actually the posts that I read were old and I wanted to ask if the newer versions of MapSuite support these geometries (we are using version 4.5) and if they don't, it would be really nice if you could help and advice me on how to make the created curved line to be part of a polygon which then can be inserted into DB.


Thanks in advance!


Arber


 



 Arber,


Thanks for your question.


You can look at another post gis.thinkgeo.com/Support/Dis...fault.aspx which included sample for your requirement, however it used WpfDesktopEdition which has the similar API with DesktopEdition.


If you encoutern any trouble please let me know.


Thanks,


James



Hello James, 
  
 Thank you for your reply. 
  
 Actually I was based on that post to draw the arc. I would be really interested in seeing implemented what is suggested in the last reply of that post (to have a CurvedLineStyle inheriting from LineStyle) and my main concern is how will these features be stored in DB. I think they will be stored as points in the actual case or lines if we inherit from LineStyle and if this is the case how can I detect if the line should be drawn as a normal line or as an arc. 
  
 Regards, 
  
 Arber

 Arber,



 Instead of a custom Style, I think you need to create a Custom CurvedLineShape which can Save To / Load from a PostGre WKT.  Here is a simple example how to do it by creating a new shape from BaseShape.  Just call LoadFromCustomWellKnownData to load the special WKT from database, and call GetCustomWellKnownText() and save it.  It should work for you.




// The CurvedLineShape Class
    class CurvedLineShape : BaseShape
    {
        private PointShape centerPoint;
        private PointShape startPoint;
        private double angle;

        public CurvedLineShape()
            : this(new PointShape(0, 0), new PointShape(0, 0), 0)
        { }

        public CurvedLineShape(PointShape centerPoint, PointShape startPoint, int angle)
        {
            this.centerPoint = centerPoint;
            this.startPoint = startPoint;
            this.angle = angle;
        }

        public CurvedLineShape(string wellKnownText)
        {
            if (wellKnownText == null || !wellKnownText.StartsWith("CurvedLineShape"))
            {
                throw new ArgumentException("The wellKnownText is not supported");
            }

            LoadFromCustomWellKnownData(wellKnownText);
        }

        protected override string GetWellKnownTextCore()
        {
            LineShape line = new LineShape();
            line.Vertices.Add(new Vertex(startPoint));

            double radius = Math.Sqrt(Math.Pow(startPoint.X - centerPoint.X, 2) + Math.Pow(startPoint.Y - centerPoint.Y, 2));
            double startAngle = Math.Asin(startPoint.Y / radius);

            for (int i = 1; i <= angle; i++)
            {
                double x = Math.Cos(Math.PI / 180 * i + startAngle) * radius + centerPoint.X;
                double y = Math.Sin(Math.PI / 180 * i + startAngle) * radius + centerPoint.Y;

                line.Vertices.Add(new Vertex(x, y));
            }

            return line.GetWellKnownText();
        }

        public string GetCustomWellKnownText()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("CurvedLineShape(");
            sb.Append(centerPoint.X + " " + centerPoint.Y);
            sb.Append(",");
            sb.Append(startPoint.X + " " + startPoint.Y);
            sb.Append(",");
            sb.Append(angle);
            sb.Append(")");

            return sb.ToString();
        }

        public void LoadFromCustomWellKnownData(string wellKnownText)
        {
            string wkt = wellKnownText.Replace("CurvedLineShape(", "");
            wkt = wkt.Remove(wkt.Length - 1);
            string[] wkts = wkt.Split(',');

            string[] data = wkts[0].Split(' ');
            this.centerPoint = new PointShape(Double.Parse(data[0]), Double.Parse(data[1]));

            data = wkts[1].Split(' ');
            this.startPoint = new PointShape(Double.Parse(data[0]), Double.Parse(data[1]));

            this.angle = Double.Parse(wkts[2]);
        }

        protected override void LoadFromWellKnownDataCore(string wellKnownText)
        {
        }
    }

        // The references. 
        private void WpfMap_Loaded(object sender, RoutedEventArgs e)
        {
            InMemoryFeatureLayer inm = new InMemoryFeatureLayer();
            inm.InternalFeatures.Add(new CurvedLineShape("CurvedLineShape(0 0,10 10, 90)").GetFeature());
            inm.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.Canal1;
            inm.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

            LayerOverlay overlay = new LayerOverlay();
            overlay.Layers.Add(inm);
            Map1.MapUnit = GeographyUnit.DecimalDegree;
            Map1.CurrentExtent = new RectangleShape(-155.733, 95.60, 104.42, -81.9);
            Map1.Overlays.Add(overlay);
            Map1.Refresh();
        }

Here is what looks like:



Thanks,


Bai