Quantcast
Channel: Manufacturing DevBlog
Viewing all 516 articles
Browse latest View live

Run Stress Simulation by code

$
0
0

By Xiaodong Liang

Currently, API has not exposed the ability to work with Stress Simulation. The only way which may be of a bit help is to execute the corresponding commands by ControlDefinition.Execute. e.g. in this case, the command is “”

“FeaSimulateCmd”.

image

But this can only pop out the dialog, instead of running it automatically. A workaround is to take advantage of VB: SendKeys since the default focused button in this dialog is [Run]. That is to say, we send key [Enter] to the dialog thus it can be executed automatically. I have to confess, however SendKeys is not always working in all cases. But in this case, it is quite simple. It works well at my side.

 

image

 

In addition, you need to make sure to activate the enviorment of Sress Simulation before running simulation. The following is a code demo.

 

Public Sub DoFea()

     Dim oDoc As Document

     Set oDoc = ThisApplication.ActiveDocument

     ‘if stress simulation is activated
     Dim UIManager As UserInterfaceManager

    Set UIManager = ThisApplication.UserInterfaceManager

If UIManager.ActiveEnvironment.InternalName <> "FEA Environment Internal Name" Then

        ‘if it is not activated

        Dim environmentMgr As EnvironmentManager

        Set environmentMgr = oDoc.EnvironmentManager

        Dim dsEnv As Environment

        Set dsEnv = UIManager.Environments.Item("FEA Environment Internal Name")

        Call environmentMgr.SetCurrentEnvironment(dsEnv)

    End If

   ‘get [simulation] command

    Dim oCol As ControlDefinition

    Set oCol = ThisApplication.CommandManager.ControlDefinitions("FeaSimulateCmd")

    ‘send [enter] key to the dialog to mimic the clicking [Run]

SendKeys "{ENTER}"

‘execute the command. The dialog will pop out and execute run automatically.
    oCol.Execute

End Sub


Inventor: Dirty flag of Inventor document

$
0
0

by Vladimir Ananyev

Q: Has API any settings that may influence the Dirty flag of the Inventor documents?

A: Since Inventor 11 there is a setting that is affecting the true/false behavior of the dirty property. In UI this setting is on the Save tab of the Application Options: "Prompt to save for re-computable updates". This flag is unchecked by default. It specifies whether a prompt to save the document should be displayed when the document is closed without being explicitly saved after any recomputable changes. The API exposes this option as SaveOptions.PromptSaveForRecomputableChanges.

Hide drawing dimensions which are orphaned

$
0
0

By Xiaodong Liang

For some reasons such as the corresponding components are removed/suppressed, the dimensions which ever attach to the components will be orphaned and can be removed.

image

Recently, I got a question that the user wants to hide the orphaned dimension. Once the components are available again, he wants to display the dimension again.

DrawingDimension.Attached indicates whether this dimension is attached to anything. But there is no property to control the visibility of the dimension. You can only remove it completely by DrawingDimension.Delete

After some investigations,  a workaround came to my brain. We could move the orphaned dimension to a layer which is switched off. And set its layer back to a normal dimension layer if the user wants to reset.

The following is some code snippet of iLogic.

hideUnAttachedDim:

doc=ThisDoc.Document''assume a layer named "Dimension (ISO)" exists. '  If no, you could use other existing layers.DimoHideLayeroHideLayer=doc.StylesManager.Layers.Item("Dimension (ISO)").Copy("dummy")'iterate each dimension  DimoEachDimAsDrawingDimensionForEachoEachDimIndoc.ActiveSheet.DrawingDimensions'if it is orphaned  IfNotoEachDim.AttachedThen' set the layer to the dummy layer oEachDim.Layer=oHideLayerEndIfNext'hide this layer oHideLayer.Visible=Falsedoc.Update

resetDim:

doc=ThisDoc.Document'Set the dimensions whose layer Is "dummy" To "Dimension (ISO)"DimoEachDimAsDrawingDimensionForEachoEachDimIndoc.ActiveSheet.DrawingDimensionsIfoEachDim.Layer.Name="dummy"ThenoEachDim.Layer=doc.StylesManager.Layers.Item(""Dimension(ISO)")EndIfNextdoc.Update

Access Inventor Studio by code

$
0
0

By Xiaodong Liang

Inventor Studio is also an add-in of Inventor. The corresponding *.dll locates at <Inventor Installation Path>\bin\Archon.dll. This dll provides some basic interfaces of Studio. The Interop.InventorStudioLib.dll is generated by VS when you add the lib from
- 32bits: [Add Reference] >> [COM tab] >> [Inventor Studio Library ]
- 64bits: <Inventor Install Path>\bin\archon.dll  (you may need to run regsvr32 to register the dll firstly if you get a failure when adding the dll)

image

After inporting the library, you could get its Automation interface by the add-in. e.g. the code below gets the constraints names the animation uses.

using InventorStudioLib;

 

namespace WindowsFormsApplication3

{

    publicpartialclassForm1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        privatevoid button1_Click(object sender, EventArgs e)

