Hi,
I want to create a parallel copy of an element descriptor using the Miter mode. I have searched the net and found an example for a complete command that use a function named mdlSolid_offsetWire() that does just that but I have a hard time to extract the code needed to work with an element descriptors.The source descriptor is 2D and contains only lines and arcs.
My question is if anyone has the code for a function that takes the source descriptor and an offset and returns the paralleled descriptor? Just like the mdlElmdscr_copyParallel() function does. (But using the Miter mode)
Thanks!
Christian
Christian,
what's wrong with mdlElmdscr_copyParallel ? What results do you receive and what do you expect ? I use this function a lot, and never figured out any problem or receiving anything else than a mitered parallel !
Michael
thank you for your answer.
The problem is that the mdlElmdscr_copyParallel() function can add 'knots' to the parallel line depending on how the original line looks. This is like the original mode in the move/copy parallel command works. I hope that this picture show what I mean:
Thanks
Excellent illustration!
I looks like you need to add a post-processing step after calling mdlElmdscr_copyParallel. You've shown a complex string, made up of line and arc elements.
Step through the complex element components, checking for intersections between adjacent elements. Where you find an intersection, you should trim back a copy of each element to the intersect point. Finally, replace the modified element(s) in the complex string.
Something like this …
void mitreComplexString (MSElementDescrP* modified, MSElementDescrCP complexString) { mdlElmdscr_duplicate (modified, complexString); MSElementDescrP component1 = (*modified)->h.firstElem; DPoint3d p1 [1]; DPoint3d p2 [1]; const double Tolerance = ((double)mdlModelRef_getUorPerMaster (ACTIVEMODEL)) / 10.0; while (component1) { MSElementDescrP component2 = component1->h.next; if (NULL != component2 && 0 < mdlIntersect_allBetweenElms (p1, p2, 1, component1, component2, NULL, Tolerance)) { // Trim component elements MSElementDescrP copy1 = NULL; MSElementDescrP copy2 = NULL; mdlElmdscr_duplicateSingle (©1, component1); mdlElmdscr_duplicateSingle (©2, component2); // trim geometry here // Replace components in complex string mdlElmdscr_replace (&component1, copy1); mdlElmdscr_replace (&component2, copy2); // Don't free copy1 or copy2 } component1 = component1->h.next; } }
Regards, Jon Summers LA Solutions
Thanks for your reply Jon,
it proves not to be that simple though. Except from the 'knots' on the 'inside' it also adds extra lines on the outside and it isn't always correct either. In the image below the original line is red. It is created using the smart line tool. The thick lines are created with miter mode and the thin with original mode. As you can see the original mode doesn't create a god result.
So it looks like I need to find another way than mdlElmdscr_copyParallel to create the parallel lines. The question is what that way is.
ThanksChristian
Try a different approach. You could construct a set of shapes, somewhat like this:
Oops -- the colours have disappeared. The SmartLine is the original; the shapes are constructed by creating blocks or wedges from each piece of the complex string. The resulting 'parallel' copy is the opposite edge of each shape.
You have to differ between Polyline and Arc parallels. What the original mode does, is connecting each and every generated parallel with an additional line. In your case it's up to you to use copyParallel for each part of a complex element and enhance or clip those elements to the point(s) calculated by mdlIntersect_allBetweenExtendedElms. I haven't done so, because in my cases each arc is tangent to the previous and follow up lines, so that the parallels work as expected.
HTH Michael
I recommend to use mdlKISolid_offsetWire to do this. The following code is an example which I DO NOT test in practice (And I also forget where I get it :)).
int CreateElementByBody (MSElementDescr** resultEdp, KIBODY* pBody){ *resultEdp = NULL; KIBODY* pCopy = NULL; mdlKISolid_copyBody (&pCopy, pBody); bool simplified = false; if (SUCCESS == mdlKISolid_simplifyBody (&pCopy, FALSE)) simplified = true; if (SUCCESS != mdlKISolid_bodyToElementD (resultEdp, simplified ? pCopy : pBody, TRUE, -1, NULL, ACTIVEMODEL, false) || NULL == *resultEdp) { if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return ERROR; } if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return (NULL == *resultEdp) ? ERROR : SUCCESS;}MdlPublic int mdlElmdscr_copyParallelExt (MSElementDescr** outDscr , MSElementDescr* inDscr , DPoint3d* point , double distance , DPoint3d* normal, int gapFill // 0 for arc fill, 1 for tangent extension fill, 2 for curve extension fill }{ KIENTITY_LIST* pList = NULL; mdlKISolid_listCreate (&pList); KIBODY* pWireBody = NULL; KIEDGE* pEdge = NULL; mdlKISolid_bodyAskFirstEdge (&pEdge, pWireBody); if (NULL == pEdge) return ERROR; if (SUCCESS != mdlKISolid_offsetWire (pList, pWireBody, pEdge, normal, distance, tol, gapFill, FALSE)) { mdlSolid_listDelete (&pList); return ERROR; } int count = 0; mdlKISolid_listCount(&count, pList); for (int i=0; i<count; i++) { KIBODY* pBody = NULL; MSElementDescr* tempEdp = NULL; mdlKISolid_listNthEl (&pBody, pList, i); if (SUCCESS != CreateElementByBody (&tempEdp, pBody) || NULL == tempEdp) { if (NULL != tempEdp) { mdlElmdscr_freeAll (&tempEdp); tempEdp = NULL; } continue; } mdlElmdscr_initOrAddToChain (outDscr, tempEdp); } mdlKISolid_freeEntityList (pList); mdlKISolid_listDelete (&pList); return (NULL == *outDscr) ? ERROR : SUCCESS;}HTH, YongAn
int CreateElementByBody (MSElementDescr** resultEdp, KIBODY* pBody){ *resultEdp = NULL; KIBODY* pCopy = NULL; mdlKISolid_copyBody (&pCopy, pBody);
bool simplified = false; if (SUCCESS == mdlKISolid_simplifyBody (&pCopy, FALSE)) simplified = true;
if (SUCCESS != mdlKISolid_bodyToElementD (resultEdp, simplified ? pCopy : pBody, TRUE, -1, NULL, ACTIVEMODEL, false) || NULL == *resultEdp) { if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return ERROR; } if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return (NULL == *resultEdp) ? ERROR : SUCCESS;}
MdlPublic int mdlElmdscr_copyParallelExt (MSElementDescr** outDscr , MSElementDescr* inDscr , DPoint3d* point , double distance , DPoint3d* normal, int gapFill // 0 for arc fill, 1 for tangent extension fill, 2 for curve extension fill }{ KIENTITY_LIST* pList = NULL; mdlKISolid_listCreate (&pList); KIBODY* pWireBody = NULL;
KIEDGE* pEdge = NULL; mdlKISolid_bodyAskFirstEdge (&pEdge, pWireBody); if (NULL == pEdge) return ERROR; if (SUCCESS != mdlKISolid_offsetWire (pList, pWireBody, pEdge, normal, distance, tol, gapFill, FALSE)) { mdlSolid_listDelete (&pList); return ERROR; } int count = 0; mdlKISolid_listCount(&count, pList); for (int i=0; i<count; i++) { KIBODY* pBody = NULL; MSElementDescr* tempEdp = NULL; mdlKISolid_listNthEl (&pBody, pList, i); if (SUCCESS != CreateElementByBody (&tempEdp, pBody) || NULL == tempEdp) { if (NULL != tempEdp) { mdlElmdscr_freeAll (&tempEdp); tempEdp = NULL; } continue; } mdlElmdscr_initOrAddToChain (outDscr, tempEdp); } mdlKISolid_freeEntityList (pList); mdlKISolid_listDelete (&pList);
return (NULL == *outDscr) ? ERROR : SUCCESS;}
Unknown said:mdlElmdscr_copyParallelExt (MSElementDescr** outDscr , MSElementDescr* inDscr, ... )
The input element inDscr is never used, so that can't possibly work.
pWireBody is never assigned, so remains NULL. What's missing is the code to convert inDscr into pWireBody.
The test-passed code shown here. I corrected serveral errors in my original UNTESTED code.
int CreateElementByBody (MSElementDescr** resultEdp, KIBODY* pBody){ *resultEdp = NULL; KIBODY* pCopy = NULL; mdlKISolid_copyBody (&pCopy, pBody); bool simplified = false; if (SUCCESS == mdlKISolid_simplifyBody (&pCopy, FALSE)) simplified = true; if (SUCCESS != mdlKISolid_bodyToElementD (resultEdp, simplified ? pCopy : pBody, TRUE, -1, NULL, ACTIVEMODEL, false) || NULL == *resultEdp) { if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return ERROR; } if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return (NULL == *resultEdp) ? ERROR : SUCCESS;}MdlPublic int mdlElmdscr_copyParallelExt (MSElementDescr** outDscr , MSElementDescr* inDscr , double distance , DPoint3d* normal, int gapFill // 0 for arc fill, 1 for tangent extension fill, 2 for curve extension fill ){ KIBODY* pWireBody = NULL; int status = mdlKISolid_elementToBody (&pWireBody, inDscr, MASTERFILE); if (SUCCESS != status || !mdlKISolid_isWireBody (pWireBody)) { if (pWireBody) mdlKISolid_freeBody (pWireBody); return ERROR; } KIEDGE* pEdge = NULL; mdlKISolid_bodyAskFirstEdge (&pEdge, pWireBody); if (NULL == pEdge) { mdlKISolid_freeBody (pWireBody); return ERROR; } KIENTITY_LIST* pList = NULL; mdlKISolid_listCreate (&pList); double tol = 0.1; mdlKISolid_beginCurrTrans (ACTIVEMODEL); mdlCurrTrans_invScaleDoubleArray (&distance, &distance, 1); mdlCurrTrans_invScaleDoubleArray (&tol, &tol, 1); mdlKISolid_endCurrTrans (); if (SUCCESS != mdlKISolid_offsetWire (pList, pWireBody, pEdge, normal, distance, tol, gapFill, FALSE)) { mdlKISolid_freeBody (pWireBody); mdlKISolid_listDelete (&pList); return ERROR; } int count = 0; mdlKISolid_listCount(&count, pList); for (int i=0; i<count; i++) { KIBODY* pBody = NULL; MSElementDescr* tempEdp = NULL; mdlKISolid_listNthEl (&pBody, pList, i); if (SUCCESS != CreateElementByBody (&tempEdp, pBody) || NULL == tempEdp) { if (NULL != tempEdp) { mdlElmdscr_freeAll (&tempEdp); tempEdp = NULL; } continue; } mdlElmdscr_initOrAddToChain (outDscr, tempEdp); } mdlKISolid_listDelete (&pList); return (NULL == *outDscr) ? ERROR : SUCCESS;}void test (){ MSElementDescrP inEdP = NULL, outEdP = NULL; DPoint3d pt = {0, -1, 0}, normal, defaultNormal={0,0,1}; mdlAssoc_getElementDescr (&inEdP, NULL, 770, ACTIVEMODEL, FALSE); mdlElmdscr_extractNormalTight (&normal, &pt, inEdP, &defaultNormal); mdlElmdscr_copyParallelExt (&outEdP, inEdP, 7000, &normal, 1); EditElemHandle eeh (outEdP, true, false); eeh.AddToModel (ACTIVEMODEL);}
int CreateElementByBody (MSElementDescr** resultEdp, KIBODY* pBody){ *resultEdp = NULL; KIBODY* pCopy = NULL; mdlKISolid_copyBody (&pCopy, pBody); bool simplified = false; if (SUCCESS == mdlKISolid_simplifyBody (&pCopy, FALSE)) simplified = true; if (SUCCESS != mdlKISolid_bodyToElementD (resultEdp, simplified ? pCopy : pBody, TRUE, -1, NULL, ACTIVEMODEL, false) || NULL == *resultEdp) { if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return ERROR; } if (NULL != pCopy) mdlKISolid_deleteEntity (pCopy); return (NULL == *resultEdp) ? ERROR : SUCCESS;}
MdlPublic int mdlElmdscr_copyParallelExt (MSElementDescr** outDscr , MSElementDescr* inDscr , double distance , DPoint3d* normal, int gapFill // 0 for arc fill, 1 for tangent extension fill, 2 for curve extension fill ){ KIBODY* pWireBody = NULL; int status = mdlKISolid_elementToBody (&pWireBody, inDscr, MASTERFILE); if (SUCCESS != status || !mdlKISolid_isWireBody (pWireBody)) { if (pWireBody) mdlKISolid_freeBody (pWireBody); return ERROR; } KIEDGE* pEdge = NULL; mdlKISolid_bodyAskFirstEdge (&pEdge, pWireBody); if (NULL == pEdge) { mdlKISolid_freeBody (pWireBody); return ERROR; } KIENTITY_LIST* pList = NULL; mdlKISolid_listCreate (&pList); double tol = 0.1; mdlKISolid_beginCurrTrans (ACTIVEMODEL); mdlCurrTrans_invScaleDoubleArray (&distance, &distance, 1); mdlCurrTrans_invScaleDoubleArray (&tol, &tol, 1); mdlKISolid_endCurrTrans ();
if (SUCCESS != mdlKISolid_offsetWire (pList, pWireBody, pEdge, normal, distance, tol, gapFill, FALSE)) { mdlKISolid_freeBody (pWireBody); mdlKISolid_listDelete (&pList); return ERROR; } int count = 0; mdlKISolid_listCount(&count, pList); for (int i=0; i<count; i++) { KIBODY* pBody = NULL; MSElementDescr* tempEdp = NULL; mdlKISolid_listNthEl (&pBody, pList, i); if (SUCCESS != CreateElementByBody (&tempEdp, pBody) || NULL == tempEdp) { if (NULL != tempEdp) { mdlElmdscr_freeAll (&tempEdp); tempEdp = NULL; } continue; } mdlElmdscr_initOrAddToChain (outDscr, tempEdp); } mdlKISolid_listDelete (&pList); return (NULL == *outDscr) ? ERROR : SUCCESS;}
void test (){ MSElementDescrP inEdP = NULL, outEdP = NULL; DPoint3d pt = {0, -1, 0}, normal, defaultNormal={0,0,1}; mdlAssoc_getElementDescr (&inEdP, NULL, 770, ACTIVEMODEL, FALSE); mdlElmdscr_extractNormalTight (&normal, &pt, inEdP, &defaultNormal); mdlElmdscr_copyParallelExt (&outEdP, inEdP, 7000, &normal, 1); EditElemHandle eeh (outEdP, true, false); eeh.AddToModel (ACTIVEMODEL);}
HTH, YongAn
Thank you very much YongAn!
The function works perfect!
I just added an element template pointer to the CreateElementByBody() which is used in dlKISolid_bodyToElementD(), to be able to preserver the colors, line type etc.
Thanks also to Jon and Michael for your help.