private static IEnumerable <List <IRing> > GetPolygons([NotNull] IMultiPatch multipatch, [NotNull] GeometryPart part) { var result = new Dictionary <IRing, List <IRing> >(); foreach (IRing ring in part.LowLevelGeometries.Cast <IRing>()) { bool beginning = false; esriMultiPatchRingType type = multipatch.GetRingType(ring, ref beginning); if (type != esriMultiPatchRingType.esriMultiPatchInnerRing) { result.Add(ring, new List <IRing>()); } else { IRing outerRing = multipatch.FindBeginningRing(ring); Assert.True(result.ContainsKey(outerRing), "No outer ring found for inner ring."); result[outerRing].Add(ring); } } foreach (KeyValuePair <IRing, List <IRing> > keyValuePair in result) { List <IRing> polygonRings = keyValuePair.Value; polygonRings.Insert(0, keyValuePair.Key); yield return(polygonRings); } }
public static RingGroup CreateRingGroup([NotNull] GeometryPart part) { RingGroup result = CreateRingGroup( Assert.NotNull(part.MainOuterRing), part.InnerRings.Cast <IRing>().ToList()); return(result); }
private static void CutAndAssignToFootprintParts( [NotNull] GeometryPart multipatchPart, [NotNull] IPolyline cutLine, [NotNull] IDictionary <RingGroup, List <RingGroup> > splitPartsByFootprintPart, ChangeAlongZSource zSource) { double tolerance = GeometryUtils.GetXyTolerance(multipatchPart.FirstGeometry); double zTolerance = GeometryUtils.GetZTolerance(multipatchPart.FirstGeometry); RingGroup ringGroup = GeometryConversionUtils.CreateRingGroup(multipatchPart); int pointId; if (GeometryUtils.HasUniqueVertexId( Assert.NotNull(multipatchPart.MainOuterRing), out pointId)) { ringGroup.Id = pointId; } bool inverted = ringGroup.ClockwiseOriented == false; if (inverted) { ringGroup.ReverseOrientation(); } IList <RingGroup> cutRingGroups = CutRingGroupPlanar(ringGroup, cutLine, tolerance, zSource, zTolerance); AssignResultsToFootprintParts(cutRingGroups, splitPartsByFootprintPart, tolerance); if (inverted) { foreach (RingGroup cutRingGroup in cutRingGroups) { cutRingGroup.ReverseOrientation(); } } }
public byte[] WriteMultipatch([NotNull] IMultiPatch multipatch, bool groupPartsByPointIDs = false) { Assert.True(GeometryUtils.IsRingBasedMultipatch(multipatch), "Unsupported (non-ring-based) multipatch."); // TODO: Initialize with the proper size or allow providing the actual byte[] MemoryStream memoryStream = InitializeWriter(); Ordinates ordinates = GetOrdinatesDimension(multipatch); WriteWkbType(WkbGeometryType.MultiSurface, ordinates); var geometryParts = GeometryPart.FromGeometry(multipatch, groupPartsByPointIDs).ToList(); Writer.Write(geometryParts.Count); foreach (GeometryPart part in geometryParts) { WriteWkbType(WkbGeometryType.PolyhedralSurface, ordinates); List <List <IRing> > polygonGroup = GetPolygons(multipatch, part).ToList(); Writer.Write(polygonGroup.Count); foreach (List <IRing> rings in polygonGroup) { WriteWkbType(WkbGeometryType.Polygon, ordinates); WriteLineStringsCore(GetAsPointList(rings).ToList(), ordinates); } } return(memoryStream.ToArray()); }
public override int FromBytes(byte[] _FromBytes, int _Head) { int Head = _Head; Head += base.FromBytes(_FromBytes, Head); GeometryParts = new List <GeometryPart>(); Convert.BytesToValue(out ParentID, _FromBytes, ref Head); Convert.BytesToValue(out MetadataID, _FromBytes, ref Head); Convert.BytesToValue(out int Size, _FromBytes, ref Head); for (int i = 0; i < Size; ++i) { var NewPart = new GeometryPart(); Convert.BytesToValue(out NewPart.GeometryID, _FromBytes, ref Head); NewPart.Location = Vector3D.FromBytes(_FromBytes, ref Head); NewPart.Rotation = Vector3D.FromBytes(_FromBytes, ref Head); NewPart.Scale = Vector3D.FromBytes(_FromBytes, ref Head); NewPart.Color = Color.FromBytes(_FromBytes, ref Head); GeometryParts.Add(NewPart); } Convert.BytesToValue(out Size, _FromBytes, ref Head); ChildNodes = new List <ulong>(); for (int i = 0; i < Size; ++i) { Convert.BytesToValue(out ulong NewChild, _FromBytes, ref Head); ChildNodes.Add(NewChild); } return(Head - _Head); }
/// <summary> /// Cuts the provided multipatch along the specified cutLine. /// </summary> /// <param name="multipatch"></param> /// <param name="cutLine"></param> /// <param name="zSource">The source of the Z values to be used for the new vertices of the result features.</param> /// <param name="usedCutLine">The cut result containing information about the cut operation.</param> /// <param name="nonSimpleFootprintAction">The action to be performed if one of the result multipatches /// has a degenerate footprint (because it is a sliver polygon with sub-tolerance self intersections).</param> /// <returns></returns> public static IDictionary <IPolygon, IMultiPatch> TryCut( [NotNull] IMultiPatch multipatch, [NotNull] IPolyline cutLine, ChangeAlongZSource zSource, [CanBeNull] CutPolyline usedCutLine = null, DegenerateMultipatchFootprintAction nonSimpleFootprintAction = DegenerateMultipatchFootprintAction.Throw) { Assert.ArgumentNotNull(multipatch, nameof(multipatch)); Assert.ArgumentNotNull(cutLine, nameof(cutLine)); bool allRings = GeometryUtils.IsRingBasedMultipatch(multipatch); Assert.True(allRings, "The multipatch geometry contains triangles, triangle fans or triangle strips, which are currently not supported"); // NOTE: ITopologicalOperator4 is not supported by multipatch, ITopologicalOperator3.Cut returns non-Z-aware polygons // -> Use GeomUtils.Cut implementation which could eventually classify the left/right parts and avoid footprint-cutting // only to find the correct assignment to result features. // TODO: Create footprint as RingGroups directly from multipatch rings IPolygon footprint = GeometryFactory.CreatePolygon(multipatch); IList <IGeometry> cutFootprintParts = TryCutRingGroups(footprint, cutLine, ChangeAlongZSource.Target); if (cutFootprintParts == null || cutFootprintParts.Count == 0) { _msg.DebugFormat( "Not even the footprint could be cut. No multipatch cutting performed."); if (usedCutLine != null) { usedCutLine.Polyline = cutLine; usedCutLine.SuccessfulCut = false; } return(new Dictionary <IPolygon, IMultiPatch>(0)); } // Get the 'connected components', i.e. outer ring with respective inner rings. IList <GeometryPart> multipatchParts = GeometryPart.FromGeometry(multipatch).ToList(); Dictionary <RingGroup, List <RingGroup> > splitPartsByFootprintPart = PrepareSplitPartsDictionary(cutFootprintParts); foreach (GeometryPart part in multipatchParts) { CutAndAssignToFootprintParts(part, cutLine, splitPartsByFootprintPart, zSource); } // make a separate multipatch per footprint-part with all respective ring-groups Dictionary <IPolygon, IMultiPatch> result = BuildResultMultipatches( multipatch, splitPartsByFootprintPart, nonSimpleFootprintAction); if (usedCutLine != null && splitPartsByFootprintPart.Values.Count > 1) { // TODO: Extract actual cutLine from inBound/outBound intersections usedCutLine.Polyline = cutLine; usedCutLine.SuccessfulCut = false; } return(result); }