Code Red > .NET

Transforming point from PaperSpace to ModelSpace

(1/3) > >>

gile:
Hi,

This post is related to this one on AutoCAD DevBlog where it si showned how to convert a point from PaperSpace to ModelSpace P/Invoking acedTrans.

It appears the code doesn't work as expected. There're, IMO, two mistakes:

1. PSDCS and DCS are related to the active Viewport, so it's needed to activate the Viewport (switching to ModelSpace if it's assumed there's only one viewport in the current layout) after the prompt for point and before calling acedTrans().

2. The returned point coordinates are DCS coordinates which need a second transformation from DCS to WCS coordinates before passing them to the DBPoint constructor.
With LISP:

--- Code - Auto/Visual Lisp: ---(trans (trans pt 3 2) 2 0)
So, here's the 'corrected' code:

--- Code - C#: ---        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]        static extern int acedTrans(double[] point, IntPtr fromRb, IntPtr toRb, int disp, double[] result);         [CommandMethod("ps2ms", CommandFlags.NoTileMode)]        static public void ps2ms()        {            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;            // pick some point in PS            PromptPointResult res = ed.GetPoint("Pick Model Space Point");            if (res.Status == PromptStatus.OK)            {                // Transform from PS point to MS point                ResultBuffer rbPSDCS = new ResultBuffer(new TypedValue(5003, 3));                ResultBuffer rbDCS = new ResultBuffer(new TypedValue(5003, 2));                ResultBuffer rbWCS = new ResultBuffer(new TypedValue(5003, 0));                double[] retPoint = new double[] { 0, 0, 0 };                ed.SwitchToModelSpace();                using (Viewport vp = (Viewport)ed.CurrentViewportObjectId.Open(OpenMode.ForRead))                {                     // translate from from the DCS of Paper Space (PSDCS) RTSHORT=3                     // to the DCS of the current model space viewport RTSHORT=2                    acedTrans(res.Value.ToArray(), rbPSDCS.UnmanagedObject, rbDCS.UnmanagedObject, 0, retPoint);                     //translate the DCS of the current model space viewport RTSHORT=2                    //to the WCS RTSHORT=0                    acedTrans(retPoint, rbDCS.UnmanagedObject, rbWCS.UnmanagedObject, 0, retPoint);                }                ed.SwitchToPaperSpace();                 // create a new DBPoint and add to model space to show where we picked                using (DBPoint pnt = new DBPoint(new Point3d(retPoint[0], retPoint[1], retPoint[2])))                using (BlockTable bt = ed.Document.Database.BlockTableId.Open(OpenMode.ForRead) as BlockTable)                using (BlockTableRecord ms = bt[BlockTableRecord.ModelSpace].Open(OpenMode.ForWrite) as BlockTableRecord)                    ms.AppendEntity(pnt);            }        }
But this can be done without P/Invoke by using some extension methods from the GeometryExtensions library.

The same as upper using the Point3d.Trans() extension method. This method is overloaded and may accept arguments from the CoordSystem enum or integers (as acedTrans or trans LISP function).


--- Code - C#: ---using GeometryExtensions;         [CommandMethod("ps2ms", CommandFlags.NoTileMode)]        public void ps2ms()        {            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;            Database db = HostApplicationServices.WorkingDatabase;                        PromptPointResult res = ed.GetPoint("Pick Model Space Point");            if (res.Status != PromptStatus.OK) return;             //Point3d pt = res.Value.Trans(3, 2).Trans(2, 0);            Point3d pt = res.Value                .Trans(GeomExt.CoordSystem.PSDCS, GeomExt.CoordSystem.DCS)                .Trans(GeomExt.CoordSystem.DCS, GeomExt.CoordSystem.WCS);             using (Transaction tr = db.TransactionManager.StartTransaction())            {                BlockTableRecord ms =                    (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);                DBPoint dbPt = new DBPoint(pt);                ms.AppendEntity(dbPt);                tr.AddNewlyCreatedDBObject(dbPt, true);                tr.Commit();            }        }
The upper examples are both not very safe, because they activate a viewport in the the current layout which may not be the required one if there're many.

In the GeometryExtensions library some methods extend the Viewport class returning transformation Matrix3d which can be used for this task avoiding the viewport activation.

Here's the same command using this way. It needs to prompt the user for selection the viewport.


