How to use code to implement the same function as the command ‘chspace’?

How to use code to implement the same function as the command ‘chspace’?

swaywood
Collaborator Collaborator
624 Views
3 Replies
Message 1 of 4

How to use code to implement the same function as the command ‘chspace’?

swaywood
Collaborator
Collaborator

Hi:

I have a problem.

There are multiple viewports in a layout.

Now I want to copy the elements in the viewport to the current layout by selecting the viewport.

The effect is like the command chspace.

However, for some reason, I cannot use the chspace command.

I also tried to use the GetPaperToModelTransform method to convert elements,

but the elements were only scaled and did not come to the current layout.

    [CommandMethod("TIV")]
    public void TIV()
    {

      Document doc = null;
      Database db = null;
      Editor ed = null;



      try
      {
        doc = AcadApp.DocumentManager.MdiActiveDocument;
        db = doc.Database;
        ed = doc.Editor;
        LayoutManager layoutManager = LayoutManager.Current;


        string layoutName = layoutManager.CurrentLayout;
        ObjectId layoutId = layoutManager.GetLayoutId(layoutName);

        ObjectId vpId = ObjectId.Null;
        using (Transaction tr = db.TransactionManager.StartTransaction())
        {
          Layout layout = (Layout)tr.GetObject(layoutId, OpenMode.ForRead);
          var vpIds = layout.GetViewports();
          if (vpIds.Count > 0)
            vpId = vpIds[1];        // First Viewport is Paperspace itself. Only one Viewport will be evaluated.
          tr.Commit();
        }
        if (vpId.IsNull)
          throw new System.Exception("No Viewport found in: " + layoutName);


        List<Point3d> vpOutlinePntsInMs = null;
        Viewport vp = null;
        using (Transaction tr = db.TransactionManager.StartTransaction())
        {
          vp = (Viewport)tr.GetObject(vpId, OpenMode.ForRead);
          //For now w'll assume the Viewport outline is a Polyline.
          Polyline vpOutlineInMs = null;
          if (vp.NonRectClipOn)
          {
            ObjectId vpClipId = vp.NonRectClipEntityId;
            Entity vpBoundary = (Entity)tr.GetObject(vpClipId, OpenMode.ForRead);
            vpOutlineInMs = (Polyline)vpBoundary.Clone();
          }
          else
          {
            Extents3d vpExt = vp.GeometricExtents;
            vpOutlineInMs = new Polyline(4);
            vpOutlineInMs.AddVertexAt(0, new Point2d(vpExt.MinPoint.X, vpExt.MinPoint.Y), 0, 0, 0);
            vpOutlineInMs.AddVertexAt(1, new Point2d(vpExt.MaxPoint.X, vpExt.MinPoint.Y), 0, 0, 0);
            vpOutlineInMs.AddVertexAt(2, new Point2d(vpExt.MaxPoint.X, vpExt.MaxPoint.Y), 0, 0, 0);
            vpOutlineInMs.AddVertexAt(3, new Point2d(vpExt.MinPoint.X, vpExt.MaxPoint.Y), 0, 0, 0);
            vpOutlineInMs.Closed = true;

          }


          // ViewportExtensionMethods.cs  (c) 2007-2012  Tony Tanzillo
          Point3d center = new Point3d(vp.ViewCenter.X, vp.ViewCenter.Y, 0.0);
          Matrix3d msToPs = Matrix3d.Displacement(new Vector3d(vp.CenterPoint.X - center.X, vp.CenterPoint.Y - center.Y, 0.0))
                                  * Matrix3d.Scaling(vp.CustomScale, center)
                                  * Matrix3d.Rotation(vp.TwistAngle, Vector3d.ZAxis, Point3d.Origin)
                                  * Matrix3d.WorldToPlane(new Plane(vp.ViewTarget, vp.ViewDirection));
          vpOutlineInMs.TransformBy(msToPs.Inverse());

          vpOutlinePntsInMs = new List<Point3d>();
          for (int i = 0; i < vpOutlineInMs.NumberOfVertices; i++)
            vpOutlinePntsInMs.Add(vpOutlineInMs.GetPoint3dAt(i));

          List<Entity> lst = new List<Entity>();

          var ms = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead);
          foreach (ObjectId entId in ms)
          {
            Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForRead);
            var entExtents = ent.GeometricExtents;

            //For now the entity is inside when all Extent points are.
            var pt1 = ent.GeometricExtents.MinPoint;
            var pt2 = new Point3d(ent.GeometricExtents.MaxPoint.X, ent.GeometricExtents.MinPoint.Y, 0);
            var pt3 = ent.GeometricExtents.MaxPoint;
            var pt4 = new Point3d(ent.GeometricExtents.MinPoint.X, ent.GeometricExtents.MaxPoint.Y, 0);

            if (IsInside2D(vpOutlinePntsInMs.ToArray(), pt1) && IsInside2D(vpOutlinePntsInMs.ToArray(), pt2) &&
                IsInside2D(vpOutlinePntsInMs.ToArray(), pt2) && IsInside2D(vpOutlinePntsInMs.ToArray(), pt4))
            {
              ed.WriteMessage("\n Entity in Viewport: {0} ({1})", entId.Handle, entId.ObjectClass.DxfName);
              lst.Add(ent);
            }
          }

          vp.UpgradeOpen();
          lst.ModelToPaper(vp);
          vp.DowngradeOpen();
          tr.Commit();
        }
      }
      catch (System.Exception ex)
      {
        if (ed != null)
          ed.WriteMessage("\n Error: " + ex.Message);
      }
    }

 

    public static void ModelToPaper(this List<Entity> src, Viewport viewport)
    {
      Matrix3d xform = GetModelToPaperTransform(viewport);
      foreach (Entity ent in src)
      {
        ent.UpgradeOpen();
        ent.TransformBy(xform);
        ent.DowngradeOpen();
      }
    }

    public static Matrix3d GetModelToPaperTransform(this Viewport vport)
    {
      if (vport.PerspectiveOn)
        throw new NotSupportedException("不支持透视图");
      Point3d center = new Point3d(vport.ViewCenter.X, vport.ViewCenter.Y, 0.0);
      Vector3d v = new Vector3d(vport.CenterPoint.X - center.X, vport.CenterPoint.Y - center.Y, 0.0);
      return Matrix3d.Displacement(v)
        * Matrix3d.Scaling(vport.CustomScale, center)
        * Matrix3d.Rotation(vport.TwistAngle, Vector3d.ZAxis, Point3d.Origin)
        * Matrix3d.WorldToPlane(new Plane(vport.ViewTarget, vport.ViewDirection));
    }
