Code Red > .NET

Creating hatch from Polyline3D using UCS


Dear Swamp users,

I'm facing issues while creating a hatch that properly aligns with a polyline3d. Currently, the function loops through all the objects in the ModelSpace and checks if the object is a 3D polyline with a layer that starts with "FACET_". If the object meets this condition, the function retrieves the UCS (User Coordinate System) by the layer name and sets it as the active viewport's UCS. The function then creates a temporary copy of the 3D polyline and transforms it by the current user coordinate system. Next, a new hatch object is created and added to the block table record. The properties of the hatch object are set, including pattern, angle, and scale, and the normal and elevation of the hatch are set based on the current user coordinate system.

However, I suspect that the elevation/normal of the hatch is set at some basepoint that is not a property I can access. Currently, I'm offsetting the elevation by the difference between the first vertex of the polyline and the origin of the UCS, hoping that this is where the elevation of the hatch is being set. This doesn't seem to be the case (though it is closer than without the offset so right direction). If I can get the Point2d or Point3d of the hatch, I can create an offset from the origin to adjust for this, but I'm unsure how to obtain it. I might also be overcomplicating things, and any assistance would be appreciated.

***Outerloops is currently being set to null until I can get the base case setup*** can ignore that bit.

Command Entry Point:

--- Code: ---        [CommandMethod("CreateHatches")]
        public void CreateHatches()
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            using (Transaction tr = db.TransactionManager.StartTransaction())
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);

                string hatchPattern = "ANSI31";
                double angle = 45;
                double scale = 192.0;

                foreach (ObjectId objectId in btr)
                    Entity entity = tr.GetObject(objectId, OpenMode.ForRead) as Entity;
                    if (entity != null && entity is Polyline3d polyline3d && entity.Layer.StartsWith("FACET_"))
                        ViewportTableRecord acVportTblRec;
                        acVportTblRec = tr.GetObject(doc.Editor.ActiveViewportId, OpenMode.ForWrite) as ViewportTableRecord;

                        UcsTableRecord ucsRecord = Utilities.GetUCSByName(entity.Layer);

                        var wcsOrgin = Point3d.Origin;
                        var wcsX = Vector3d.XAxis;
                        var wcsY = Vector3d.YAxis;
                        var wcsZ = Vector3d.ZAxis;

/*                        var ucsOrgin = ucsRecord.Origin;
                        var ucsX = ucsRecord.XAxis;
                        var ucsY = ucsRecord.YAxis;
                        var ucsZ = ucsRecord.XAxis.CrossProduct(ucsRecord.YAxis);*/

                        ed.WriteMessage("The current UCS is" + ed.CurrentUserCoordinateSystem);
                        ed.WriteMessage("The current UCS is" + ed.CurrentUserCoordinateSystem);
                        Utilities.CreateHatch(polyline3d, hatchPattern, angle, scale, null);

--- End code ---

--- Code: ---        public void CreateHatch(Polyline3d outerLoop, String hatchName, Double angle, Double scale, List<Polyline3d> holePolylines = null)
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;
            Editor ed = acDoc.Editor;

            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
                var vertices = outerLoop.Cast<ObjectId>()
                       .Select(id => (PolylineVertex3d)id.GetObject(OpenMode.ForRead))
                       .Select(vertex => vertex.Position)
                var offset = vertices[0].Z;

                ViewportTableRecord acVportTblRec;
                acVportTblRec = acTrans.GetObject(acDoc.Editor.ActiveViewportId, OpenMode.ForWrite) as ViewportTableRecord;

                UcsTableRecord ucsRecord = Utilities.GetUCSByName(outerLoop.Layer);

                BlockTable acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                var newMatrix = Matrix3d.AlignCoordinateSystem(acVportTblRec.Ucs.Origin,
                // Create a temporary copy of the 3D polyline and transform it by the current user coordinate system
                Polyline3d outerLoopTemp = (Polyline3d)outerLoop.Clone();
                acTrans.AddNewlyCreatedDBObject(outerLoopTemp, true);

                // Adds the outerLoopTemp ObjectId to an object id array
                ObjectIdCollection acObjIdColl = new ObjectIdCollection();

                // Create the hatch object and append it to the block table record
                Hatch acHatch = new Hatch();
                acTrans.AddNewlyCreatedDBObject(acHatch, true);

                // Set the properties of the hatch object
                acHatch.SetHatchPattern(HatchPatternType.PreDefined, hatchName);
                acHatch.PatternScale = scale;
                acHatch.PatternAngle = angle;
                acHatch.AppendLoop(HatchLoopTypes.Outermost, acObjIdColl);
                acHatch.Associative = true;

                // Get the normal vector and elevation of the UCS
                Vector3d normal = ed.CurrentUserCoordinateSystem.CoordinateSystem3d.Zaxis;
                ed.WriteMessage("The normal extracted is" + normal);
                double elevation = ed.CurrentUserCoordinateSystem.CoordinateSystem3d.Origin.Z;
                ed.WriteMessage("The elevation extracted is" + elevation);
                // Set the normal and elevation of the hatch
                acHatch.Normal = normal;
                acHatch.Elevation = elevation + (elevation - offset);

                outerLoopTemp.Layer = acHatch.Layer;
                // Handle holePolylines as inner loops
                if (holePolylines != null)
                    foreach (Polyline3d holePolyline in holePolylines)
                        // Create a temporary copy of the holePolyline and transform it by the current user coordinate system
                        Polyline3d holePolylineTemp = (Polyline3d)holePolyline.Clone();
                        acTrans.AddNewlyCreatedDBObject(holePolylineTemp, true);

                        // Adds the holePolylineTemp ObjectId to an object id array
                        ObjectIdCollection holeObjIdColl = new ObjectIdCollection();

                        // Append hole polyline as inner loop
                        acHatch.AppendLoop(HatchLoopTypes.Default, holeObjIdColl);

                // Remove temporary polylines
                // outerLoopTemp.Erase();

                // Save the new object to the database
--- End code ---


I replied a similar (same?) question in the discussion group.

The following example creates a Hatch with any planar closed Curve entity:

--- Code - C#: ---        public static void HatchCurve(Curve curve, Transaction tr)        {            if (!curve.Closed)            {                Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(                    "\nCurve is not closed.");                return;            }            var curve3d = curve.GetGeCurve();            if (!curve3d.IsPlanar(out Plane plane))            {                Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(                    "\nCurve is not planar.");                return;            }            var normal = plane.Normal;            var ids = new ObjectIdCollection { curve.ObjectId };            var owner = (BlockTableRecord)tr.GetObject(curve.OwnerId, OpenMode.ForWrite);            var hatch = new Hatch();            hatch.SetHatchPattern(HatchPatternType.PreDefined, "ANSI31");            hatch.Normal = normal;            hatch.Elevation = plane.PointOnPlane                .TransformBy(Matrix3d.WorldToPlane(new Plane(Point3d.Origin, normal)))                .Z;            owner.AppendEntity(hatch);            tr.AddNewlyCreatedDBObject(hatch, true);            hatch.Associative = true;            hatch.AppendLoop(HatchLoopTypes.Default, ids);            hatch.EvaluateHatch(true);        }

Dear gile,

I really appreciate your response! I was looking at curves but I really didn't want to make the commitment to dealing with another type, especially since I don't ever know before trying if the thought even pans out :/

I was very frustrated that I did all my preprocessing of fitting the poly's to best fit planes and creating ucs's. And orienting those so they aren't bottom up or oriented with +z slope going towards -z in wcs, then to have friken hatches halt me for 3-5 days  :idiot2:

Moments after posting this in frustrating on the swamp (it is indeed the same question), I happened upon a way of solving the problem.

--- Code: ---var _ = (Entity)acHatch;
--- End code ---

I was looking through AcDbMgd.dll, seems Entity's TransformBy expects a 3D transformation matrix. Where Hatch's TransformBy wants 2D. I removed the setting of Elevation and Normal of the hatch property and things work out.

I did get a bit ahead of myself and there seems to be unintended consequences to my approach..The hatch pattern angle seems to be out of my control. I can see changes relative to my input but not 1:1, possible by TransformBy?

I always want the Hatch to be 0degrees relative to the yaxis of the UCS it was created with. It seems to be weirdly off from typical ANSI31. Normally when when I create and set ANSI31 to angle 45 under any UCS, it is 0 degrees relative to the y axis.

You may be able to use angleonplane (part of vectors)
Plane plane = new Plane(Cs.Origin, Cs.Zaxis);
            Rot = (P2 - P1).AngleOnPlane(plane);


[0] Message Index

Go to full version