--- Code - C#: ---using GeometryExtensions         [CommandMethod("ps2ms", CommandFlags.NoTileMode)]        public void ps2ms()        {            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;            Database db = HostApplicationServices.WorkingDatabase;             PromptPointResult res = ed.GetPoint("Pick Model Space Point");            if (res.Status != PromptStatus.OK) return;             PromptEntityOptions opts = new PromptEntityOptions("\nSelect a viewport: ");            opts.SetRejectMessage("Object non valide.");            opts.AddAllowedClass(typeof(Viewport), true);            PromptEntityResult per = ed.GetEntity(opts);            if (per.Status != PromptStatus.OK) return;             using (Transaction tr = db.TransactionManager.StartTransaction())            {                Viewport vp = (Viewport)tr.GetObject(per.ObjectId, OpenMode.ForRead);                Point3d pt = res.Value.TransformBy(vp.DCS2WCS() * vp.PSDCS2DCS());                DBPoint dbPt = new DBPoint(pt);                BlockTableRecord ms =                    (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);                ms.AppendEntity(dbPt);                tr.AddNewlyCreatedDBObject(dbPt, true);                tr.Commit();            }        }

TheMaster:
Nice work.

Would any of the properties of the View class (AcGsView) help simplify this?

gile:
Thanks Tony.


--- Quote ---Would any of the properties of the View class (AcGsView) help simplify this?
--- End quote ---
I never look this way before. I'll do it as soon as I have some time to.

Draftek:
Thanks,
I need to go back and look how I'm doing this in some previous written apps.

TheMaster:

--- Quote from: gile on August 15, 2012, 04:17:44 PM ---Thanks Tony.


--- Quote ---Would any of the properties of the View class (AcGsView) help simplify this?
--- End quote ---
I never look this way before. I'll do it as soon as I have some time to.

--- End quote ---

Well, they might be useful, and I just checked my code bin here and found these:


--- Code - C#: ---// ViewportExtensionMethods.cs  (c) 2007-2012  Tony Tanzillo using System;using System.Collections.Generic;using System.Linq;using System.Text;using Autodesk.AutoCAD.Geometry; namespace Autodesk.AutoCAD.DatabaseServices{   public static class ViewportExtensionMethods   {      public static Matrix3d GetModelToPaperTransform( this Viewport vport )      {         if( vport.PerspectiveOn )            throw new NotSupportedException( "Perspective views not supported" );         Point3d center = new Point3d( vport.ViewCenter.X, vport.ViewCenter.Y, 0.0 );         return Matrix3d.Displacement( new Vector3d( vport.CenterPoint.X - center.X, vport.CenterPoint.Y - center.Y, 0.0 ) )            * Matrix3d.Scaling( vport.CustomScale, center )            * Matrix3d.Rotation( vport.TwistAngle, Vector3d.ZAxis, Point3d.Origin )            * Matrix3d.WorldToPlane( new Plane( vport.ViewTarget, vport.ViewDirection ) );      }       public static Matrix3d GetPaperToModelTransform( this Viewport vport )      {         return GetModelToPaperTransform( vport ).Inverse();      }       public static Point3d PaperToModel( this Point3d point, Viewport vport )      {         return point.TransformBy( GetModelToPaperTransform( vport ).Inverse() );      }       public static Point3d ModelToPaper( this Point3d point, Viewport viewport )      {         return point.TransformBy( GetModelToPaperTransform( viewport ) );      }       public static void PaperToModel( this Entity entity, Viewport vport )      {         entity.TransformBy( GetModelToPaperTransform( vport ).Inverse() );      }       public static void ModelToPaper( this Entity entity, Viewport viewport )      {         entity.TransformBy( GetModelToPaperTransform( viewport ) );      }       public static IEnumerable<Point3d> PaperToModel( this IEnumerable<Point3d> source, Viewport viewport )      {         Matrix3d xform = GetModelToPaperTransform( viewport ).Inverse();         return source.Select( p => p.TransformBy( xform ) );      }       public static IEnumerable<Point3d> ModelToPaper( this IEnumerable<Point3d> source, Viewport viewport )      {         Matrix3d xform = GetModelToPaperTransform( viewport );         return source.Select( p => p.TransformBy( xform ) );      }       public static void PaperToModel( this IEnumerable<Entity> src, Viewport viewport )      {         Matrix3d xform = GetModelToPaperTransform( viewport ).Inverse();         foreach( Entity ent in src )            ent.TransformBy( xform );      }       public static void ModelToPaper( this IEnumerable<Entity> src, Viewport viewport )      {         Matrix3d xform = GetModelToPaperTransform( viewport );         foreach( Entity ent in src )            ent.TransformBy( xform );      }   }}  

Navigation

[0] Message Index

[#] Next page

Go to full version