Perimeter of a hatch using ObjectARX and AutoCAD .Net API

By Balaji Ramamoorthy

A hatch entity in AutoCAD stores its geometry information in its “loops”. Traversing the loops of a hatch can help in computing its perimeter by accessing the geometry. Also, based on whether a loop is an “internal” or an “external” one, the perimeter of the islands can be separately computed if required. Here is a sample code that computes the perimeter of a hatch entity using ObjectARX and the AutoCAD .Net API. Error checking has been kept limted to improve readability of the code.

// Perimeter calculation of a hatch using ObjectARX
static void ADS_HatchTest(void)
{
    ads_name en;
    ads_point pt;
    if( acedEntSel(
                    ACRX_T("nSelect a hatch :"), 
                    en, 
                    pt
                   ) != RTNORM ) 
    {
        return;
    }
 
    AcDbObjectId entId = AcDbObjectId::kNull;
    Acad::ErrorStatus es;
    es = acdbGetObjectId(entId, en); 
    if(es != Acad::eOk) 
          return; 
 
    HatchPerimeter(entId);
}
 
static void HatchPerimeter(AcDbObjectId entId)
{
    Acad::ErrorStatus es;
    AcDbEntity *pEnt;
    es = acdbOpenAcDbEntity(
                            pEnt, 
                            entId, 
                            AcDb::kForRead
                           ); 
    if( es != Acad::eOk )
        return;
 
    if( pEnt->isA() != AcDbHatch::desc() ) 
    {
        acutPrintf(ACRX_T("n Please select a hatch."));
        pEnt->close(); 
        return; 
    }
 
    AcDbHatch* pHatch = AcDbHatch::cast(pEnt);
 
    int nLoops = pHatch->numLoops();  
    double totalExternalPerimeter =0.0;  
    double totalInternalPerimeter =0.0;
 
    for(int i=0; i < nLoops; i++) 
    {   
        double loopLength = 0.0;
        long loopType; 
 
        if( pHatch->loopTypeAt( i ) 
          & AcDbHatch::kPolyline )
        {     
            AcGePoint2dArray vertices;      
            AcGeDoubleArray bulges;      
            pHatch->getLoopAt( 
                                i, 
                                loopType, 
                                vertices, 
                                bulges 
                             );    
            int nVertices = vertices.length(); 
 
            AcDbPolyline testPoly(nVertices);   
 
            for( int vx=0; vx < nVertices; vx++) 
            {
                double bulge = 0.0;
                if(bulges.length() < nVertices)
                  bulge = 0.0;
                else
                  bulge = bulges[vx];  
                testPoly.addVertexAt( 
                                        vx, 
                                        vertices[vx],
                                        bulge 
                                    ); 
            }   
 
            AcGeLineSeg3d ls;
            AcGeCircArc3d as;
            double d = 0.0, p1 = 0.0, p2 = 1.0;
 
            for(int ver = 0; ver < nVertices; ver++)
            {
                es = testPoly.getBulgeAt( i, d );
                if( es != Acad::eOk ) 
                    break;
 
                if( d getLoopAt(i, loopType,edgePtrs, edgeTypes );  
            AcGeCompositeCurve2d compCurve( edgePtrs );  
 
            AcGeInterval interval;    
            compCurve.getInterval( interval ); 
 
            loopLength 
                = compCurve.length(
                                    interval.lowerBound(), 
                                    interval.upperBound()
                                  );
        }   
 
        if( nLoops > 1 && !(loopType & AcDbHatch::kExternal ))     
            totalInternalPerimeter += loopLength;
        else
            totalExternalPerimeter += loopLength;
    }  
 
    acutPrintf(
                ACRX_T("nExternal Perimeter : %lf"),
                totalExternalPerimeter 
              );
 
    acutPrintf(
                ACRX_T("nInternal Perimeter : %lf"), 
                totalInternalPerimeter 
              );
 
    pEnt->close();
}
 
 
 
// Perimeter calculation of a hatch using AutoCAD.Net API
[CommandMethod("HatchTest")]
public void HatchTestMethod()
{
    Document activeDoc 
            = Application.DocumentManager.MdiActiveDocument;
    Editor ed = activeDoc.Editor;
 
    PromptEntityOptions peo 
        = new PromptEntityOptions("Select a hatch : ");
 
    peo.SetRejectMessage("nPlease select a hatch");
    peo.AddAllowedClass(typeof(Hatch), true);
 
    PromptEntityResult per = ed.GetEntity(peo);
    if (per.Status != PromptStatus.OK)
        return;
 
    HatchPerimeter(per.ObjectId);
}
 
 
void HatchPerimeter(ObjectId entId)
{
    Document activeDoc = Application.DocumentManager.MdiActiveDocument;
    Database db = activeDoc.Database;
    Editor ed = activeDoc.Editor;
 
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        Hatch hatch = tr.GetObject(entId, OpenMode.ForRead) as Hatch;
        int nLoops = hatch.NumberOfLoops; 
 
        double totalExternalPerimeter =0.0; 
        double totalInternalPerimeter =0.0;
 
        for(int i=0; i < nLoops; i++) 
        {
            double loopLength = 0.0;
            HatchLoopTypes hlt = hatch.LoopTypeAt(i);
            HatchLoop hatchLoop = hatch.GetLoopAt(i);
 
            if ((hatch.LoopTypeAt(i) & HatchLoopTypes.Polyline)
                                    == HatchLoopTypes.Polyline)
            { 
                BulgeVertexCollection bulges 
                                            = hatchLoop.Polyline;
 
                int nVertices = bulges.Count; 
                Polyline testPoly = new Polyline(nVertices); 
 
                for(int vx = 0; vx < bulges.Count; vx++) 
                {
                    BulgeVertex bv = bulges[vx];
                    testPoly.AddVertexAt(
                                            vx, 
                                            bv.Vertex, 
                                            bv.Bulge, 
                                            1.0, 
                                            1.0
                                        );
                } 
 
                LineSegment3d ls = new LineSegment3d();
                CircularArc3d cs = new CircularArc3d();
                double d = 0.0, p1 = 0.0, p2 = 1.0;
 
                for(int ver = 0; ver < nVertices-1; ver++)
                {
                    d = testPoly.GetBulgeAt(ver);
                    if( d  1 && 
                    ((hlt & HatchLoopTypes.External) != HatchLoopTypes.External)) 
            {
                totalInternalPerimeter += loopLength;
            }
            else
            {
                totalExternalPerimeter += loopLength;
            }
        } 
 
        ed.WriteMessage(
                            string.Format
                            (
                                "nExternal Perimeter : {0}",
                                totalExternalPerimeter
                            )
                       );
 
        ed.WriteMessage(
                            string.Format
                            (
                                "nInternal Perimeter : {0}",
                                totalInternalPerimeter
                            )
                       );
        tr.Commit();
    }
}

Comments

One response to “Perimeter of a hatch using ObjectARX and AutoCAD .Net API”

  1. Hi Balaji!
    My colleague found a bug in your’s code. As far as bulge can be < 0.0 then instead of:
    if( d <= 1e-5 )
    have to be in ObjectARX:
    if( fabs(d) <= 1e-5 )
    and in .NET:
    if( Math.Abs(d) <= 1e-5)
    Discussion: http://adn-cis.org/forum/index.php?topic=6078.msg18136#msg18136

Leave a Reply to Alexander RivlisCancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading