Author Topic: Matrix3d and TransformBy help  (Read 55611 times)

0 Members and 1 Guest are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Matrix3d and TransformBy help
« Reply #15 on: July 23, 2008, 01:17:20 AM »

Interesting stuff guys .. wish I could make time to play :-(

Dan/Paul : Perhaps Kean should be advised about the crashes. I'm not sure if he still visits here, so giving him a link  to this thread may be needed.


be well.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Matrix3d and TransformBy help
« Reply #16 on: July 23, 2008, 01:40:00 AM »

Interesting stuff guys .. wish I could make time to play :-(

Dan/Paul : Perhaps Kean should be advised about the crashes. I'm not sure if he still visits here, so giving him a link  to this thread may be needed.


be well.



Hi Kerry,

That’s a good idea, I was kind of assuming that my code was the cause, but since Paul is having issues as well, we should probably pass this on to the big guy.

Paul Richardson

  • Guest
Re: Matrix3d and TransformBy help
« Reply #17 on: July 23, 2008, 08:14:30 AM »
This just looks for the longest edge in each solid for a test. See attached brep.dwg to see a solid with multiple Complexes and the file TimberData.csv for the results.

See notes in Commands.cs. Code crashes randomly when looping 'brep.Complexes'. Seems to happen more as the number of solids increases - anyone know why?

Nice work Paul. Thanks for sharing!
So far I am finding the brep stuff slightly unstable too, no error messages, just poof. 


Daniel,

I see yours is crashing randomly too. I'm going to try in native brep and see if I get the same crash - maybe we can narrow it down to the wrapper.

Paul Richardson

  • Guest
Re: Matrix3d and TransformBy help
« Reply #18 on: July 23, 2008, 08:16:58 AM »

Interesting stuff guys .. wish I could make time to play :-(

Dan/Paul : Perhaps Kean should be advised about the crashes. I'm not sure if he still visits here, so giving him a link  to this thread may be needed.


be well.



Hi Kerry,

That’s a good idea, I was kind of assuming that my code was the cause, but since Paul is having issues as well, we should probably pass this on to the big guy.


I was hoping I was just missing something in my code which was causing the crash - I think there is someplace to enter API bug reports. I'll take a look.

Paul Richardson

  • Guest
Re: Matrix3d and TransformBy help
« Reply #19 on: July 23, 2008, 08:36:07 AM »
This just looks for the longest edge in each solid for a test. See attached brep.dwg to see a solid with multiple Complexes and the file TimberData.csv for the results.

See notes in Commands.cs. Code crashes randomly when looping 'brep.Complexes'. Seems to happen more as the number of solids increases - anyone know why?

My original version of 'LongestEdges' method did not loop each Complex so I had no need to
reset 'tempLongestEdge' to 0. Quick change in this version which resets it before looping the
next Complex.

Code: [Select]
    private static double[] LongestEdges(Solid3d sol)
    {

      double tempLongestEdge = 0;
      int complexCounter = 0;

      Brep brep = new Brep(sol);
      double[] tempLongestEdges = new double[ComplexCount(brep)];

      foreach (Complex complex in brep.Complexes)
      {

        foreach (Shell shell in complex.Shells)
        {

          foreach (Autodesk.AutoCAD.BoundaryRepresentation.Face face in shell.Faces)
          {

            foreach (BoundaryLoop loop in face.Loops)
            {
              //Find longest edge.
              foreach (Edge edge in loop.Edges)

                if (edge.Vertex1.Point.DistanceTo(edge.Vertex2.Point)
                  > tempLongestEdge)

                  tempLongestEdge =
                    edge.Vertex1.Point.DistanceTo(edge.Vertex2.Point);
            }
          }
        }

        tempLongestEdges[complexCounter] = tempLongestEdge;
        complexCounter++;
        //forget to reset in last version
        tempLongestEdge = 0;
      }

      return tempLongestEdges;
    }

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Matrix3d and TransformBy help
« Reply #20 on: July 23, 2008, 10:21:46 AM »
Just thinking out loud, would something like this work? … Pseudo code…

Code: [Select]
 
   public static int EdgeComparer(AcBr.Edge A, AcBr.Edge B)
    {
      return A.GetPerimeterLength().CompareTo(B.GetPerimeterLength());
    }

    private static double[] LongestEdges(Solid3d sol)
    {
      AcBr.Brep brep = new AcBr.Brep(sol);

      List<List<AcBr.Edge>> MyEdges = new List<List<AcBr.Edge>>();

      foreach (AcBr.Complex c in brep.Complexes)
        MyEdges.Add(new List<AcBr.Edge>(c.Brep.Edges));
     
      MyEdges.ForEach(L => L.Sort(EdgeComparer));

      double[] tempLongestEdges = new double[MyEdges.Count];

      for (int i = 0; i < MyEdges.Count; i++)
        tempLongestEdges[i] = MyEdges[i][0].GetPerimeterLength();
     
      return tempLongestEdges;
    }

Paul Richardson

  • Guest
Re: Matrix3d and TransformBy help
« Reply #21 on: July 23, 2008, 01:04:57 PM »
Just thinking out loud, would something like this work? … Pseudo code…

Code: [Select]
 
   public static int EdgeComparer(AcBr.Edge A, AcBr.Edge B)
    {
      return A.GetPerimeterLength().CompareTo(B.GetPerimeterLength());
    }

    private static double[] LongestEdges(Solid3d sol)
    {
      AcBr.Brep brep = new AcBr.Brep(sol);

      List<List<AcBr.Edge>> MyEdges = new List<List<AcBr.Edge>>();

      foreach (AcBr.Complex c in brep.Complexes)
        MyEdges.Add(new List<AcBr.Edge>(c.Brep.Edges));
     
      MyEdges.ForEach(L => L.Sort(EdgeComparer));

      double[] tempLongestEdges = new double[MyEdges.Count];

      for (int i = 0; i < MyEdges.Count; i++)
        tempLongestEdges[i] = MyEdges[i][0].GetPerimeterLength();
     
      return tempLongestEdges;
    }

Very nice... But same error - looks pretty while doing it though...)

m.araujo

  • Guest
Re: Matrix3d and TransformBy help
« Reply #22 on: July 23, 2008, 07:09:12 PM »
Hi everyone,

I'm just a noob, but I've been following this post, because I'm the one who posited the question which got it all started back on the autodesk website.  I'm working on a solution for creating a lumber schedule from a 3d timber frame model that uses the I-J-K info from
MASSPROP to realign the ucs to an object. From there you can get the coords for an oriented bounding box (these OOB's are something that game programmers use alot).  This would essentially be the original uncut timber. I've been researching methods to calculate oriented bounding boxes using descriptive geometry....there's info if you want to google it.  A guy named o'Rourke wrote a algorithm back in the 90's that will do it for you based on coordinates....Its a rather complicated formula.

I wanted to comment on the approach of grabbing the longest edge of a "timber"  I am a timber framer and have attached a dwg with a single timber in which the longest edge does not accurately describe the required length of the uncut timber.  It is a Valley rafter and is essentially a parallelogram.  Does this in any way complicate the methods by which you guys are approaching this task?

keep up the great work,

Matt Araujo

Paul Richardson

  • Guest
Re: Matrix3d and TransformBy help
« Reply #23 on: July 23, 2008, 08:01:42 PM »
Hi everyone,

I'm just a noob, but I've been following this post, because I'm the one who posited the question which got it all started back on the autodesk website.  I'm working on a solution for creating a lumber schedule from a 3d timber frame model that uses the I-J-K info from
MASSPROP to realign the ucs to an object. From there you can get the coords for an oriented bounding box (these OOB's are something that game programmers use alot).  This would essentially be the original uncut timber. I've been researching methods to calculate oriented bounding boxes using descriptive geometry....there's info if you want to google it.  A guy named o'Rourke wrote a algorithm back in the 90's that will do it for you based on coordinates....Its a rather complicated formula.

I wanted to comment on the approach of grabbing the longest edge of a "timber"  I am a timber framer and have attached a dwg with a single timber in which the longest edge does not accurately describe the required length of the uncut timber.  It is a Valley rafter and is essentially a parallelogram.  Does this in any way complicate the methods by which you guys are approaching this task?

keep up the great work,

Matt Araujo

Getting the longest line was just for a test, you can grab any data you want. Since brep.net seems to be buggy I'd keep going with your and Daniel's methods...

Paul Richardson

  • Guest
Re: Matrix3d and TransformBy help
« Reply #24 on: July 24, 2008, 05:26:53 AM »
Just thinking out loud, would something like this work? … Pseudo code…

Code: [Select]
 
   public static int EdgeComparer(AcBr.Edge A, AcBr.Edge B)
    {
      return A.GetPerimeterLength().CompareTo(B.GetPerimeterLength());
    }

    private static double[] LongestEdges(Solid3d sol)
    {
      AcBr.Brep brep = new AcBr.Brep(sol);

      List<List<AcBr.Edge>> MyEdges = new List<List<AcBr.Edge>>();

      foreach (AcBr.Complex c in brep.Complexes)
        MyEdges.Add(new List<AcBr.Edge>(c.Brep.Edges));
     
      MyEdges.ForEach(L => L.Sort(EdgeComparer));

      double[] tempLongestEdges = new double[MyEdges.Count];

      for (int i = 0; i < MyEdges.Count; i++)
        tempLongestEdges[i] = MyEdges[i][0].GetPerimeterLength();
     
      return tempLongestEdges;
    }

Very nice... But same error - looks pretty while doing it though...)

fyi - Fenton Webb Just confirmed that there is a bug with 'Autodesk.AutoCAD.DatabaseServices.Solid3d.RemoveFaces' as the underlying AcDb3dSolid pointer is NULL and cannot be accessed... He is looking at this issue too - I'll let ya know.

SEANT

  • Bull Frog
  • Posts: 345
Re: Matrix3d and TransformBy help
« Reply #25 on: July 24, 2008, 09:33:54 AM »
Here’s my contribution to the effort.  I made things easy on myself by increasing the level of symmetry, thus avoiding any “roll” axis concerns. 

I originally figured a “cylinder length” method would be fairly straight forward but it turned out rather elusive.  So much so I can virtually guarantee I missed a better method along the way.  Casting a Face's Surface as a Cylinder, which seems appropriate, was a big roadblock.

The only success I could realize was via Face/NurbsSurface conversion.  I don’t find that conversion particularly dreadful (as I have done some programming for Rhino) but can see how it would be distasteful to others.

In any event, the code is below.  It only processes one solid at a time but will probably suffer the same level of inconsistency - as mentioned previously in this thread - for larger selection sets.

Code: [Select]
using System;
using System.Text;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.BoundaryRepresentation;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using System.Runtime.InteropServices;

using AcAp = Autodesk.AutoCAD.ApplicationServices;
using AcEd = Autodesk.AutoCAD.EditorInput;
using AcGe = Autodesk.AutoCAD.Geometry;
using AcRx = Autodesk.AutoCAD.Runtime;
using AcDb = Autodesk.AutoCAD.DatabaseServices;
using AcWd = Autodesk.AutoCAD.Windows;
using AcBr = Autodesk.AutoCAD.BoundaryRepresentation;

[assembly: CommandClass(typeof(CsMgdAcad5.STSCCommands))]

namespace CsMgdAcad5
{
    public class STSCCommands
    {

    /// <summary>
    /// Orient cylinder to return usefull BB info
    /// </summary>         
        public STSCCommands()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        // Define Command "CylinderSize"
        [CommandMethod("CylSize")]
        static public void CylinderDimensions() // This method can have any name
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            Transaction tr = db.TransactionManager.StartTransaction();

            try
            {
                // Prompt for selection of a solid
                PromptEntityOptions prEntOpt = new PromptEntityOptions("Select a 3D solid: ");
                prEntOpt.SetRejectMessage("\nPlease select only a 3D Solid");
                prEntOpt.AddAllowedClass(typeof(Solid3d), true);

                PromptEntityResult prEntRes = ed.GetEntity(prEntOpt);
                ObjectId[] objIds = { prEntRes.ObjectId };

                Solid3d sol = (Solid3d)tr.GetObject(prEntRes.ObjectId, OpenMode.ForRead);
                Brep brp = new Brep(sol);
                int cmplxCount = 0, shllCount = 0;

                foreach (Complex cmplx in brp.Complexes)
                {
                    ++cmplxCount;
                }
                if (cmplxCount == 1)
                {
                    List<AcBr.Complex> lstCmPlx = new List<AcBr.Complex>();
                    lstCmPlx.AddRange(brp.Complexes);
                    foreach (Shell shll in lstCmPlx[0].Shells)
                       {
                            ++shllCount;
                       }
                    if (shllCount == 1)
                    {
                        List<AcBr.Shell> lstShell = new List<AcBr.Shell>();
                        lstShell.AddRange(brp.Shells);
                        double LargestArea = 0.0;
                        Autodesk.AutoCAD.BoundaryRepresentation.Face FaceLarge = null;
                        foreach (Autodesk.AutoCAD.BoundaryRepresentation.Face fce in lstShell[0].Faces)
                            //Let's assume the Face with the largest area defines extrusion direction.
                            //This is certainly not a bullet proof assumption but will work for the time being
                        {
                            if (fce.GetArea() > LargestArea)
                            {
                                FaceLarge = fce;
                                LargestArea = FaceLarge.GetArea();
                            }
                        }
                        NurbSurface NS = FaceLarge.GetSurfaceAsNurb();
                        if (NS.IsPeriodicInU ^ NS.IsPeriodicInV)//Locate cylindrical like surface (needs work to exclude Cone and Torus)
                        {
                            NurbSurfaceDefinition NSD = NS.GetDefinition();
                            Point3dCollection P3C = NSD.ControlPoints;
                            int CPCount = P3C.Count;
                            int CPCountU = NS.NumControlPointsInU;
                            int CPCountV = NS.NumControlPointsInV;
                            Point3d dir1;
                            Point3d dir2;
                            if (NS.IsPeriodicInU)
                            {
                                dir1 = P3C[0];
                                dir2 = P3C[CPCount / CPCountV];
                            }
                            else
                            {
                                dir1 = P3C[0];
                                dir2 = P3C[CPCount / CPCountU];                                   
                            }
                            Vector3d DirV = (dir2.Subtract(dir1.GetAsVector())).GetAsVector();
                            Matrix3d mat = Matrix3d.WorldToPlane(DirV);
                            mat = mat.Inverse();
                            mat = mat.Transpose();
                            sol.UpgradeOpen();
                            sol.TransformBy(mat);
                            dir1 = sol.GeometricExtents.MinPoint;
                            dir2 = sol.GeometricExtents.MaxPoint;
                            double X = Math.Round(Math.Abs(dir1.X - dir2.X),6);
                            double Y = Math.Round(Math.Abs(dir1.Y - dir2.Y),6);
                            double Z = Math.Round(Math.Abs(dir1.Z - dir2.Z),6);
                            StringBuilder sb = new StringBuilder();
                            sb.Append("(");
                            sb.Append(X.ToString());
                            sb.Append(",");
                            sb.Append(Y.ToString());
                            sb.Append(",");
                            sb.Append(Z.ToString());
                            sb.Append(")");
                            ed.WriteMessage("\n" + sb.ToString());
                        }                           
                    }
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage("\nException in traversal: {0}", ex.Message);
            }
            finally
            {
                tr.Dispose();
            }
        }
    }
}
 
Sean Tessier
AutoCAD 2016 Mechanical

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Matrix3d and TransformBy help
« Reply #26 on: July 24, 2008, 12:35:05 PM »
fyi - Fenton Webb Just confirmed that there is a bug with 'Autodesk.AutoCAD.DatabaseServices.Solid3d.RemoveFaces' as the underlying AcDb3dSolid pointer is NULL and cannot be accessed... He is looking at this issue too - I'll let ya know.

Well at least we know what’s going on. Thanks for sharing the info  :-)

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Matrix3d and TransformBy help
« Reply #27 on: July 24, 2008, 12:38:12 PM »
Here’s my contribution to the effort.  ....

Wow! Very nice programming Sean!  8-)
I’ll give it a run in the AM.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Matrix3d and TransformBy help
« Reply #28 on: July 24, 2008, 01:07:14 PM »
Hi everyone,

I'm just a noob, but I've been following this post, because I'm the one who posited the question which got it all started back on the autodesk website.  I'm working on a solution for creating a lumber schedule from a 3d timber frame model that uses the I-J-K info from
MASSPROP to realign the ucs to an object. From there you can get the coords for an oriented bounding box (these OOB's are something that game programmers use alot).  This would essentially be the original uncut timber. I've been researching methods to calculate oriented bounding boxes using descriptive geometry....there's info if you want to google it.  A guy named o'Rourke wrote a algorithm back in the 90's that will do it for you based on coordinates....Its a rather complicated formula.

I wanted to comment on the approach of grabbing the longest edge of a "timber"  I am a timber framer and have attached a dwg with a single timber in which the longest edge does not accurately describe the required length of the uncut timber.  It is a Valley rafter and is essentially a parallelogram.  Does this in any way complicate the methods by which you guys are approaching this task?

keep up the great work,

Matt Araujo

Matt, I have compiled my routine for you to try. Some info for you, the routine searches for two edges in the solid that are perpendicular and share a common point, starting with the longest edge then iterating through until a match is found. If a match is found, the data from the edges is used to align the solid with the WCS; the routine then gets the bounding box data. Caveat,  It would be possible for the routine to pickup edges on say a compound miter and return incorrect dimensions.

Give it a shot, the command is Timber, you can find the DLL in the release folder of the attached solution


edit: removed old code
« Last Edit: August 06, 2008, 04:51:48 AM by Daniel »

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Matrix3d and TransformBy help
« Reply #29 on: July 24, 2008, 05:44:42 PM »
Nice work guys!

Dan'
instead of using 2 edges, can you grab the longest edge's normal? or maybe one off the edge's face (one of it's owners) to construct a matrix for xform.
Another way too, you don't need a perp edge, just grab any edge and xproduct it to give a perp vector to both edges, you can then square up the matrix by xproducting the new vec with the first edge vec ;)
hth
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien