.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

3D XCLIP

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
matinau
1561 Views, 10 Replies

3D XCLIP

Hi

Anyone had any success XCLIPPING both 2d and 3d references using .NET ?

 

I found an excellent post by Kean Walmsley here covering 2d references http://through-the-interface.typepad.com/through_the_interface/au/page/4/

 

How can I cater for 3d references?

 

The "SpatialFilterDefinition" contains all the juice, but I haven't managed to succesfully pass elevation and clipping depths.

 

SpatialFilterDefinitionsfd = newSpatialFilterDefinition(pts, Vector3d.ZAxis, 0.0, 0.0, 0.0, true);

 

thanks in advance

10 REPLIES 10
Message 2 of 11
matinau
in reply to: matinau

Any ideas?

Tags (1)
Message 3 of 11
matinau
in reply to: matinau

Thought I should put the portion of the code up I'm having trouble with:

 

// Transform points to selected clipping block ucs
pt1 = pt1.TransformBy(selectedBlock.BlockTransform);
pt2 = pt2.TransformBy(selectedBlock.BlockTransform);
pt3 = pt3.TransformBy(selectedBlock.BlockTransform);
pt4 = pt4.TransformBy(selectedBlock.BlockTransform);

 

var ms = (BlockTableRecord) tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead);

foreach (ObjectId id in ms)
{
 var ent = (Entity) tr.GetObject(id, OpenMode.ForRead);

 if (ent != null)
 {
  if (ent.GetType() == typeof (BlockReference))
  {
   var br = (BlockReference) ent; // Get block reference

   var btr = (BlockTableRecord) tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);

   // Check whether the blockreference is an external reference
   if (btr.IsFromExternalReference && btr.IsResolved)
   {
    var pts = new Point2dCollection(4)
     {
      new Point2d(pt1.X, pt1.Y),
      new Point2d(pt2.X, pt2.Y),
      new Point2d(pt3.X, pt3.Y),
      new Point2d(pt4.X, pt4.Y)
     };

 

    // Create spatial filter
    var sfd = new SpatialFilterDefinition(pts, Vector3d.ZAxis, 0.0, 0.0, 0.0, true);
    
    var sf = new SpatialFilter {Definition = sfd};

    // Create extension dictionary if doesn't exist
    if (br.ExtensionDictionary == ObjectId.Null)
    {
     br.UpgradeOpen();
     br.CreateExtensionDictionary();
     br.DowngradeOpen();
    }

    // Add spatial filter to extension dictionary
    var extDict = (DBDictionary) tr.GetObject(br.ExtensionDictionary, OpenMode.ForWrite);

    if (extDict.Contains(filterDictName))
    {
     var filterDict = (DBDictionary) tr.GetObject(extDict.GetAt(filterDictName), OpenMode.ForWrite);

     if (filterDict.Contains(spatialName))
      filterDict.Remove(spatialName);

     filterDict.SetAt(spatialName, sf);
    }
    else
    {
     var filterDict = new DBDictionary();
     extDict.SetAt(filterDictName, filterDict);
     tr.AddNewlyCreatedDBObject(filterDict, true);
     filterDict.SetAt(spatialName, sf);
    }

    tr.AddNewlyCreatedDBObject(sf, true);
   }
  }
 }
}

tr.Commit();

 

Message 4 of 11
Balaji_Ram
in reply to: matinau

Sorry for the delay.

 

Can you please explain the issue you are having with the clip parameters to the "SpatialFilterDefinition" ?

The elevation parameter can simply be set to 0.0. This along with the normal will set the reference for the other two parameters (front clip and back clip).

 

Front clip distcance is to be provided in the positive extrusion direction (in the same direction as that of the normal) and back clip distance in the negative extrusion direction.

 

I would suggest using the XCLIP command in AutoCAD to achieve the desired 3D clipping of the Xref and then using the ArxDbg to view the Dxf values of the clipped Xref to determine the values for the front clip distance, back clip distance, elevation and normal values. You can then use the same values in your code to achieve the desired 3d clipping.

 

From the Dxf reference guide, the group codes 40 and 41 store the front clip distance and back clip distance for a spatial filter.



Balaji
Developer Technical Services
Autodesk Developer Network

Message 5 of 11
matinau
in reply to: Balaji_Ram

Thanks for the reply...really not sure whats going wrong

 

I've tested the points are properly transformed and tried setting the spatial filter as follows following several comments.

 

var sfd = new SpatialFilterDefinition(pts, Vector3d.ZAxis, 0.0, double.PositiveInfinity, double.NegativeInfinity, true);

 

Yet the xref won't clip in the correct place? Not sure what I'm missing. I've tried with both World & User coordinates systems with similar results.

 

Do you need to pass 5 points for a rectangular boundary? My point list is generated from a block selection not via user prompt.

Message 6 of 11
Balaji_Ram
in reply to: matinau

The problem could be due to the coordinate system of the clip boundary points.

 

Can you please try using the index filter manager to add the spatial filter as explained in these posts ?

In the sample code, the elevation and normal that define the ECS are computed from the ucs directions.

 

http://adndevblog.typepad.com/autocad/2013/01/spatial-filter-xclip-command-command-in-c.html

 

http://adndevblog.typepad.com/autocad/2013/03/xclip-xrefs-using-objectarx.html

The "ACDB_INFINITE_XCLIP_DEPTH" is a very large number defined in dpspfilt.h

 

If this does not help, can you please provide a simple drawing and a sample project to reproduce the problem ?

 

 

 



Balaji
Developer Technical Services
Autodesk Developer Network

Message 7 of 11
matinau
in reply to: Balaji_Ram

Ok so I tweaked my code after reading the 2 posts you mentioned but the clip is still falling in the wrong place for both 2d and 3d block references? I added the "DrawClipBoundary" method which successfully places an outline around the intended Xclip boundary. Can you spot where I'm going wrong? Its driving me potty.

 

Also I wrote an additional function to read existing XCLIP information which returned some interesting results, it appears the clip retains the coordainate system values at the time of creation?

 

[CommandMethod("XCLIPALL")]
public static void XRefClipAll()
{
 var doc = Application.DocumentManager.MdiActiveDocument;
 var db = doc.Database;
 var ed = doc.Editor;

 using (Transaction tr = db.TransactionManager.StartTransaction())
 {
  const string filterDictName = "ACAD_FILTER";
  const string spatialName = "SPATIAL";

  var peo = new PromptEntityOptions("\nSelect a block: ");
  peo.SetRejectMessage("\nMust be a block reference.");
  peo.AddAllowedClass(typeof (BlockReference), true);

  var per = ed.GetEntity(peo);
  if (per.Status != PromptStatus.OK) return;

  var ppo = new PromptPointOptions("\nSelect rect clip 1st corner: ");
  var ppr1 = ed.GetPoint(ppo);

  if (ppr1.Status != PromptStatus.OK)
   return;

  var pco = new PromptCornerOptions( "\nSelect rect clip 2nd corner: ", ppr1.Value)
   {
    UseDashedLine = true
   };

  var ppr2 = ed.GetCorner(pco);

  if (ppr2.Status != PromptStatus.OK)
   return;

  var bref = (BlockReference) tr.GetObject(per.ObjectId, OpenMode.ForRead);

  var bottomLeftCorner = ppr1.Value.TransformBy(bref.BlockTransform.Inverse());
  var upperRightCorner = ppr2.Value.TransformBy(bref.BlockTransform.Inverse());
  
  var pts = new Point2dCollection(2)
   {
    new Point2d(bottomLeftCorner.X, bottomLeftCorner.Y),
    new Point2d(upperRightCorner.X, upperRightCorner.Y),
   };

  Vector3d normal;
  double elev;

  if (db.TileMode)
  {
   normal = db.Ucsxdir.CrossProduct(db.Ucsydir);
   elev = db.Elevation;
  }
  else
  {
   normal = db.Pucsxdir.CrossProduct(db.Pucsydir);
   elev = db.Pelevation;
  }
  normal.GetNormal();

  // Create spatial filter
  var sfd = new SpatialFilterDefinition(
   pts,
   normal, elev,
   double.PositiveInfinity,
   double.NegativeInfinity,
   true);

  // Show Intend xclip boundary
  DrawClipBoundary(pts, bref, normal, elev);

  var sf = new SpatialFilter {Definition = sfd};

  // Create extension dictionary if doesn't exist
  if (br.ExtensionDictionary == ObjectId.Null)
  {
   br.UpgradeOpen();
   br.CreateExtensionDictionary();
   br.DowngradeOpen();
  }

  // Add spatial filter to extension dictionary
  var xDict = (DBDictionary) tr.GetObject(br.ExtensionDictionary, OpenMode.ForWrite);

  if (xDict.Contains(filterDictName))
  {
   var filterDict =
    (DBDictionary) tr.GetObject(xDict.GetAt(filterDictName), OpenMode.ForWrite);

   if (filterDict.Contains(spatialName))
    filterDict.Remove(spatialName);

   filterDict.SetAt(spatialName, sf);
  }
  else
  {
   var fDict = new DBDictionary();
   xDict.SetAt(filterDictName, fDict);
   tr.AddNewlyCreatedDBObject(fDict, true);
   fDict.SetAt(spatialName, sf);
  }
  
  tr.AddNewlyCreatedDBObject(sf, true);
  tr.Commit();
 }
 ed.Regen();
}

 

------------------------------------- 

READ FUNCTION

-------------------------------------

 

[CommandMethod("XCLIPREAD")]
public static void XRefClipRead()
{
 var doc = Application.DocumentManager.MdiActiveDocument;
 var db = doc.Database;
 var ed = doc.Editor;

 using (Transaction tr = db.TransactionManager.StartTransaction())
 {
  const string filterDictName = "ACAD_FILTER";
  const string spatialName = "SPATIAL";

  var peo = new PromptEntityOptions("\nSelect MVF block: ");
  peo.SetRejectMessage("\nMust be a block reference.");
  peo.AddAllowedClass(typeof (BlockReference), true);

  PromptEntityResult per = ed.GetEntity(peo);
  if (per.Status != PromptStatus.OK) return;

  var br = (BlockReference) tr.GetObject(per.ObjectId, OpenMode.ForRead);

  

  if (br.ExtensionDictionary == ObjectId.Null) return;

 

  var xDict = (DBDictionary)tr.GetObject(br.ExtensionDictionary, OpenMode.ForWrite);

  if (xDict.Contains(filterDictName))
  {
   var filterDict = (DBDictionary) tr.GetObject(xDict.GetAt(filterDictName), OpenMode.ForRead);

   if(!filterDict.Contains(spatialName)) return;

   var sf = tr.GetObject(filterDict.GetAt(spatialName), OpenMode.ForRead) as SpatialFilter;

   SpatialFilterDefinition def = sf.Definition;

   foreach (Point2d pt in def.GetPoints())
   {
    ed.WriteMessage("\nPoints: " + pt);
   }

   ed.WriteMessage("\nNormal: " + def.Normal);
   ed.WriteMessage("\nElevation: " + def.Elevation);
   ed.WriteMessage("\nFront clip: " + def.FrontClip);
   ed.WriteMessage("\nBack clip: " + def.BackClip);
  }
 }
}

 

Message 8 of 11
matinau
in reply to: matinau

I found the route of my problem! its's the Vector3d part of the SpatialFilterDefinition

 

When the coordinate system is set to World Vector3d.ZAxis works perfectly until I change to a UCS. This neesd tweaking.

 

Vector3d normal;
double elev;

if (db.TileMode)
{
 normal = db.Ucsxdir.CrossProduct(db.Ucsydir);
 elev = db.Elevation;
}
else
{
 normal = db.Pucsxdir.CrossProduct(db.Pucsydir);
 elev = db.Pelevation;
}
normal.GetNormal();

Message 9 of 11
matinau
in reply to: matinau

With all the code floating around I feel I may have blurred my initial question. Probably better to start from the beginnning.

 

I'm trying to write a function in c# that clips all loaded xrefs based on a particular block called (for exmaple) "rectangle_boundary". I want to use this block to determine the 4 corners of the clipping boundary and cater for the current coordinate system.

 

I have the code that calculates the length and width of the "rectangle_boundary" block so all I need to do now is tie this together successfully with a SpatialFilter.

 

As you can see above I've made several attempts with no success.

Message 10 of 11
Balaji_Ram
in reply to: matinau

Please provide a buildable sample project with the code that you are having trouble with along with the sample drawing that you are using to test.

 

If you prefer, you can use the sample project from the blog post that I mentioned in my previous reply.

 

This will help in identifying the issue.



Balaji
Developer Technical Services
Autodesk Developer Network

Message 11 of 11
matinau
in reply to: Balaji_Ram

Thanks Balaji, I figured it out 🙂

 

I had to create 2 Transformation Matrix's 1.) the clipping block 2.) The reference. Then using your example to calculate the norm and elevation I was able to tie it all together.

 

Thanks so much for your help.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost