How to use Relations2d.AddAutoConstraints?

Solution Partner Phenom Solution Partner Phenom
Solution Partner Phenom

Has anyone already used the Relations2d.AddAutoConstraints method for sketch profiles?

 

I am including some edges via API to my sketch profile and would like them to be connected automatically, like it happens when doing this manually.

Before starting to run through several tests to find out, which parameters to pass to this method, I thought I will ask first, as the documentation does not help on that!!

 

If I find a solution, I will post it here...

4 REPLIES

Re: How to use Relations2d.AddAutoConstraints?

Solution Partner Phenom Solution Partner Phenom
Solution Partner Phenom

My first findings on the usage of AddAutoConstraints:

 

* It cannot be used inside an addin command which runs in Part environment, as this method automatically switches to the Sketch View and leaves the current Part environment. That automatically terminates my command and I cannot finish my task!!!

 

This type of requirement needs to be included in the documentation, if anyone ever should use the API!!

 

I don't want to criticize anyone who writes the documentation, but the ones who design the API and know all of the pre- and post conditions of an API call and the required arguments, but do NOT forward this valuable information to the documentation staff.

Re: How to use Relations2d.AddAutoConstraints?

Solution Partner Phenom Solution Partner Phenom
Solution Partner Phenom

I tried to prepare a sample in VB.NET, but got "Invalid Pointer" exceptions. Probably because I did not generate correctly the arguments. So I decided to do the tests in C++, which is my "bread and butter" programming language.

The sample itself is (almost) working. I can add automatically all Connect relations in the sketch profile, but the sketch is in some unknown state after calling the method. I cannot show/hide it, nor edit it. If I save my document and reopen it, or even with SE Spy before saving it, I can see the 4 new relations being added.

I was testing the AddAutoConstraints method BEFORE calling Profile.End and AFTER ending the profile, but in both cases with the same result.

To use the code, you will need some helper functions and macros, but it will give you the idea on how to use the Relations2d.AddAutoConstraints() method:

 

NOTE: The code MUST run in an external macro and NOT in an addin command, as the AddAutoConstraints method automatically terminates any running command !!

 

(EDIT: all code was tested under ST8 MP1)

 

HRESULT RunMacro(ApplicationPtr pSEApp)
{
  HRESULT hr = NOERROR;

  try
  {
    //-----------------------------------------------------------------
    // TODO: Create a new empty part document and run this code
    //-----------------------------------------------------------------
    PartDocumentPtr pDoc = pSEApp->GetActiveDocument();

    // Create a synchronous Box feature (100 x 50 x 30 mm)
    pDoc->PutModelingMode(seModelingModeSynchronous);

    KeyPointExtentConstants kptFlags;
    RefPlanePtr pTopPlane = pDoc->GetRefPlanes()->Item(1L);
    pDoc->GetModels()->AddBoxByCenter(0., 0., 0., 0.100, 0.050, 0., 0.030, pTopPlane, igBoth, VARIANT_FALSE, NULL, &kptFlags);

    // Create a sketch in ordered mode and include all edges of the box's front face
    pDoc->PutModelingMode(seModelingModeOrdered);

    ModelPtr pModel = pDoc->GetModels()->Item(1L);
    BodyPtr pBody = pModel->GetBody();
    FacesPtr pFaces = pBody->GetFaces(igQueryAll);
    FacePtr pFrontFace = pFaces->Item(2L);
    SketchPtr pSketch = pDoc->GetSketches()->Add();
    RefPlanePtr pFrontPlane = pDoc->GetRefPlanes()->Item(3L);
    ProfilePtr pProf = pSketch->GetProfiles()->Add(pFrontPlane);
    LPDISPATCH lpdDrawObjs[4];
    EdgesPtr pEdges = pFrontFace->GetEdges();
    long nEdges = pEdges->GetCount();
    for (long i=1; i<=nEdges; i++)
    {
      EdgePtr pEdge = pEdges->Item(i);
      VARIANT vDisp;
      V_VT(&vDisp) = VT_DISPATCH;
      V_DISPATCH(&vDisp) = NULL;
      pProf->IncludeEdge(pEdge, &vDisp);

      IDispatchPtr  pDrawObj = V_DISPATCH(&vDisp);
      lpdDrawObjs[i-1] = pDrawObj;
    }

    // Declare SAFEARRAYs outside the try/catch block to be able to clean them on exceptions
    SAFEARRAY *psaProjEdges = NULL,
              *psaConstrTypes = NULL,
              *psaConstr = NULL;
    try
    {
      // I am only interested in getting the 4 lines connected (no other constraints)
      long constrTypes[] = { igKeyPointRelation2d }; //= "Connect" relation
      long nConstrTypes = sizeof(constrTypes) / sizeof(*constrTypes);
      long nConstr = 0;
      PutValuesInSafeArray(nEdges, lpdDrawObjs, &psaProjEdges);
      PutValuesInSafeArray(nConstrTypes, constrTypes, &psaConstrTypes);
      Relations2dPtr pRels2d = pProf->GetRelations2d();
      hr = pRels2d->AddAutoConstraints(1.e-6, 1.e-4, nEdges, &psaProjEdges, nConstrTypes, &psaConstrTypes, &nConstr, &psaConstr,
                                       vtMissing, vtMissing, vtMissing, vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
                                       VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE);
      CHK_RESULT(hr);
      ASSERT(nConstr == 4); // The API should have created 4 new connect relations
    }
    catch (_com_error &e)
    {
      CString msg;
      msg.Format("COM ERROR while adding auto constraints in line %d\n\n==> %s (%08x)", __LINE__, e.ErrorMessage(), e.Error());
      AfxMessageBox(msg, MB_ICONERROR|MB_OK);
    }

    // Clean up memory
    CLEANSAFEARRAY(psaConstr);
    CLEANSAFEARRAY(psaConstrTypes);
    CLEANSAFEARRAY(psaProjEdges);

    // End the profile creation
    long stat = pProf->End(igProfileClosed);
  }
  catch (_com_error &e)
  {
    CString msg;
    msg.Format("COM ERROR in %s (line %d)\n\n==> %s (%08x)", __FUNCTION__, __LINE__, e.ErrorMessage(), e.Error());
    AfxMessageBox(msg, MB_ICONERROR|MB_OK);
  }
  catch (...)
  {
    AfxMessageBox("ERROR: unexpected exception caught!", MB_ICONERROR|MB_OK);
  }   

  return hr;
}

 