        {

            Inventor.Application m_inventorApplication =

            (Inventor.Application)System.Runtime.InteropServices.Marshal.

            GetActiveObject("Inventor.Application");

            if (m_inventorApplication == null)

            {

                MessageBox.Show("no Inventor running!");

                return;

            }

            Inventor._Document oActivedoc = m_inventorApplication.ActiveDocument;

            if (oActivedoc == null)

            {

                MessageBox.Show("Please open an assembly document!");

                return;

            }

            //studio is also an addin which has its guid

            string sutdioAddinGuid =

            "{F3D38928-74D1-4814-8C24-A74CE8F3B2E3}";

            Inventor.ApplicationAddIn oStudioAddin = null;

            try

            {

                // try to get studio addin

                oStudioAddin =

                m_inventorApplication.ApplicationAddIns.

                get_ItemById(sutdioAddinGuid);

            }

            catch

            {

                // any error...

                return;

            }

            if (oStudioAddin != null)

            {

                // activate the addin

                if (!oStudioAddin.Activated)

                    oStudioAddin.Activate();

 

                //get property EnvironmentManager

                object oObj = oActivedoc.GetType().InvokeMember(

                "EnvironmentManager",

                System.Reflection.BindingFlags.GetProperty,

                null, oActivedoc, null, null, null, null);

                Inventor.EnvironmentManager oEnvironmentMgr =

                (Inventor.EnvironmentManager)oObj;

 

                //activate the enviroment of Studio

                Inventor.UserInterfaceManager UIManager =

                m_inventorApplication.UserInterfaceManager;

 

                if (UIManager.ActiveEnvironment.InternalName != "Archon:Env")

                {

                    Inventor.Environment studioEnv =

                    UIManager.Environments["Archon:Env"];

                    oEnvironmentMgr.SetCurrentEnvironment(studioEnv);

                }

 

                // get the automation interface of Studio

                InventorStudio oInventorStudio = oStudioAddin.Automation;

 

                //AnimationManager

                AnimationManager oAM = oInventorStudio.AnimationManager;

 

                if (oAM.AnimationFavorites.Count >0)

                {

                    MessageBox.Show("Studio has AnimationFavourites not empty");

 

                    // get first item in AnimationFavorites

                    object oAF = oAM.AnimationFavorites[1];

                    Inventor.AssemblyConstraint oAC = (Inventor.AssemblyConstraint) oAF;

                    MessageBox.Show("AnimationFavourites first item: " + oAC.Name);

                }

            }

 

        }

    }

}

Create workplane at the intersecting point of an axis and a face

$
0
0

By Xiaodong Liang

Question:
Is there a way to add a WorkPoint where an Axis and a Part Face Intersect?  I need this to be able to create a WorkPlane normal to the surface of the part at that location.

Solution:
TransientGeometry.CurveSurfaceIntersection can tell the intersecting points of a curve and a surface. And WorkPlanes collection provides the method AddByPointAndTangent creates a new work plane through the input point and tangent to the input surface. But this method does not accept Point as the argument.  We can workaround it by creating a tempeory sketch3d point. The code below demos it.

 

Sub addWPByIntersectPtAtFace()

    Dim oDoc As PartDocument
    Set oDoc = ThisApplication.ActiveDocument
   
    Dim oWorkAxis As WorkAxis
    Set oWorkAxis = ThisApplication.CommandManager.Pick(kWorkAxisFilter, "pick an axis")
   
    Dim oFace As Face
    Set oFace = ThisApplication.CommandManager.Pick(kPartFaceFilter, "pick an face")
   
    Dim oTG As TransientGeometry
    Set oTG = ThisApplication.TransientGeometry
   
    Dim oObjs As ObjectsEnumerator
    Set oObjs = oTG.CurveSurfaceIntersection(oWorkAxis.Line, oFace.Geometry)
   
    ' assume only one intersect point
    Dim oIntersecPt As Point
    Set oIntersecPt = oObjs(1)
   
    'WorkPlanes.AddByPointAndTangent does not accept Point
    ' so use sketch3d point as an alternative
    Dim oDef As PartComponentDefinition
    Set oDef = oDoc.ComponentDefinition
   
    Dim oTemp3dSketch As Sketch3D
    Set oTemp3dSketch = oDef.Sketches3D.Add
   
    Dim oSketchPt3d As SketchPoint3D
    Set oSketchPt3d = oTemp3dSketch.SketchPoints3D.Add(oIntersecPt)
    
    Call oDef.WorkPlanes.AddByPointAndTangent(oSketchPt3d, oFace)
   
    'delete the temp sketch 3d
    oTemp3dSketch.Delete
   
   
End Sub

Crash when not using raw COM interface

$
0
0

By Adam Nagy

Let's say we have the following code:

// First select a RectangularPatternFeature then run the code

CComQIPtr<RectangularPatternFeature> pPattern =

  pInvApp->ActiveDocument->SelectSet->Item[1];

for (int i = 1; i <= pPattern->PatternElements->Count; i++)

{

  CComPtr<FeaturePatternElement> pElem =

    pPattern->PatternElements->Item[i];

 

  // In this case there is no crash

  pElem->put_Suppressed(false); // or true

 

  // No matter if I use false or true

  // both cases will cause an error

  pElem->Suppressed = false; // or true

}

The difference between put_Suppressed(false) and Suppressed = false is that the former is the raw interface which simply provides an HRESULT value to let you know if there was an error, while the latter is a wrapper around it that is throwing a _com_error exception in case of an error.

You can also check the rxinventor.tli file of your project to see the exact implementation of the raw and wrapper functions:

#pragma implementation_key(29648)

inlinevoid Inventor::RectangularPatternFeature::PutSuppressed ( VARIANT_BOOL _arg1 ) {

    _com_dispatch_method(this, 0x500030a, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,

        L"\x000b", _arg1);

}

 

#pragma implementation_key(29649)

inline HRESULT Inventor::RectangularPatternFeature::put_Suppressed ( VARIANT_BOOL _arg1 ) {

    return _com_dispatch_raw_method(this, 0x500030a, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,

        L"\x000b", _arg1);

}

What is the error in our code? The problem is that the first element of a rectangular pattern cannot be suppressed - you can easily verify this in the user interface:

PatternElementSuppress

While put_Suppressed(false) simply returns an error code, Suppressed = false will throw an error that you would need to catch. You can solve it like this:

// First select a RectangularPatternFeature then run the code

CComQIPtr<RectangularPatternFeature> pPattern =

  pInvApp->ActiveDocument->SelectSet->Item[1];

for (int i = 1; i <= pPattern->PatternElements->Count; i++)

{

  CComPtr<FeaturePatternElement> pElem =

    pPattern->PatternElements->Item[i];

 

  // In this case no crash

  pElem->put_Suppressed(false); // or true

 

  // Now we catch the error so nothing will crash

  // Note: the real solution would be to start the iteration

  // from 2 instead of 1 if we just want to change the

  // Suppressed state of the items. I left it on 1 just to

  // show that the error handling works 

  try

  {

    pElem->Suppressed = false; // or true

  }

  catch (_com_error e)

  {

    // do something if you want

  }

}

Project Curve to Surface

$
0
0

By Xiaodong Liang

