TheSwamp

Code Red => .NET => Topic started by: kdub_nz on March 06, 2023, 08:09:42 PM

Title: Stretch pline (segment ) in XAxis
Post by: kdub_nz on March 06, 2023, 08:09:42 PM
This is a proof of concept in answer to a request here :
https://forums.autodesk.com/t5/net/how-to-make-two-polylines-eachother/m-p/11769374#M75981
Quote
How to make two polylines eachother.
Hello, everyone. Now I have to make two polylines (these are separated each other) touch.Is there a way to implement this process

Expectatons:
Target segment endpoints shall be align in the Y axis ( same X value ).
Actor segment shall be 'moved' to align with Target segment.
Polylines are expected to be planar.

No special consideration given to UCS (polylines are generated on world X-Y

The new vertex points seem to be accurate ( out to a displayable 11 decimal places )

This code needs polishing before being used in production code, but it seems adequate.

Code - C#: [Select]
  1. // (C) CodeHimBelonga: kdub 2023/03/07
  2. //
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.EditorInput;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.Runtime;
  7. using System;
  8.  
  9. //using Kdub.Common;
  10. using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
  11.  
  12. [assembly: CommandClass(typeof(TouchingPolylines.TestCommands_02))]
  13.  
  14. namespace TouchingPolylines
  15. {
  16.    /// <summary>
  17.    /// Refer Commands_02_Helper.cs
  18.    /// </summary>
  19.    public partial class TestCommands_02
  20.    {
  21.       [CommandMethod("StretchPline")]
  22.       public static void StretchPline()
  23.       {
  24.          var peo = new PromptEntityOptions("\nSelect a Polyline Segment to Stretch: ");
  25.          peo.SetRejectMessage("\nMust be a Polyline...");
  26.          peo.AddAllowedClass(typeof(Polyline), true);
  27.          var perActor = _ed.GetEntity(peo);
  28.  
  29.          if (perActor.Status != PromptStatus.OK) return;
  30.  
  31.          peo = new PromptEntityOptions("\nSelect a Target Polyline Segment: ");
  32.          peo.SetRejectMessage("\nMust be a Polyline...");
  33.          peo.AddAllowedClass(typeof(Polyline), true);
  34.          var perTarget = _ed.GetEntity(peo);
  35.  
  36.          if (perTarget.Status != PromptStatus.OK) { return; }
  37.  
  38.          using (Transaction tr = _doc.TransactionManager.StartTransaction())
  39.          {
  40.             (bool success, double XAxis) = GetTargetSegmentXAxis(perTarget);
  41.  
  42.             // TODO : refactor out debug statements
  43.             if (success) { _ed.WriteMessage($"\nGetTargetSegmentXAxis: {XAxis}\n"); }
  44.             else
  45.             {
  46.                _ed.WriteMessage($"GetTargetSegmentXAxis: Failed\n");
  47.                return;
  48.             }
  49.  
  50.             // . . . . continue and change Actor VertexPoints
  51.             SetActorVertexPoints(perActor, XAxis);
  52.  
  53.             tr.Commit();
  54.          }
  55.       }
  56.  
  57.       private static void SetActorVertexPoints(PromptEntityResult perActor, double xAxis)
  58.       {
  59.          Transaction tr = _db.TransactionManager.TopTransaction;
  60.          var pline = (Polyline)tr.GetObject(perActor.ObjectId, OpenMode.ForWrite);
  61.          var wcsPickedPoint = perActor.PickedPoint.TransformBy(_ed.CurrentUserCoordinateSystem);
  62.          var wcspointOnPline = pline.GetClosestPointTo(wcsPickedPoint, false);
  63.          var segmentIndex = (int)pline.GetParameterAtPoint(wcspointOnPline);
  64.  
  65.          if (pline.GetSegmentType(segmentIndex) == SegmentType.Line)
  66.          {
  67.             Point2d p1 = pline.GetPoint2dAt(segmentIndex);
  68.             int vertexCount = pline.NumberOfVertices;
  69.             int p2Index =  segmentIndex + 1 < vertexCount ? segmentIndex + 1 : 0;
  70.             Point2d p2 = pline.GetPoint2dAt(p2Index);
  71.  
  72.             // TODO : refactor out debug statements
  73.             _ed.WriteMessage($"p1: {p1}\n");
  74.             _ed.WriteMessage($"p2: {p2}\n");
  75.  
  76.             p1 = new Point2d(xAxis, p1.Y);
  77.             pline.SetPointAt(segmentIndex, p1);
  78.             p2 = new Point2d(xAxis, p2.Y);
  79.             pline.SetPointAt(p2Index, p2);
  80.  
  81.             _ed.WriteMessage($"NEW p1: {p1}\n");
  82.             _ed.WriteMessage($"NEW p2: {p2}\n");
  83.          }
  84.       }
  85.       private static Tuple<bool, double> GetTargetSegmentXAxis(PromptEntityResult per)
  86.       {
  87.          bool success = default;
  88.          double xAxis = default;
  89.          
  90.          Transaction tr = _db.TransactionManager.TopTransaction;
  91.  
  92.          var pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForRead);
  93.          var wcsPickedPoint = per.PickedPoint.TransformBy(_ed.CurrentUserCoordinateSystem);
  94.          var wcspointOnPline = pline.GetClosestPointTo(wcsPickedPoint, false);
  95.          var segmentIndex = (int)pline.GetParameterAtPoint(wcspointOnPline);
  96.          if (pline.GetSegmentType(segmentIndex) == SegmentType.Line)
  97.          {
  98.             LineSegment2d segment = pline.GetLineSegment2dAt(segmentIndex);
  99.             xAxis = segment.StartPoint.X;
  100.             success = true;
  101.          }
  102.  
  103.          return Tuple.Create(success, xAxis);
  104.       }
  105.    }
  106. }
  107.  
  108.  

Partial Class Helper
Code - C#: [Select]
  1. // (C) CodeHimBelonga: kdub 2023/03/03
  2. //
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.EditorInput;
  6. using Autodesk.AutoCAD.Geometry;
  7.  
  8. using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
  9.  
  10. namespace TouchingPolylines
  11. {
  12.    /// <summary>
  13.    /// Required for Commands_02.cs
  14.    /// </summary>
  15.    public partial class TestCommands_02
  16.    {
  17.       private static Document _doc => AcadApp.DocumentManager.MdiActiveDocument;
  18.       private static Database _db => _doc.Database;
  19.       private static Editor _ed => _doc.Editor;
  20.  
  21.       /// <summary>
  22.       /// Writes the message.
  23.       /// </summary>
  24.       /// <param name="msg">The MSG.</param>
  25.       private static void WriteMessage(string msg) => _ed.WriteMessage(msg);
  26.  
  27.       // A generalized IsPointOnCurve function that works on all
  28.       // types of Curve (including PolyLines), and checks the position
  29.       // of the returned point rather than relying on catching an
  30.       // exception
  31.       /// <summary>
  32.       /// Determines [is point on the specified curve],
  33.       /// using GetClosestPointTo() with Tolerance.Global.EqualPoint.
  34.       /// </summary>
  35.       /// <param name="cv">The cv.</param>
  36.       /// <param name="pt">The pt.</param>
  37.       /// <returns>
  38.       ///   <c>true</c> if [is point on the specified curve]; otherwise, <c>false</c>.
  39.       /// </returns>
  40.       private static bool IsPointOnCurveGCP(Curve cv, Point3d pt)
  41.       {
  42.          try
  43.          {            
  44.             Point3d p = cv.GetClosestPointTo(pt, false);
  45.             return ( p - pt ).Length <= Tolerance.Global.EqualPoint;
  46.          }
  47.          catch { }
  48.  
  49.          // Otherwise we return false
  50.          return false;
  51.       }    
  52.    }
  53. }
  54.