Center and orient the view according to a rectangular polyline

Center and orient the view according to a rectangular polyline

Anonymous
Not applicable
1,702 Views
5 Replies
Message 1 of 6

Center and orient the view according to a rectangular polyline

Anonymous
Not applicable

Hello,

 

I'm trying to create a function wich create a "local" UCS based on an angle of a rectangle polyline. Associate to this custum UCS I create a View which is centered and oriented on the polyline. Here is a diagram to explain : 

 

View_Center.jpg

 

My issue here is to centering the view when the polyline is rotated.  Here is how I compute the polyline center :

 

private double symbol(double number)
        {
            return Math.Abs(number) / number;
        }

        private Point2d computeCenter(Point2d A, Point2d B)
        {
            double xCenter = A.X + symbol(A.X) * (B.X - Math.Abs(A.X)) / 2;
            double yCenter = A.Y + symbol(A.Y) * (B.Y - Math.Abs(A.Y)) / 2;
            
            return new Point2d(xCenter, yCenter);
        }

        public Point2d computeCenterRectangle(Polyline pline, Point3d origin, out Vector2d delta_X, out Vector2d delta_Y)
        {
            var pt1 = pline.GetPoint2dAt(0);
            var pt2 = pline.GetPoint2dAt(1);
            var pt3 = pline.GetPoint2dAt(2);
            var pt4 = pline.GetPoint2dAt(3);

            delta_X = new Vector2d();
            delta_Y = new Vector2d();

            Point2d center;

            // The point numbers are assigned in a clockwise direction
            if ((pt1.X < pt3.X && pt1.Y > pt3.Y) || (pt1.X > pt3.X && pt1.Y < pt3.Y))
            {
                if (origin == pline.GetPoint3dAt(0))
                {
                    delta_X = pt4 - pt1;
                    delta_Y = pt2 - pt1;

                    center = computeCenter(pt1, pt3);
                }
                else if (origin == pline.GetPoint3dAt(1))
                {
                    delta_X = pt1 - pt2;
                    delta_Y = pt3 - pt2;

                    center = computeCenter(pt2, pt4);
                }
                else if (origin == pline.GetPoint3dAt(2))
                {
                    delta_X = pt2 - pt3;
                    delta_Y = pt4 - pt3;

                    center = computeCenter(pt3, pt1);
                }
                else
                {
                    delta_X = pt3 - pt4;
                    delta_Y = pt1 - pt4;

                    center = computeCenter(pt4, pt2);
                }
            }
            // Point numbers are assigned counter-clockwise
            else
            {
                if (origin == pline.GetPoint3dAt(0))
                {
                    delta_X = pt2 - pt1;
                    delta_Y = pt4 - pt1;

                    center = computeCenter(pt1, pt3);
                }
                else if (origin == pline.GetPoint3dAt(1))
                {
                    delta_X = pt3 - pt2;
                    delta_Y = pt1 - pt2;

                    center = computeCenter(pt2, pt4);
                }
                else if (origin == pline.GetPoint3dAt(2))
                {
                    delta_X = pt4 - pt3;
                    delta_Y = pt2 - pt3;

                    center = computeCenter(pt3, pt1);
                }
                else
                {
                    delta_X = pt1 - pt4;
                    delta_Y = pt3 - pt4;

                    center = computeCenter(pt4, pt2);
                }
            }
            return center;
        }

 

 

