Polygons with arcs do not have the correct area

8927
33
Jump to solution
01-08-2016 08:59 AM
DonnyVelazquez
Occasional Contributor

It appears there's a bug in the fgdapi when inserting polygons with arcs. It doesn't calculate the area correctly. It only calculates the straight sides and does not include the area the arc is creating. Once you run it through repair geometry, it fixes the calculation.

Anyone else run across this? Vince Angelo

0 Kudos
33 Replies
DonnyVelazquez
Occasional Contributor

I'v already sent ESRI support a code sample. Just waiting to see what they find.

I'll update this thread when I find out.

0 Kudos
VinceAngelo
Esri Esteemed Contributor

Tech Support generally doesn't support the File Geodatabase API.  This GeoNet place is the closest thing available to a support mechanism.  The people who maintain the FGDBAPI monitor this place, so if you want timely response, I would suggest you post the code here.

- V

DonnyVelazquez
Occasional Contributor

So I finally got a chance to get back to this problem.

Code that creates 1 feature with an arc in it. When you look at that feature in ArcMap it doesn't have the correct area or length.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Esri.FileGDB;
using System.IO;


namespace GeoDBTest
{
    class Program
    {


        static void Main(string[] args)
        {
            CPoint[] arrPoints = {
                               new CPoint(280216.393,336991.323),
                               new CPoint(280218.563,336609.378),
                               new CPoint(280116.567,336609.378),
                               new CPoint(280116.567,336993.493),
                               new CPoint(280216.393,336991.323)
                           };


            // arc lies between point 1 & 2
            CArc arc = new CArc(new CPoint(280116.567, 336993.493), new CPoint(280116.567, 336609.378), new CPoint(279953.806, 336801.436));


            Geodatabase geodatabase = null;
            string geoPath = "geoTest.gdb";


            geodatabase = OpenGeoDB(geoPath);
            Table tblTestArea = null;


            if(geodatabase != null)
            {
                ClearTable(geodatabase);
                tblTestArea = OpenGDBTable(geodatabase);
                if(tblTestArea != null)
                {
                    int iMultipart = 1, iPoints = 5, iArcs = 1;


                    uint iSize = (uint)(4 * sizeof(int) + iMultipart * sizeof(int) + 4 * sizeof(double) + (2 * sizeof(double) * iPoints) + ((sizeof(int) * 3 + sizeof(double) * 2) * iArcs));
                    int offset = 0;
                    Byte[] shapeBuffer = new Byte[iSize];




                    // type
                    int type = (int)Esri.FileGDB.ShapeType.GeneralPolyline;


                    type = 536870963; //Byte 29,28 ON and Byte 0 is 51 


                    Buffer.BlockCopy(BitConverter.GetBytes(type), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);


                    // Extent


                    // 280116.567   336609.378
                    // 280220.013   336607.577
                    // minimum X
                    Buffer.BlockCopy(BitConverter.GetBytes(arc.pMidPoint.dX), 0, shapeBuffer, offset, sizeof(double));
                    offset += sizeof(double);


                    // minimum Y
                    Buffer.BlockCopy(BitConverter.GetBytes(arrPoints[2].dY), 0, shapeBuffer, offset, sizeof(double));
                    offset += sizeof(double);


                    // 280218.563   336991.323
                    // 279945.499   336995.913
                    // maximum X
                    Buffer.BlockCopy(BitConverter.GetBytes(arrPoints[0].dX), 0, shapeBuffer, offset, sizeof(double));
                    offset += sizeof(double);


                    // maximum Y
                    Buffer.BlockCopy(BitConverter.GetBytes(arrPoints[0].dY), 0, shapeBuffer, offset, sizeof(double));
                    offset += sizeof(double);


                    // number of parts
                    Buffer.BlockCopy(BitConverter.GetBytes(iMultipart), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);
                    
                    // number of points
                    Buffer.BlockCopy(BitConverter.GetBytes(iPoints), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);


                    // load number of parts
                    Buffer.BlockCopy(BitConverter.GetBytes(0), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);
                    


                    // Load all points
                    for (int pt = 0; pt < arrPoints.Count(); pt++)
                    {
                        Buffer.BlockCopy(BitConverter.GetBytes(arrPoints[pt].dX), 0, shapeBuffer, offset, sizeof(double));
                        offset += sizeof(double);
                        Buffer.BlockCopy(BitConverter.GetBytes(arrPoints[pt].dY), 0, shapeBuffer, offset, sizeof(double));
                        offset += sizeof(double);
                    }


                    // number of Arcs
                    int numCurves = 1;
                    Buffer.BlockCopy(BitConverter.GetBytes(numCurves), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);




                    // Load  ARC


                    //segment point index - arc is starting from point 2
                    Buffer.BlockCopy(BitConverter.GetBytes(2), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);


                    //segment type 1- circular arc
                    Buffer.BlockCopy(BitConverter.GetBytes(1), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);


                    // ESRI expecting the center point of the 2 cord not the center of the circle (curve)
                    CPoint arcMidPoint = arc.pMidPoint;


                    // Center point
                    Buffer.BlockCopy(BitConverter.GetBytes(arcMidPoint.dX), 0, shapeBuffer, offset, sizeof(double));
                    offset += sizeof(double);


                    Buffer.BlockCopy(BitConverter.GetBytes(arcMidPoint.dY), 0, shapeBuffer, offset, sizeof(double));
                    offset += sizeof(double);


                    // It doesn't matter it calculates the arc based on the mid point
                    int minor = 16;


                    int bits = 256 | 128 | 0 | 0 | minor | 0 | 4 | 2 | 0;
                    // copy bits
                    Buffer.BlockCopy(BitConverter.GetBytes(bits), 0, shapeBuffer, offset, sizeof(int));
                    offset += sizeof(int);


                    // Loading to the Geo Table


                    Row polyRow = tblTestArea.CreateRowObject();
                    ShapeBuffer polylinesGeometry = new ShapeBuffer(iSize);
                    polylinesGeometry.Allocate(iSize);
                    polylinesGeometry.shapeBuffer = shapeBuffer;
                    polylinesGeometry.inUseLength = iSize;
                    //MultiPartShapeBuffer multiGeometry = polylinesGeometry;
                    polyRow.SetGeometry(polylinesGeometry);


                    tblTestArea.Insert(polyRow);


                    tblTestArea.Close();
                    tblTestArea.Dispose();


                    geodatabase.Close();
                    geodatabase.Dispose();
                }


            }


        }




        static Geodatabase OpenGeoDB(string geoDbPath)
        {
            Geodatabase geodb = null;
            try
            {
                try
                {
                    geodb = Geodatabase.Open(geoDbPath);
                }
                catch (Exception ex)
                {
                    //ignore if file is not present
                }
                try
                {
                    if (geodb == null)
                    {
                        geodb = Geodatabase.Create(geoDbPath);
      
                    }
                }
                catch (Exception ex)
                {
                }
            }
            finally
            {


            }


            return geodb;
        }




        static Table OpenGDBTable(Geodatabase geodatabase)
        {
            Table geodbTbl = null;
            string catPath = "";
            string tblName = "";
            string templatePath = @"PARCELS_TEMPLATE.xml";
            try
            {

                string featureClassDef = "";
                using (StreamReader sr = new StreamReader(templatePath))
                {
                    while (sr.Peek() >= 0)
                    {
                        featureClassDef += sr.ReadLine() + "\n";
                    }
                    sr.Close();
                }
                catPath = @"/FD=CAD2GIS/FC=" + "AreaTest";
                tblName = "AreaTest";


                featureClassDef = featureClassDef.Replace("_CATLOGPATH_", catPath);
                featureClassDef = featureClassDef.Replace("_TABLENAME_", tblName);
    
                geodbTbl = geodatabase.CreateTable(featureClassDef, "");


            }
            catch (Exception ex)
            {
            }
            finally
            {

            }


            return geodbTbl;
        }




        static Table ClearTable(Geodatabase geodatabase)
        {
            string tblName = "";
            Table tblData = null;


            tblName = "AreaTest";
            try
            {
                geodatabase.Delete(tblName, "Table");
            }
            catch (Exception ex)
            {
            }
            finally
            {
            }
            return tblData;
        }






    } // end class


    class CPoint
    {
        public double dX;
        public double dY;


        public CPoint(double x, double y)
        {
            dX = x;
            dY = y;
        }
    }


    class CArc
    {
        public CPoint pStartPoint;
        public CPoint pEndPoint;
        public CPoint pMidPoint;


        public CArc(CPoint SPoint, CPoint EPoint, CPoint MPoint)
        {
            pStartPoint = new CPoint(SPoint.dX, SPoint.dY);
            pEndPoint = new CPoint(EPoint.dX, EPoint.dY);
            pMidPoint = new CPoint(MPoint.dX, MPoint.dY);


        }
    }
}
VinceAngelo
Esri Esteemed Contributor

Please include your code in the post, as not everyone would be willing to download a zipfile from some other location (as part of computer security policy, I won't even download zipfiles from GeoNet)

- V

0 Kudos
DonnyVelazquez
Occasional Contributor

Code is posted.

0 Kudos
LanceShipman
Esri Regular Contributor

Area calculation in the file geodatabase API does not include curves in the calculation. We will consider it in a later release.

DonnyVelazquez
Occasional Contributor

Yes I think people would want a feature that properly calculates the area in a gis library.

0 Kudos
VinceAngelo
Esri Esteemed Contributor

The work-around is to populate vertices in the shape buffer which approximate the curve, instead of relying on ArcGIS to use CAD curves to hide the blocky shapes which are being populated in the shape buffer (which are used to calculate area via Simpson's Rule, as stated back in January).

- V

0 Kudos
DonnyVelazquez
Occasional Contributor

I guess this is never getting fixed?

0 Kudos
LanceShipman
Esri Regular Contributor

Also, what version of the API are you using? The current version is 1.4.

0 Kudos