Question:
I would like to realize ‘Project Curve to Surface’ capability using Inventor API. This means the function below. Is it possible to implement using API ?

image

 

clip_image001

 

Solution:
As shown in the UI, there are 3 types of projections:

1. project along a vector: 
     projects the spline along the normal to the surface. i.e. project each point of the spline to the surface along the normal vector.  In UI, the projection of Inventor allows the user to select a direction to project. For 2d curve, the default direction is the normal of the plane the curve locates in. While if you try to project a 3d curve, you must select a direction. Otherwise, the [OK] button is disable.

2. project to the closet point: 
    finds the closest point of each spline point on the surface.

3. curl to the surface: 
    forms the projected curve around the curvature of selected face or faces. Note: For Wrap to Surface output, the faces must be a cylinder, cone, or planar. The curves must be planar and tangent to the selected faces

It is easier to implement 1 or 2. For 1, we just need to build the normal  and project the point by FindUsingRay. For 2, the method is Face.GetClosestPointTo . The following code asks the the user to select a spline  (2d/3d) and a surface. next project and create a 3d spline on the surface.

   PrivateSub test()

 

        ' get inventor appliaction

        Dim _InvApp As Inventor.Application = Nothing

        _InvApp =

            System.Runtime.InteropServices.Marshal.

                GetActiveObject("Inventor.Application")

 

        Dim oPartDoc AsPartDocument

        oPartDoc = _InvApp.ActiveDocument

 

        Dim oTG AsTransientGeometry

        oTG = _InvApp.TransientGeometry

 

        Dim oDef AsPartComponentDefinition

        oDef = oPartDoc.ComponentDefinition

 

        'select the spline to project

        Dim oObject AsObject

        oObject =

            _InvApp.CommandManager.Pick(

                SelectionFilterEnum.kSketch3DCurveFilter,

                               "Pick a sketch spline")

 

        Dim oSplineToPro AsObject

        oSplineToPro = oObject

 

        'select the surface to project to

        oObject =

            _InvApp.CommandManager.Pick(

                SelectionFilterEnum.kPartFaceFilter,

                "Pick a surface")

 

        Dim oSurface AsFace

        oSurface = oObject

 

        'projection type

        Dim oProType AsString

        oProType = "project along vector"

        'oProType = "project to the closet point"

 

 

        'get spline param extents

        Dim oEV AsCurveEvaluator

        oEV = oSplineToPro.Geometry.Evaluator

        Dim oMinP AsDouble

        Dim oMaxP AsDouble

        Call oEV.GetParamExtents(oMinP, oMaxP)

 

        ' number of points we want to project

        Dim oNumOfPt AsInteger

        oNumOfPt = 50

 

        'the result points of projection

        Dim oPointCoords AsObjectCollection

        oPointCoords =

            _InvApp.TransientObjects.

            CreateObjectCollection()

 

        ' select a vector for type 1: "project along vector"

        Dim oVectorForProject AsUnitVector

        oVectorForProject =

                oTG.CreateUnitVector()

        If oProType = "project along vector"Then

            Dim oObjectTemp AsObject

            oObjectTemp =

           _InvApp.CommandManager.Pick(

               SelectionFilterEnum.kAllLinearEntities,

               "Pick a linear edge")

 

            IfNot oObjectTemp IsNothingThen

                Dim oLine AsLineSegment

                oLine = oObjectTemp.Geometry

                oVectorForProject =

                    oLine.Direction

            Else

                MsgBox("select a linear edge as"&

                        "the projection vector!!")

                Return

            EndIf

        EndIf

 

        ' iterate each point and get the projection point

        Dim i AsInteger

        For i = 0 To oNumOfPt

 

            Dim params(0) AsDouble

            params(0) = oMinP + i * (oMaxP - oMinP) / oNumOfPt

 

            Dim points(2) AsDouble

            Call oEV.GetPointAtParam(params, points)

 

            Dim oInvPt As Inventor.Point

            oInvPt = oTG.CreatePoint(points(0), points(1), points(2))

 

         

            'type 1

            If oProType = "project along vector"Then

                Dim oFoundEntities AsObjectsEnumerator =

              _InvApp.TransientObjects.CreateObjectCollection()

 

                Dim oLocatePtArray AsObjectsEnumerator =

                    _InvApp.TransientObjects.

                      CreateObjectCollection()

                ' project each point of the spline to

                'the surface along the normal vector

                oDef.FindUsingRay(oInvPt,

                                  oVectorForProject,

                                  0.000000000000001,

                                  oFoundEntities,

                                  oLocatePtArray,

                                  True)

                If oLocatePtArray.Count > 0 Then

                    oPointCoords.Add(

                        oTG.CreatePoint(oLocatePtArray(1).x,

                                       oLocatePtArray(1).Y,

                                       oLocatePtArray(1).Z))

                EndIf

 

                'type 2

            ElseIf oProType = "project to the closet point"Then

 

                'finds the closest point of each spline point on the surface.

                Dim oClosestPt As Inventor.Point

                oClosestPt =

                    oSurface.GetClosestPointTo(oInvPt)

                oPointCoords.Add(

                      oTG.CreatePoint(oClosestPt.X,

                                      oClosestPt.Y,

                                      oClosestPt.Z))

            Else

 

            EndIf

 

 

        Next

 

        ' create the 3d sketch spline with the result points

        Dim oNew3dSketch AsSketch3D

        oNew3dSketch = oDef.Sketches3D.Add

 

        oNew3dSketch.SketchSplines3D.Add(oPointCoords)

    EndSub

 

 image

Autodesk exchange Portathon event – update

$
0
0

By Virupaksha Aithal

Since we began the registration for Autodesk exchange Portathon event, we received 127 registrations till date. We have received 98 Apps as part of the event and out of which we have published 52 Apps in the exchange store already.

There is less than 9 days to the event. if you have not registered yet, visit Autodesk® Exchange Apps Portathon event page


Unused sketch geometry

$
0
0

By Adam Nagy

If you need to find all the sketch entities that are not used then you can simply iterate through the sketches and their entities and check which ones are not part of a profile yet:

Public Sub HighlighUncosumedSketchEntities()
    Dim oDoc As PartDocument
    Set oDoc = ThisApplication.ActiveDocument
    Dim oSel As SelectSet
    Set oSel = oDoc.SelectSet
    Dim oSketches As PlanarSketches
    Set oSketches = oDoc.ComponentDefinition.Sketches
    Dim oUnconsumed As ObjectCollection
    Set oUnconsumed = 
ThisApplication.TransientObjects.CreateObjectCollection
    Dim oSketch As PlanarSketch
    For Each oSketch In oSketches' First collect all the sketch entities
Dim oEnt As SketchEntity For Each oEnt In oSketch.SketchEntities Call oUnconsumed.Add(oEnt) Next' If the sketch is consumed then some of its' entities are already used for something' so we need to remove those from the collection If oSketch.Consumed Then Dim oProfile As Profile For Each oProfile In oSketch.Profiles Dim oPath As ProfilePath For Each oPath In oProfile Dim oPEnt As ProfileEntity For Each oPEnt In oPath Call oUnconsumed.RemoveByObject( _
oPEnt.SketchEntity) Next Next Next End If Next Call oSel.SelectMultiple(oUnconsumed) End Sub

Run iLogic rule from external application

$
0
0

By Adam Nagy

While in case of an Inventor AddIn you can use early binding to access the iLogic COM objects, in case of an external application you need to use late binding. That's because the iLogic objects are not real COM objects, but COM wrappers around .NET objects. In case of VB.NET it's been really simple from the start to do late binding, because it's been enough to declare the variables as Object instead of the specific type. Since version 4 of C# it's just as simple there because of the arrival of the dynamic keyword.

Below is the external application equivalent of the code used in this blog post: http://adndevblog.typepad.com/manufacturing/2013/04/call-ilogic-from-net.html 

staticvoid test_iLogic()

{

  Inventor.Application oApp =

    System.Runtime.InteropServices.Marshal.

    GetActiveObject("Inventor.Application") as Inventor.Application;

 

  //iLogic is also an addin which has its guid

  string iLogicAddinGuid = "{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}";

 

  Inventor.ApplicationAddIn addin = null;

  try

  {

    // try to get iLogic addin

    addin = oApp.ApplicationAddIns.get_ItemById(iLogicAddinGuid);

  }

  catch

  {

    // any error...

  }

 

  if (addin != null)

  {

    // activate the addin

    if (!addin.Activated)

      addin.Activate();

 

    // entrance of iLogic

    dynamic _iLogicAutomation = addin.Automation;

 

    Document oCurrentDoc = oApp.ActiveDocument;

 

    dynamic myRule = null;

    //dump all rules

    foreach (dynamic eachRule in _iLogicAutomation.Rules(oCurrentDoc))

    {

      if (eachRule.Name == "MyRule")

      {

        myRule = eachRule;

        //list the code of rule to the list box

        MessageBox.Show(myRule.Text);

        break;

      }

    }

    if (myRule != null)

      _iLogicAutomation.RunRule(oCurrentDoc, "MyRule");

  }

}

In C++ it's not so simple. Fortunately I found this MSDN article which makes things a bit easier: http://support.microsoft.com/kb/238393

// http://support.microsoft.com/kb/238393

//

// AutoWrap() - Automation helper function...

//

HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp,

      LPOLESTR ptName, int cArgs...)

{

  // Begin variable-argument list...

  va_list marker;

  va_start(marker, cArgs);

 

  if(!pDisp) {

    MessageBox(NULL, _T("NULL IDispatch passed to AutoWrap()"),

      _T("Error"), 0x10010);

    _exit(0);

  }

 

  // Variables used...

  DISPPARAMS dp = { NULL, NULL, 0, 0 };

  DISPID dispidNamed = DISPID_PROPERTYPUT;

  DISPID dispID;

  HRESULT hr;

  TCHAR buf[200];

 

  // Get DISPID for name passed...

  hr = pDisp->GetIDsOfNames(

    IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);

 

  if(FAILED(hr)) {

    _stprintf(buf,

      _T("IDispatch::GetIDsOfNames(\"%s\") failed w/err0x%08lx"),

      ptName, hr);

    MessageBox(NULL, buf, _T("AutoWrap()"), 0x10010);

    _exit(0);

    return hr;

  }

 

  // Allocate memory for arguments...

  VARIANT *pArgs = new VARIANT[cArgs+1];

 

  // Extract arguments...

  for(int i=0; i<cArgs; i++) {

    pArgs[i] = va_arg(marker, VARIANT);

  }

 

  // Build DISPPARAMS

  dp.cArgs = cArgs;

  dp.rgvarg = pArgs;

 

  // Handle special-case for property-puts!

  if(autoType & DISPATCH_PROPERTYPUT) {

    dp.cNamedArgs = 1;

    dp.rgdispidNamedArgs = &dispidNamed;

  }

 

  // Make the call!

  hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,

    autoType, &dp, pvResult, NULL, NULL);

 

  if(FAILED(hr)) {

    _stprintf(buf,

      _T("IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx"),

      ptName, dispID, hr);

    MessageBox(NULL, buf, _T("AutoWrap()"), 0x10010);

    _exit(0);

    return hr;

  }

 

  // End variable-argument section...

  va_end(marker);

 

  delete [] pArgs;

 

  return hr;

}

 

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

  int nRetCode = 0;

 

  HRESULT Result = NOERROR;

 

  ::CoInitialize(NULL);

 

  // Access Inventor

  {

    CLSID InvAppClsid;

    Result = CLSIDFromProgID (
      _T("Inventor.Application"), &InvAppClsid);

    if (FAILED(Result)) return Result;

 

    CComPtr<IUnknown> pInvAppUnk;

    Result = ::GetActiveObject (InvAppClsid, NULL, &pInvAppUnk);

    if (FAILED (Result))

      _tprintf_s(_T("Could not get the active Inventor instance\n"));

    if (FAILED(Result)) return Result;

 

    CComPtr<Application> pInvApp;

    Result = pInvAppUnk->QueryInterface(

      __uuidof(Application), (void **) &pInvApp);

    if (FAILED(Result)) return Result;

 

    CComPtr<ApplicationAddIn> pAddIn =

      pInvApp->ApplicationAddIns->ItemById[

        _T("{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}")];

 

    // Calling iLogic functions

    {

      CComPtr<IDispatch> pAuto = pAddIn->Automation;

 

      CComPtr<Document> pDoc = pInvApp->ActiveDocument;

 

      VARIANT ret;

      VARIANT param1;

 

      param1.vt = VT_DISPATCH;

      param1.pdispVal = pDoc;

      Result = AutoWrap(

        DISPATCH_PROPERTYGET, &ret, pAuto, _T("Rules"), 1, param1);

 

      // Rules() returns an IEnumarator - it will be wrapped as

      // IEnumVARIANT returned by GetEnumerator()

      // http://stackoverflow.com/questions/7399447/com-use-ienumerable-in-atl-c-project

      CComPtr<IDispatch> pRules = ret.pdispVal;

      Result = AutoWrap(

        DISPATCH_METHOD, &ret, pRules, _T("GetEnumerator"), 0);

 

      CComQIPtr<IEnumVARIANT> pRulesEnum = ret.punkVal;

 

      VARIANT rule;

      ULONG celt = 1, celtFetched;

      while (pRulesEnum->Next(celt, &rule, &celtFetched) == S_OK)

      {

        CComPtr<IDispatch> pRule = rule.pdispVal;

        Result = AutoWrap(

          DISPATCH_PROPERTYGET, &ret, pRule, _T("Name"), 0);

        BSTR name = ret.bstrVal;

 

        if (_tcscmp(name, _T("MyRule")) == 0)

        {

          Result = AutoWrap(

            DISPATCH_PROPERTYGET, &ret, pRule, _T("Text"), 0);

          BSTR text = ret.bstrVal;

          MessageBox(NULL, text, _T("Rule Text"), MB_OK);

 

          VARIANT param2;

          param2.vt = VT_BSTR;

          param2.bstrVal = name;

          // Parameters need to be added in reverse order.

          // In the C# code you'd call it like

          // _iLogicAutomation.RunRule(oCurrentDoc, "MyRule");

          Result = AutoWrap(

            DISPATCH_METHOD, &ret, pAuto, _T("RunRule"),
            2, param2, param1);

        }

      }

    }

  }

 
  ::CoUninitialize();

 

  return nRetCode;

Cast between COM types in C++

$
0
0

By Adam Nagy

Sometimes you may need to cast an object to a different type. E.g. when trying to get to the Parameters property of a ComponentDefinition got from a ComponentOccurrence. ComponentDefinition does not have a Parameters property, but PartComponentDefinition and AssemblyComponentDefinition do. You have two ways to solve this problem:
1) Either use early binding and cast ComponentDefinition to PartComponentDefinition or AssemblyComponentDefinition using CComQIPtr (QI = Query Interface)
2) Use late binding to access the Parameters property through the ComponentDefinition object

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

  int nRetCode = 0;

 

  HRESULT Result = NOERROR;

 

  ::CoInitialize(NULL);

 

  // Access Inventor

  {

    CLSID InvAppClsid;

    Result = CLSIDFromProgID (_T("Inventor.Application"), &InvAppClsid);

    if (FAILED(Result)) return Result;

 

    CComPtr<IUnknown> pInvAppUnk;

    Result = ::GetActiveObject (InvAppClsid, NULL, &pInvAppUnk);

    if (FAILED (Result))

      _tprintf_s(_T("Could not get the active Inventor instance\n"));

    if (FAILED(Result)) return Result;

 

    CComPtr<Application> pInvApp;

    Result = pInvAppUnk->QueryInterface(

      __uuidof(Application), (void **) &pInvApp);

    if (FAILED(Result)) return Result;

 

    CComPtr<ApplicationAddIn> pAddIn =

      pInvApp->ApplicationAddIns->ItemById[

        _T("{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}")];

 

    // Get Parameters

    {

      // First the occurrence needs to be selected

      // in the user interface

      CComQIPtr<ComponentOccurrence> oOcc =

        pInvApp->ActiveDocument->SelectSet->Item[1];

 

      // 1) Use early binding and CComQIPtr

 

      CComPtr<Parameters> pParams;

      CComQIPtr<PartComponentDefinition> pPartCompDef =
        oOcc->Definition;

      if (pPartCompDef)

      {

        // It is a part component definition, so we can get the

        // parameters of the part definition

        pParams = pPartCompDef->Parameters;

      }

 

      CComQIPtr<AssemblyComponentDefinition> pAsmCompDef =
        oOcc->Definition;

      if (pAsmCompDef)

      {

        // It is an assembly component definition, so we
        // can get the 
parameters of the assembly definition

        pParams = pAsmCompDef->Parameters;

      }

 

      MessageBox(NULL, pParams->Item[1]->Name,

        _T("Name of first parameter (early binding)"), MB_OK);

 

      // 2) Use late binding

      // This requires the AutoWrap function from article

      // http://adndevblog.typepad.com/manufacturing/2013/09/run-ilogic-rule-from-external-application.html

 

      // Since both PartComponentDefinition and

      // AssemblyComponentDefinition have a Parameters property

      // we could get it like this too

      VARIANT res;

      AutoWrap(

        DISPATCH_PROPERTYGET, &res, oOcc->Definition,
        _T("Parameters"), 0);

      CComQIPtr<Parameters> pParamsLate = res.pdispVal; 

 

      MessageBox(NULL, pParamsLate->Item[1]->Name,

        _T("Name of first parameter (late binding)"), MB_OK);

    }
  }

  ::CoUninitialize();

 

  return nRetCode;

Remove illegal text formatting

$
0
0

By Adam Nagy

Not sure how you end up with text formatting in DrawingNote's where the Font is set to nothing, i.e. the DrawingNote.FormattedText contains things like this:

<StyleOverride Font=''>

Maybe the Font type being used on the system where the drawing was created does not exist on the other system where the drawing has been opened? 

Unfortunately, this seems to cause issues when exporting your drawing to other formats like PDF or DWF and you will get a message like the following:

Fontformatting2

... and the exported document might contain illegible text:

Fontformatting

If you know the exact problem you are looking for - in our case Font='' - then you could simply remove these from the FormattedText of the notes. In case of VBA you could use the Microsoft VBScript Regular Expressions COM library. If you are using .NET or C++ there would be other options.

' Using 'Microsoft VBScript Regular Expressions 5.5' COM library' C:\Windows\System32\vbscript.dll\3
Public Sub RemoveInvalidNoteFormatting(ByRef note As DrawingNote)' Remove bad formatting in tags like <StyleOverride Font=''>' where Font is set to nothing ''
    Dim r As New RegExp
    r.Global = True
    r.IgnoreCase = True
    r.Pattern = "Font=''"
    note.formattedText = r.Replace(note.formattedText, "")
End Sub

Public Sub RemoveInvalidFormatting()
    Dim doc As DrawingDocument
    Set doc = ThisApplication.ActiveDocument
    
    Dim sht As Sheet
    For Each sht In doc.Sheets
        Dim note As DrawingNote
        For Each note In sht.DrawingNotes
            Call RemoveInvalidNoteFormatting(note)
        Next
    Next
End Sub

Once I've run the above code on the drawing, I could export it without any problem.

Cloud and AppStore Usage Grows – Portathon Reminder

AutoCAD 2014 Vault Add-In connection

$
0
0

By Wayne Brill

You may want to get the login from the AutoCAD 2014 Vault Add-In. Here is a VB.NET example that does this. Please keep in mind that this approach has not been through any QA and is not officially supported. It does work in my tests however.

Download AutoCAD_Vault_2014_get_Connection 

This discussion group thread has a suggestion for getting the login from the AutoCAD 2013 Vault Add-In.

http://forums.autodesk.com/t5/Autodesk-Vault-Customization/Get-Securityheader-from-Vault-Login-in-AutoCAD/td-p/3773017

 

Here is the command from the AutoCAD VB.NET the project:

<CommandMethod("MyGroup", "testVault", "testVault",

    CommandFlags.Modal)> _

PublicSub test_Vault()

 

    Dim ed AsEditor = Application.DocumentManager.

                           MdiActiveDocument.Editor

    Dim myConnection As VDF.Vault.Currency.

                  Connections.Connection = Nothing

 

    ' Get the Vault connection from

    ' the AutoCAD Vault log in

    myConnection = Connectivity.Application.

                    VaultBase.ConnectionManager.

                           Instance.Connection()

 

    If myConnection IsNothingThen

        ed.WriteMessage _

             ("Unable to get Vault connection")

        Return

    EndIf

 

    ' test the connection

    Dim myRootFolder AsFolder =

        myConnection.FolderManager.RootFolder()

    Dim myWebServ AsWebServiceManager =

                 myConnection.WebServiceManager

    Dim myDocServ AsDocumentService =

                        myWebServ.DocumentService

 

    Dim MyFolder AsFolder = Nothing

    Try

        ' Need to change the string argument

        ' to a Folder in your vault

        MyFolder = myDocServ.

            GetFolderByPath("$/wb_Excel_Files")

        ed.WriteMessage("$/wb_Excel_Files created: " _

                     & MyFolder.CreateDate.ToString())

    Catch ex As System.Exception

        ed.WriteMessage("unable to get Folder.  "& _

                                       ex.ToString())

    EndTry

 

EndSub

put a drawing view name to prompted entry symbol

$
0
0

By Xiaodong Liang

Question:
The user wants to pick a drawing view, and change the result string of prmpted entry text in all sketched symbols, with the view name as the prefix.

Solution:
The prmpted entry text is defined in SketchedSymbolDefinition. And the final SkecthedSymbol provides the method SetPromptResultText which can set the result string of the specific prmpted entry text. The code below asks the user to pick one drawing view, find the specific prmpted entry text, and change its result string. It assumes the SketchedSymbolDefinition is named “MySymbol”and the prmpted entry text is named “MY_PROMPT”in the SketchedSymbolDefinition.

Actually, this workflow also applies TitleBlock, Border etc.

Dimdoc as DrawingDocument

    doc=ThisApplication.ActiveDocument

   

       

    DimoObjAsObject     

    oObj=ThisApplication.CommandManager.

                Pick(SelectionFilterEnum.kDrawingViewFilter,"Select a view:")

   

   

    IfoObjIs Nothing Then

   

    Else

         DimviewNameAsString=oObj.Name

        

         DimoNewResultText

         oNewResultText=viewName+"other description"

                 

         DimoPromptText  AsTextBox

        

        

         ' assume the name of sketched symbol definition is

         '"MySymbol"

         DimoSSDAsSketchedSymbolDefinition

         oSSD=doc.SketchedSymbolDefinitions("MySymbol")

        

        

         '' search the prompt textbox in definition

         DimoEachTextAsTextBox

         DimI

         ForI=1TooSSD.Sketch.TextBoxes.Count

          oEachText=oSSD.Sketch.TextBoxes(I)

          If(oEachText.Text="MY_PROMPT")Then

            ' found the prompt text we want to copy

              oPromptText=oEachText

            ExitFor

          EndIf

        NextI

       

        'change the result text of the SketchedSymbol

        DimoSSAsSketchedSymbol

        ForEachoSSIndoc.ActiveSheet.SketchedSymbols

           IfoSS.Definition.Name="MySymbol"Then

              MsgBox(oNewResultText)

               oSS.SetPromptResultText(oEachText,oNewResultText)

           EndIf

        Next

   

    EndIf

 

 

image


Autodesk exchange Portathon event – Day1 update

$
0
0

By Virupaksha Aithal

We are now into second day of two day Autodesk exchange Portathon event. Response is very positive, Since we began the registration for Autodesk exchange Portathon event, we received 166 registrations till date. We have received 180+ Apps as part of the event and out of which we have published 62 Apps in the exchange store already.

Last 20 hours left to submit the apps as part of Autodesk exchange Portathon event.

Autodesk exchange Portathon event – Big Success

$
0
0

By Virupaksha Aithal

The Autodesk Exchange Apps Portathon event is over. On behalf of the Autodesk Developer Network (ADN) team I’d like to say a big “thank you” to all the publishers who has registered and submitted Apps to Autodesk exchange store. We have received more than 240 Apps as part of this event.

Vault 2014 API example that Adds a file and associates it to an existing file in the vault

$
0
0

By Wayne Brill

You may need to add a file and associate it to a file that already exists in the vault. This VB.NET example shows how this can be done. The example as I tested it adds an excel file to an idw file.

connection.FileManager.AddFile() is used to add a file from the disk to the vault.

connection.FileManager.AcquireFiles() is used to check out the file that is going to have another file attached to it. (it is checked out without being downloaded).

connection.FileManager.GetFileAssociationLites() is used to get the existing file associations. A new FileAssocParam is used to add the attachment. The associated files are added as a parameter to the connection.FileManager.CheckinFile method.

The CheckinFile method has two signatures. The one with the System.IO.Stream bytes parameter is used to check in a file that was not downloaded. (the parameter is Nothing)

The connection object is an: Autodesk.DataManagement.Client.Framework.Vault.Currency.Connections.Connection

You could use the WebService function GetFileAssociationsByIds to get the associated files. One of my colleagues in engineering has found that GetFileAssociationLites() works better if there are a large number of associated files and is used in this example. (GetFileAssociationsByIds() is in the example as comments)

Note: Currently the Vault API does not support adding cad files such as Inventor Assemblies.

 Download Vault_list_Add_Associate

The example is an update to VaultList SDK sample. It has three new buttons. One of the buttons will do the “add and attach file”.

image

From the attached project:

PrivateSub Button4_Click(sender As System.Object,

       e As System.EventArgs) Handles Button4.Click

 

    ' For demonstration purposes, the information

    ' is hard-coded.

    Dim results As VDF.Vault.Results.LogInResult =

        VDF.Vault.Library.ConnectionManager.LogIn _

        ("localhost", "Vault", "Administrator", "",

        VDF.Vault.Currency.Connections. _

                  AuthenticationFlags.Standard,

         Nothing)

 

    IfNot results.Success Then

        Return

    EndIf

 

    Dim connection As  _

    VDF.Vault.Currency.Connections.Connection _

                          = results.Connection

 

    ' Need to change this string to a file on

    ' a drive that you want to add to the vault

    Dim filePath AsString =

                      "C:\Temp\myFile_test.xlsx"

 

 

    Dim myFldrCol As System.Collections.Generic.List _

               (Of VDF.Vault.Currency.Entities.Folder)

    myFldrCol = connection.FolderManager. _

GetChildFolders(connection.FolderManager.RootFolder,

                                       False, False)

 

    Dim myFolder As  _

                VDF.Vault.Currency.Entities.Folder =

                       CType(myFldrCol.ElementAt(2),

                VDF.Vault.Currency.Entities.Folder)

 

    Dim myFileIterationNewFile As  _

    VDF.Vault.Currency.Entities.FileIteration = _

                                           Nothing

 

    Using fileStream AsStream = NewFileStream _

       (filePath, FileMode.Open, FileAccess.Read)

 

        ' Add the file to the vault

        myFileIterationNewFile =

            connection.FileManager.AddFile(myFolder,

            Path.GetFileName(filePath),

            "Added by wB code",

            DateTime.Now, Nothing, Nothing,

            ACW.FileClassification.None,

            False, fileStream)

 

    EndUsing

 

    IfNot myFileIterationNewFile IsNothingThen

        Dim bAddedAttachment AsBoolean = False

        'Need to change this string to an existing

        ' file in the Vault

        Dim strNameOfFileToAddTo =

                 "wb_testing_vault_UDPs_2.idw"

 

 

        Dim fldrId AsLong =

               myFileIterationNewFile.FolderId

 

        bAddedAttachment = AddMyAttachment _

            (strNameOfFileToAddTo,

             myFileIterationNewFile.EntityIterationId,

             fldrId, connection)

 

        If bAddedAttachment = FalseThen

            MessageBox.Show _

         ("Unable to get FileIteration object")

        Else

            MessageBox.Show _

          ("Success - Added and attached file")

        EndIf

    EndIf

 

    'Logout

    VDF.Vault.Library.ConnectionManager.LogOut _

                                    (connection)

EndSub

 

 

PublicFunction AddMyAttachment _

                 (nameOfFileToAttachTo AsString,

                       myFileIterationId AsLong,

            myFolderIdOfNewFileIteration AsLong,

            connection As  _

    VDF.Vault.Currency.Connections.Connection) _

                                      AsBoolean

    Dim oFileIteration As  _

    VDF.Vault.Currency.Entities.FileIteration =

getFileIteration(nameOfFileToAttachTo, connection)

 

    If oFileIteration IsNothingThen

        MessageBox.Show("Unable to get FileIteration")

        ReturnFalse

    EndIf

 

    ' Get settings

    Dim oSettings As  _

        VDF.Vault.Settings.AcquireFilesSettings =

      New VDF.Vault.Settings.AcquireFilesSettings _

                                       (connection)

 

    ' Going to Check Out (not download file)

    oSettings.DefaultAcquisitionOption =

        VDF.Vault.Settings.AcquireFilesSettings. _

                        AcquisitionOption.Checkout

 

    ' add the file to the settings

    oSettings.AddEntityToAcquire(oFileIteration)

 

    'Do the CheckOut

    Dim myAcquireVaultSettings As  _

        VDF.Vault.Results.AcquireFilesResults

    myAcquireVaultSettings =

  connection.FileManager.AcquireFiles(oSettings)

 

    Dim oNewFileIteration As  _

        VDF.Vault.Currency.Entities.FileIteration

 

    Dim myFileAcqRes As  _

        VDF.Vault.Results.FileAcquisitionResult

 

    myFileAcqRes =

          myAcquireVaultSettings.FileResults(0)

 

    oNewFileIteration =

                   myFileAcqRes.NewFileIteration

 

    If oNewFileIteration.IsCheckedOut = TrueThen

 

        ' settings used in GetFileAssociationLites()

        Dim myFileRelationshipSettings As  _

VDF.Vault.Settings.FileRelationshipGatheringSettings

        myFileRelationshipSettings = _

New VDF.Vault.Settings.FileRelationshipGatheringSettings

 

        myFileRelationshipSettings. _

                            IncludeAttachments = True

 

        Dim myColOfFileAssocLite As  _

            System.Collections.Generic.IEnumerable _

                   (Of ACW.FileAssocLite) = Nothing

 

        myColOfFileAssocLite =

    connection.FileManager.GetFileAssociationLites _

  (NewLong() {oNewFileIteration.EntityIterationId},

                        myFileRelationshipSettings)

 

        ' Going to add new FileAssocParam

        ' objects to this list

 

        ' ArrayList to contain

        ' FileAssocParam objects

        Dim fileAssocParams AsArrayList =

                                NewArrayList

 

        ' Add FileAssocParam objects to the ArrayList

        ' using values from the collection

        ' of FileAssocLite in the collection

        ' returned from GetFileAssociationLites()

        IfNot myColOfFileAssocLite IsNothingThen

            Dim myFileAssocLite AsFileAssocLite

            '    'Go through each FileAssoLite in the

            '   in the collection of FileAssocLite

            ForEach myFileAssocLite In

                               myColOfFileAssocLite

                ' This is a new FileAssocParam that

                ' is going to be added to the List

                ' getting the properties

                Dim par AsFileAssocParam =

                               NewFileAssocParam()

                par.CldFileId =

                         myFileAssocLite.CldFileId

                par.RefId = myFileAssocLite.RefId

                par.Source = myFileAssocLite.Source

                par.Typ = myFileAssocLite.Typ

                par.ExpectedVaultPath =

                   myFileAssocLite.ExpectedVaultPath

                fileAssocParams.Add(par)

            Next

        EndIf

 

 

        ' Get the folder of the file

        ' we are associating

        Dim myDictionary AsIDictionary _

       (OfLong, VDF.Vault.Currency.Entities.Folder)

        myDictionary =

         connection.FolderManager.GetFoldersByIds _

        (NewLong() {myFolderIdOfNewFileIteration})

 

        ' Get the folder from the dictionary

        Dim keyPair As Generic.KeyValuePair _

     (OfLong, VDF.Vault.Currency.Entities.Folder)

 

        keyPair = myDictionary.First

        Dim myFldr As  _

            VDF.Vault.Currency.Entities.Folder _

                                  = keyPair.Value

 

        ' Add the new association

        Dim newFileAssocPar As  _

        FileAssocParam = NewFileAssocParam()

        newFileAssocPar.CldFileId = _

                            myFileIterationId

        newFileAssocPar.RefId = Nothing

        newFileAssocPar.Source = Nothing

        newFileAssocPar.Typ = _

                    AssociationType.Attachment

        newFileAssocPar.ExpectedVaultPath = _

                            myFldr.FolderPath

 

 

        ' Add our new FileAssocParam

        fileAssocParams.Add(newFileAssocPar)

 

        ' Populate this with the FileAssocParam

        ' objects that we create from properties'

        ' in the FileAssocArray and the new file

        Dim myFileAssocParamArray AsFileAssocParam() _

            = DirectCast(fileAssocParams.ToArray _

          (GetType(FileAssocParam)), FileAssocParam())

 

        ' Use the overloaded method of CheckInFile

        ' that takes a stream This will allow

        ' checking in a file that has not been

        ' downloaded

        ' (by passing in a stream that is Nothing)

        Dim myStream As System.IO.Stream = Nothing

        connection.FileManager.CheckinFile _

            (oFileIteration, "wbTesting", False,

                                       Date.Now,

                          myFileAssocParamArray,

                          Nothing, False, Nothing,

                      ACW.FileClassification.None,

                                  False, myStream)

 

    Else

        MessageBox.Show("Unable to check out")

        ReturnFalse

    EndIf

 

    ReturnTrue

 

EndFunction

Method to get the age and name of an ETO Member file

$
0
0

By Wayne Brill

You may want to get the name and age of a member file used by an Inventor Engineer-To-Order adopted part. Here are a couple of methods that show how this can be done. Notice it uses the default rule memberPathName to get the path to the member file. .NET System.IO methods are used to get the difference between the current time and the last time the member file was written to.

Note: If you use cacheFileName to create your own naming scheme for member files you would need to update this example to get the get the name of the member file. The cacheFileName gives you the filename. The memberPathName ensures that the file specified by cacheFileName is created. Depending on the scenario, one of these two Rules can be used.

Methods from an ETO Design:

Method IPTFileAgeInFullDays( p As Part) As Integer

      If Not p.IsKindOf?( :IvAdoptedPart) Then _

       Error( "Wrong Part", "IvAdoptedPart expected")

 

      Dim memberPathname As String = p.memberPathname

      Dim  memberCacheFileName As String = p.cacheFileName

      printValue(memberCacheFileName)

      printValue(memberPathName)

 

      Return FileAgeInFullDays( memberPathname)

 

End Method

 

'This Method returns the age of the existing file

'(based on last modification time), In full days :

 

Method FileAgeInFullDays( fileName As String) As Integer

      If Not system.IO.File.Exists(fileName) _

      Then Error("Error", "File "  + fileName + _

      " does not exist.")

 

      Dim lwt = system.IO.File.GetLastWriteTime( fileName)

      Dim now = system.Datetime.Now

      Dim span = now.Subtract( lwt)

      Return floor(span.TotalDays)

End Method

ETO Studio - "No such Interface supported" error when saving a newly created project

$
0
0

By Wayne Brill

If you use the Visual Studio ETO wizard to create a new ETO project an error may occur when you Save the project. (If it was created in the C:\Users\xxxxxx\AppData\Local\Temporary Projects\)

image

Error that can occur when you do a Save All:

image

The work around to this problem is to enable “Save new projects when created” in Visual Studio Options:

image

With this setting enabled a new project is created and saved without error. When this option is unchecked you can create and discard projects quickly. Unfortunately this is adversely effecting the creation of new ETO Studio projects. This behavior has been reported to ETO Engineering.

Viewing all 516 articles
Browse latest View live