[MDL V8XM/i] Copy parallel using Miter mode

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

Parents
  • 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

    Christian

  • 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 (&copy1, component1);
          mdlElmdscr_duplicateSingle (&copy2, 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

     
    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.

    Thanks
    Christian

  • Try a different approach.  You could construct a set of shapes, somewhat like this:

    Block Algorithm

    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.

     
    Regards, Jon Summers
    LA Solutions

  • Christian

    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



Reply
  • 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



Children
  • 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.

     
    Regards, Jon Summers
    LA Solutions

  • 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);
    }

    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.

    Christian