Select to view content in your preferred language

Need Help for Generating a Fan-shaped Buffer

1275
2
02-07-2011 11:13 PM
YuguangZhang
New Contributor
I want to create a fan-shaped buffer using a point with a given orientation and a radius r, just like this:



I've come up with an idea already, but it's quite complicate and I'm wondering if there are any better ways to do it.

My idea is to do the following steps:



1. use point p and radius r to generate a circle buffer. (I drew r wrong in the fig. it should be the radius of the circle. poor drawing. I know..)

2. draw a triangle of which the vertex is p and the perpendicular is pointing in my desired direction.

3. do an intersect operation between the circle and the triangle.

The problem is that I really don't have a clue about how to generate the triangle I want. How should  make the angle P = 2?? ?

Really appreciated if some one could help me with this with some demo codes in C++/C#.:D
0 Kudos
2 Replies
BrianBottoms
Emerging Contributor
Here is one possible solution.  I thought it was an interesting question so I gave it a try.  I tested it a few times to see if it would work, BUT I'm not totally sure I've thought through the azimuth vs. degrees thing.  All it does is create 3 lines (2 straight and 1 curved) and uses them to create a polygon.  I know you asked for C# - it shouldn't be too hard to convert since most of it is standard stuff.  I tested it in UTM zone10, feet.


Option Strict On
Imports ESRI.ArcGIS.DataSourcesGDB
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS


Module Module1
    Const dbPath As String = "C:\temp\TestFan.gdb"
    Const LayerName As String = "Fans"

    Sub Main()
        Try
            'Get license
            ESRI.ArcGIS.RuntimeManager.BindLicense(ESRI.ArcGIS.ProductCode.EngineOrDesktop)

            'Get target featureclass for polygon creation
            Dim WorkspaceFactory As IWorkspaceFactory = New ESRI.ArcGIS.DataSourcesGDB.FileGDBWorkspaceFactory
            Dim Workspace As IFeatureWorkspace = CType(WorkspaceFactory.OpenFromFile(dbPath, 0), IFeatureWorkspace)
            Dim pFc As IFeatureClass
            pFc = Workspace.OpenFeatureClass(LayerName)
            Dim pGeoDataset As IGeoDataset = CType(pFc, IGeoDataset)
            Dim pSpatRef As ISpatialReference = pGeoDataset.SpatialReference

            Dim pPoly As IPolygon = CreateWedgePoly(pSpatRef, 2000, 40, 30, 1778291, 16892929)

            'Create a new feature in the target layer
            Dim pF As IFeature = pFc.CreateFeature
            pF.Shape = pPoly
            pF.Store()
        Catch ex As Exception
            Debug.Print(ex.Message)

        End Try
       

    End Sub
    Private Function CreateWedgePoly(ByVal pSpatRef As ISpatialReference, ByVal radius As Double, _
                                     ByVal FanOrientation As Double, ByVal degreesOpen As Double, _
                                     ByVal originX As Double, ByVal OriginY As Double) As IPolygon
        ' radius
        ' FanOrientation - azimuth from origin through curved segment apex.
        ' degreesOpen - total span in degrees
        ' originX - Origin point x (utm feet for test)
        ' originY - Origin point y (utm feet for test)

        'Create origin point
        Dim ptOrigin As IPoint = New Point
        ptOrigin.PutCoords(originX, originY)

        'Create first point along circle
        Dim pt1 As IPoint = New Point
        Dim az As Double = 90 - (FanOrientation - (degreesOpen / 2))
        pt1.X = radius * Math.Cos(az * Math.PI / 180.0F) + originX
        pt1.Y = radius * Math.Sin(az * Math.PI / 180.0F) + OriginY

        'Create second point along circle
        Dim pt2 As IPoint = New Point
        az = 90 - (FanOrientation + (degreesOpen / 2))
        pt2.X = radius * Math.Cos(az * Math.PI / 180.0F) + originX
        pt2.Y = radius * Math.Sin(az * Math.PI / 180.0F) + OriginY

        'Create first straight leg.
        Dim pPolyline1 As IPolyline5 = New Polyline
        pPolyline1.SpatialReference = pSpatRef
        pPolyline1.FromPoint = ptOrigin
        pPolyline1.ToPoint = pt1
        pPolyline1.SimplifyEx(True)

        'Create second straight leg
        Dim pPolyline2 As IPolyline5 = New Polyline
        pPolyline2.SpatialReference = pSpatRef
        pPolyline2.FromPoint = ptOrigin
        pPolyline2.ToPoint = pt2
        pPolyline2.SimplifyEx(True)

        'Create curved leg and QI/Densify to polyline
        Dim cirArc As ICircularArc = New CircularArc
        cirArc.SpatialReference = pSpatRef
        cirArc.PutCoords(ptOrigin, pt1, pt2, esriArcOrientation.esriArcClockwise)

        Dim path1 As ESRI.ArcGIS.Geometry.ISegmentCollection
        path1 = New ESRI.ArcGIS.Geometry.Path
        path1.AddSegment(CType(cirArc, ISegment))

        Dim pSegPoly As ESRI.ArcGIS.Geometry.IPolyline
        pSegPoly = New ESRI.ArcGIS.Geometry.Polyline
        Dim pGeoColl As ESRI.ArcGIS.Geometry.IGeometryCollection
        pGeoColl = CType(pSegPoly, IGeometryCollection)
        pGeoColl.AddGeometry(CType(path1, IGeometry))

        Dim pPolyline3 As IPolyline5 = New Polyline
        pPolyline3 = CType(pGeoColl, IPolyline5)
        pPolyline3.Densify(-1, 0)
        pPolyline3.SimplifyEx(True)

        'Union 2 straight and 1 curved leg.
        Dim pTempPolyline As ITopologicalOperator = CType(pPolyline1, ITopologicalOperator)
        pTempPolyline = CType(pTempPolyline.Union(pPolyline2), ITopologicalOperator)
        pTempPolyline = CType(pTempPolyline.Union(pPolyline3), ITopologicalOperator)

        'Create polygon and add to feataure class.
        Dim pPolygonpointcoll As IPointCollection
        Dim pPolygon As IPolygon = New Polygon
        pPolygonpointcoll = New Polygon
        pPolygonpointcoll.AddPointCollection(CType(pTempPolyline, IPointCollection))
        pPolygon = CType(pPolygonpointcoll, IPolygon) 'QI
        pPolygon.Close()
        Return ppolygon
    End Function
