/// <summary> /// Assumes the halfedges of the given graph are correctly sorted around each vertex. /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <param name="graph"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <returns></returns> public TM CreateFromGraph <UV, UE>(HeGraph <UV, UE> graph, Action <TV, UV> setVertex = null, Action <TE, UE> setHedge = null) where UV : HeGraph <UV, UE> .Vertex where UE : HeGraph <UV, UE> .Halfedge { // TODO implement throw new NotImplementedException(); }
/// <summary> /// Appends a deep copy of the given graph to this graph. /// Allows projection of element data to a different form. /// </summary> /// <typeparam name="UE"></typeparam> /// <typeparam name="UV"></typeparam> /// <param name="other"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> public void Append <UV, UE>(HeGraph <UV, UE> other, Action <TV, UV> setVertex = null, Action <TE, UE> setHedge = null) where UV : HeGraph <UV, UE> .Vertex where UE : HeGraph <UV, UE> .Halfedge { var vertsB = other.Vertices; var hedgesB = other.Halfedges; int nvA = Vertices.Count; int nhA = Halfedges.Count; // cache in case of appending to self int nvB = vertsB.Count; int nhB = hedgesB.Count; // append new elements for (int i = 0; i < nvB; i++) { AddVertex(); } for (int i = 0; i < nhB; i += 2) { AddEdge(); } // set vertex refs for (int i = 0; i < nvB; i++) { var v0 = vertsB[i]; var v1 = Vertices[i + nvA]; // transfer attributes setVertex?.Invoke(v1, v0); if (v0.IsUnused) { continue; } v1.First = Halfedges[v0.First.Index + nhA]; } // set halfedge refs for (int i = 0; i < nhB; i++) { var he0 = hedgesB[i]; var he1 = Halfedges[i + nhA]; // transfer attributes setHedge?.Invoke(he1, he0); if (he0.IsUnused) { continue; } he1.Previous = Halfedges[he0.Previous.Index + nhA]; he1.Next = Halfedges[he0.Next.Index + nhA]; he1.Start = Vertices[he0.Start.Index + nvA]; } }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="graph"></param> /// <param name="setVertexAttributes"></param> /// <param name="setHedgeAttributes"></param> public static void ReadFromJson <V, E, VA, EA>(string path, HeGraph <V, E> graph, Action <V, VA> setVertexAttributes = null, Action <E, EA> setHedgeAttributes = null) where V : HeGraph <V, E> .Vertex where E : HeGraph <V, E> .Halfedge { var buffer = CoreIO.DeserializeJson <HeGraphJsonBuffer <VA, EA> >(path); buffer.ReadTo(graph, setVertexAttributes, setHedgeAttributes); }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> public static void WriteToJson <V, E, VA, EA>(HeGraph <V, E> graph, string path, Func <V, VA> getVertexAttributes = null, Func <E, EA> getHedgeAttributes = null) where V : HeGraph <V, E> .Vertex where E : HeGraph <V, E> .Halfedge { var buffer = new HeGraphJsonBuffer <VA, EA>(); buffer.WriteFrom(graph, getVertexAttributes, getHedgeAttributes); CoreIO.SerializeJson(buffer, path); }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <param name="graph"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <returns></returns> public TG CreateCopy <UV, UE>(HeGraph <UV, UE> graph, Action <TV, UV> setVertex = null, Action <TE, UE> setHedge = null) where UV : HeGraph <UV, UE> .Vertex where UE : HeGraph <UV, UE> .Halfedge { var copy = Create(graph.Vertices.Capacity, graph.Halfedges.Capacity); copy.Append(graph, setVertex, setHedge); return(copy); }
/// <summary> /// Writes the given graph to this buffer. /// </summary> public void WriteFrom <V, E>(HeGraph <V, E> graph, Func <V, VA> getVertexAttributes = null, Func <E, EA> getHedgeAttributes = null) where V : HeGraph <V, E> .Vertex where E : HeGraph <V, E> .Halfedge { var verts = graph.Vertices; var hedges = graph.Halfedges; _vertexRefs = new int[verts.Count]; _hedgeRefs = new int[hedges.Count][]; // write vertex topology for (int i = 0; i < verts.Count; i++) { var v = verts[i]; _vertexRefs[i] = v.First ?? -1; } // write halfedge topology for (int i = 0; i < hedges.Count; i++) { var he = hedges[i]; _hedgeRefs[i] = new int[] { he.Previous ?? -1, he.Next, he.Start }; } // write vertex attributes if (getVertexAttributes != null) { _vertexAttributes = new VA[verts.Count]; for (int i = 0; i < verts.Count; i++) { _vertexAttributes[i] = getVertexAttributes(verts[i]); } } // write halfedge attributes if (getHedgeAttributes != null) { _hedgeAttributes = new EA[hedges.Count]; for (int i = 0; i < hedges.Count; i++) { _hedgeAttributes[i] = getHedgeAttributes(hedges[i]); } } }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <param name="graph"></param> /// <param name="componentIndices"></param> /// <param name="edgeIndices"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <returns></returns> public TG[] CreateConnectedComponents <UV, UE>(HeGraph <UV, UE> graph, out int[] componentIndices, out int[] edgeIndices, Action <TV, UV> setVertex = null, Action <TE, UE> setHedge = null) where UV : HeGraph <UV, UE> .Vertex where UE : HeGraph <UV, UE> .Halfedge { int ne = graph.Edges.Count; componentIndices = new int[ne]; edgeIndices = new int[ne]; return(CreateConnectedComponents( graph, Halfedge <UE> .CreateEdgeProperty(componentIndices), Halfedge <UE> .CreateEdgeProperty(edgeIndices), setVertex, setHedge )); }
/// <summary> /// Throws an exception if the topology of the given mesh is not valid. /// </summary> /// <typeparam name="TV"></typeparam> /// <typeparam name="TE"></typeparam> /// <typeparam name="TF"></typeparam> /// <param name="mesh"></param> internal static void CheckTopology <TV, TE>(HeGraph <TV, TE> graph) where TV : HeGraph <TV, TE> .Vertex where TE : HeGraph <TV, TE> .Halfedge { var verts = graph.Vertices; var hedges = graph.Halfedges; // ensure halfedges are reciprocally linked foreach (var he in hedges) { if (he.IsUnused) { continue; } if (he.Previous.Next != he && he.Next.Previous != he) { Throw(); } if (he.Start.IsUnused) { Throw(); } } // ensure consistent start vertex during circulation foreach (var v in verts) { foreach (var he in v.OutgoingHalfedges) { if (he.Start != v) { Throw(); } } } void Throw() { throw new Exception("The topology of the given mesh is invalid"); } }
/// <summary> /// Reads this buffer to the given graph. /// </summary> public void ReadTo <V, E>(HeGraph <V, E> graph, Action <V, VA> setVertexAttributes = null, Action <E, EA> setHedgeAttributes = null) where V : HeGraph <V, E> .Vertex where E : HeGraph <V, E> .Halfedge { var verts = graph.Vertices; var hedges = graph.Halfedges; int nv = verts.Count; int nhe = hedges.Count; // add new vertices for (int i = 0; i < _vertexRefs.Length; i++) { graph.AddVertex(); } // add new halfedges for (int i = 0; i < _hedgeRefs.Length; i += 2) { graph.AddEdge(); } // link up vertices for (int i = 0; i < _vertexRefs.Length; i++) { var v = verts[i + nv]; var first = _vertexRefs[i]; if (first > -1) { v.First = hedges[first + nhe]; } } // link up halfedges for (int i = 0; i < _hedgeRefs.Length; i++) { var he = hedges[i + nhe]; var refs = _hedgeRefs[i]; var prev = refs[0]; if (prev != -1) { he.Previous = hedges[prev + nhe]; } he.Next = hedges[refs[1] + nhe]; var start = refs[2]; if (start > -1) { he.Start = verts[start + nhe]; } } // TODO validate topology? // set vertex attributes if (setVertexAttributes != null) { for (int i = 0; i < _vertexAttributes.Length; i++) { setVertexAttributes(verts[i + nv], _vertexAttributes[i]); } } // set vertex attributes if (setHedgeAttributes != null) { for (int i = 0; i < _hedgeAttributes.Length; i++) { setHedgeAttributes(hedges[i + nhe], _hedgeAttributes[i]); } } }
/// <summary> /// /// </summary> /// <param name="other"></param> public void Append(HeGraph other) { Append(other, delegate { }, delegate { }); }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <param name="graph"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <returns></returns> public TG[] CreateConnectedComponents <UV, UE>(HeGraph <UV, UE> graph, Action <TV, UV> setVertex = null, Action <TE, UE> setHedge = null) where UV : HeGraph <UV, UE> .Vertex where UE : HeGraph <UV, UE> .Halfedge { return(CreateConnectedComponents(graph, out int[] compIds, out int[] edgeIds, setVertex, setHedge)); }
/// <summary> /// /// </summary> /// <typeparam name="UV"></typeparam> /// <typeparam name="UE"></typeparam> /// <param name="graph"></param> /// <param name="componentIndex"></param> /// <param name="edgeIndex"></param> /// <param name="setVertex"></param> /// <param name="setHedge"></param> /// <returns></returns> public TG[] CreateConnectedComponents <UV, UE>(HeGraph <UV, UE> graph, Property <UE, int> componentIndex, Property <UE, int> edgeIndex, Action <TV, UV> setVertex = null, Action <TE, UE> setHedge = null) where UV : HeGraph <UV, UE> .Vertex where UE : HeGraph <UV, UE> .Halfedge { var vertices = graph.Vertices; var hedges = graph.Halfedges; int ncomp = graph.GetEdgeComponentIndices(componentIndex.Set); var comps = new TG[ncomp]; // initialize components for (int i = 0; i < comps.Length; i++) { comps[i] = Create(); } // create component halfedges for (int i = 0; i < hedges.Count; i += 2) { var heA = hedges[i]; if (heA.IsUnused) { continue; } var comp = comps[componentIndex.Get(heA)]; var heB = comp.AddEdge(); edgeIndex.Set(heA, heB.Index >> 1); } // set component halfedge->halfedge refs for (int i = 0; i < hedges.Count; i++) { var heA0 = hedges[i]; if (heA0.IsUnused) { continue; } // the component to which heA0 was copied var compHedges = comps[componentIndex.Get(heA0)].Halfedges; var heA1 = heA0.NextAtStart; // set refs var heB0 = compHedges[(edgeIndex.Get(heA0) << 1) + (i & 1)]; var heB1 = compHedges[(edgeIndex.Get(heA1) << 1) + (heA1.Index & 1)]; heB0.MakeConsecutive(heB1); // transfer attributes setHedge?.Invoke(heB0, heA0); } // create component vertices for (int i = 0; i < vertices.Count; i++) { var vA = vertices[i]; if (vA.IsUnused) { continue; } var heA = vA.First; var comp = comps[componentIndex.Get(heA)]; var heB = comp.Halfedges[(edgeIndex.Get(heA) << 1) + (heA.Index & 1)]; // set vertex refs var vB = comp.AddVertex(); vB.First = heB; foreach (var he in heB.CirculateStart) { he.Start = vB; } // transfer attributes setVertex?.Invoke(vB, vA); } return(comps); }