0 Likes
Accepted solutions (1)
625 Views
3 Replies
Replies (3)
Message 2 of 4

norman.yuan
Mentor
Mentor

All your code do are transforming entities geometrically (scaling), as you already know, but the entities still belong to the space (ModelSpace or corresponding Layout/PaperSpace) they were before the transforming.  If you want to achieve the same effect as the "chspace" command, you need to actually change these entities from ModelSpace to PaperSpace (or the reverse)., either by changing the entity's owner, or creating new one in one space and erase old one in the other space.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 4

_gile
Consultant
Consultant
Accepted solution

Hi,

Here's a way:

 

        [CommandMethod("TIV", CommandFlags.NoTileMode)]
        public void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            if ((short)Application.GetSystemVariable("CVPORT") != 1)
                ed.SwitchToPaperSpace();

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                var vp = curSpace
                    .Cast<ObjectId>()
                    .Where(id => id.ObjectClass.Name == "AcDbViewport")
                    .Select(id => (Viewport)tr.GetObject(id, OpenMode.ForRead))
                    .Where(v => 1 < v.Number)
                    .FirstOrDefault();

                if (vp == null || !ViewportToPolygon(vp).Any())
                    return;

                var PSDCS2WCS = vp.DCS2WCS() * vp.PSDCS2DCS();
                var polygon = new Point3dCollection(
                    ViewportToPolygon(vp)
                    .Select(p => p.TransformBy(PSDCS2WCS))
                    .ToArray());

                ed.SwitchToModelSpace();
                Application.SetSystemVariable("CVPORT", vp.Number);
                var selection = ed.SelectWindowPolygon(polygon);
                if (selection.Status != PromptStatus.OK)
                    return;

                ed.SwitchToPaperSpace();
                var mapping = new IdMapping();
                db.DeepCloneObjects(
                    new ObjectIdCollection(selection.Value.GetObjectIds()),
                    db.CurrentSpaceId,
                    mapping,
                    false);
                var WCS2PSDCS = vp.DCS2PSDCS() * vp.WCS2DCS();
                foreach (IdPair pair in mapping)
                {
                    if (pair.IsCloned && pair.IsPrimary)
                    {
                        var clone = (Entity)tr.GetObject(pair.Value, OpenMode.ForWrite);
                        clone.TransformBy(WCS2PSDCS);
                        tr.GetObject(pair.Key, OpenMode.ForWrite).Erase();
                    }
                }
                tr.Commit();
            }
        }

 

 