And here is my function wich create the UCS and the view :

 

        public void DocumentCmd()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;

            // Polyline parameters
            ObjectId ids;
            Polyline pline;
            Point2d center;

            // UCS paramters
            Point3d origin;
            string nameUcs;
            
            // View parameters
            double viewAngle;
            string viewName;
            
            

            // Change the current USC to the usc's selected obect
            ed.Command("_.UCS", "_ob");


            // Save the new USC with the layout name
            nameUcs = "UCS_" + LA_Layout_Helper.nameLayout;
            ed.Command("_.UCS", "_name", "_sa", nameUcs, "");

            // Get the last objet selected
            PromptSelectionResult rectangleSelected = ed.SelectLast();
            if (rectangleSelected == null) return;
            ids = rectangleSelected.Value.GetObjectIds().ElementAt(0);

            using (var tr = db.TransactionManager.StartTransaction())
            {
                // Initialise the new SCU
                UcsTableRecord ucsRecord;

                // Open the UCS table for read
                var ucsTable = (UcsTable)tr.GetObject(db.UcsTableId, OpenMode.ForRead);


                // Check to see if the table record exists
                if (ucsTable.Has(nameUcs))
                {
                    ucsRecord = tr.GetObject(ucsTable[nameUcs], OpenMode.ForWrite) as UcsTableRecord;
                }
                else
                {
                    ucsRecord = new UcsTableRecord();
                    try
                    {
                        ucsRecord.Name = nameUcs;
                    }
                    catch (System.Exception)
                    {
                        ucsRecord.Name = "USC_";
                    }
                    

                    // Open the UCSTable for write
                    ucsTable.UpgradeOpen();

                    // Add the new UCS table record
                    ucsTable.Add(ucsRecord);
                    tr.AddNewlyCreatedDBObject(ucsRecord, true);
                }

                // Open the active viewport
                ViewportTableRecord acVportTblRec;
                acVportTblRec = tr.GetObject(doc.Editor.ActiveViewportId, OpenMode.ForWrite) as ViewportTableRecord;

                // Display the UCS Icon at the origin of the current viewport
                acVportTblRec.IconAtOrigin = true;
                acVportTblRec.IconEnabled = true;

                // Set the UCS current
                acVportTblRec.SetUcs(ucsRecord.ObjectId);
                doc.Editor.UpdateTiledViewportsFromDatabase();


                // Display the name of the current UCS
                UcsTableRecord uscTblRecActive;
                uscTblRecActive = tr.GetObject(acVportTblRec.UcsName, OpenMode.ForRead) as UcsTableRecord;

                Matrix3d newMatrix = new Matrix3d();
                newMatrix = Matrix3d.AlignCoordinateSystem(Point3d.Origin, 
                                                           Vector3d.XAxis, 
                                                           Vector3d.YAxis, Vector3d.ZAxis, 
                                                           acVportTblRec.Ucs.Origin, 
                                                           acVportTblRec.Ucs.Xaxis, 
                                                           acVportTblRec.Ucs.Yaxis, 
                                                           acVportTblRec.Ucs.Zaxis);


                // Save transformation matrix 
                LA_Layout_Helper.matrixLayout = new S_Matrix(newMatrix.ToString());
                la_project.Layouts[la_project.Layouts.Count - 1].Matrix = Matrix_Helper.S_Matrix_BuilderFromMatrixAcad(newMatrix);
                

                origin    = acVportTblRec.Ucs.Origin;
                viewAngle = (acVportTblRec.Ucs.Xaxis).GetAngleTo(Vector3d.XAxis, Vector3d.ZAxis);
                viewName  = "Vue_" + LA_Layout_Helper.nameLayout;
                pline     = (Polyline)tr.GetObject(ids, OpenMode.ForRead);
                center    = computeCenterRectangle(pline, origin, out Vector2d delta_X, out Vector2d delta_Y);             
                


                //réinitialise le ucs en wcs
                //ed.Command("_.UCS", "");

                ViewTable view;
                view = tr.GetObject(db.ViewTableId, OpenMode.ForRead) as ViewTable;
                
               
                // Check to see if the named view 'View1' exists
                if (view.Has(viewName) == false)
                {
                    // Open the View table for write
                    view.UpgradeOpen();

                    // Create a new View table record
                    ViewTableRecord viewRec = new ViewTableRecord();                   

                    viewRec.Name        = viewName;
                    viewRec.CenterPoint = center; 
                    viewRec.Height      = Math.Abs(delta_Y.Length);
                    viewRec.Width       = Math.Abs(delta_X.Length) + 50;
                    viewRec.ViewTwist   = viewAngle;

                    // Add the new View table record to the View table and the transaction
                    view.Add(viewRec);
                    tr.AddNewlyCreatedDBObject(viewRec, true);

                    // Set view current
                    doc.Editor.SetCurrentView(viewRec);                 
                   
                }                

                
                tr.Commit();
            }

            Vector3d Xucs = db.Ucsxdir;            
            Vector3d Xwcs = db.Ucsxdir;
			
            //Gives the angle of rotation of the board /WCS
            LA_Layout_Helper.angleLayout = Xucs.GetAngleTo(Xwcs);
        }

 

I think the problem comes from working in the wrong UCS but I do not see how to do otherwise. Initially I used the command : 

doc.SendStringToExecute("_.PLAN  ", false, false, false);

 

but it zooms out on the whole drawing when I just want to zoom in on a polyline.

 

 

Thank you for your help,
Alexis

0 Likes
Accepted solutions (2)
1,703 Views
5 Replies
Replies (5)
Message 2 of 6

Anonymous
Not applicable

Hello,

 

Hello,

To illustrate my issue, I drew a rectangular polyline with a random orientation. Then I executed my function.

 

I manually get the center of the polyline and it is the same as the "center" that I computed in my function. The problem here is the "viewRec.CenterPoint" does not have the same value... And I don't know why ?

 

View_Center_UCS_Problem.jpg

 

I don't know when we set the CenterPoint paramater in which UCS is it store ?

0 Likes
Message 3 of 6

_gile
Consultant
Consultant
Accepted solution

I'm afraid that as often, there is confusion between UCS and view which are two independent things. You can define a new User Coordinate System without affecting the view just as you can define a view without changing the current coordinate system.
So, first of all, the request should be clarified: is it just to define a view or is it also necessary to register a User Coordinate System for each polyline?
In any case, there is no direct correlation between UCS and view (command _PLAN option UCS does not define entirely the view, only its orientation).

 

