question:How can I use ObjectARX to color the interstecting area between a solid and an entity? The colored area is the new face that was created for the modified solid.
How to color the area where 3DSOLID and entity intersect? The shaded area is the new section of the modified 3DSLID.
solution:Use the AcBrBrep library to iterate through the faces of the sliced solid. The plane of the slicer, the 2D entity, indicates the plane where the new face of the solid lies. Therefore, a point can be determined that lies on the surface of a face provided by the AcBrBrepFaceTraverser. The point's distance to the slicer's plane is then measured. The face that exhibits a point closest (a distance of 0 is optimal) to the slicer's plane is considered the new face, and AcDb3dSolid::setSubentColor() can be called on it in order to adjust color.
Below is the command from the attached VS 2005 example. The zip file includes a test drawing.
Another approach to consider is to use the SectionPlane object. See this sample in the ObjectARX SDK for more details about this. C:\ObjectARX 2009\samples\graphics\SectionPlane
Use the AcBrBrep library to traverse the 3DSOLID after the slice. The slice is a 2D curve entity. This slice is a surface after slicing the 3DSOLID. Therefore, calculate the distance from the point on the 2D slice to all faces of 3DSOLID. The face with distance = 0 is what we are looking for. Finally, set the color of this surface through AcDb3dSolid::setSubentColor().
The following is the ARX implementation code:
static void ASDKTS51618_GetSlice_MySlice(void)
{
if (!acrxClassDictionary->at(_T("AcBrEntity")))
bool found = acrxDynamicLinker->loadModule(_T("acbr17.dbx"), 0);
Acad::ErrorStatus es;
AcDb3dSolid *pSol;
ads_name en1, en2;
ads_point pt;
AcDbObjectId eId;
acedEntSel(_T("\nSelect a solid: "), en1, pt);
if (Acad::eOk != acdbGetObjectId(eId, en1))
return;
acdbOpenObject(pSol, eId, AcDb::kForWrite);
if (pSol == NULL) {
acutPrintf(_T("Can't access solid - aborting"));
return;
}
AcDbEntity *pEnt;
acedEntSel(_T("\nPick the 2-D slicing entity: "), en2, pt);
if (Acad::eOk != acdbGetObjectId(eId, en2))
return;
acdbOpenObject(pEnt, eId, AcDb::kForRead);
if (pEnt == NULL) {
acutPrintf(_T("Can't access slicing entity - aborting"));
return;
}
AcGePlane plane;
AcDb::Planarity flag;
pEnt->getPlane(plane, flag);
if (flag != AcDb::kPlanar) {
acutPrintf(_T("Not a 2d curve - aborting"));
return;
}
pEnt->close();
AcDb3dSolid* pJunkSolid;
es = pSol->getSlice(plane, Adesk::kTrue, pJunkSolid);
if (!pJunkSolid) return; //no slice made
AcBrBrep *pBrepSol = new AcBrBrep;
AcBr::ErrorStatus brErr = pBrepSol->setSubentPath(AcDbFullSubentPath(pSol->objectId(), kNullSubentId));
AcCmColor Col;
Col.setColorIndex(1);
AcBrBrepFaceTraverser brepFaceTrav;
AcBrFace currentFace;
AcGeSurface* surface;
brepFaceTrav.setBrep(*pBrepSol);
double bestDist = 1000;
AcDbSubentId closestSubId;
bool faceFound = false;
while (!brepFaceTrav.done()) {
brepFaceTrav.getFace(currentFace);
brErr = currentFace.getSurface(surface);
AcGePointOnSurface *repPntSurf = new AcGePointOnSurface(*surface);
AcGePoint3d repPnt = repPntSurf->point3d();
double dist = abs(plane.signedDistanceTo(repPnt));
//does this surface point lie on the plane that contains the 2d slicer?
if (dist < bestDist) {
bestDist = dist;
AcDbFullSubentPath subPath(kNullSubent);
currentFace.getSubentPath(subPath);
closestSubId = subPath.subentId();
if (bestDist == 0.000)
break; //can't do better than zero distance
}
delete surface;
delete repPntSurf;
brepFaceTrav.next();
}
delete pBrepSol;
pSol->setSubentColor(closestSubId, Col);
pSol->close();
}
The following is the LISP solution code for the ACBR library function of the XDRX API:
(defun _traversface
(e ln
) (setq plane
(xdrx_curve_getplane ln
) vz (xdrx_vector_crossproduct vx vy)
mPlane (xdge::constructor "kPlane" ori vz)
)
(setq e1
(xdrx_getpropertyvalue e
"slice" mplane t
));;3dsolid getSlice section (xdrx_entity_delete e);;Delete the upper part and leave the lower part
(setq br
(xdbr::constructor e1
)) ;;Create AcBrBrep from BODY
(setq tr
(xdbr::constructor
"brepfacetraverser" br
)) ;;Build Brep->Face traverser
;;FACE traversal
ints nil
bestDist 1e100
tf
)
(if (setq face
(xdbr::getpropertyvalue tr
"face")) ;;Get AcBrFace at the current traversal position
(progn (setq gface
(xdbr::getpropertyvalue face
"surface"));;AcBrFace->AcGeSurface (setq ptOnSurf
(xdge::constructor
"kPointOnSurface" gface
));;Construct AcGePointOnCurve object (setq pnt
(xdge::getpropertyvalue ptOnSurf
"point");;Get the previous point of AcGePointOnCurve dist (xdge::getpropertyvalue mPlane "signeddistanceto" pnt);; Find the signed distance from the point to the section
subEntPath (xdbr::getpropertyvalue face "subentpath");; Get the subentity path of AcBrFace
subEntId (xdrx_getpropertyvalue subEntPath "subentid");; Get the subentity ID of the subentity path
)
(if (< dist bestDist
);;If the distance is less than the preset, the current distance is stored by default )
(if (equal bestDist
0.0 1e
-5
);; If distance = 0, find the AcBrFace on the 3DSOLID corresponding to the cross section, and end the loop )
(xdrx_object_release face gface ptonsurf subentpath);;Release the intermediate object
)
)
(xdbr::traverser:next tr);;Traverse the next face
)
(xdrx_setpropertyvalue e1
"SubEntColor" (list subentid
1));;Set the color of 3DSOLID subentity (face) (xdrx_object_release tr br subentid);;Release intermediate object
(xdrx_entity_delete ln);;Delete polyline
)
(if (and (setq e
(car (xdrx_entsel
"\nSelect 3DSOLID<Exit>:" '
((0 .
"3DSOLID")))) )
)
(xdrx_entsel "\nSelect section line<Exit>:" '((0 . "LWPOLYLINE")))
)
)
)
(progn (xdrx_begin
) (_traversface e ln
) (xdrx_end
)) )
)
The above LISP code uses the XDRX-API, which can be downloaded from
https://github.com/xdcad/XDrx-APIThe XDRX API encapsulates AcDb, AcEd, AcGe, AcBr... C++ library, using C++ methods to develop LISP programs.Thousands of Lisp functions are available.