Some extension methods from GeometryExtension library:

 

    public static class Extension
    {
        /// <summary>
        /// Gets the transformation matrix of the display coordinate system (DCS)
        /// of the specified window to the world coordinate system (WCS).
        /// </summary>
        /// <param name="vp">The instance to which this method applies.</param>
        /// <returns>The transformation matrix from DCS to WCS.</returns>
        public static Matrix3d DCS2WCS(this Viewport vp)
        {
            return
                Matrix3d.Rotation(-vp.TwistAngle, vp.ViewDirection, vp.ViewTarget) *
                Matrix3d.Displacement(vp.ViewTarget.GetAsVector()) *
                Matrix3d.PlaneToWorld(vp.ViewDirection);
        }

        /// <summary>
        /// Gets the transformation matrix of the world coordinate system (WCS)
        /// to the display coordinate system (DCS) of the specified window.
        /// </summary>
        /// <param name="vp">The instance to which this method applies.</param>
        /// <returns>The transformation matrix from WCS to DCS.</returns>
        public static Matrix3d WCS2DCS(this Viewport vp)
        {
            return
                Matrix3d.WorldToPlane(vp.ViewDirection) *
                Matrix3d.Displacement(vp.ViewTarget.GetAsVector().Negate()) *
                Matrix3d.Rotation(vp.TwistAngle, vp.ViewDirection, vp.ViewTarget);
        }

        /// <summary>
        /// Gets the transformation matrix of the display coordinate system of the specified paper space window (DCS)
        /// to the paper space display coordinate system (PSDCS).
        /// </summary>
        /// <param name="vp">The instance to which this method applies.</param>
        /// <returns>The transformation matrix from DCS to PSDCS.</returns>
        public static Matrix3d DCS2PSDCS(this Viewport vp)
        {
            return
                Matrix3d.Scaling(vp.CustomScale, vp.CenterPoint) *
                Matrix3d.Displacement(vp.ViewCenter.Convert3d().GetVectorTo(vp.CenterPoint));
        }

        /// <summary>
        /// Gets the transformation matrix of the paper space display coordinate system (PSDCS)
        /// to the display coordinate system of the specified paper space window (DCS). 
        /// </summary>
        /// <param name="vp">The instance to which this method applies.</param>
        /// <returns>The transformation matrix from PSDCS to DCS.</returns>
        public static Matrix3d PSDCS2DCS(this Viewport vp)
        {
            return
                Matrix3d.Displacement(vp.CenterPoint.GetVectorTo(vp.ViewCenter.Convert3d())) *
                Matrix3d.Scaling(1.0 / vp.CustomScale, vp.CenterPoint);
        }

        /// <summary>
        /// Converts a Point2d into a Point3d with a Z coordinate equal to 0.
        /// </summary>
        /// <param name="pt">The instance to which this method applies.</param>
        /// <returns>The corresponding Point3d.</returns>
        public static Point3d Convert3d(this Point2d pt) =>
            new Point3d(pt.X, pt.Y, 0.0);
    }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 4

swaywood
Collaborator
Collaborator
thanks again Giles
0 Likes