NP CAD Page | Articles | Russian | Download

Intersection of Entities
(from "Geometrical Calculations" of chapter 5 "ObjectARX (Ń++)",
book: "AutoCAD: Application Development, Tuning and Customization")

There is a function (intersectWith) that is often used in a very important geometrical calculation, that is entities intersection. AcGe-objects as well as objects derived from AcDbEntity class possess a method with such a name.
An example of programmatic calculation of two selectable entities intersection is given in listing 5.15.

Listing 5.15. Intersection of entities
// Based on:
// N.Poleshchuk, Chapter 05\Book09\acrxEntryPoint.cpp
// Based on book "AutoCAD: Application Development, Tuning and Customization"
// (BHV-Petersburg Publishing House, Russia, 2006)
// http://poleshchuk.spb.ru/cad/2006/Razr2006e.htm
//
// ----- ads_book09 symbol (do not rename)
static int ads_book09(void)
{
int es1, es2;
ads_name ent1, ent2;
ads_point pt1, pt2;
AcDbObjectId entId1, entId2;
AcDbEntity* pEnt1 = NULL;
AcDbEntity* pEnt2 = NULL;
AcGePoint3dArray points;
 
// First object selection by inquiry
es1 = acedEntSel("\nSpecify entity No. 1: ", ent1, pt1);
if (es1 != RTNORM)
{
acutPrintf("\nObject is not selected.");
return (RSRSLT);
}
 
// Calculation of ID to switch from ads_name to AcDbObjectId
es1 = acdbGetObjectId(entId1, ent1);
if (es1 != Acad::eOk)
{
acutPrintf("\nNo Id 1 ");
return (RSRSLT);
}
// Calculation of pointer to AcDbEntity
es1 = acdbOpenAcDbEntity(pEnt1, entId1, AcDb::kForRead);
if (es1 != Acad::eOk)
{
acutPrintf("\nObject 1 is not opened ");
return (RSRSLT);
}
// Highlighting first object
pEnt1->highlight();
 
// Second object selection by inquiry
label_select2:
es2 = acedEntSel("\nSpecify object No. 2: ", ent2, pt2);
if (es2 != RTNORM)
{
pEnt1->unhighlight(); // unhighlighting
pEnt1->close(); // we’ll close object 1
acutPrintf("\nObject is not selected. ");
return (RSRSLT);
}
// Calculation of ID to switch from ads_name to AcDbObjectId
es2 = acdbGetObjectId(entId2, ent2);
if (es2 != Acad::eOk)
{
pEnt1->unhighlight();
pEnt1->close(); // we’ll close object 1
acutPrintf("\nNo Id 2 ");
return (RSRSLT);
}
// Check for coincidence
if(entId2 == entId1)
{
acutPrintf(" Repeat selection: ");
goto label_select2;
}
 
// Calculation of pointer to AcDbEntity
es2 = acdbOpenAcDbEntity(pEnt2, entId2, AcDb::kForRead);
if (es2 != Acad::eOk)
{
pEnt1->unhighlight();
pEnt1->close(); // closing object 1
acutPrintf("\nObject 2 is not opened ");
return (RSRSLT);
}
 
// Highlighting second object
pEnt2->highlight();
 
// Printing selected objects
acutPrintf("\n"); // to a new line
pEnt1->list();
acutPrintf("\n");
pEnt2->list();
 
// Calculation of entities intersection points
es1 = pEnt2->intersectWith(pEnt1, AcDb::kOnBothOperands, points);
int len;
if ( (es1 != Acad::eOk) || ((len = points.length() ) == 0) )
acutPrintf("\nObjects do not intersect.");
else
{
acutPrintf("\nIntersection points:");
for (int i=0; i<len; ++i)
{
acutPrintf("\n%d: %.6f %.6f %.6f",
i+1, points[i].x, points[i].y, points[i].z);
}
}
 
// Unhighlighting
pEnt1->unhighlight();
pEnt2->unhighlight();
 
// Closing objects with memory release
pEnt1->close();
pEnt2->close();
 
// TODO: Replace the following line by your returned value if any
acedRetVoid () ;
return (RSRSLT) ;
}

Let's give some explanations to source text. To select entity in an interactive mode the acedEntSel function is used. This function is declared in acedads.h so:

int acedEntSel(const char * str, ads_name entres, ads_point ptres);

The first argument is a prompt text to be displayed and the second and the third arguments by reference return selection result (entity name and point for entity specification). Unlike entsel (LISP function) integer code is returned, not list. The normal return value is RTNORM.
The first one of specified entities is saved in ent1 variable having ads_name type which is one of the types for entity presentation in the ObjectARX programming system. To transform entity from a presentation to another one, appropriate functions are used.
For further work with the first selected object we should get its drawing base identificator, or ID (Object ID). Those identificators as well as entity names (ads_name) are not constant and in every new session they have different values.
Entity name ent1 is being transformed to identificator entId1 with the help of acdbGetObjectId function that is declared in dbmain.h so:

Acad::ErrorStatus acdbGetObjectId (AcDbObjectId& objId, const ads_name objName);

Computed entity ID is passed by reference through the first argument.
Next by entId1 with the help of acdbOpenAcDbEntity function one can by reference get value of pointer to entity as a member of AcDbEntity class and then access to entity properties and methods. The function is declared in dbmain.h file:

Acad::ErrorStatus acdbOpenAcDbEntity (AcDbEntity*& pEnt, AcDbObjectId id, AcDb::OpenMode mode, bool openErasedEntity = false);

The first argument of the acdbOpenAcDbEntity function is a countable pointer, the second one is an object ID, the third one is an access mode and the fourth one is a flag of accessing erased entities (by default erased entities are unavailable). So for the first object selected on screen we've got pEnt1 pointer that is already pointing to the object of AcDbEntity type.
With the help of pEnt1 pointer one can call a method for highlighting the specified entity. The highlight function is used for this purpose.
Next all that was mentioned above is applied in the program to the second object. Second object ID (entId2) is being calculated and afterwards pEnt2 is calculated too and the entity is being highlighted too (it is difficult to catch this because the program is being run very quickly and and at the end highlighting is canceled).
During the execution it is being verified if the same object is specified twice (in this case entId2 == entId1) and if yes then control is being passed to the label_select2 label, which is used to mark the second entity selection operation.
Later details concerning entities selected are output to the screen with the help of list function as if it were done by the LIST command.
After that we may go to immediate points calculation using for this purpose the intersectWith method (function) mentioned above. This function is virtual in the AcDbEntity class and it is declared so in the dbmain.h file:

virtual  Acad::ErrorStatus intersectWith (const AcDbEntity* pEnt, AcDb::Intersect intType, AcGePoint3dArray& points, int thisGsMarker = 0, int otherGsMarker = 0) const;

In this prototype (and there exists another overloaded declaration, with other arguments) the function accepts pointer to auxiliary AcDbEntity object as a first argument, flag of extension for one or both primitives as a second argument and reference to array of points belonging to AcGePoint3d type as a third argument. We do not use the fouth and the fifth arguments in an explicit way (the default values are sufficient).
In our example the main entity is the first one of the objects specified on screen and pEnt2 is a pointer to the secondary primitive to be passed to the function. Extension flag intType may receive the following values:

AcDb::kOnBothOperands - to extend no objects;
AcDb::kExtendThis - to extend only the main object;
AcDb::kExtendArg - to extend only the second object;
AcDb::kExtendBoth - to extend both objects.

In the example the "no extension" case is applied.
Results of intersection operation are returned through the points array. As all the STL arrays it "can" extend dynamically and number of the really written into it points can be got by a standard length function.
Next with the help of a loop the program sends coordinates of all the calculated intersection points to the text screen window (in the form of float numbers with six digits after decimal point). For extracting three coordinates from the points class members x, y and z are used.
At the program end highlighting entities is disabled and they are closed for access. Sample results of a LISP function book09 for the case of intersection between a spline and a line is shown in listing 5.16.

Listing 5.16. Sample results of the function book09 execution

SPLINE Layer: "0"
Space: Model space
Handle = 2f
Length: 1244.8908
Order: 4
Properties: Planar, Non-Rational, Non-Periodic
Parametric Range: Start 0.0000
End 1186.5631
Number of control points: 14
Control points: X = 34.8204 , Y = 60.1364, Z = 0.0000
X = 8.7752 , Y = 66.6973, Z = 0.0000
X = 49.5011 , Y = 148.8445 , Z = 0.0000
X = 110.4608 , Y = 220.3712 , Z = 0.0000
X = 204.9088 , Y = 126.1070 , Z = 0.0000
X = 270.0202 , Y = 14.8550 , Z = 0.0000
X = 446.3496 , Y = 29.8802 , Z = 0.0000
X = 505.9071 , Y = 185.9470 , Z = 0.0000
X = 377.7646 , Y = 260.1995 , Z = 0.0000
X = 253.5653 , Y = 233.3190 , Z = 0.0000
X = 232.3561 , Y = 128.3835 , Z = 0.0000
X = 327.4772 , Y = 60.9859< , Z = 0.0000
X = 392.1199 , Y = 123.8904 , Z = 0.0000
X = 416.6153 , Y = 158.3182 , Z = 0.0000
Number of fit points 12
User Data: Fit Points
X = 34.8204 , Y = 60.1364 , Z = 0.0000
X = 48.7485 , Y = 139.5000 , Z = 0.0000
X = 106.9190 , Y = 193.5000 , Z = 0.0000
X = 193.7650 , Y = 131.3182 , Z = 0.0000
X = 275.6953 , Y = 44.5909 , Z = 0.0000
X = 442.8330 , Y = 68.3182 , Z = 0.0000
X = 478.0630 , Y = 170.5909 , Z = 0.0000
X = 376.4695 , Y = 241.7727 , Z = 0.0000
X = 256.0320 , Y = 203.3182 , Z = 0.0000
X = 246.2004 , Y = 137.8636 , Z = 0.0000
X = 310.1060 , Y = 89.5909 , Z = 0.0000
X = 416.6153 , Y = 158.3182 , Z = 0.0000
Fit point tolerance: 1.0000E-10
 
Start Tangent
X = -0.9697 , Y = 0.2443 , Z = 0.0000
End Tangent
X = 0.5797 , Y = 0.8148 , Z = 0.0000
 
LINE Layer: "0"
Space: Model space
Handle = 30
From point, X= 26.6273 Y= 144.4091 Z= 0.0000
To point, X= 547.7037 Y= 123.1364 Z= 0.0000
Length = 521.5104, Angle in XY Plane = 358
Delta X = 521.0764, Delta Y = -21.2727, Delta Z = 0.0000
 
Intersection points:
1: 51.195222 143.406117 0.000000
2: 188.388814 137.805246 0.000000
3: 477.399623 126.006499 0.000000
4: 247.140662 135.406726 0.000000
5: 392.756432 129.462022 0.000000


NP CAD Page | Articles | Russian | Download