As SendCommand does not run synchronously, it is not possible to specify center and zoom of the view after calling this method (use Editor command instead).

 

Je crains que comme souvent, il y a confusion entre UCS et vue qui sont deux chose indépendantes. On peut définir un nouveau Système de Coordonnées Utilisateur sans que ça n'affecte la vue tout comme on peut définir une vue sans modifier le système de coordonnées courant.
Il s'agirait donc tout d'abord de préciser la demande : s'agit-il juste de définir une vue ou est-il aussi nécessaire d'enregistrer un Système de Coordonnées Utilisateur pour chaque polyligne ?
Dans tous les cas, il n'y a pas de corrélation directe entr UCS et vue (la commande _PLAN option UCS ne définit pas entièrement la vue, uniquement son orientation).

 

Comme SendCommand ne s'exécute pas de façon synchrone, il n'est pas possible de spécifier le centre et le zoom de la vue après l'appel de cette méthode (utiliser Editor.Command à la place).



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 4 of 6

Anonymous
Not applicable

Thank you for your explanation.

 

Merci d'avoir pris le temps de me ré-expliquer ces notions 🙂 

 

 

If I understand correctly, the CenterPoint coordinates is based on the current UCS ?

 

So if I want to set it, is it recommended to come back to the default UCS

ed.Command("_.UCS", "");

 

set the CenterPoint and then use the new UCS ?

acVportTblRec.SetUcs(ucsRecord.ObjectId);
ed.UpdateTiledViewportsFromDatabase();

0 Likes
Message 5 of 6

_gile
Consultant
Consultant
Accepted solution

Only the editor environment uses UCS coordinates, in other words, prompt result outputs and command inputs.

So, if you pass a point to Editor.Command(), it have to be expressed in the current UCS.

 

But, in my opinion, you should try to avoid calling native commands when programming. Here's a little example on how to align the view to the selected segment of a rectangular polyline by code without using UCS. It works whatever the current UCS, the current view and the polyline plane.

 

        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var options = new PromptEntityOptions("\nSelect Polyline: ");
            options.SetRejectMessage("\nSelected object is not a Polyline.");
            options.AddAllowedClass(typeof(Polyline), true);
            var result = ed.GetEntity(options);
            if (result.Status != PromptStatus.OK) 
                return;
            using (var tr = new OpenCloseTransaction())
            {
                var pline = (Polyline)tr.GetObject(result.ObjectId, OpenMode.ForWrite);
                var ucs = ed.CurrentUserCoordinateSystem;

                using (var view = ed.GetCurrentView())
                {
                    var pt1 = pline.GetClosestPointTo(result.PickedPoint.TransformBy(ucs), view.ViewDirection, false);
                    int index = (int)pline.GetParameterAtPoint(pt1);

                    // assuming the select polyline is rectangular
                    var seg1 = pline.GetLineSegment2dAt(index);
                    double angle = seg1.Direction.Angle;
                    LineSegment2d seg2;
                    Point2d center2d;
                    if (index == 0)
                    {
                        seg2 = pline.GetLineSegment2dAt(index + 1);
                        center2d = new LineSegment2d(seg1.StartPoint, seg2.EndPoint).MidPoint;
                    }
                    else
                    {
                        seg2 = pline.GetLineSegment2dAt(index - 1); 
                        center2d = new LineSegment2d(seg2.StartPoint, seg1.EndPoint).MidPoint;
                    }
                    var wcsCenter = new Point3d(center2d.X, center2d.Y, pline.Elevation)
                        .TransformBy(Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, pline.Normal)));
                    var worldToEye =
                        Matrix3d.WorldToPlane(view.ViewDirection) *
                        Matrix3d.Displacement(view.Target.GetAsVector().Negate()) *
                        Matrix3d.Rotation(view.ViewTwist, view.ViewDirection, view.Target);
                    var viewCenter = wcsCenter.TransformBy(worldToEye);

                    view.Width = seg1.Length * 1.2;
                    view.Height = seg2.Length * 1.2;
                    view.ViewDirection = pline.Normal;
                    view.ViewTwist = -angle;
                    view.CenterPoint = new Point2d(viewCenter.X, viewCenter.Y);
                    ed.SetCurrentView(view);
                }
                tr.Commit();
            }
        }

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 6 of 6

Anonymous
Not applicable

Thank you very much for your help and time, as I had been struggling with this problem for a long time.

 

I will try to adapt this solution to create and save the view at the same time as I create the UCS (so that the user only needs to click on this rectangular polyline once). Because in my case, the user can have different rectangular polylines that represent a work area (in French Métrés) and switch from one to another. So for each work area there is a specific view and when this area is selected (in a combobox) I zoom in on it.

0 Likes