Author Topic: Export only viewable objects from viewport to a new DWG  (Read 4601 times)

0 Members and 1 Guest are viewing this topic.

AngelKostadinov

  • Newt
  • Posts: 30
Export only viewable objects from viewport to a new DWG
« on: April 18, 2013, 08:36:25 AM »
Hey there!!!
I'd like to propose on your attention the newest task that I'm working on.
I have to export only viewable objects from viewport to a new DWG file, using ODA Teigha.NET Classic dlls.

More detailed explanation:
Let's guess the source DWG has 1000 objects in modelSpace (lines, arcs, solids, block references etc...) but only 3 or 4 of those objects are visible through a viewport in paper space. I have to remove(delete) all 997 or 996 "non visible" objects form ModelSpace and then to save modified dwg.
Any ideas?

BoundBlock3D is not an option because it includes all objects in model space, not only viewable through the viewport.
What actualy represents CenterPoint property of viewport object -->(from ACAD documentation) Accesses the center point of the viewport entity in WCS coordinates (within Paper Space).
If someone is experienced in Teigha.NET pls help me, Thank you!

kaefer

  • Guest
Re: Export only viewable objects from viewport to a new DWG
« Reply #1 on: April 18, 2013, 11:26:49 AM »
What actualy represents CenterPoint property of viewport object -->(from ACAD documentation) Accesses the center point of the viewport entity in WCS coordinates (within Paper Space).
If someone is experienced in Teigha.NET pls help me, Thank you!

I'm not, so please forgive me for not grasping how to get a Viewport object in BricsCAD (Database.GetViewports says eNotImplementedYet). But once you're there, you could transform its corner points to WCS and use them to select the elements via SelectPolygon. Otherwise I would have tried to utilize this extension from AutoCAD:

Code - F#: [Select]
  1. type Viewport with
  2.     // Vector from center point to top border
  3.     member vp.ModelCenterX = new Vector2d(0., vp.Height * 0.5 / vp.CustomScale)
  4.     // Vector from center point to right border
  5.     member vp.ModelCenterY = new Vector2d(vp.Width * 0.5 / vp.CustomScale, 0.)
  6.     // Transform paper space view coordinates to WCS
  7.     member vp.ModelSpaceTransform =
  8.         Matrix3d.PlaneToWorld vp.ViewDirection *
  9.         Matrix3d.Rotation(-vp.TwistAngle, vp.ViewDirection, vp.ViewTarget) *
  10.         Matrix3d.Displacement(vp.ViewTarget - Point3d.Origin)

AngelKostadinov

  • Newt
  • Posts: 30
Re: Export only viewable objects from viewport to a new DWG
« Reply #2 on: April 19, 2013, 02:47:46 AM »
Thank you for fast replay!
I have to make standalone application witch is not related with both ACAD or BricsCAD, so I suppose to use only Teigha's dlls and all functionality embedded in.
This is what I've done so far:

Code: [Select]
   var fieldWidth = abstractViewportData.FieldWidth;
   var fieldHeight = abstractViewportData.FieldHeight;
   var extents = new Extents2d(-fieldWidth / 2, -FieldHeight/ 2, fieldWidth / 2, FieldHeight/ 2);   <-- This are extents of viewport in WCS
   var projectionPlane =new Plane(viewTarget,_viewport.ViewDirection);                              <-- This is projection plane which is shown by viewport
   var projectionCS = projectionPlane.GetCoordinateSystem();                                        <-- This is maybe new coordinate system related with projection plane, but I am not sure
   var WCSToProjectionCS = Matrix3d.PlaneToWorld(projectionPlane).Inverse();                         <--  This is transformation matrix from World to plane but I am not entirely sure again
   var line = new Line(new Point3d(0, 0, 0), new Point3d(10, 0, 0));                                    <--  Tree perpendicular lines  for testing
   var line2 = new Line(new Point3d(0, 0, 0), new Point3d(0, 10, 0));
   var line3 = new Line(new Point3d(0, 0, 0), new Point3d(0, 0, 10));
   line.TransformBy(WCSToProjectionCS);
   line2.TransformBy(WCSToProjectionCS);
   line3.TransformBy(WCSToProjectionCS);
   AttachEntityToModelSpace(line);
   AttachEntityToModelSpace(line2);
   AttachEntityToModelSpace(line3);

The three lines appear attached into ModelSpace, but they are in the same plane, they shouldn't be, so I did something wrong above...
I'm continuing with experiments and tests.
Thank you, kaefer!
« Last Edit: April 19, 2013, 02:52:11 AM by AngelKostadinov »

kaefer

  • Guest
Re: Export only viewable objects from viewport to a new DWG
« Reply #3 on: April 19, 2013, 06:04:48 AM »
I have to make standalone application witch is not related with both ACAD or BricsCAD, so I suppose to use only Teigha's dlls and all functionality embedded in.

Sorry for missing that requirement. So you cannot use anything of the EditorInput namespace?

I imagine two obstacles you'd have to overcome: first to determine the geometric extent of the Viewport, and then to decide which elements fulfill the condition of being inside it.

Your code seems to concern something called AbstractViewportData, of which I can't find an exact AutoCAD equivalent. To solve the first problem, I expect a solution to be based on a Viewport proper. Would an Overrule help solving the second?

FWIW here's the code using the transformations mentioned above, for selecting elements residing geometrically inside one or more Viewports. Alas, AutoCAD only and EditorInput required.

Code - F#: [Select]
  1. [<CommandMethod "SELELE">]
  2. let SelEleCmd () =
  3.     let doc = acApp.DocumentManager.MdiActiveDocument
  4.     let ed = doc.Editor
  5.     let db = doc.Database
  6.  
  7.     // Start transaction and open modelspace for write        
  8.     use tr = db.TransactionManager.StartTransaction()
  9.     let msId = SymbolUtilityServices.GetBlockModelSpaceId db
  10.     let btr = tr.GetObject(msId, OpenMode.ForWrite) :?> BlockTableRecord
  11.  
  12.     // Transform Point2d from paper space to UCS, m3d is for paper space to WCS
  13.     let transform3d m3d (p2d: Point2d) =
  14.         let p3d = new Point3d(p2d.X, p2d.Y, 0.)
  15.         p3d.TransformBy m3d
  16.  
  17.     // Select Elements inside corner points of Viewport
  18.     let selectElements p3d =
  19.         let psr = ed.SelectWindowPolygon(new Point3dCollection(p3d))
  20.         if psr.Status = PromptStatus.OK then psr.Value.GetObjectIds()
  21.         else Array.empty
  22.  
  23.     // Do it for all floating Viewports
  24.     [| for oid in db.GetViewports false -> oid |]
  25.     |> Array.collect (fun oid ->
  26.         let vp = tr.GetObject(oid, OpenMode.ForRead) :?> Viewport
  27.         ed.WriteMessage("\n{0} ID {1} ", [| box vp.Id; box vp.Number |])
  28.         // THe corners of the modelspace view
  29.         [|  vp.ViewCenter - vp.ModelCenterX - vp.ModelCenterY
  30.             vp.ViewCenter - vp.ModelCenterX + vp.ModelCenterY
  31.             vp.ViewCenter + vp.ModelCenterX + vp.ModelCenterY
  32.             vp.ViewCenter + vp.ModelCenterX - vp.ModelCenterY |]
  33.         |> Array.map (transform3d vp.ModelSpaceTransform)
  34.         |> selectElements )
  35.     |> ed.SetImpliedSelection
  36.  
  37.     tr.Commit()

AngelKostadinov

  • Newt
  • Posts: 30
Re: Export only viewable objects from viewport to a new DWG
« Reply #4 on: April 19, 2013, 08:07:29 AM »
I can't use single class from AutoCAD API, only from Teigha.netClassic.
You can find AbstractViewportData class in Teigha.DatabaseServices namespace.

Code: [Select]
var basePoints = new Point3dCollection
                                 {
                                     new Point3d(
                                         -abstractViewportData.FieldWidth / 2,
                                         -abstractViewportData.FieldHeight / 2,
                                         0),
                                     new Point3d(
                                         abstractViewportData.FieldWidth / 2,
                                         -abstractViewportData.FieldHeight / 2,
                                         0),
                                     new Point3d(
                                         abstractViewportData.FieldWidth / 2,
                                         abstractViewportData.FieldHeight / 2,
                                         0),
                                     new Point3d(
                                         -abstractViewportData.FieldWidth / 2,
                                         abstractViewportData.FieldHeight / 2,
                                         0)
                                 };

            var baseOfParallelepiped = new Polyline3d(Poly3dType.SimplePoly, basePoints, true);
            AttachEntityToModelSpace(baseOfParallelepiped);

            var projectionPlane =
                new Plane(viewport.ViewTarget, viewport.ViewDirection);

            var projectionCS = projectionPlane.GetCoordinateSystem();

            var transMatrix = Matrix3d.AlignCoordinateSystem(
                Point3d.Origin,
                Vector3d.XAxis,
                Vector3d.YAxis,
                Vector3d.ZAxis,
                projectionCS.Origin,
                projectionCS.Xaxis,
                projectionCS.Yaxis,
                projectionCS.Zaxis);

            baseOfParallelepiped.TransformBy(transMatrix);

            AttachEntityToModelSpace(baseOfParallelepiped);

The code from above generates the black rectangle, which is situated in the correct plane actually, but its center is not where it should be. It should be in the place of the red one, which is drawn by myself to show what's wrong. The problem is somewhere in transformations, maybe I have to add some translation but I don't see yet what exactly it should be.
« Last Edit: April 19, 2013, 08:22:12 AM by AngelKostadinov »

kaefer

  • Guest
Re: Export only viewable objects from viewport to a new DWG
« Reply #5 on: April 19, 2013, 09:53:35 AM »
The problem is somewhere in transformations, maybe I have to add some translation but I don't see yet what exactly it should be.

Could it be the translation from Origin to ViewTarget, maybe?

Edit:

More likely the ViewCenter... Thanks for bringing to my attention that my untried but trusted transformation didn't actually work when not in plan view. This will hopefully deliver a projection onto World's XY-Plane, like the CHSPACE command does but flatted, based on your approach :

Code - F#: [Select]
  1. type Viewport with
  2.     member vp.ModelSpaceTransform =
  3.         let projectionPlane = new Plane(vp.ViewTarget, vp.ViewDirection)
  4.         let projectionCS = projectionPlane.GetCoordinateSystem()
  5.        
  6.         Matrix3d.Rotation(-vp.TwistAngle, vp.ViewDirection, vp.ViewTarget) *
  7.         Matrix3d.AlignCoordinateSystem(
  8.                 Point3d.Origin,
  9.                 Vector3d.XAxis,
  10.                 Vector3d.YAxis,
  11.                 Vector3d.ZAxis,
  12.                 projectionCS.Origin,
  13.                 projectionCS.Xaxis,
  14.                 projectionCS.Yaxis,
  15.                 projectionCS.Zaxis )
« Last Edit: April 19, 2013, 02:40:18 PM by kaefer »

AngelKostadinov

  • Newt
  • Posts: 30
Re: Export only viewable objects from viewport to a new DWG
« Reply #6 on: April 22, 2013, 05:09:20 AM »
Thank you!
This works exactly it should be ! ViewCenter property represents the center of viewport in DCS( center of viewport in ProjectionPlane ), that's why it has only X and Y coordinates (without Z).

Code: [Select]
var projectionPlane = new Plane(viewport.ViewTarget, viewport.ViewDirection);
var projectionCS = projectionPlane.GetCoordinateSystem();
var fromWcsToProjectionPlane = Matrix3d.Rotation(-viewport.TwistAngle, viewport.ViewDirection, viewport.ViewTarget) *
            Matrix3d.AlignCoordinateSystem(
                                               Point3d.Origin,
                                               Vector3d.XAxis,
                                               Vector3d.YAxis,
                                               Vector3d.ZAxis,
                                               projectionCS.Origin,
                                               projectionCS.Xaxis,
                                               projectionCS.Yaxis,
                                               projectionCS.Zaxis);

var basePoints = new Point3dCollection
                                 {
                                     new Point3d(
                                         -abstractViewportData.FieldWidth / 2,
                                         -abstractViewportData.FieldHeight / 2,
                                         0),
                                     new Point3d(
                                         abstractViewportData.FieldWidth / 2,
                                         -abstractViewportData.FieldHeight / 2,
                                         0),
                                     new Point3d(
                                         abstractViewportData.FieldWidth / 2,
                                         abstractViewportData.FieldHeight / 2,
                                         0),
                                     new Point3d(
                                         -abstractViewportData.FieldWidth / 2,
                                         abstractViewportData.FieldHeight / 2,
                                         0)
                                 };

var viewCenter = new Point3d(viewport.ViewCenter.X,viewport.ViewCenter.Y,0);
var baseOfParallelepiped = new Polyline3d(Poly3dType.SimplePoly, basePoints, true);
baseOfParallelepiped.TransformBy(Matrix3d.Displacement(viewCenter.GetAsVector()));  <-- That's what I've missed so far.
baseOfParallelepiped.TransformBy(fromWcsToProjectionPlane);
AttachEntityToModelSpace(baseOfParallelepiped);