Jump to content

Who knows how to solve this piping problem with AutoCAD


nestly

Recommended Posts

Yeah, that drawing is far from self-explanatory. The crux, though, are the tangent lines (the red line, and the two rays). They describe the mating condition of arc/arc and line/arc. The arc/arc mate (red line) will always be at 45 degrees to its axis, no matter the rotation. A Cone is the 3d manifestation of that.

 

I’m only interested in one elevation. A cone sliced at one elevation (an elevation parallel to the axis) will produce a hyperbola. I remembered that from the “Conic Section” section of some HS math classes. I was able to analyze a progression of tangent lines as they made their way through the circle/hyperbola to find a point where a 12” radius (for example) was available.

 

That demo drawing leaves out much of the latter analysis – it just illustrates a way of reducing the amount of variables.

 

I’ll compile the routine, post that and the source code sometime tomorrow.

 

I'd have never thought about slicing a cone... most of my efforts involved a sphere. There's no hurry, I don't have any current projects with this condition, but I am looking forward to knowing how to do it right for future application, as well as updating my existing facility plans where I had to "fudge it"

Link to comment
Share on other sites

  • Replies 78
  • Created
  • Last Reply

Top Posters In This Topic

  • nestly

    27

  • SEANT

    12

  • ROBP

    12

  • JD Mather

    11

Top Posters In This Topic

Posted Images

Here is the compiled routine. Unzip the file and save it to a location on the local machine. NETLOAD it into AutoCAD – depending on where the file is located, AutoCAD may warn you that a file is being run from a non-trusted location.

 

Type BiRollOffset to initiate the command.

 

Enter angle off of parallel

 

Enter elevation change

 

Enter elbow radius

 

This is still a fairly crude routine, i.e. not a lot of error handling. It may be wise to only use it in an isolated instance of AutoCAD.

If you prefer to compile the routine yourself, see the source below.

 

 

 

// (C) Copyright 2014 by Sean Tessier  
//
using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;


[assembly: CommandClass(typeof(BiRollOffset.MyCommands))]

namespace BiRollOffset
{

   public class MyCommands
   {
       //Fields
       private double m_radOfElbowBend;
       private CircularArc3d m_controlRevolve;
       private double m_elevChange;
       private double m_angOffColinear;
       private NurbCurve3d m_hyperbola;
       private Ray3d m_offAnglePipe;
       private CircularArc3d m_control;
       private CircularArc3d m_variable;
       private Vector3d m_offAngleDirection;
       private Vector3d m_toCirc;
       private double m_toCircLen;
       private double m_tempAng;

       [CommandMethod("STSCGroup", "BiRollOffset", "BiRoll", CommandFlags.Modal)]
       public void CommandInit() 
       {
           Document doc = Application.DocumentManager.MdiActiveDocument;
           Database db = doc.Database;
           Editor ed = doc.Editor;
           PromptDoubleOptions pdo = new PromptDoubleOptions("\nEnter angle off of parallel: ");
           pdo.AllowArbitraryInput = false;
           pdo.AllowNegative = false;
           PromptDoubleResult pdr = ed.GetDouble(pdo);
           if (pdr.Status != PromptStatus.OK || pdr.Value <= 0) return;
           m_angOffColinear = Math.PI * (pdr.Value + 90.0) / 180;
           m_offAngleDirection = new Vector3d(Math.Cos(m_angOffColinear), Math.Sin(m_angOffColinear), 0.0);

           pdo.Message = " Enter elevation of higher pipe above lower:";
           pdr = ed.GetDouble(pdo);
           if (pdr.Status != PromptStatus.OK || pdr.Value <= 0) return;
           m_elevChange = pdr.Value;

           pdo.Message = " Enter bend radius of elbows";
           pdr = ed.GetDouble(pdo);
           if (pdr.Status != PromptStatus.OK || pdr.Value <= 0) return;
           m_radOfElbowBend = pdr.Value;

           m_hyperbola = CreateHyperbola(m_elevChange);
           double YProj;
           m_controlRevolve = CreateRevolve(m_radOfElbowBend, out YProj);
           m_control = new CircularArc3d(new Point3d(0.0, -YProj, m_radOfElbowBend), new Vector3d(1.0, 0.0, 0.0), new Vector3d(0.0, 0.0, -1.0), m_radOfElbowBend, 0.0, Math.PI / 4);
           PointOnCurve3d POC3D = new PointOnCurve3d(m_hyperbola, 0.5);
           PointOnCurve3d POC3DCirc = new PointOnCurve3d(m_controlRevolve, 0.0);
           Interval TargetRegion = new Interval(0.0, 0.5, .0000001);
           double SpanIncrement = TargetRegion.Length / 100.0;
           for (int i = 0; i < 100; i++)
           {
               if (CompAngles(ref TargetRegion, i, SpanIncrement, ref POC3D, ref POC3DCirc))
               {
                   SpanIncrement = TargetRegion.Length / 100.0;
                   for (int j = 0; j < 100; j++)
                   {
                       if (CompAngles(ref TargetRegion, j, SpanIncrement, ref POC3D, ref POC3DCirc))
                       {
                           SpanIncrement = TargetRegion.Length / 100.0;
                           for (int k = 0; k < 100; k++)
                           {
                               if (CompAngles(ref TargetRegion, k, SpanIncrement, ref POC3D, ref POC3DCirc))
                               {
                                   m_offAnglePipe = new Ray3d(POC3D.Point, m_offAngleDirection);
                                   double Param = m_offAnglePipe.GetParameterAtLength(0.0, m_toCircLen, true, 0.003);
                                   Point3d OffAngStart = m_offAnglePipe.EvaluatePoint(Param);
                                   MakeVariableArc(ref POC3DCirc, OffAngStart);
                                   MakeDrawing(ref POC3D, ref POC3DCirc, ref db, OffAngStart);
                                   if (POC3D != null) POC3D.Dispose();
                                   if (m_hyperbola != null) m_hyperbola.Dispose();
                                   return; 
                               } 
                           }  
                       }
                   }
               }
           }
           ed.WriteMessage("\nNo solution Found!");
       }

       //Create hyperbola geometry based and 45 degree elbow of the given radius
       private NurbCurve3d CreateHyperbola(double Elev)
       {
           NurbCurve3d ToReturn = null;
           KnotCollection KC = new KnotCollection();
           KC.Add(0.0);
           KC.Add(0.0);
           KC.Add(0.0);
           KC.Add(1.0);
           KC.Add(1.0);
           KC.Add(1.0);

           DoubleCollection DC = new DoubleCollection(3);
           DC.Add(1.0);
           DC.Add(2.0);
           DC.Add(1.0);

           Double Offset = (Elev * (Math.Sqrt(3 / 4.0))) * 2.0;
           Point3dCollection P3Dc = new Point3dCollection();
           P3Dc.Add(new Point3d(-Offset, 2.0 * Elev, Elev));
           P3Dc.Add(new Point3d(0, Elev / 2.0, Elev));
           P3Dc.Add(new Point3d(Offset, 2.0 * Elev, Elev));
           ToReturn = new NurbCurve3d(2, KC, P3Dc, DC, false);
           return ToReturn;
       }

       //Circle that represents the revoved end of 45 deg elbow
       private CircularArc3d CreateRevolve(double Rad, out double ArcStart)
       {
           double Offset = (1 - Math.Sqrt(1 / 2.0)) * Rad;
           CircularArc3d ToReturn = null;
           ToReturn = new CircularArc3d(new Point3d(0, Offset, 0), new Vector3d(0, -1, 0), Offset);
           double YProj = Rad * Math.Sqrt(1 / 2.0);
           ArcStart = YProj - Offset;
           return ToReturn;
       }

       //Determine if the angle between tangent line and off angle pipe run allows for desired elbow radius
       private bool CompAngles(ref Interval TargetRegion, int Step, double SpanIncrement, ref PointOnCurve3d POCHyp, ref PointOnCurve3d POCCirc)
       {
           double toModify = Step * SpanIncrement;
           double StartParam = TargetRegion.UpperBound;
           StartParam -= toModify;
           POCHyp.Parameter = StartParam;
           POCCirc = m_controlRevolve.GetClosestPointTo(POCHyp.Point);
           m_toCirc = POCHyp.Point.GetVectorTo(POCCirc.Point);
           m_tempAng = m_toCirc.GetAngleTo(m_offAngleDirection) / 2.0;
           m_tempAng = (Math.PI / 2) - m_tempAng;
           m_toCircLen = m_toCirc.Length;
           double TempToCirc = m_toCircLen / Math.Abs(Math.Tan(m_tempAng));
           if (TempToCirc > m_radOfElbowBend)
           {
               TargetRegion = new Interval(StartParam, StartParam + SpanIncrement, .0000001);
               return true;
           }
           return false;
       }

       //Create geometry for arc insertion into drawing
       private void MakeVariableArc(ref PointOnCurve3d POCCirc, Point3d EndPoint)
       {
           Vector3d Norm = m_offAngleDirection.CrossProduct(m_toCirc).GetNormal();
           Vector3d RotatedCircCopy = new Vector3d(m_toCirc.X, m_toCirc.Y, m_toCirc.Z);
           RotatedCircCopy = RotatedCircCopy.RotateBy(Math.PI / 2, Norm);
           Line3d FromCirc = new Line3d(POCCirc.Point, RotatedCircCopy);

           Vector3d RotatedHypCopy = new Vector3d(m_offAngleDirection.X, m_offAngleDirection.Y, m_offAngleDirection.Z);
           RotatedHypCopy = RotatedHypCopy.RotateBy(Math.PI / 2, Norm);
           Line3d FromHyp = new Line3d(EndPoint, RotatedHypCopy);
           Point3d Center = FromCirc.IntersectWith(FromHyp)[0];
           m_variable = new CircularArc3d(Center, Norm, RotatedCircCopy, m_radOfElbowBend, 0.0, m_tempAng * 2.0);

       }

       //Insert the various elements into drawing
       private void MakeDrawing(ref PointOnCurve3d POC3DHyp, ref PointOnCurve3d POC3DCirc, ref Database db, Point3d OffAngStart)
       {
           Point3d Intersect = POC3DCirc.Point;
           double Angle = Math.Atan(Math.Abs(Intersect.X) / Math.Abs(Intersect.Z));
           m_control.RotateBy(Angle, new Vector3d(0.0, -1.0, 0.0), new Point3d());
           Arc ControlArc = Curve.CreateFromGeCurve(m_control) as Arc;
           if (ControlArc == null) return;

           Ray ToControl = new Ray();
           ToControl.BasePoint = m_control.StartPoint;
           ToControl.SecondPoint = m_control.StartPoint + new Vector3d(0.0, -1.0, 0.0);

           Arc OffAngArc = Curve.CreateFromGeCurve(m_variable) as Arc;
           if (OffAngArc == null) return;

           Ray OffAng = new Ray();
           OffAng.BasePoint = m_variable.EndPoint;
           OffAng.SecondPoint = m_variable.EndPoint + m_offAngleDirection;

           using (Transaction tr = db.TransactionManager.StartTransaction())
           {

               BlockTableRecord btr = (BlockTableRecord)(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite));

               ControlArc.SetDatabaseDefaults();
               btr.AppendEntity(ControlArc);
               tr.AddNewlyCreatedDBObject(ControlArc, true);

               ToControl.SetDatabaseDefaults();
               btr.AppendEntity(ToControl);
               tr.AddNewlyCreatedDBObject(ToControl, true);

               OffAngArc.SetDatabaseDefaults();
               btr.AppendEntity(OffAngArc);
               tr.AddNewlyCreatedDBObject(OffAngArc, true);

               OffAng.SetDatabaseDefaults();
               btr.AppendEntity(OffAng);
               tr.AddNewlyCreatedDBObject(OffAng, true);

               tr.Commit();

           }

       }


   }

}

BiRollOffset.zip

Link to comment
Share on other sites

I should also point out that the routine is only compatible with AutoCAD 2013, 2014, and (conceivably) 2015.

 

 

And another aspect of the routines crude nature is that it only produces geometry in one orientation - with the off angle pipe centerline set counterclockwise from the positive Y axis.

Link to comment
Share on other sites

Hi Sean, I'm not sure what I'm doing wrong, but I can't get it to load (AutoCAD2014) I put it in my Lisps folder, so it's in a Trusted location, but I get an Unknown Command error when I try to run it.

 

