//This function gets the transform matrix of a given component respect to its father.
        public static MyTransformMatrix GetTransformMatrix(Component2 swComponent, SldWorks swApplication)
        {
            var componentXForm = swComponent.GetTotalTransform(true);

            var newMyTransformMatrix = new MyTransformMatrix();

            if (componentXForm != null)
            {
                var xForm = (Array)componentXForm.ArrayData;
                double[,] newRotationMatrix = new double[3, 3]
                {
                    { (double)xForm.GetValue(0), (double)xForm.GetValue(3), (double)xForm.GetValue(6) },
                    { (double)xForm.GetValue(1), (double)xForm.GetValue(4), (double)xForm.GetValue(7) },
                    { (double)xForm.GetValue(2), (double)xForm.GetValue(5), (double)xForm.GetValue(8) }
                };
                double[] newTranslationalVector =
                { (double)xForm.GetValue(9), (double)xForm.GetValue(10), (double)xForm.GetValue(11) };
                newMyTransformMatrix = new MyTransformMatrix(newRotationMatrix, newTranslationalVector,
                                                             (double)xForm.GetValue(12));
            }
            else
            {
                swApplication.SendMsgToUser("La componente " + swComponent.Name +
                                            " ha matrice di trasformazione NULLA ---->> ERRORE.");
            }


            return(newMyTransformMatrix);
        }
Exemplo n.º 2
0
        public static bool ConvertMateToPython(
            ref Feature swMateFeature,
            ref string asciitext,
            ref ISldWorks mSWApplication,
            ref Hashtable saved_parts,
            ref int num_link,
            ref MathTransform roottrasf,
            ref Component2 assemblyofmates
            )
        {
            if (swMateFeature == null)
            {
                return(false);
            }

            Mate2 swMate = (Mate2)swMateFeature.GetSpecificFeature2();

            if (swMate == null)
            {
                return(false);
            }

            object foo = null;

            bool[] suppressedflags;
            suppressedflags = (bool[])swMateFeature.IsSuppressed2((int)swInConfigurationOpts_e.swThisConfiguration, foo);
            if (suppressedflags[0] == true)
            {
                return(false);
            }

            if (swMate.GetMateEntityCount() >= 2)
            {
                // Get the mated parts
                MateEntity2 swEntityA = swMate.MateEntity(0);
                MateEntity2 swEntityB = swMate.MateEntity(1);
                Component2  swCompA   = swEntityA.ReferenceComponent;
                Component2  swCompB   = swEntityB.ReferenceComponent;
                double[]    paramsA   = (double[])swEntityA.EntityParams;
                double[]    paramsB   = (double[])swEntityB.EntityParams;
                // this is needed because parts might reside in subassemblies, and mate params are expressed in parent subassembly
                MathTransform invroottrasf = (MathTransform)roottrasf.Inverse();
                MathTransform trA          = roottrasf;
                MathTransform trB          = roottrasf;

                if (assemblyofmates != null)
                {
                    MathTransform partrasfA = assemblyofmates.GetTotalTransform(true);
                    if (partrasfA != null)
                    {
                        trA = partrasfA.IMultiply(invroottrasf); // row-ordered transf. -> reverse mult.order!
                    }
                    MathTransform partrasfB = assemblyofmates.GetTotalTransform(true);
                    if (partrasfB != null)
                    {
                        trB = partrasfB.IMultiply(invroottrasf); // row-ordered transf. -> reverse mult.order!
                    }
                }


                // Fetch the python names using hash map (python names added when scanning parts)
                ModelDocExtension swModelDocExt = default(ModelDocExtension);
                ModelDoc2         swModel       = (ModelDoc2)mSWApplication.ActiveDoc;
                swModelDocExt = swModel.Extension;
                String name1 = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompA)];
                String name2 = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompB)];

                // Only constraints between two parts or part & layout can be created
                if (((name1 != null) || (name2 != null)) && (name1 != name2))
                {
                    CultureInfo bz = new CultureInfo("en-BZ");

                    if (name1 == null)
                    {
                        name1 = "body_0";
                    }
                    if (name2 == null)
                    {
                        name2 = "body_0";
                    }

                    // Add some comment in Python, to list the referenced SW items
                    asciitext += "\n# Mate constraint: " + swMateFeature.Name + " [" + swMateFeature.GetTypeName2() + "]" + " type:" + swMate.Type + " align:" + swMate.Alignment + " flip:" + swMate.Flipped + "\n";
                    for (int e = 0; e < swMate.GetMateEntityCount(); e++)
                    {
                        MateEntity2 swEntityN = swMate.MateEntity(e);
                        Component2  swCompN   = swEntityN.ReferenceComponent;
                        String      ce_nameN  = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompN)];
                        if (ce_nameN == "")
                        {
                            ce_nameN = "body_0"; // reference assembly
                        }
                        asciitext += "#   Entity " + e + ": C::E name: " + ce_nameN + " , SW name: " + swCompN.Name2 + " ,  SW ref.type:" + swEntityN.Reference.GetType() + " (" + swEntityN.ReferenceType2 + ")\n";
                    }
                    asciitext += "\n";

                    //
                    // For each type of SW mate, see which C::E mate constraint(s)
                    // must be created. Some SW mates correspond to more than one C::E constraints.
                    //

                    bool   swapAB_1             = false;
                    bool   do_CHmate_Xdistance  = false;
                    double do_distance_val      = 0.0;
                    bool   do_CHmate_parallel   = false;
                    bool   do_parallel_flip     = false;
                    bool   do_CHmate_orthogonal = false;
                    bool   do_CHmate_spherical  = false;
                    bool   do_CHmate_pointline  = false;

                    // to simplify things later...
                    // NOTE: swMate.MateEntity(0).Reference.GetType() seems equivalent to  swMate.MateEntity(0).ReferenceType2
                    // but in some cases the latter fails.

                    /*
                     * bool entity_0_as_FACE   = (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelFACES);
                     * bool entity_0_as_EDGE   = (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelEDGES) ||
                     *                        (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelSKETCHSEGS) ||
                     *                        (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelDATUMAXES);
                     * bool entity_0_as_VERTEX = (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelVERTICES) ||
                     *                        (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                     *                        (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelDATUMPOINTS);
                     *
                     * bool entity_1_as_FACE   = (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelFACES);
                     * bool entity_1_as_EDGE   = (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelEDGES) ||
                     *                        (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelSKETCHSEGS) ||
                     *                        (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelDATUMAXES);
                     * bool entity_1_as_VERTEX = (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelVERTICES) ||
                     *                        (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                     *                        (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelDATUMPOINTS);
                     */

                    // NOTE: swMate.MateEntity(0).Reference.GetType() seems equivalent to  swMate.MateEntity(0).ReferenceType2
                    // but in some cases the latter fails. However, sometimes swMate.MateEntity(0).Reference.GetType() is null ReferenceType2 is ok,
                    // so do the following trick:
                    int entity0_ref = swMate.MateEntity(0).Reference.GetType();
                    if (entity0_ref == (int)swSelectType_e.swSelNOTHING)
                    {
                        entity0_ref = swMate.MateEntity(0).ReferenceType2;
                    }
                    int entity1_ref = swMate.MateEntity(1).Reference.GetType();
                    if (entity1_ref == (int)swSelectType_e.swSelNOTHING)
                    {
                        entity1_ref = swMate.MateEntity(1).ReferenceType2;
                    }

                    bool entity_0_as_FACE = (entity0_ref == (int)swSelectType_e.swSelFACES) ||
                                            (entity0_ref == (int)swSelectType_e.swSelDATUMPLANES);
                    bool entity_0_as_EDGE = (entity0_ref == (int)swSelectType_e.swSelEDGES) ||
                                            (entity0_ref == (int)swSelectType_e.swSelSKETCHSEGS) ||
                                            (entity0_ref == (int)swSelectType_e.swSelDATUMAXES);
                    bool entity_0_as_VERTEX = (entity0_ref == (int)swSelectType_e.swSelVERTICES) ||
                                              (entity0_ref == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                              (entity0_ref == (int)swSelectType_e.swSelDATUMPOINTS);

                    bool entity_1_as_FACE = (entity1_ref == (int)swSelectType_e.swSelFACES) ||
                                            (entity1_ref == (int)swSelectType_e.swSelDATUMPLANES);
                    bool entity_1_as_EDGE = (entity1_ref == (int)swSelectType_e.swSelEDGES) ||
                                            (entity1_ref == (int)swSelectType_e.swSelSKETCHSEGS) ||
                                            (entity1_ref == (int)swSelectType_e.swSelDATUMAXES);
                    bool entity_1_as_VERTEX = (entity1_ref == (int)swSelectType_e.swSelVERTICES) ||
                                              (entity1_ref == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                              (entity1_ref == (int)swSelectType_e.swSelDATUMPOINTS);


                    Point3D  cA = new Point3D(0, 0, 0);
                    Point3D  cB = new Point3D(0, 0, 0);
                    Vector3D dA = new Vector3D(1, 0, 0);
                    Vector3D dB = new Vector3D(1, 0, 0);

                    Point3D cAloc = new Point3D(paramsA[0], paramsA[1], paramsA[2]);
                    cA = SWTaskpaneHost.PointTransform(cAloc, ref trA);
                    Point3D cBloc = new Point3D(paramsB[0], paramsB[1], paramsB[2]);
                    cB = SWTaskpaneHost.PointTransform(cBloc, ref trB);

                    if (!entity_0_as_VERTEX)
                    {
                        Vector3D dAloc = new Vector3D(paramsA[3], paramsA[4], paramsA[5]);
                        dA = SWTaskpaneHost.DirTransform(dAloc, ref trA);
                    }

                    if (!entity_1_as_VERTEX)
                    {
                        Vector3D dBloc = new Vector3D(paramsB[3], paramsB[4], paramsB[5]);
                        dB = SWTaskpaneHost.DirTransform(dBloc, ref trB);
                    }



                    if (swMateFeature.GetTypeName2() == "MateCoincident")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_spherical = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_pointline = true;
                            swapAB_1            = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_Xdistance = true;
                            swapAB_1            = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance  = true;
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_Xdistance  = true;
                            do_CHmate_orthogonal = true;
                            swapAB_1             = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                        {
                            do_parallel_flip = true;
                        }
                    }

                    if (swMateFeature.GetTypeName2() == "MateConcentric")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_pointline = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_pointline = true;
                            swapAB_1            = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel  = true;
                            swapAB_1            = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                        {
                            do_parallel_flip = true;
                        }
                    }

                    if (swMateFeature.GetTypeName2() == "MateParallel")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_orthogonal = true;
                            swapAB_1             = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                        {
                            do_parallel_flip = true;
                        }
                    }


                    if (swMateFeature.GetTypeName2() == "MatePerpendicular")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_parallel = true;
                            swapAB_1           = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                        {
                            do_parallel_flip = true;
                        }
                    }

                    if (swMateFeature.GetTypeName2() == "MateDistanceDim")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_Xdistance = true;
                            swapAB_1            = true;
                        }

                        //***TO DO*** cases of distance line-vs-line and line-vs-vertex and vert-vert.
                        //           Those will require another .cpp ChLinkMate specialized class(es).

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                        {
                            do_parallel_flip = true;
                        }

                        // Get the imposed distance value, in SI units
                        string confnames = "";
                        do_distance_val = swMate.DisplayDimension.GetDimension2(0).IGetSystemValue3((int)swInConfigurationOpts_e.swThisConfiguration, 0, ref confnames);

                        if (swMate.Flipped)
                        {
                            do_distance_val = -do_distance_val;
                        }
                    }

                    ////
                    //// WRITE PYHTON CODE CORRESPONDING TO CONSTRAINTS
                    ////

                    if (do_CHmate_Xdistance)
                    {
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateXdistance()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cA.X * ChScale.L,
                                                   cA.Y * ChScale.L,
                                                   cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cB.X * ChScale.L,
                                                   cB.Y * ChScale.L,
                                                   cB.Z * ChScale.L);
                        if (!entity_0_as_VERTEX)
                        {
                            asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       dA.X, dA.Y, dA.Z);
                        }
                        if (!entity_1_as_VERTEX)
                        {
                            asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       dB.X, dB.Y, dB.Z);
                        }

                        // Initialize link, by setting the two csys, in absolute space,
                        if (!swapAB_1)
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dB)\n", linkname, name1, name2);
                        }
                        else
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dA)\n", linkname, name2, name1);
                        }

                        //if (do_distance_val!=0)
                        asciitext += String.Format(bz, "{0}.SetDistance({1})\n", linkname,
                                                   do_distance_val * ChScale.L * -1);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                    }

                    if (do_CHmate_parallel)
                    {
                        if (Math.Abs(Vector3D.DotProduct(dA, dB)) > 0.98)
                        {
                            num_link++;
                            String linkname = "link_" + num_link;
                            asciitext += String.Format(bz, "{0} = chrono.ChLinkMateParallel()\n", linkname);

                            asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       cA.X * ChScale.L,
                                                       cA.Y * ChScale.L,
                                                       cA.Z * ChScale.L);
                            asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       dA.X, dA.Y, dA.Z);
                            asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       cB.X * ChScale.L,
                                                       cB.Y * ChScale.L,
                                                       cB.Z * ChScale.L);
                            asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       dB.X, dB.Y, dB.Z);

                            if (do_parallel_flip)
                            {
                                asciitext += String.Format(bz, "{0}.SetFlipped(True)\n", linkname);
                            }

                            // Initialize link, by setting the two csys, in absolute space,
                            if (!swapAB_1)
                            {
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);
                            }
                            else
                            {
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dB,dA)\n", linkname, name2, name1);
                            }

                            asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                            // Insert to a list of exported items
                            asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                        }
                        else
                        {
                            asciitext += "\n# ChLinkMateParallel skipped because directions not parallel! \n";
                        }
                    }

                    if (do_CHmate_orthogonal)
                    {
                        if (Math.Abs(Vector3D.DotProduct(dA, dB)) < 0.02)
                        {
                            num_link++;
                            String linkname = "link_" + num_link;
                            asciitext += String.Format(bz, "{0} = chrono.ChLinkMateOrthogonal()\n", linkname);

                            asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       cA.X * ChScale.L,
                                                       cA.Y * ChScale.L,
                                                       cA.Z * ChScale.L);
                            asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       dA.X, dA.Y, dA.Z);
                            asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       cB.X * ChScale.L,
                                                       cB.Y * ChScale.L,
                                                       cB.Z * ChScale.L);
                            asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                       dB.X, dB.Y, dB.Z);

                            // Initialize link, by setting the two csys, in absolute space,
                            if (!swapAB_1)
                            {
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);
                            }
                            else
                            {
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dB,dA)\n", linkname, name2, name1);
                            }

                            asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                            // Insert to a list of exported items
                            asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                        }
                        else
                        {
                            asciitext += "\n# ChLinkMateOrthogonal skipped because directions not orthogonal! \n";
                        }
                    }

                    if (do_CHmate_spherical)
                    {
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateSpherical()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cA.X * ChScale.L,
                                                   cA.Y * ChScale.L,
                                                   cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cB.X * ChScale.L,
                                                   cB.Y * ChScale.L,
                                                   cB.Z * ChScale.L);

                        // Initialize link, by setting the two csys, in absolute space,
                        if (!swapAB_1)
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB)\n", linkname, name1, name2);
                        }
                        else
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA)\n", linkname, name2, name1);
                        }

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                    }

                    if (do_CHmate_pointline)
                    {
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateGeneric()\n", linkname);
                        asciitext += String.Format(bz, "{0}.SetConstrainedCoords(False, True, True, False, False, False)\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cA.X * ChScale.L,
                                                   cA.Y * ChScale.L,
                                                   cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cB.X * ChScale.L,
                                                   cB.Y * ChScale.L,
                                                   cB.Z * ChScale.L);
                        if (!entity_0_as_VERTEX)
                        {
                            asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n", dA.X, dA.Y, dA.Z);
                        }
                        else
                        {
                            asciitext += String.Format(bz, "dA = chrono.VNULL\n");
                        }
                        if (!entity_1_as_VERTEX)
                        {
                            asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n", dB.X, dB.Y, dB.Z);
                        }
                        else
                        {
                            asciitext += String.Format(bz, "dB = chrono.VNULL\n");
                        }

                        // Initialize link, by setting the two csys, in absolute space,
                        if (!swapAB_1)
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);
                        }
                        else
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dB,dA)\n", linkname, name2, name1);
                        }

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                    }



                    // Now, do some other special mate type that did not fall in combinations
                    // of do_CHmate_pointline, do_CHmate_spherical, etc etc

                    if (swMateFeature.GetTypeName2() == "MateHinge")
                    {
                        // auto flip direction if anti aligned (seems that this is assumed automatically in MateHinge in SW)
                        if (Vector3D.DotProduct(dA, dB) < 0)
                        {
                            dB.Negate();
                        }

                        // Hinge constraint must be splitted in two C::E constraints: a coaxial and a point-vs-plane
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateCoaxial()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cA.X * ChScale.L,
                                                   cA.Y * ChScale.L,
                                                   cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   dA.X, dA.Y, dA.Z);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cB.X * ChScale.L,
                                                   cB.Y * ChScale.L,
                                                   cB.Z * ChScale.L);
                        asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   dB.X, dB.Y, dB.Z);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);


                        // Initialize link, by setting the two csys, in absolute space,
                        asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);

                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n", linkname);


                        // NOTE!!! The 'hinge' mate uses 4 references: fetch the two others remaining
                        // and build another C::E link, for point-vs-face mating

                        MateEntity2   swEntityC = swMate.MateEntity(2);
                        MateEntity2   swEntityD = swMate.MateEntity(3);
                        Component2    swCompC   = swEntityC.ReferenceComponent;
                        Component2    swCompD   = swEntityD.ReferenceComponent;
                        double[]      paramsC   = (double[])swEntityC.EntityParams;
                        double[]      paramsD   = (double[])swEntityD.EntityParams;
                        String        name3     = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompC)];
                        String        name4     = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompD)];
                        MathTransform trC       = roottrasf;
                        MathTransform trD       = roottrasf;

                        if (assemblyofmates != null)
                        {
                            MathTransform partrasfC = assemblyofmates.GetTotalTransform(true);
                            if (partrasfC != null)
                            {
                                trC = partrasfC.IMultiply(invroottrasf);
                            }
                            MathTransform partrasfD = assemblyofmates.GetTotalTransform(true);
                            if (partrasfD != null)
                            {
                                trD = partrasfD.IMultiply(invroottrasf);
                            }
                        }

                        // NOTE: swMate.MateEntity(0).Reference.GetType() seems equivalent to  swMate.MateEntity(0).ReferenceType2
                        // but in some cases the latter fails. However, sometimes swMate.MateEntity(0).Reference.GetType() is null ReferenceType2 is ok,
                        // so do the following trick:
                        int entity2_ref = swMate.MateEntity(2).Reference.GetType();
                        if (entity2_ref == (int)swSelectType_e.swSelNOTHING)
                        {
                            entity2_ref = swMate.MateEntity(2).ReferenceType2;
                        }
                        int entity3_ref = swMate.MateEntity(3).Reference.GetType();
                        if (entity3_ref == (int)swSelectType_e.swSelNOTHING)
                        {
                            entity3_ref = swMate.MateEntity(3).ReferenceType2;
                        }

                        bool entity_2_as_VERTEX = (entity2_ref == (int)swSelectType_e.swSelVERTICES) ||
                                                  (entity2_ref == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                                  (entity2_ref == (int)swSelectType_e.swSelDATUMPOINTS);
                        bool entity_3_as_VERTEX = (entity3_ref == (int)swSelectType_e.swSelVERTICES) ||
                                                  (entity3_ref == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                                  (entity3_ref == (int)swSelectType_e.swSelDATUMPOINTS);

                        Point3D  cC = new Point3D(0, 0, 0);
                        Point3D  cD = new Point3D(0, 0, 0);
                        Vector3D dC = new Vector3D(1, 0, 0);
                        Vector3D dD = new Vector3D(1, 0, 0);

                        Point3D cCloc = new Point3D(paramsC[0], paramsC[1], paramsC[2]);
                        cC = SWTaskpaneHost.PointTransform(cCloc, ref trC);
                        Point3D cDloc = new Point3D(paramsD[0], paramsD[1], paramsD[2]);
                        cD = SWTaskpaneHost.PointTransform(cDloc, ref trD);

                        if (!entity_2_as_VERTEX)
                        {
                            Vector3D dCloc = new Vector3D(paramsC[3], paramsC[4], paramsC[5]);
                            dC = SWTaskpaneHost.DirTransform(dCloc, ref trC);
                        }

                        if (!entity_3_as_VERTEX)
                        {
                            Vector3D dDloc = new Vector3D(paramsD[3], paramsD[4], paramsD[5]);
                            dD = SWTaskpaneHost.DirTransform(dDloc, ref trD);
                        }

                        num_link++;
                        linkname   = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateXdistance()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cC.X * ChScale.L,
                                                   cC.Y * ChScale.L,
                                                   cC.Z * ChScale.L);
                        asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   dC.X, dC.Y, dC.Z);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   cD.X * ChScale.L,
                                                   cD.Y * ChScale.L,
                                                   cD.Z * ChScale.L);
                        asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                                   dD.X, dD.Y, dD.Z);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);


                        // Initialize link, by setting the two csys, in absolute space,
                        if (entity_2_as_VERTEX)
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA)\n", linkname, name3, name4);
                        }
                        else
                        {
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dB)\n", linkname, name3, name4);
                        }

                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n", linkname);

                        return(true);
                    }
                }
            }
            return(false);
        }
        public static bool ConvertMateToPython( 
                                    ref Feature swMateFeature,
                                    ref string asciitext, 
                                    ref ISldWorks mSWApplication,
                                    ref Hashtable saved_parts,
                                    ref int num_link,
                                    ref MathTransform roottrasf,
                                    ref Component2 assemblyofmates
                                    )
        {
            if (swMateFeature == null)
                return false;

            Mate2 swMate = (Mate2)swMateFeature.GetSpecificFeature2();

            if (swMate == null)
                return false;

            object foo =null;
            bool[] suppressedflags;
            suppressedflags = (bool[])swMateFeature.IsSuppressed2((int)swInConfigurationOpts_e.swThisConfiguration, foo);
            if (suppressedflags[0] == true)
                return false;

            if (swMate.GetMateEntityCount() >= 2)
            {
                 // Get the mated parts
                MateEntity2 swEntityA = swMate.MateEntity(0);
                MateEntity2 swEntityB = swMate.MateEntity(1);
                Component2 swCompA = swEntityA.ReferenceComponent;
                Component2 swCompB = swEntityB.ReferenceComponent;
                double[] paramsA = (double[])swEntityA.EntityParams;
                double[] paramsB = (double[])swEntityB.EntityParams;
                 // this is needed because parts might reside in subassemblies, and mate params are expressed in parent subassembly
                MathTransform invroottrasf = (MathTransform)roottrasf.Inverse();
                MathTransform trA = roottrasf;
                MathTransform trB = roottrasf;

                if (assemblyofmates != null)
                {
                    MathTransform partrasfA = assemblyofmates.GetTotalTransform(true);
                    if (partrasfA != null)
                        trA = partrasfA.IMultiply(invroottrasf); // row-ordered transf. -> reverse mult.order!
                    MathTransform partrasfB = assemblyofmates.GetTotalTransform(true);
                    if (partrasfB != null)
                        trB = partrasfB.IMultiply(invroottrasf); // row-ordered transf. -> reverse mult.order!
                }

                 // Fetch the python names using hash map (python names added when scanning parts)
                ModelDocExtension swModelDocExt = default(ModelDocExtension);
                ModelDoc2 swModel = (ModelDoc2)mSWApplication.ActiveDoc;
                swModelDocExt = swModel.Extension;
                String name1 = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompA)];
                String name2 = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompB)];

                 // Only constraints between two parts or part & layout can be created
                if ( ((name1 != null) || (name2 != null)) && (name1 != name2) )
                {
                    CultureInfo bz = new CultureInfo("en-BZ");

                    if (name1 == null)
                        name1 = "body_0";
                    if (name2 == null)
                        name2 = "body_0";

                    // Add some comment in Python, to list the referenced SW items
                    asciitext += "\n# Mate constraint: " + swMateFeature.Name + " [" + swMateFeature.GetTypeName2() + "]" + " type:" + swMate.Type + " align:" + swMate.Alignment + " flip:" + swMate.Flipped + "\n";
                    for (int e = 0; e < swMate.GetMateEntityCount(); e++)
                    {
                        MateEntity2 swEntityN = swMate.MateEntity(e);
                        Component2 swCompN = swEntityN.ReferenceComponent;
                        String ce_nameN = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompN)];
                        asciitext += "#   Entity " + e + ": C::E name: " + ce_nameN + " , SW name: " + swCompN.Name2 + " ,  SW ref.type:" + swEntityN.Reference.GetType() + " (" + swEntityN.ReferenceType2 + ")\n";
                    }
                    asciitext += "\n";

                    //
                    // For each type of SW mate, see which C::E mate constraint(s)
                    // must be created. Some SW mates correspond to more than one C::E constraints.
                    //

                    bool swapAB_1 = false;
                    bool do_CHmate_Xdistance  = false;
                    double do_distance_val  = 0.0;
                    bool do_CHmate_parallel   = false;
                    bool   do_parallel_flip     = false;
                    bool do_CHmate_orthogonal = false;
                    bool do_CHmate_spherical  = false;
                    bool do_CHmate_pointline  = false;

                    // to simplify things later...
                    // NOTE: swMate.MateEntity(0).Reference.GetType() seems equivalent to  swMate.MateEntity(0).ReferenceType2
                    // but in some cases the latter fails.
                    bool entity_0_as_FACE   = (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelFACES);
                    bool entity_0_as_EDGE   = (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelEDGES) ||
                                              (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelSKETCHSEGS) ||
                                              (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelDATUMAXES);
                    bool entity_0_as_VERTEX = (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelVERTICES) ||
                                              (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                              (swMate.MateEntity(0).Reference.GetType() == (int)swSelectType_e.swSelDATUMPOINTS);

                    bool entity_1_as_FACE   = (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelFACES);
                    bool entity_1_as_EDGE   = (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelEDGES) ||
                                              (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelSKETCHSEGS) ||
                                              (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelDATUMAXES);
                    bool entity_1_as_VERTEX = (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelVERTICES) ||
                                              (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                              (swMate.MateEntity(1).Reference.GetType() == (int)swSelectType_e.swSelDATUMPOINTS);

                    Point3D cA  = new Point3D(0, 0, 0);
                    Point3D cB  = new Point3D(0, 0, 0);
                    Vector3D dA = new Vector3D(1, 0, 0);
                    Vector3D dB = new Vector3D(1, 0, 0);

                    Point3D cAloc = new Point3D(paramsA[0], paramsA[1], paramsA[2]);
                    cA = SWTaskpaneHost.PointTransform(cAloc, ref trA);
                    Point3D cBloc = new Point3D(paramsB[0], paramsB[1], paramsB[2]);
                    cB = SWTaskpaneHost.PointTransform(cBloc, ref trB);

                    if (!entity_0_as_VERTEX)
                    {
                        Vector3D dAloc = new Vector3D(paramsA[3], paramsA[4], paramsA[5]);
                        dA = SWTaskpaneHost.DirTransform(dAloc, ref trA);
                    }

                    if (!entity_1_as_VERTEX)
                    {
                        Vector3D dBloc = new Vector3D(paramsB[3], paramsB[4], paramsB[5]);
                        dB = SWTaskpaneHost.DirTransform(dBloc, ref trB);
                    }

                    if (swMateFeature.GetTypeName2() == "MateCoincident")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel  = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_spherical = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_pointline = true;
                            swapAB_1 = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_Xdistance = true;
                            swapAB_1 = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_Xdistance = true;
                            do_CHmate_orthogonal = true;
                            swapAB_1 = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                            do_parallel_flip = true;
                    }

                    if (swMateFeature.GetTypeName2() == "MateConcentric")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_pointline = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_pointline = true;
                            swapAB_1 = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_pointline = true;
                            do_CHmate_parallel = true;
                            swapAB_1 = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                            do_parallel_flip = true;
                    }

                    if (swMateFeature.GetTypeName2() == "MateParallel")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_orthogonal = true;
                            swapAB_1 = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                            do_parallel_flip = true;
                    }

                    if (swMateFeature.GetTypeName2() == "MatePerpendicular")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_orthogonal = true;
                        }
                        if ((entity_0_as_EDGE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_parallel = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_EDGE))
                        {
                            do_CHmate_parallel = true;
                            swapAB_1 = true;
                        }

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                            do_parallel_flip = true;
                    }

                    if (swMateFeature.GetTypeName2() == "MateDistanceDim")
                    {
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance  = true;
                            do_CHmate_parallel   = true;
                        }
                        if ((entity_0_as_VERTEX) &&
                            (entity_1_as_FACE))
                        {
                            do_CHmate_Xdistance = true;
                        }
                        if ((entity_0_as_FACE) &&
                            (entity_1_as_VERTEX))
                        {
                            do_CHmate_Xdistance = true;
                            swapAB_1 = true;
                        }

                        //***TO DO*** cases of distance line-vs-line and line-vs-vertex and vert-vert.
                        //           Those will require another .cpp ChLinkMate specialized class(es).

                        if (swMate.Alignment == (int)swMateAlign_e.swMateAlignANTI_ALIGNED)
                            do_parallel_flip = true;

                        // Get the imposed distance value, in SI units
                        string confnames = "";
                        do_distance_val = swMate.DisplayDimension.GetDimension2(0).IGetSystemValue3((int)swInConfigurationOpts_e.swThisConfiguration, 0, ref confnames);

                        if (swMate.Flipped)
                            do_distance_val = -do_distance_val;
                    }

                    ////
                    //// WRITE PYHTON CODE CORRESPONDING TO CONSTRAINTS
                    ////

                    if (do_CHmate_Xdistance)
                    {
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateXdistance()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cA.X * ChScale.L,
                                  cA.Y * ChScale.L,
                                  cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cB.X * ChScale.L,
                                  cB.Y * ChScale.L,
                                  cB.Z * ChScale.L);
                        if (!entity_0_as_VERTEX)
                         asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  dA.X, dA.Y, dA.Z);
                        if (!entity_1_as_VERTEX)
                         asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  dB.X, dB.Y, dB.Z);

                        // Initialize link, by setting the two csys, in absolute space,
                        if (!swapAB_1)
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dB)\n", linkname, name1, name2);
                        else
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dA)\n", linkname, name2, name1);

                        //if (do_distance_val!=0)
                            asciitext += String.Format(bz, "{0}.SetDistance({1})\n", linkname,
                                do_distance_val * ChScale.L *-1);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                    }

                    if (do_CHmate_parallel)
                    {
                        if (Math.Abs(Vector3D.DotProduct(dA, dB)) > 0.98)
                        {
                            num_link++;
                            String linkname = "link_" + num_link;
                            asciitext += String.Format(bz, "{0} = chrono.ChLinkMateParallel()\n", linkname);

                            asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      cA.X * ChScale.L,
                                      cA.Y * ChScale.L,
                                      cA.Z * ChScale.L);
                            asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      dA.X, dA.Y, dA.Z);
                            asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      cB.X * ChScale.L,
                                      cB.Y * ChScale.L,
                                      cB.Z * ChScale.L);
                            asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      dB.X, dB.Y, dB.Z);

                            if (do_parallel_flip)
                                asciitext += String.Format(bz, "{0}.SetFlipped(True)\n", linkname);

                            // Initialize link, by setting the two csys, in absolute space,
                            if (!swapAB_1)
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);
                            else
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dB,dA)\n", linkname, name2, name1);

                            asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                            // Insert to a list of exported items
                            asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                        }
                        else
                        {
                            asciitext += "\n# ChLinkMateParallel skipped because directions not parallel! \n";
                        }
                    }

                    if (do_CHmate_orthogonal)
                    {
                        if (Math.Abs(Vector3D.DotProduct(dA, dB)) < 0.02)
                        {
                            num_link++;
                            String linkname = "link_" + num_link;
                            asciitext += String.Format(bz, "{0} = chrono.ChLinkMateOrthogonal()\n", linkname);

                            asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      cA.X * ChScale.L,
                                      cA.Y * ChScale.L,
                                      cA.Z * ChScale.L);
                            asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      dA.X, dA.Y, dA.Z);
                            asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      cB.X * ChScale.L,
                                      cB.Y * ChScale.L,
                                      cB.Z * ChScale.L);
                            asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                      dB.X, dB.Y, dB.Z);

                            // Initialize link, by setting the two csys, in absolute space,
                            if (!swapAB_1)
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);
                            else
                                asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dB,dA)\n", linkname, name2, name1);

                            asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                            // Insert to a list of exported items
                            asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                        }
                        else
                        {
                            asciitext += "\n# ChLinkMateOrthogonal skipped because directions not orthogonal! \n";
                        }
                    }

                    if (do_CHmate_spherical)
                    {
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateSpherical()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cA.X * ChScale.L,
                                  cA.Y * ChScale.L,
                                  cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cB.X * ChScale.L,
                                  cB.Y * ChScale.L,
                                  cB.Z * ChScale.L);

                        // Initialize link, by setting the two csys, in absolute space,
                        if (!swapAB_1)
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB)\n", linkname, name1, name2);
                        else
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA)\n", linkname, name2, name1);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                    }

                    if (do_CHmate_pointline)
                    {
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateGeneric()\n", linkname);
                        asciitext += String.Format(bz, "{0}.SetConstrainedCoords(False, True, True, False, False, False)\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cA.X * ChScale.L,
                                  cA.Y * ChScale.L,
                                  cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cB.X * ChScale.L,
                                  cB.Y * ChScale.L,
                                  cB.Z * ChScale.L);
                        if (!entity_0_as_VERTEX)
                            asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n", dA.X, dA.Y, dA.Z);
                        else
                            asciitext += String.Format(bz, "dA = chrono.VNULL\n");
                        if (!entity_1_as_VERTEX)
                            asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n", dB.X, dB.Y, dB.Z);
                        else
                            asciitext += String.Format(bz, "dB = chrono.VNULL\n");

                        // Initialize link, by setting the two csys, in absolute space,
                        if (!swapAB_1)
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);
                        else
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cB,cA,dB,dA)\n", linkname, name2, name1);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);
                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n\n", linkname);
                    }

                    // Now, do some other special mate type that did not fall in combinations
                    // of do_CHmate_pointline, do_CHmate_spherical, etc etc

                    if (swMateFeature.GetTypeName2() == "MateHinge")
                    {
                        // auto flip direction if anti aligned (seems that this is assumed automatically in MateHinge in SW)
                        if (Vector3D.DotProduct(dA, dB) < 0)
                            dB.Negate();

                        // Hinge constraint must be splitted in two C::E constraints: a coaxial and a point-vs-plane
                        num_link++;
                        String linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateCoaxial()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cA.X * ChScale.L,
                                  cA.Y * ChScale.L,
                                  cA.Z * ChScale.L);
                        asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  dA.X, dA.Y, dA.Z);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cB.X * ChScale.L,
                                  cB.Y * ChScale.L,
                                  cB.Z * ChScale.L);
                        asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  dB.X, dB.Y, dB.Z);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);

                        // Initialize link, by setting the two csys, in absolute space,
                        asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA,dB)\n", linkname, name1, name2);

                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n", linkname);

                        // NOTE!!! The 'hinge' mate uses 4 references: fetch the two others remaining
                        // and build another C::E link, for point-vs-face mating

                        MateEntity2 swEntityC = swMate.MateEntity(2);
                        MateEntity2 swEntityD = swMate.MateEntity(3);
                        Component2 swCompC = swEntityC.ReferenceComponent;
                        Component2 swCompD = swEntityD.ReferenceComponent;
                        double[] paramsC = (double[])swEntityC.EntityParams;
                        double[] paramsD = (double[])swEntityD.EntityParams;
                        String name3 = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompC)];
                        String name4 = (String)saved_parts[swModelDocExt.GetPersistReference3(swCompD)];
                        MathTransform trC = roottrasf;
                        MathTransform trD = roottrasf;

                        if (assemblyofmates != null)
                        {
                            MathTransform partrasfC = assemblyofmates.GetTotalTransform(true);
                            if (partrasfC != null)
                                trC = partrasfC.IMultiply(invroottrasf);
                            MathTransform partrasfD = assemblyofmates.GetTotalTransform(true);
                            if (partrasfD != null)
                                trD = partrasfD.IMultiply(invroottrasf);
                        }

                        bool entity_2_as_VERTEX = (swMate.MateEntity(2).Reference.GetType() == (int)swSelectType_e.swSelVERTICES) ||
                                                  (swMate.MateEntity(2).Reference.GetType() == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                                  (swMate.MateEntity(2).Reference.GetType() == (int)swSelectType_e.swSelDATUMPOINTS);
                        bool entity_3_as_VERTEX = (swMate.MateEntity(3).Reference.GetType() == (int)swSelectType_e.swSelVERTICES) ||
                                                  (swMate.MateEntity(3).Reference.GetType() == (int)swSelectType_e.swSelSKETCHPOINTS) ||
                                                  (swMate.MateEntity(3).Reference.GetType() == (int)swSelectType_e.swSelDATUMPOINTS);
                        Point3D cC  = new Point3D(0, 0, 0);
                        Point3D cD  = new Point3D(0, 0, 0);
                        Vector3D dC = new Vector3D(1, 0, 0);
                        Vector3D dD = new Vector3D(1, 0, 0);

                        Point3D cCloc = new Point3D(paramsC[0], paramsC[1], paramsC[2]);
                        cC = SWTaskpaneHost.PointTransform(cCloc, ref trC);
                        Point3D cDloc = new Point3D(paramsD[0], paramsD[1], paramsD[2]);
                        cD = SWTaskpaneHost.PointTransform(cDloc, ref trD);

                        if (!entity_2_as_VERTEX)
                        {
                            Vector3D dCloc = new Vector3D(paramsC[3], paramsC[4], paramsC[5]);
                            dC = SWTaskpaneHost.DirTransform(dCloc, ref trC);
                        }

                        if (!entity_3_as_VERTEX)
                        {
                            Vector3D dDloc = new Vector3D(paramsD[3], paramsD[4], paramsD[5]);
                            dD = SWTaskpaneHost.DirTransform(dDloc, ref trD);
                        }

                        num_link++;
                        linkname = "link_" + num_link;
                        asciitext += String.Format(bz, "{0} = chrono.ChLinkMateXdistance()\n", linkname);

                        asciitext += String.Format(bz, "cA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cC.X * ChScale.L,
                                  cC.Y * ChScale.L,
                                  cC.Z * ChScale.L);
                        asciitext += String.Format(bz, "dA = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  dC.X, dC.Y, dC.Z);
                        asciitext += String.Format(bz, "cB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  cD.X * ChScale.L,
                                  cD.Y * ChScale.L,
                                  cD.Z * ChScale.L);
                        asciitext += String.Format(bz, "dB = chrono.ChVectorD({0:g},{1:g},{2:g})\n",
                                  dD.X, dD.Y, dD.Z);

                        asciitext += String.Format(bz, "{0}.SetName(\"{1}\")\n", linkname, swMateFeature.Name);

                        // Initialize link, by setting the two csys, in absolute space,
                        if (entity_2_as_VERTEX)
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dA)\n", linkname, name3, name4);
                        else
                            asciitext += String.Format(bz, "{0}.Initialize({1},{2},False,cA,cB,dB)\n", linkname, name3, name4);

                        // Insert to a list of exported items
                        asciitext += String.Format(bz, "exported_items.append({0})\n", linkname);

                        return true;
                    }
                }
            }
            return false;
        }
        public void PythonTraverseFeatures_for_collshapes(Component2 swComp, long nLevel, ref  string asciitext, int nbody, ref MathTransform chbodytransform, ref bool found_collisionshapes, Component2 swCompBase)
        {
            CultureInfo bz = new CultureInfo("en-BZ");
            Feature swFeat;
            swFeat = (Feature)swComp.FirstFeature();

            String bodyname = "body_" + nbody;

            MathTransform subcomp_transform = swComp.GetTotalTransform(true);
            MathTransform invchbody_trasform = (MathTransform)chbodytransform.Inverse();
            MathTransform collshape_subcomp_transform = subcomp_transform.IMultiply(invchbody_trasform); // row-ordered transf. -> reverse mult.order!

            // Export collision shapes
            if (this.checkBox_collshapes.Checked)
            {
                object[] bodies;
                object bodyInfo;
                bodies = (object[])swComp.GetBodies3((int)swBodyType_e.swAllBodies, out bodyInfo);

                if (bodies != null)
                {
                    // see if it contains some collision shape
                    bool build_collision_model = false;
                    for (int ib = 0; ib < bodies.Length; ib++)
                    {
                        Body2 swBody = (Body2)bodies[ib];
                        if (swBody.Name.StartsWith("COLL."))
                            build_collision_model = true;
                    }

                    if (build_collision_model)
                    {
                        if (!found_collisionshapes)
                        {
                            found_collisionshapes = true;

                            // fetch SW attribute with Chrono parameters
                            SolidWorks.Interop.sldworks.Attribute myattr = (SolidWorks.Interop.sldworks.Attribute)swCompBase.FindAttribute(this.mSWintegration.defattr_chbody, 0);

                            if (myattr != null)
                            {
                                asciitext += "\n# Collision parameters \n";
                                double param_friction = ((Parameter)myattr.GetParameter("friction")).GetDoubleValue();
                                double param_restitution = ((Parameter)myattr.GetParameter("restitution")).GetDoubleValue();
                                double param_rolling_friction = ((Parameter)myattr.GetParameter("rolling_friction")).GetDoubleValue();
                                double param_spinning_friction = ((Parameter)myattr.GetParameter("spinning_friction")).GetDoubleValue();
                                double param_collision_envelope = ((Parameter)myattr.GetParameter("collision_envelope")).GetDoubleValue();
                                double param_collision_margin = ((Parameter)myattr.GetParameter("collision_margin")).GetDoubleValue();
                                int    param_collision_family = (int)((Parameter)myattr.GetParameter("collision_family")).GetDoubleValue();

                                asciitext += String.Format(bz, "{0}.SetFriction({1:g});\n", bodyname, param_friction);
                                if (param_restitution != 0)
                                    asciitext += String.Format(bz, "{0}.SetImpactC({1:g});\n", bodyname, param_restitution);
                                if (param_rolling_friction != 0)
                                    asciitext += String.Format(bz, "{0}.SetRollingFriction({1:g});\n", bodyname, param_rolling_friction);
                                if (param_spinning_friction != 0)
                                    asciitext += String.Format(bz, "{0}.SetSpinningFriction({1:g});\n", bodyname, param_spinning_friction);
                                //if (param_collision_envelope != 0.03)
                                    asciitext += String.Format(bz, "{0}.GetCollisionModel().SetEnvelope({1:g});\n", bodyname, param_collision_envelope * ChScale.L);
                                //if (param_collision_margin != 0.01)
                                    asciitext += String.Format(bz, "{0}.GetCollisionModel().SetSafeMargin({1:g});\n", bodyname, param_collision_margin * ChScale.L);
                                if (param_collision_family != 0)
                                    asciitext += String.Format(bz, "{0}.GetCollisionModel().SetFamily({1});\n", bodyname, param_collision_family);
                            }

                            // clear model only at 1st subcomponent where coll shapes are found in features:
                            asciitext += "\n# Collision shapes \n";
                            asciitext += String.Format(bz, "{0}.GetCollisionModel().ClearModel()\n", bodyname);
                        }

                        for (int ib = 0; ib < bodies.Length; ib++)
                        {
                            Body2 swBody = (Body2)bodies[ib];

                            if (swBody.Name.StartsWith("COLL."))
                            {
                                bool rbody_converted = false;
                                if (ConvertToCollisionShapes.SWbodyToSphere(swBody))
                                {
                                    Point3D center_l = new Point3D(); // in local subcomponent
                                    double rad = 0;
                                    ConvertToCollisionShapes.SWbodyToSphere(swBody, ref rad, ref center_l);
                                    Point3D center = SWTaskpaneHost.PointTransform(center_l, ref collshape_subcomp_transform);
                                    asciitext += String.Format(bz, "{0}.GetCollisionModel().AddSphere({1}, chrono.ChVectorD({2},{3},{4}))\n", bodyname,
                                        rad * ChScale.L,
                                        center.X * ChScale.L,
                                        center.Y * ChScale.L,
                                        center.Z * ChScale.L);
                                    rbody_converted = true;
                                }
                                if (ConvertToCollisionShapes.SWbodyToBox(swBody))
                                {
                                    Point3D  vC_l = new Point3D();
                                    Vector3D eX_l = new Vector3D(); Vector3D eY_l = new Vector3D(); Vector3D eZ_l = new Vector3D();
                                    ConvertToCollisionShapes.SWbodyToBox(swBody, ref vC_l, ref eX_l, ref eY_l, ref eZ_l);
                                    Point3D  vC = SWTaskpaneHost.PointTransform(vC_l, ref collshape_subcomp_transform);
                                    Vector3D eX = SWTaskpaneHost.DirTransform(eX_l, ref collshape_subcomp_transform);
                                    Vector3D eY = SWTaskpaneHost.DirTransform(eY_l, ref collshape_subcomp_transform);
                                    Vector3D eZ = SWTaskpaneHost.DirTransform(eZ_l, ref collshape_subcomp_transform);
                                    double hsX = eX.Length * 0.5;
                                    double hsY = eY.Length * 0.5;
                                    double hsZ = eZ.Length * 0.5;
                                    Point3D  vO = vC + 0.5 * eX + 0.5 * eY + 0.5 * eZ;
                                    Vector3D Dx = eX; Dx.Normalize();
                                    Vector3D Dy = eY; Dy.Normalize();
                                    Vector3D Dz = Vector3D.CrossProduct(Dx, Dy);
                                    asciitext += String.Format(bz, "mr = chrono.ChMatrix33D()\n");
                                    asciitext += String.Format(bz, "mr[0,0]={0}; mr[1,0]={1}; mr[2,0]={2} \n", Dx.X, Dx.Y, Dx.Z);
                                    asciitext += String.Format(bz, "mr[0,1]={0}; mr[1,1]={1}; mr[2,1]={2} \n", Dy.X, Dy.Y, Dy.Z);
                                    asciitext += String.Format(bz, "mr[0,2]={0}; mr[1,2]={1}; mr[2,2]={2} \n", Dz.X, Dz.Y, Dz.Z);
                                    asciitext += String.Format(bz, "{0}.GetCollisionModel().AddBox({1},{2},{3},chrono.ChVectorD({4},{5},{6}),mr)\n", bodyname,
                                        hsX * ChScale.L,
                                        hsY * ChScale.L,
                                        hsZ * ChScale.L,
                                        vO.X * ChScale.L,
                                        vO.Y * ChScale.L,
                                        vO.Z * ChScale.L);
                                    rbody_converted = true;
                                }
                                if (ConvertToCollisionShapes.SWbodyToCylinder(swBody))
                                {
                                    Point3D p1_l = new Point3D();
                                    Point3D p2_l = new Point3D();
                                    double rad = 0;
                                    ConvertToCollisionShapes.SWbodyToCylinder(swBody, ref p1_l, ref p2_l, ref rad);
                                    Point3D p1 = SWTaskpaneHost.PointTransform(p1_l, ref collshape_subcomp_transform);
                                    Point3D p2 = SWTaskpaneHost.PointTransform(p2_l, ref collshape_subcomp_transform);
                                    Vector3D Dy = p1 - p2; Dy.Normalize();
                                    double hsY = (p1 - p2).Length * 0.5;
                                    double hsZ = rad;
                                    double hsX = rad;
                                    Point3D  vO = p1 + 0.5 * (p2 - p1);
                                    Vector3D Dx = new Vector3D();
                                    if (Dy.X < 0.9)
                                    {
                                        Vector3D Dtst = new Vector3D(1, 0, 0);
                                        Dx = Vector3D.CrossProduct(Dtst, Dy);
                                    }
                                    else
                                    {
                                        Vector3D Dtst = new Vector3D(0, 1, 0);
                                        Dx = Vector3D.CrossProduct(Dtst, Dy);
                                    }
                                    Vector3D Dz = Vector3D.CrossProduct(Dx, Dy);
                                    asciitext += String.Format(bz, "mr = chrono.ChMatrix33D()\n");
                                    asciitext += String.Format(bz, "mr[0,0]={0}; mr[1,0]={1}; mr[2,0]={2} \n", Dx.X, Dx.Y, Dx.Z);
                                    asciitext += String.Format(bz, "mr[0,1]={0}; mr[1,1]={1}; mr[2,1]={2} \n", Dy.X, Dy.Y, Dy.Z);
                                    asciitext += String.Format(bz, "mr[0,2]={0}; mr[1,2]={1}; mr[2,2]={2} \n", Dz.X, Dz.Y, Dz.Z);
                                    asciitext += String.Format(bz, "{0}.GetCollisionModel().AddCylinder({1},{2},{3},chrono.ChVectorD({4},{5},{6}),mr)\n", bodyname,
                                        hsX * ChScale.L,
                                        hsZ * ChScale.L,
                                        hsY * ChScale.L,
                                        vO.X * ChScale.L,
                                        vO.Y * ChScale.L,
                                        vO.Z * ChScale.L); // note order hsX-Z-Y
                                    rbody_converted = true;
                                }

                                if (ConvertToCollisionShapes.SWbodyToConvexHull(swBody, 30) && !rbody_converted)
                                {
                                    Point3D[] vertexes = new Point3D[1]; // will be resized by SWbodyToConvexHull
                                    ConvertToCollisionShapes.SWbodyToConvexHull(swBody, ref vertexes, 30);
                                    if (vertexes.Length > 0)
                                    {
                                        asciitext += String.Format(bz, "pt_vect = chrono.vector_ChVectorD()\n");
                                        for (int iv = 0; iv < vertexes.Length; iv++)
                                        {
                                            Point3D vert_l = vertexes[iv];
                                            Point3D vert   = SWTaskpaneHost.PointTransform(vert_l, ref collshape_subcomp_transform);
                                            asciitext += String.Format(bz, "pt_vect.push_back(chrono.ChVectorD({0},{1},{2}))\n",
                                                vert.X * ChScale.L,
                                                vert.Y * ChScale.L,
                                                vert.Z * ChScale.L);
                                        }
                                        asciitext += String.Format(bz, "{0}.GetCollisionModel().AddConvexHull(pt_vect)\n", bodyname);
                                    }
                                }

                            } // end dealing with a collision shape

                        } // end solid bodies traversal for converting to coll.shapes

                    } // end if build_collision_model
                }

            } // end collision shapes export
        }
        public void PythonTraverseComponent_for_visualizationshapes(Component2 swComp, long nLevel, ref string asciitext, int nbody, ref int nvisshape, Component2 chbody_comp)
        {
            CultureInfo bz = new CultureInfo("en-BZ");
            object[] bodies;
            object bodyInfo;
            bodies = (object[])swComp.GetBodies3((int)swBodyType_e.swAllBodies, out bodyInfo);

            if (bodies != null)
              if (bodies.Length > 0)
            {
                // Export the component shape to a .OBJ file representing its SW body(s)
                nvisshape += 1;
                string bodyname  = "body_" + nbody;
                string shapename = "body_" + nbody + "_" + nvisshape;
                string obj_filename = this.save_dir_shapes + "\\" + shapename + ".obj";

                ModelDoc2 swCompModel = (ModelDoc2)swComp.GetModelDoc();
                if (!this.saved_shapes.ContainsKey(swCompModel.GetPathName()))
                {
                    try
                    {
                        FileStream ostream = new FileStream(obj_filename, FileMode.Create, FileAccess.ReadWrite);
                        StreamWriter writer = new StreamWriter(ostream); //, new UnicodeEncoding());
                        string asciiobj = "";
                        if (this.swProgress != null)
                            this.swProgress.UpdateTitle("Exporting " + swComp.Name2 + " (tesselate) ...");
                        // Write the OBJ converted visualization shapes:
                        TesselateToObj.Convert(swComp, ref asciiobj, this.checkBox_saveUV.Checked, ref this.swProgress);
                        writer.Write(asciiobj);
                        writer.Flush();
                        ostream.Close();

                        this.saved_shapes.Add(swCompModel.GetPathName(), shapename);
                    }
                    catch (Exception)
                    {
                        System.Windows.Forms.MessageBox.Show("Cannot write to file: " + obj_filename);
                    }
                }
                else
                {
                    // reuse the already-saved shape name
                    shapename = (String)saved_shapes[swCompModel.GetPathName()];
                }

                asciitext += String.Format(bz, "\n# Visualization shape \n", bodyname);
                asciitext += String.Format(bz, "{0}_shape = chrono.ChObjShapeFile() \n", shapename);
                asciitext += String.Format(bz, "{0}_shape.SetFilename(shapes_dir +'{0}.obj') \n", shapename);

                object foo = null;
                double[] vMatProperties = (double[])swComp.GetMaterialPropertyValues2((int)swInConfigurationOpts_e.swThisConfiguration, foo);

                if (vMatProperties != null)
                    if (vMatProperties[0] != -1)
                    {
                        asciitext += String.Format(bz, "{0}_shape.SetColor(chrono.ChColor({1},{2},{3})) \n", shapename,
                            vMatProperties[0], vMatProperties[1], vMatProperties[2]);
                        asciitext += String.Format(bz, "{0}_shape.SetFading({1}) \n", shapename, vMatProperties[7]);
                    }

                MathTransform absframe_chbody = chbody_comp.GetTotalTransform(true);
                MathTransform absframe_shape  = swComp.GetTotalTransform(true);
                MathTransform absframe_chbody_inv = absframe_chbody.IInverse();
                MathTransform relframe_shape = absframe_shape.IMultiply(absframe_chbody_inv);  // row-ordered transf. -> reverse mult.order!
                double[] amatr = (double[])relframe_shape.ArrayData;
                double[] quat  = GetQuaternionFromMatrix(ref relframe_shape);

                asciitext += String.Format(bz, "{0}_level = chrono.ChAssetLevel() \n", shapename);
                asciitext += String.Format(bz, "{0}_level.GetFrame().SetPos(chrono.ChVectorD({1},{2},{3})) \n", shapename,
                    amatr[9] *ChScale.L,
                    amatr[10]*ChScale.L,
                    amatr[11]*ChScale.L);
                asciitext += String.Format(bz, "{0}_level.GetFrame().SetRot(chrono.ChQuaternionD({1},{2},{3},{4})) \n", shapename, quat[0], quat[1], quat[2], quat[3]);
                asciitext += String.Format(bz, "{0}_level.GetAssets().push_back({0}_shape) \n", shapename);

                asciitext += String.Format(bz, "{0}.GetAssets().push_back({1}_level) \n", bodyname, shapename);

            }

            // Recursive scan of subcomponents

            Component2 swChildComp;
            object[] vChildComp = (object[])swComp.GetChildren();

            for (long i = 0; i < vChildComp.Length; i++)
            {
                swChildComp = (Component2)vChildComp[i];

                if (swChildComp.Visible == (int)swComponentVisibilityState_e.swComponentVisible)
                    PythonTraverseComponent_for_visualizationshapes(swChildComp, nLevel + 1, ref asciitext, nbody, ref nvisshape, chbody_comp);
            }
        }
        //
        // BODY EXPORTING FUNCTIONS
        //
        public void PythonTraverseComponent_for_markers(Component2 swComp, long nLevel, ref  string asciitext, int nbody)
        {
            // Look if component contains markers
            Feature swFeat = (Feature)swComp.FirstFeature();
            MathTransform swCompTotalTrasf = swComp.GetTotalTransform(true);
            PythonTraverseFeatures_for_markers(swFeat, nLevel, ref asciitext, nbody, swCompTotalTrasf);

            // Recursive scan of subcomponents

            Component2 swChildComp;
            object[] vChildComp = (object[])swComp.GetChildren();

            for (long i = 0; i < vChildComp.Length; i++)
            {
                swChildComp = (Component2)vChildComp[i];

                PythonTraverseComponent_for_markers(swChildComp, nLevel + 1, ref asciitext, nbody);
            }
        }
        public void PythonTraverseComponent_for_ChBody(Component2 swComp, long nLevel, ref  string asciitext,  int nbody)
        {
            CultureInfo bz = new CultureInfo("en-BZ");
            object[] vmyChildComp = (object[])swComp.GetChildren();
            bool found_chbody_equivalent = false;

            if (nLevel > 1)
                if (nbody == -1)
                    if ((swComp.Solving == (int)swComponentSolvingOption_e.swComponentRigidSolving) ||
                        (vmyChildComp.Length == 0))
            {
                // OK! this is a 'leaf' of the tree of ChBody equivalents (a SDW subassebly or part)

                found_chbody_equivalent = true;

                this.num_comp++;

                nbody = this.num_comp;  // mark the rest of recursion as 'n-th body found'

                if (this.swProgress != null)
                {
                    this.swProgress.UpdateTitle("Exporting " + swComp.Name2 + " ...");
                    this.swProgress.UpdateProgress(this.num_comp % 5);
                }

                // fetch SW attribute with Chrono parameters
                SolidWorks.Interop.sldworks.Attribute myattr = (SolidWorks.Interop.sldworks.Attribute)swComp.FindAttribute(this.mSWintegration.defattr_chbody, 0);

                MathTransform chbodytransform = swComp.GetTotalTransform(true);
                double[] amatr;
                amatr = (double[])chbodytransform.ArrayData;
                string bodyname = "body_" + this.num_comp;

                // Write create body
                asciitext += "# Rigid body part\n";
                asciitext += bodyname + "= chrono.ChBodyAuxRef()" + "\n";

                // Write name
                asciitext += bodyname + ".SetName('" + swComp.Name2 + "')" + "\n";

                // Write position
                asciitext += bodyname + ".SetPos(chrono.ChVectorD("
                           + (amatr[9] * ChScale.L).ToString("g", bz) + ","
                           + (amatr[10]* ChScale.L).ToString("g", bz) + ","
                           + (amatr[11]* ChScale.L).ToString("g", bz) + "))" + "\n";

                // Write rotation
                double[] quat = GetQuaternionFromMatrix(ref chbodytransform);
                asciitext += String.Format(bz, "{0}.SetRot(chrono.ChQuaternionD({1:g},{2:g},{3:g},{4:g}))\n",
                           bodyname, quat[0], quat[1], quat[2], quat[3]);

                // Compute mass

                int nvalid_bodies = 0;
                PythonTraverseComponent_for_countingmassbodies(swComp, ref nvalid_bodies);

                int addedb = 0;
                object[] bodies_nocollshapes = new object[nvalid_bodies];
                PythonTraverseComponent_for_massbodies(swComp, ref bodies_nocollshapes, ref addedb);

                MassProperty swMass;
                swMass = (MassProperty)swComp.IGetModelDoc().Extension.CreateMassProperty();
                bool boolstatus = false;
                boolstatus = swMass.AddBodies((object[])bodies_nocollshapes);
                swMass.SetCoordinateSystem(chbodytransform);
                swMass.UseSystemUnits = true;
                //note: do not set here the COG-to-REF position because here SW express it in absolute coords
                // double cogX = ((double[])swMass.CenterOfMass)[0];
                // double cogY = ((double[])swMass.CenterOfMass)[1];
                // double cogZ = ((double[])swMass.CenterOfMass)[2];
                double mass = swMass.Mass;
                double[] Itensor = (double[])swMass.GetMomentOfInertia((int)swMassPropertyMoment_e.swMassPropertyMomentAboutCenterOfMass);
                double Ixx = Itensor[0];
                double Iyy = Itensor[4];
                double Izz = Itensor[8];
                double Ixy = Itensor[1];
                double Izx = Itensor[2];
                double Iyz = Itensor[5];

                MassProperty swMassb;
                swMassb = (MassProperty)swComp.IGetModelDoc().Extension.CreateMassProperty();
                bool boolstatusb = false;
                boolstatusb = swMassb.AddBodies(bodies_nocollshapes);
                swMassb.UseSystemUnits = true;
                double cogXb = ((double[])swMassb.CenterOfMass)[0];
                double cogYb = ((double[])swMassb.CenterOfMass)[1];
                double cogZb = ((double[])swMassb.CenterOfMass)[2];

                asciitext += String.Format(bz, "{0}.SetMass({1:g})\n",
                           bodyname,
                           mass * ChScale.M);

                // Write inertia tensor
                asciitext += String.Format(bz, "{0}.SetInertiaXX(chrono.ChVectorD({1:g},{2:g},{3:g}))\n",
                           bodyname,
                           Ixx * ChScale.M * ChScale.L * ChScale.L,
                           Iyy * ChScale.M * ChScale.L * ChScale.L,
                           Izz * ChScale.M * ChScale.L * ChScale.L);
                // Note: C::E assumes that's up to you to put a 'minus' sign in values of Ixy, Iyz, Izx
                asciitext += String.Format(bz, "{0}.SetInertiaXY(chrono.ChVectorD({1:g},{2:g},{3:g}))\n",
                           bodyname,
                           -Ixy * ChScale.M * ChScale.L * ChScale.L,
                           -Izx * ChScale.M * ChScale.L * ChScale.L,
                           -Iyz * ChScale.M * ChScale.L * ChScale.L);

                // Write the position of the COG respect to the REF
                asciitext += String.Format(bz, "{0}.SetFrame_COG_to_REF(chrono.ChFrameD(chrono.ChVectorD({1:g},{2:g},{3:g}),chrono.ChQuaternionD(1,0,0,0)))\n",
                            bodyname,
                            cogXb * ChScale.L,
                            cogYb * ChScale.L,
                            cogZb * ChScale.L);

                // Write 'fixed' state
                if (swComp.IsFixed())
                    asciitext += String.Format(bz, "{0}.SetBodyFixed(True)\n", bodyname);

                // Write shapes (saving also Wavefront files .obj)
                if (this.checkBox_surfaces.Checked)
                {
                    int nvisshape = 0;

                    if (swComp.Visible == (int)swComponentVisibilityState_e.swComponentVisible)
                        PythonTraverseComponent_for_visualizationshapes(swComp, nLevel, ref asciitext, nbody, ref nvisshape, swComp);
                }

                // Write markers (SW coordsystems) contained in this component or subcomponents
                // if any.
                PythonTraverseComponent_for_markers(swComp, nLevel, ref asciitext, nbody);

                // Write collision shapes (customized SW solid bodies) contained in this component or subcomponents
                // if any.
                bool param_collide = true;
                if (myattr != null)
                    param_collide = Convert.ToBoolean(((Parameter)myattr.GetParameter("collision_on")).GetDoubleValue());

                if (param_collide)
                {
                    bool found_collisionshapes = false;
                    PythonTraverseComponent_for_collshapes(swComp, nLevel, ref asciitext, nbody, ref chbodytransform, ref found_collisionshapes, swComp);
                    if (found_collisionshapes)
                    {
                        asciitext += String.Format(bz, "{0}.GetCollisionModel().BuildModel()\n", bodyname);
                        asciitext += String.Format(bz, "{0}.SetCollide(True)\n", bodyname);
                    }
                }

                // Insert to a list of exported items
                asciitext += String.Format(bz, "\n" +"exported_items.append({0})\n", bodyname);

                // End writing body in Python-
                asciitext += "\n\n\n";

            } // end if ChBody equivalent (tree leaf or non-flexible assembly)

            // Things to do also for sub-components of 'non flexible' assemblies:
            //

                // store in hashtable, will be useful later when adding constraints
            if ((nLevel > 1) && (nbody != -1))
            try
            {
                string bodyname = "body_" + this.num_comp;

                ModelDocExtension swModelDocExt = default(ModelDocExtension);
                ModelDoc2 swModel = (ModelDoc2)this.mSWApplication.ActiveDoc;
                //if (swModel != null)
                swModelDocExt = swModel.Extension;
                this.saved_parts.Add(swModelDocExt.GetPersistReference3(swComp), bodyname);
            }
            catch
            {
                System.Windows.Forms.MessageBox.Show("Cannot add part to hashtable?");
            }

            // Traverse all children, proceeding to subassemblies and parts, if any
            //

            object[] vChildComp;
            Component2 swChildComp;

            vChildComp = (object[])swComp.GetChildren();

            for (long i = 0; i < vChildComp.Length; i++)
            {
                swChildComp = (Component2)vChildComp[i];

                PythonTraverseComponent_for_ChBody(swChildComp, nLevel + 1, ref asciitext, nbody);
            }
        }