Re: How to use Relations2d.AddAutoConstraints?

Experimenter
Experimenter

I tried with C# in a macro but with similar issues:

 

1.
If the part document is created with the API (seApplication.Documents.Add(…)), it throws an Exception:
The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG)

The Sketch environment is not closed and I have to terminate the running process.

 

2.
If the document is created manually, it's working, but the sketch is missing from the screen until I save/reopen the file.

 

C# Code:

 

int numOfLines = kicadDocument.BoardOutlines.Length;

//generic array for SolidEdge Line2d objects
Array SELineArray = Array.CreateInstance( typeof( SolidEdgeFrameworkSupport.Line2d ), numOfLines );

//populating generic array
for ( int i = 0; i < numOfLines; i++ )
{
	SELineArray.SetValue( createSELine( kicadDocument.BoardOutlines[ i ], transformLine ), i );
}

//generic array to set which types of geometric relationships I want to add
Array relationTypes = Array.CreateInstance( typeof( int ), 1 );
relationTypes.SetValue( ( int )SolidEdgeFramework.ObjectType.igKeyPointRelation2d, 0 );

//method outputs
int numOfCreatedRelation;
Array createdRelations = Array.CreateInstance( typeof( SolidEdgeFrameworkSupport.Relation2d ), numOfLines);

try
{
	currentRelations.AddAutoConstraints(
	dist_tol: 0.01 / 1000.0,
	angle_tol: 0.01 / 1000.0,
	NumElements: SELineArray.Length,
	Elements: SELineArray,
	NumCnstrTypes: 1,
	CnstrTypes: relationTypes,
	NumCnstrs: out numOfCreatedRelation,
	Cnstrs: ref createdRelations );
}
catch ( Exception ex )
{
	//The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
	Console.WriteLine( ex.Message );
}

EndCurrentProfileDefinition( 
	SolidEdgePart.ProfileValidationType.igProfileClosed,
	SolidEdgeFrameworkSupport.Geom2dFormConstants.igGeom2dFormClosed );

Windows10 SEST8 noMPs

 

Re: How to use Relations2d.AddAutoConstraints?

Solution Partner Phenom Solution Partner Phenom
Solution Partner Phenom

Thanks for your confirmation.

I will file an IR, although I already worked-around this problem by creating all "Connect" (Keypoint) relations via API one-by-one.