Command: _NETLOAD
Cannot load assembly. Error details: System.IO.FileLoadException: Could not load file or assembly 'file:///C:\AutoCAD2014 Support Files\Lisps\BiRollOffset.dll' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
File name: 'file:///C:\AutoCAD2014 Support Files\Lisps\BiRollOffset.dll' ---> System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable ....

Edited by nestly
Link to comment
Share on other sites

Sorry, should have mentioned this earlier, you will probably have to Unblock the file (a Windows safety feature for files originating on a Computer other than the current). Right-click on the file and look for Unblock on the General tab.

Link to comment
Share on other sites

Incidentally, post back if you run into any bugs. Early on a ran into a couple of parameter sets that caused trouble, those particular sets are now working.

 

 

As it stands the routine will just produce wanky geometry if the input radius is incapable of spanning the vertical rise. Down the road I'll try to correct these issues.

Link to comment
Share on other sites

It's working perfectly without any errors so far. :notworthy: I can't thank you enough for your help... this solves a problem that's been bugging me for years.

Link to comment
Share on other sites

. . . . he can just conjure one up at will.

 

That would be a neat trick. Of course, I'd always be too schnockered to code straight.:)

Link to comment
Share on other sites

Update. I've used your code in several drawings now and it's working great. :D The only minor issue I've found is actually an AutoCAD limitation when the angle isn't an even number and I have to input a "rounded" angle as reported by AutoCAD (ie 51.60087231). None the less, it's still about 10000x more accurate and 100x times faster than how I had been doing it...

Link to comment
Share on other sites

Update. I've used your code in several drawings now and it's working great. :D The only minor issue I've found is actually an AutoCAD limitation when the angle isn't an even number and I have to input a "rounded" angle as reported by AutoCAD (ie 51.60087231). None the less, it's still about 10000x more accurate and 100x times faster than how I had been doing it...

 

 

That's good to hear. The routine does a fair bit of rounding as well - I can see how a couple of compounding iterations could create issues.

 

. . . .

 

The only other condition I occasionally run into is when the "rise" is too small to use a standard 45, and both fittings need to be cut back (usually to the same angle).

 

. . . .

 

 

Let me know if this is a common enough situation. The same general procedure may be malleable enough to account for this.

Link to comment
Share on other sites

 

Let me know if this is a common enough situation. The same general procedure may be malleable enough to account for this.

 

It's not a common condition. but it does happen occasionally. I'm pretty happy with what you've done, but if you want an additional challenge, it would be cool if the angle and elevation could be established by "picking" two objects (lines) and have the result appear at that location (similar to how a FILLET would work)

Link to comment
Share on other sites

Just wanted to slide in real quick to say that I'm glad to see you active again Nestly. You were on a bit of a hiatus for a while. :)

 

Sorry to thread jack.

Link to comment
Share on other sites

It's not a common condition. but it does happen occasionally. I'm pretty happy with what you've done, but if you want an additional challenge, it would be cool if the angle and elevation could be established by "picking" two objects (lines) and have the result appear at that location (similar to how a FILLET would work)

 

 

That would be very AutoCADesque. I'll give the routine some additional attention.

Link to comment
Share on other sites

Just wanted to slide in real quick to say that I'm glad to see you active again Nestly. You were on a bit of a hiatus for a while. :)

 

Sorry to thread jack.

+1 :beer:
Link to comment
Share on other sites

  • 3 weeks later...

Please understand what follows is an opinion and I recognize it as such. The moniker "rolling offset" with regard to piping is heard constantly and confuses many- not necessary to deal with. From geometry, the axiom "two parallel lines determine a plane." Using AutoCAD, pick the 3-point ucs icon, snap to the centerline of first pipe, snap to other end of that pipe, then snap to centerline of second pipe. UCS is then set to the plane determine by pipe centerlines. Type "plan"-now you're looking straight down on the two pipes and can lay out the connection using whatever degree ells you want. The problem of connecting two pipes can also be solved with trig by using the arc-tangent of the amount of offset and the centerline radius of the offset be determined, also. The problem with this method is that the radius point of pipe ells is fixed and probably want coincide with the available ells. With round sheet metal ducts, though, trig works like a champ.

Link to comment
Share on other sites

Please understand what follows is an opinion .....

 

I would caution not underestimate the true complexity of this problem.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...