End Module
0 Kudos
YuguangZhang
New Contributor
Thanks Brian!!

Wonderful idea of using the supplementary angle. I love it. I did a few tests and it run faster than mine. 😄

Here're the codes in C#, just in case someone needs them:

-------- using ESRI.ArcGIS.Geometry;
            using ESRI.ArcGIS.Display;
            using ESRI.ArcGIS.Carto;

-------- creating a fan in c#

            double radius = 400;
            double fanOrientation = 0;
            double degreesOpen = 60;

            //point origin
            //para e: ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseDownEvent
            IPoint ptOrigin = new PointClass();
            ptOrigin.PutCoords(e.mapX, e.mapY);

            //first and second point along the circle
            IPoint pt1 = new PointClass();
            double az = 90 - (fanOrientation - (degreesOpen / 2));
            pt1.X = radius * Math.Cos(az * Math.PI / 180.0F) + e.mapX;
            pt1.Y = radius * Math.Sin(az * Math.PI / 180.0F) + e.mapY;

            IPoint pt2 = new PointClass();
            az = 90 - (fanOrientation + (degreesOpen / 2));
            pt2.X = radius * Math.Cos(az * Math.PI / 180.0F) + e.mapX;
            pt2.Y = radius * Math.Sin(az * Math.PI / 180.0F) + e.mapY;

            //first and second straight leg
            IPolyline pPolyline1 = new PolylineClass();
            pPolyline1.FromPoint = ptOrigin;
            pPolyline1.ToPoint = pt1;
            pPolyline1.SimplifyNetwork();

            IPolyline pPolyline2 = new PolylineClass();
            pPolyline2.FromPoint = ptOrigin;
            pPolyline2.ToPoint = pt2;
            pPolyline2.SimplifyNetwork();

            //circular arc & QI/densify
            ICircularArc pCirArc = new CircularArcClass();
            pCirArc.PutCoords(ptOrigin, pt1, pt2, esriArcOrientation.esriArcClockwise);

            object missing = Type.Missing;
            ISegmentCollection path1 = new PathClass();
            path1.AddSegment(pCirArc as ISegment, ref missing, ref missing);

            IPolyline pSegPoly = new PolylineClass();
            IGeometryCollection pGeoColl = pSegPoly as IGeometryCollection;
            pGeoColl.AddGeometry(path1 as IGeometry, ref missing, ref missing);

            IPolyline pPolyline3 = pGeoColl as IPolyline;
            pPolyline3.Densify(-1, 0);
            pPolyline3.SimplifyNetwork();

            //union 3 legs
            ITopologicalOperator pTemgPolyline = pPolyline1 as ITopologicalOperator;
            pTemgPolyline = pTemgPolyline.Union(pPolyline2) as ITopologicalOperator;
            pTemgPolyline = pTemgPolyline.Union(pPolyline3) as ITopologicalOperator;

            //create polygon
            IPointCollection pPolygonPointColl;
            IPolygon pPolygon = new PolygonClass();
            pPolygonPointColl = new PolygonClass();
            pPolygonPointColl.AddPointCollection(pTemgPolyline as IPointCollection);
            pPolygon = pPolygonPointColl as IPolygon;
            pPolygon.Close();

            //drawing test
            ISimpleFillSymbol pFillSymbol = new SimpleFillSymbolClass();
            pFillSymbol.Color = getRGB(200, 255, 200); //method getRGB(int r, int g, int b)
            pFillSymbol.Style = esriSimpleFillStyle.esriSFSSolid;
            object o = pFillSymbol as object;
            axMapControl1.DrawShape(pPolygon, ref o);

--------
           private IColor getRGB(int r, int g, int b)
           {
               IRgbColor rgbcolor = new RgbColorClass();
               rgbcolor.Red = r;
               rgbcolor.Green = g;
               rgbcolor.Blue = b;

               IColor color = rgbcolor as IColor;
               return color;
           }
0 Kudos