Ad

Sunday, September 27, 2020

Corridor Surface Shrink

This post is in regard to this Civil 3D Idea: 

https://forums.autodesk.com/t5/civil-3d-ideas/corridor-boundaries/idi-p/5908587

This post will provide a workflow to programmatically delete tin triangles outside of the corridor. 

This code deletes triangles, but it could be modified to add the polylines as boundaries instead of going through the triangles that are outside of the corridor.

It's not full proof, but it's intended to quickly get triangles that are outside of the corridor for design purposes.

The MPolygon requires a reference to this dll: 

C:\Program Files\Autodesk\AutoCAD 2021\AcMPolygonMGD.dll

    public class CorridorShrinkwrap
    {
        [CommandMethod("CorridorShrinkwrap")]
        public void CorridorShrinkwrapCommand()
        {
            var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            var db = doc.Database;

            try
            {
                using (var tr = doc.TransactionManager.StartTransaction())
                using (var btr = db.CurrentSpaceId.GetObject(OpenMode.ForWrite) as BlockTableRecord)
                {
                    var corridorTypVals = new List<TypedValue>
                            {
                                new TypedValue((int)DxfCode.Operator, "<OR"),
                                new TypedValue((int)DxfCode.Start, RXClass.GetClass(typeof(Corridor)).DxfName),
                                new TypedValue((int)DxfCode.Operator, "OR>")
                            };

                    var corrObjIds = ed.GetEntities(corridorTypVals, "\nSelect corridor: ", "\nSelection objects to remove",
                                                     out List<FullSubentityPath> xrefPaths);

                    if (!corrObjIds.Any())
                    {
                        return;
                    }

                    ed.UnHighlightSelectedXREFSubEntities(xrefPaths);

                    var strRslt = ed.GetString("\nEnter link code to shrink to: ");

                    if (strRslt.Status != Autodesk.AutoCAD.EditorInput.PromptStatus.OK)
                    {
                        return;
                    }

                    var code = strRslt.StringResult;
                    var tolerance = Tolerance.Global.EqualPoint;

                    foreach (var corrObjId in corrObjIds)
                    {
                        var corr = corrObjId.GetObject(OpenMode.ForWrite) as Corridor;
                        var polylines = new List<Polyline>();
                        var mpolys = new List<MPolygon>();
                        foreach (var baseline in corr.Baselines)
                        {
                            foreach (var region in baseline.BaselineRegions)
                            {
                                var polyPts = new List<Tuple<ObjectId, CalculatedPoint, CalculatedPoint>>();

                                foreach (var assembly in region.AppliedAssemblies)
                                {                                    
                                    foreach (var subAss in assembly.GetAppliedSubassemblies())
                                    {
                                        var links = subAss.Links.Where(x => x.CorridorCodes.Contains(code));
                                        if (!links.Any())
                                        {
                                            continue;
                                        }
                                        var linkPoints = links.SelectMany(x => x.CalculatedPoints.Select(y => y)).OrderBy(z => z.StationOffsetElevationToBaseline.Y).ToList();
                                        polyPts.Add(new Tuple<ObjectId, CalculatedPoint, CalculatedPoint>(subAss.SubassemblyId, linkPoints.First(), linkPoints.Last()));
                                    }
                                }

                                // Collect the points by subassembly.
                                var polyInfos = polyPts.GroupBy(x => x.Item1).ToDictionary(x => x.Key, x => x.OrderBy(y => y.Item2.StationOffsetElevationToBaseline.X).ToList());

                                foreach (var kvp in polyInfos)
                                {
                                    var poly = new Polyline();

                                    foreach (var pt in kvp.Value)
                                    {
                                        poly.AddVertexAt(poly.NumberOfVertices, pt.Item2.XYZ.ToPoint2d(), 0, 0, 0);
                                    }

                                    kvp.Value.Reverse();
                                    
                                    foreach (var pt in kvp.Value)
                                    {
                                        poly.AddVertexAt(poly.NumberOfVertices, pt.Item3.XYZ.ToPoint2d(), 0, 0, 0);
                                    }

                                    poly.Closed = true;

                                    var plObjId = btr.AppendEntity(poly);
                                    tr.AddNewlyCreatedDBObject(poly, true);

                                    polylines.Add(poly);

                                    var mPoly = new MPolygon();
                                    mPoly.AppendLoopFromBoundary(poly, true, tolerance);

                                    mpolys.Add(mPoly);
                                }

                                // find the surfaces that contain the code. 
                                foreach (var corrSurf in corr.CorridorSurfaces.Where(x => x.LinkCodes().Contains(code)))
                                {
                                    var edgesToDelete = new List<TinSurfaceEdge>();
                                    var corrTinSurf = corrSurf.SurfaceId.GetObject(OpenMode.ForWrite) as TinSurface;
                                    foreach (var tinEdge in corrTinSurf.Triangles.SelectMany(x => new List<TinSurfaceEdge> { x.Edge1, x.Edge2, x.Edge3 }).Distinct())
                                    {
                                        using (var tempLine = new Line(tinEdge.Vertex1.Location, tinEdge.Vertex2.Location))
                                        {
                                            var midPt = tempLine.GetPointAtParameter((tempLine.EndParam - tempLine.StartParam) / 2);
                                            if (mpolys.Where(x => x.IsPointInsideMPolygon(midPt, tolerance).Count == 1).Any())
                                            {
                                                continue;
                                            }
                                            edgesToDelete.Add(tinEdge);
                                        }
                                    }

                                    if (!edgesToDelete.Any())
                                    {
                                        continue;
                                    }
                                    corrTinSurf.DeleteLines(edgesToDelete);
                                }
                            }
                        }

                        // dispose of the polylines. 
                        foreach (var poly in polylines)
                        {
                            poly.Dispose();
                        }

                        foreach (var mPoly in mpolys)
                        {
                            mPoly.Dispose();
                        }
                    }

                    tr.Commit();
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage("\nError: " + ex.Message);
            }
        }
    }

Corridor Gaps

Civil 3D doesn't always build every corridor section you might need. This is because where regions meet, if they have nearly the same station, then it won't draw the first section in the next region. To get a section at the adjacent regions you need to add a gap. This can be troublesome if you have lots of regions. The code below will prompt a user to select a corridor, enter a minimum gap distance, and then if the existing gap is less than the entered value the start station is modified to get the minimum gap. If the existing gap is larger than the minimum value then no change is made.

The code could be changed to save the last entered value and then make it the default value. This code can be found by using your favorite search engine.

Feel free to use this code. 

    public class CorridorGaps
    {
        [CommandMethod("MinimumCorridorGaps")]
        public void MinimumCorridorGapsCommand()
        {
            var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;

            try
            {
                using (var tr = doc.TransactionManager.StartTransaction())
                {
                    var corridorTypVals = new List<TypedValue>
                            {
                                new TypedValue((int)DxfCode.Operator, "<OR"),
                                new TypedValue((int)DxfCode.Start, RXClass.GetClass(typeof(Corridor)).DxfName),
                                new TypedValue((int)DxfCode.Operator, "OR>")
                            };

                    var corrObjIds = ed.GetEntities(corridorTypVals, "\nSelect corridor: ", "\nSelection objects to remove",
                                                     out List<FullSubentityPath> xrefPaths);

                    if (!corrObjIds.Any())
                    {
                        return;
                    }

                    ed.UnHighlightSelectedXREFSubEntities(xrefPaths);

                    var distRslt = ed.GetDistance("\nEnter minimum gap distance: ");

                    if (distRslt.Status != Autodesk.AutoCAD.EditorInput.PromptStatus.OK)
                    {
                        return;
                    }

                    var minGapDist = distRslt.Value;

                    foreach (var corrObjId in corrObjIds)
                    {
                        var corr = corrObjId.GetObject(OpenMode.ForWrite) as Corridor;
                        foreach (var baseline in corr.Baselines)
                        {
                            var lastRegionStation = double.NaN;
                            var baselineCount = baseline.BaselineRegions.Count;
                            for (int i = 0; i < baselineCount; i++)
                            {
                                if (i == 0)
                                {
                                    lastRegionStation = baseline.BaselineRegions[i].EndStation;
                                }
                                else
                                {
                                    var currentRegionStation = baseline.BaselineRegions[i].StartStation;
                                    var currentGap = currentRegionStation - lastRegionStation;
                                    if (currentGap < minGapDist)
                                    {
                                        baseline.BaselineRegions[i].StartStation = lastRegionStation + minGapDist;
                                    }
                                    lastRegionStation = baseline.BaselineRegions[i].EndStation;
                                }                                
                            }
                        }                        
                    }

                    tr.Commit();
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage("\nError: " + ex.Message);
            }
        }

LinkWithin

Blog Widget by LinkWithin

Ad