public static PFVertex PreDeserialization(Dictionary <string, object> vertexDict) { PFVertex newVert = new PFVertex(); if (vertexDict.TryGetValue("Id", out object id)) { if (id is int) { newVert.Id = (int)id; } } else { throw new PolyFrameworkException("Id data not valid or non existent"); } Dictionary <string, double> coordList = vertexDict["Point"] as Dictionary <string, double>; newVert.Point = new Point3d(coordList["X"], coordList["Y"], coordList["Z"]); newVert.External = (bool)vertexDict["External"]; // only these values are stored in the dicts - the rest are placeholders // they will be restored after all the objects are predeserialized. return(newVert); }
/// <summary> /// Finds the intersecting face and the resulting point for an offset edge /// Based on a point where the edge will be. Edge stays parallel to itself. /// </summary> /// <param name="topoLink">The moved vertex from the edge</param> /// <param name="position">New position for the moved edge</param> /// <param name="capFace">The face intersected with the offset. </param> /// <returns>The point of intersection</returns> internal Point3d OffsetIntersection(PFVertex topoLink, PfoamRef coresp, out PFVertex otherVert, out PFFace capFace) { Point3d position = coresp.Vertices[topoLink].Position; // for this I need to build overloads to see for special cases - when starting point is in face, or in edge otherVert = Vertices.Single(x => x != topoLink); var edgeDirection = otherVert.Point - topoLink.Point; edgeDirection.Unitize(); // find all the unique faces of the other point to intersect with // get plane for face // find intersection closest to position -> get that face (use normal to find it and its cell) //----------------------------------------------------------- // for each face test to see if coresp object contains an updated plane for the face //----------------------------------------------------------- // this is the otherPosition - I should output also the point and the corresponding face (cell) // if some faces(or their pair) are part of open cells exclude those faces from the intersections var edgeFaces = new HashSet <PFFace>(Faces); edgeFaces.UnionWith(Pair.Faces); var otherVertFaces = new HashSet <PFFace>(otherVert.Faces); var edgeCapFaces = otherVertFaces.Except(edgeFaces); var facingCapFaces = edgeFaces.Where(x => !x.External && Dot(x.Normal, edgeDirection) > 0).ToList(); if (edgeCapFaces.Count() < 1) { capFace = null; return(position + edgeDirection * GetLength()); } var offsetLine = new Line(position, position + edgeDirection); // now intersect line with all face planes double minPara = double.MaxValue; int minParaIndex = 0; for (int i = 0; i < facingCapFaces.Count(); i++) { var facePlane = coresp.Faces[facingCapFaces[i]].Plane; if (Rhino.Geometry.Intersect.Intersection.LinePlane(offsetLine, facePlane, out double param)) { if (param < minPara) { minPara = param; minParaIndex = i; } } } capFace = facingCapFaces[minParaIndex]; return(offsetLine.PointAt(minPara)); }
/// <summary> /// Scales an edge to a desired length. /// Changes the edge in place. /// </summary> /// <param name="setLengh"></param> public void ScaleEdge(double setLengh) { Point3d midPoint = PFVertex.AverageVertexes(Vertices); Vector3d midToStart = Vertices[0].Point - midPoint; Vector3d midToEnd = Vertices[1].Point - midPoint; midToEnd.Unitize(); midToStart.Unitize(); Vertices[0].Point = midPoint + midToStart * setLengh / 2; Vertices[1].Point = midPoint + midToEnd * setLengh / 2; }
/// <summary> /// This scales an edge while keeping a given direction /// If edge is reversed it will be un-reversed by reconstruction to the new direction. /// </summary> /// <param name="dir">imposed direction</param> /// <param name="factor">scale factor</param> public void ScaleToDir(Vector3d dir, double factor) { factor = Math.Abs(factor); double originaLength = GetLength(); Point3d midPoint = PFVertex.AverageVertexes(Vertices); Point3d startNew = midPoint + dir * originaLength / 2 * factor; Point3d endNew = midPoint + dir * -originaLength / 2 * factor; Vertices[0].Point = startNew; Vertices[1].Point = endNew; }
/// <summary> /// Gets the orientation of the edge in rapport to its dual face /// </summary> /// <returns>True if vector (v1-v0) has same general orientation like the dual face normal</returns> public bool OrientationToDual() { if (Dual == null || Dual.Normal == Vector3d.Unset) { throw new PolyFrameworkException("Edge dual is null or Dual.Normal is unset"); } Point3d midPoint = PFVertex.AverageVertexes(Vertices); Vector3d midToStart = Vertices[0].Point - midPoint; Vector3d midToEnd = Vertices[1].Point - midPoint; midToStart.Unitize(); midToEnd.Unitize(); return((Dual.Normal - midToStart).Length > (Dual.Normal - midToEnd).Length); }
public PFVertex ConstrainInMesh() { var tMesh = RestrictSupport as Brep; if (tMesh.IsSolid && tMesh.IsPointInside(Point, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance, false)) { var oldV = new PFVertex(Id, Point); oldV.InfluenceCoef = InfluenceCoef; return(oldV); } var target = tMesh.ClosestPoint(Point); var toPoint = Point + (target - Point); var newV = Move(toPoint); newV.InfluenceCoef = InfluenceCoef; return(newV); }
public PFVertex ConstrainCurve() { var tCurve = RestrictSupport as Curve; if (tCurve.ClosestPoint(Point, out double cParameter)) { var target = tCurve.PointAt(cParameter); var toPoint = Point + (target - Point); var newV = Move(toPoint); newV.InfluenceCoef = InfluenceCoef; return(newV); } var oldV = new PFVertex(Id, Point); oldV.InfluenceCoef = InfluenceCoef; return(oldV); }
/// <summary> /// Scales the edge in one step /// If target length is set - scales the edge to target /// If not set it makes sure minLen smaller that length and length is smaller than maxLegth /// Uses the constraint move of the point to limit move /// </summary> /// <returns>List of 2 new vertices after the constrained move. They have the influence coefficient of the edge </returns> public List <PFVertex> Scale_Soft() { double originaLength = GetLength(); var direction = GetDirectionVector(); direction.Unitize(); double setLength; if (!double.IsNaN(TargetLength)) { setLength = TargetLength; } else if (originaLength < MinLength) { setLength = MinLength; } else if (originaLength > MaxLength) { setLength = MaxLength; } else { setLength = originaLength; } Point3d midPoint = PFVertex.AverageVertexes(Vertices); Point3d startNew = midPoint + direction * setLength / 2; Point3d endNew = midPoint + direction * -setLength / 2; var nVertStart = Vertices[0].Move(startNew); nVertStart.InfluenceCoef = this.InfluenceCoef; var nVertEnd = Vertices[1].Move(endNew); nVertEnd.InfluenceCoef = this.InfluenceCoef; return(new List <PFVertex> { nVertStart, nVertEnd }); }
/// <summary> /// 1 Step perpendincularization of the edge /// Will change the locations of the vertexes at the ends /// This should be used on a clone of the edge /// Requires dual of the edge to be set /// </summary> /// <returns>the length of the edge after the process </returns> public void PerpEdge(bool orientation, double lAdjCoef = 1.0) { if (lAdjCoef < 0) { lAdjCoef *= -1; } double originaLength = GetLength(); if (orientation) { lAdjCoef *= -1; } Point3d midPoint = PFVertex.AverageVertexes(Vertices); Point3d startNew = midPoint + Dual.Normal * originaLength / 2 * lAdjCoef; Point3d endNew = midPoint + Dual.Normal * originaLength / 2 * -lAdjCoef; Vertices[0].Point = startNew; Vertices[1].Point = endNew; }
/// <summary> /// Intersects an offset edge with another edge from the same face /// The second edge is at the end of the point /// </summary> /// <param name="topoLink"></param> /// <param name="position"></param> /// <param name="inFace"></param> /// <returns></returns> internal Point3d OffsetIntersection(PFVertex topoLink, PfoamRef coresp, PFFace inFace, out PFVertex otherVert, out PFEdge capEdge) { // test if position is in the inFace // intersect an edge with another edge - edges are part of the same face plane //----------------------------------------------------------- // for each edge test to see if coresp object contains an updated line for the edge //----------------------------------------------------------- // there will be an line/line intersection // if other point has more than 4 connections some connections will require type 1 calculations Point3d position = coresp.Vertices[topoLink].Position; otherVert = Vertices.Single(x => x != topoLink); var edgeDirection = otherVert.Point - topoLink.Point; var offsetLine = new Line(position, position + edgeDirection); capEdge = otherVert.Edges.Single(x => inFace.Edges.Contains(x)); var otherLine = coresp.Edges[capEdge].Line; var intersection = Rhino.Geometry.Intersect.Intersection.LineLine(offsetLine, otherLine, out double a, out double b); return(offsetLine.PointAt(a)); }
/// <summary> /// Loads a structure from a set of lines and the attached serial string (JSON) /// If there is a dual present it links the dual and outputs it too /// </summary> /// <param name="edgeLines">The set of line curves with extra data in .UserDictionary</param> /// <param name="dual">The dual. If empty structure then no dual was found</param> /// <returns></returns> public static PFoam LoadFromEdges(IList <Curve> edgeLines, out PFoam dual, bool updateGeometry = false) { dual = new PFoam(); var primal = new PFoam(); var vertLocations = new Dictionary <int, List <PFVertex> >(); foreach (var edgeLine in edgeLines) { if (edgeLine.UserDictionary.TryGetInteger("V0", out int v0)) { if (vertLocations.TryGetValue(v0, out List <PFVertex> vertList)) { vertList.Add(new PFVertex(v0, edgeLine.PointAtStart)); } else { vertLocations[v0] = new List <PFVertex> { new PFVertex(v0, edgeLine.PointAtStart) }; } } if (edgeLine.UserDictionary.TryGetInteger("V1", out int v1)) { if (vertLocations.TryGetValue(v1, out List <PFVertex> vertList)) { vertList.Add(new PFVertex(v1, edgeLine.PointAtEnd)); } else { vertLocations[v1] = new List <PFVertex> { new PFVertex(v1, edgeLine.PointAtEnd) }; } } if (edgeLine.UserDictionary.TryGetString("Primal", out string primalString)) { primal = Util.DeserializeFoam(primalString); } if (edgeLine.UserDictionary.TryGetString("Dual", out string dualString)) { dual = Util.DeserializeFoam(dualString); } } if (primal.Cells.Count < 1) { throw new PolyFrameworkException("No serial data stored in the geometry or data has problems!"); } if (updateGeometry) { foreach (var vertex in primal.Vertices) { if (vertLocations.TryGetValue(vertex.Id, out List <PFVertex> vertPostions)) { vertex.Point = PFVertex.AverageVertexes(vertPostions); } if (vertex.Fixed) // update the fixed position for the vertex based on new position { vertex.RestrictSupport = new Point(vertex.Point); //vertex.RestrictPosition = vertex.ConstrainPoint; } } } foreach (var face in primal.Faces) { face.FaceMesh(); face.ComputeCentroid(); face.ComputeFaceNormal(); } foreach (var cell in primal.Cells) { cell.ComputeCentroid(); } primal.Centroid = PFVertex.AverageVertexes(primal.Vertices); if (dual.Cells.Count > 1) { //Util.ConnectDuals(ref primal, ref dual); foreach (var face in dual.Faces) { face.FaceMesh(); face.ComputeCentroid(); face.ComputeFaceNormal(); } foreach (var cell in dual.Cells) { cell.ComputeCentroid(); } dual.Centroid = PFVertex.AverageVertexes(dual.Vertices); } return(primal); }
public IList <PFEdge> PickEdgeSingle(IList <PFEdge> available = null) { var pickedEdges = new List <PFEdge>(); var doc = Rhino.RhinoDoc.ActiveDoc; var selection = new HashSet <PFEdge>(); if (available != null && available.Count > 0) { selection = new HashSet <PFEdge>(available.Where(x => x.Id > 0)); } else { selection = new HashSet <PFEdge>(Edges.Where(x => x.Id > 0)); } var intPositiveEdges = Edges.Where(x => selection.Contains(x)).ToList(); var midPoints = intPositiveEdges.Select(x => PFVertex.AverageVertexes(x.Vertices)); var edgeConduit = new DrawPFEdgeConduit(intPositiveEdges) { Enabled = true }; doc.Views.Redraw(); var gEdge = new GetPFEdge(intPositiveEdges); gEdge.AddSnapPoints(midPoints.ToArray()); while (true) { gEdge.SetCommandPrompt("select Edge by mid-point. (<ESC> to exit"); gEdge.AcceptNothing(true); gEdge.AcceptString(true); //gVert.SetCursor() // this we can change after switching to Rhino 6 - api gEdge.SetDefaultString($"({pickedEdges.Count}) edges selected press <Enter> to accept"); gEdge.Get(true); doc.Views.Redraw(); var result = gEdge.CommandResult(); var strResult = gEdge.StringResult(); pickedEdges = new List <PFEdge>(); if (gEdge.CommandResult() == Rhino.Commands.Result.Cancel) { break; } bool breakFlag = false; foreach (var edge in intPositiveEdges) { if (edge.Picked) { edge.Picked = false; pickedEdges.Add(edge); breakFlag = true; doc.Views.Redraw(); break; } } if (breakFlag) { break; } //edgeConduit.UpdateLines(); //doc.Views.Redraw(); if (gEdge.GotDefault()) { break; } } edgeConduit.Enabled = false; doc.Views.Redraw(); return(pickedEdges); }
public IList <PFEdge> PickEdge(IList <PFEdge> available = null) { var pickedEdges = new List <PFEdge>(); var doc = Rhino.RhinoDoc.ActiveDoc; var selection = new HashSet <PFEdge>(); if (available != null && available.Count > 0) { selection = new HashSet <PFEdge>(available.Where(x => x.Id > 0)); } else { selection = new HashSet <PFEdge>(Edges.Where(x => x.Id > 0)); } var intPositiveEdges = Edges.Where(x => selection.Contains(x) && x.Vertices.All(y => !y.External)).ToList(); var midPoints = intPositiveEdges.Select(x => PFVertex.AverageVertexes(x.Vertices)); var edgeConduit = new DrawPFEdgeConduit(intPositiveEdges) { Enabled = true }; doc.Views.Redraw(); var gEdge = new GetPFEdge(intPositiveEdges); //var permOption = new OptionToggle(false, "temp", "perm"); gEdge.SetCommandPrompt("select Edges by mid-points. (<ESC> to exit"); //gEdge.AddOptionToggle("Remember", ref permOption); gEdge.AcceptNothing(true); gEdge.AcceptString(true); gEdge.AddSnapPoints(midPoints.ToArray()); while (true) { gEdge.SetCursor(CursorStyle.Hand); // this we can change after switching to Rhino 6 - api gEdge.SetDefaultString($"({pickedEdges.Count}) edges selected press <Enter> to accept"); gEdge.Get(true); doc.Views.Redraw(); var result = gEdge.CommandResult(); var strResult = gEdge.StringResult(); pickedEdges = new List <PFEdge>(); if (gEdge.CommandResult() == Rhino.Commands.Result.Cancel) { break; } foreach (var edge in intPositiveEdges) { if (edge.Picked) { edge.Picked = false; pickedEdges.Add(edge); edge.TargetLength = GetData.GetDoubleInViewport(PFVertex.AverageVertexes(edge.Vertices), edge.TargetLength); edge.InfluenceCoef = 1; doc.Views.Redraw(); break; } } //edgeConduit.UpdateLines(); //doc.Views.Redraw(); if (gEdge.GotDefault()) { break; } } edgeConduit.Enabled = false; doc.Views.Redraw(); return(pickedEdges); }
//float scale = 96 / (float)(int)Registry.GetValue("HKEY_CURRENT_USER\\Control Panel\\Desktop", "LogPixels", 96); public DrawPFEdgeConduit(List <PFEdge> edges) { m_conduit_edges = edges; m_conduit_edgeLines = edges.Select(x => x.CreateLine()).ToList(); m_conduit_midPoints = edges.Select(x => PFVertex.AverageVertexes(x.Vertices)).ToList(); }
/// <summary> /// Loads a structure from a set of breps and the attached serial string (JSON) /// If there is a dual present it links the dual and outputs it too /// </summary> /// <param name="edgeLines">The set of line curves with extra data in .UserDictionary</param> /// <param name="dual">The dual. If empty structure then no dual was found</param> /// <returns></returns> public static PFoam LoadFromMeshes(IList <Mesh> meshes, out PFoam dual, bool updateGeometry = false) { dual = new PFoam(); var primal = new PFoam(); var vertLocations = new Dictionary <int, List <PFVertex> >(); foreach (var mesh in meshes) { //if (faceBrep.Faces.Count > 1) throw new PolyFrameworkException("LoadFromFaces only works with individual faces!"); if (mesh.UserDictionary.TryGetDictionary("VertexIds", out Rhino.Collections.ArchivableDictionary vertDict)) { var sortedVerts = vertDict.ToList().OrderBy(x => int.Parse(x.Key)).Select(y => new Tuple <int, int>(int.Parse(y.Key), (int)y.Value)); foreach (var indexId in sortedVerts) { if (vertLocations.TryGetValue(indexId.Item2, out List <PFVertex> vertList)) { vertList.Add(new PFVertex(indexId.Item2, new Point3d(mesh.Vertices[indexId.Item1]))); } else { vertLocations[indexId.Item2] = new List <PFVertex> { new PFVertex(indexId.Item2, new Point3d(mesh.Vertices[indexId.Item1])) }; } } } if (mesh.UserDictionary.TryGetString("Primal", out string primalString)) { primal = Util.DeserializeFoam(primalString); } if (mesh.UserDictionary.TryGetString("Dual", out string dualString)) { dual = Util.DeserializeFoam(dualString); } } if (primal.Cells.Count < 1) { throw new PolyFrameworkException("No serial data stored in the geometry or data has problems!"); } if (updateGeometry) { foreach (var vertex in primal.Vertices) { if (vertLocations.TryGetValue(vertex.Id, out List <PFVertex> vertPostions)) { vertex.Point = PFVertex.AverageVertexes(vertPostions); } } } foreach (var face in primal.Faces) { face.FaceMesh(); face.ComputeCentroid(); face.ComputeFaceNormal(); } foreach (var cell in primal.Cells) { cell.ComputeCentroid(); } primal.Centroid = PFVertex.AverageVertexes(primal.Vertices); if (dual.Cells.Count > 1) { //Util.ConnectDuals(ref primal, ref dual); foreach (var face in dual.Faces) { face.FaceMesh(); face.ComputeCentroid(); face.ComputeFaceNormal(); } foreach (var cell in dual.Cells) { cell.ComputeCentroid(); } dual.Centroid = PFVertex.AverageVertexes(dual.Vertices); } return(primal); }
/// <summary> /// Loads a structure from a set of breps and the attached serial string (JSON) /// If there is a dual present it links the dual and outputs it too /// </summary> /// <param name="edgeLines">The set of line curves with extra data in .UserDictionary</param> /// <param name="dual">The dual. If empty structure then no dual was found</param> /// <returns></returns> public static PFoam LoadFromCells(IList <Brep> cellBreps, out PFoam dual, bool updateGeometry = false) { dual = new PFoam(); var primal = new PFoam(); var vertLocations = new Dictionary <int, List <PFVertex> >(); foreach (var cellBrep in cellBreps) { if (cellBrep.Faces.Count < 2) { throw new PolyFrameworkException("LoadFromCells only works with PolySurfaces!"); } foreach (var bVert in cellBrep.Vertices) { if (bVert.UserDictionary.TryGetInteger("Id", out int vertId)) { if (vertLocations.TryGetValue(vertId, out List <PFVertex> vertList)) { vertList.Add(new PFVertex(vertId, bVert.Location)); } else { vertLocations[vertId] = new List <PFVertex> { new PFVertex(vertId, bVert.Location) }; } } } if (cellBrep.UserDictionary.TryGetString("Primal", out string primalString)) { primal = Util.DeserializeFoam(primalString); } if (cellBrep.UserDictionary.TryGetString("Dual", out string dualString)) { dual = Util.DeserializeFoam(dualString); } } if (primal.Cells.Count < 1) { throw new PolyFrameworkException("No serial data stored in the geometry or data has problems!"); } if (updateGeometry) { foreach (var vertex in primal.Vertices) { if (vertLocations.TryGetValue(vertex.Id, out List <PFVertex> vertPostions)) { vertex.Point = PFVertex.AverageVertexes(vertPostions); } } } foreach (var face in primal.Faces) { face.FaceMesh(); face.ComputeCentroid(); face.ComputeFaceNormal(); } foreach (var cell in primal.Cells) { cell.ComputeCentroid(); } primal.Centroid = PFVertex.AverageVertexes(primal.Vertices); if (dual.Cells.Count > 1) { //Util.ConnectDuals(ref primal, ref dual); foreach (var face in dual.Faces) { face.FaceMesh(); face.ComputeCentroid(); face.ComputeFaceNormal(); } foreach (var cell in dual.Cells) { cell.ComputeCentroid(); } dual.Centroid = PFVertex.AverageVertexes(dual.Vertices); } return(primal); }
/// <summary> /// This deserializes a whole foam object from a Json string. /// Since it only looks at a singular object the dual cannot be deserialized here. /// Instead placeholder object will be used in the properties for the dual. /// /// </summary> /// <param name="jsonFoam"></param> /// <returns></returns> public static PFoam DeserializeFoam(string jsonFoam) { if (jsonFoam == "") { return(new PFoam()); } // get the foam dict JavaScriptSerializer json = new JavaScriptSerializer(); json.MaxJsonLength = 2147483647; var foamPropDict = json.Deserialize <Dictionary <string, object> >(jsonFoam); // create the foam and add its ID PFoam foam = new PFoam() { Id = (string)foamPropDict["Id"] }; // extract the vertices dictionary and partially extract the vertices into the foam // create dicts for all properties that cannot be deserialized directly into the object. // also a new dict (Id, vertex) var vertObjDict = foamPropDict["Vertices"] as Dictionary <string, object>; var vertDict = new Dictionary <int, PFVertex>(); var vertEdgesId = new Dictionary <PFVertex, List <int> >(); var vertFacesId = new Dictionary <PFVertex, List <int> >(); var vertCellsId = new Dictionary <PFVertex, List <int> >(); // since there is no real object from another foam to deserialize as dual // a place holder object is to be replaced as soon as the dual is available // var vertDualId = new Dictionary<PFVertex, int>(); foreach (var vertKeyVal in vertObjDict) { var vertPropDict = vertKeyVal.Value as Dictionary <string, object>; PFVertex vert = new PFVertex(); vert.Id = (int)vertPropDict["Id"]; //Dictionary<string, double> coordList = vertPropDict["Point"] as Dictionary<string, double>; vert.Point = PointFromDict(vertPropDict["Point"] as Dictionary <string, object>); vert.External = (bool)vertPropDict["External"]; // this will make new versions compatible with older data json strings if (vertPropDict.ContainsKey("SupportGuid")) { vert.SupportGuid = Guid.Parse(vertPropDict["SupportGuid"] as string); // this will throw an exception if there is no guid vert.InfluenceCoef = Convert.ToDouble(vertPropDict["InfluenceCoef"]); // idem vert.Fixed = (bool)vertPropDict["Fixed"]; // idem vert.OnGeo = (bool)vertPropDict["OnGeo"]; if (vert.SupportGuid != Guid.Empty) // now try and find the object in the document { var restrGeo = Rhino.RhinoDoc.ActiveDoc.Objects.FindId(vert.SupportGuid); if (restrGeo != null) { foam.SetVertexConstraints(new List <PFVertex> { vert }, restrGeo, vert.InfluenceCoef, vert.OnGeo); } } if (vert.Fixed) { foam.SetVertexConstraints(new List <PFVertex> { vert }, new Point(vert.Point), 100, vert.OnGeo); // this needs to be update after the offset part... based on the geometry } } vertEdgesId[vert] = (vertPropDict["Edges"] as ArrayList).Cast <int>().ToList(); vertFacesId[vert] = (vertPropDict["Faces"] as ArrayList).Cast <int>().ToList(); vertCellsId[vert] = (vertPropDict["Cells"] as ArrayList).Cast <int>().ToList(); vert.Dual = new PFCell((int)vertPropDict["Dual"]); // dummy cell for dual //vertDualId[vert] = (int)vertPropDict["Dual"]; foam.Vertices.Add(vert); vertDict.Add(vert.Id, vert); } // extract the edges from the dictionary and put the vertices in the edges. // after also put the pairs in the edges // create dictionaries for all properties not immediately fillable var edgeObjDict = foamPropDict["Edges"] as Dictionary <string, object>; var edgeDict = new Dictionary <int, PFEdge>(); var edgePair = new Dictionary <PFEdge, int>(); var edgeFaces = new Dictionary <PFEdge, List <int> >(); var edgeFaceAngle = new Dictionary <PFEdge, List <double> >(); var edgeDual = new Dictionary <PFEdge, int>(); foreach (var edgeKeyVal in edgeObjDict) { var edgePropDict = edgeKeyVal.Value as Dictionary <string, object>; PFEdge edge = new PFEdge(Int32.Parse(edgeKeyVal.Key)); var edgeVertsIds = (edgePropDict["Vertices"] as ArrayList).Cast <int>(); foreach (int vertId in edgeVertsIds) { edge.Vertices.Add(vertDict[vertId]); // add the vertex in the edge } //edgeDict[edge.Id] = edge; edge.External = (bool)edgePropDict["External"]; edge.Deviation = Convert.ToDouble(edgePropDict["Deviation"]); // this will make new versions compatible with older data json strings if (edgePropDict.ContainsKey("TargetLength")) { edge.TargetLength = Convert.ToDouble(edgePropDict["TargetLength"]); edge.MinLength = Convert.ToDouble(edgePropDict["MinLength"]); edge.MaxLength = Convert.ToDouble(edgePropDict["MaxLength"]); edge.InfluenceCoef = Convert.ToDouble(edgePropDict["InfluenceCoef"]); } // put all properties that can't be filled right now in their dictionaries edgePair[edge] = (int)edgePropDict["Pair"]; // for keeping score of the pair easier edgeFaces[edge] = (edgePropDict["Faces"] as ArrayList).Cast <int>().ToList(); edgeFaceAngle[edge] = (edgePropDict["FaceAngle"] as ArrayList).ToArray().Select(x => Convert.ToDouble(x)).ToList(); edge.Dual = new PFFace((int)edgePropDict["Dual"]); // dummy face for dual just placeholder // add edge to foam and edgeDict; foam.Edges.Add(edge); edgeDict.Add(edge.Id, edge); } // now that all the edges have been extracted we can populate edge.Pair foreach (var edge in foam.Edges) { edge.Pair = edgeDict[edgePair[edge]]; } // extract the faces from the dictionary var faceObjDict = foamPropDict["Faces"] as Dictionary <string, object>; var faceDict = new Dictionary <int, PFFace>(); var faceCell = new Dictionary <PFFace, int>(); var facePair = new Dictionary <PFFace, int>(); foreach (var faceKeyVal in faceObjDict) { var facePropDict = faceKeyVal.Value as Dictionary <string, object>; PFFace face = new PFFace(Int32.Parse(faceKeyVal.Key)); var faceVertsIds = (facePropDict["Vertices"] as ArrayList).Cast <int>().ToList(); foreach (var vertId in faceVertsIds) { face.Vertices.Add(vertDict[vertId]); } var faceEdgesIds = (facePropDict["Edges"] as ArrayList).Cast <int>().ToList(); face.Edges = faceEdgesIds.Select(x => edgeDict[x]).ToList(); faceCell[face] = (int)facePropDict["Cell"]; facePair[face] = (int)facePropDict["Pair"]; face.Normal = VectorFromDict(facePropDict["Normal"] as Dictionary <string, object>); face.Centroid = PointFromDict(facePropDict["Centroid"] as Dictionary <string, object>); face.Dual = new PFEdge((int)facePropDict["Dual"]); // create a dummy edge as dual - replace later face.External = (bool)facePropDict["External"]; face.Area = Convert.ToDouble(facePropDict["Area"]); if (facePropDict.ContainsKey("TargetArea")) { face.TargetArea = Convert.ToDouble(facePropDict["TargetArea"]); face.InfluenceCoef = Convert.ToDouble(facePropDict["InfluenceCoef"]); } // add face to foam.faces and faceDict foam.Faces.Add(face); faceDict.Add(face.Id, face); } foreach (var face in foam.Faces) { face.Pair = faceDict[facePair[face]]; } // extract cells from the dictionary var cellObjDict = foamPropDict["Cells"] as Dictionary <string, object>; var cellDict = new Dictionary <int, PFCell>(); foreach (var cellKeyVal in cellObjDict) { var cellPropDict = cellKeyVal.Value as Dictionary <string, object>; PFCell cell = new PFCell(Int32.Parse(cellKeyVal.Key)); var cellVertsIds = (cellPropDict["Vertices"] as ArrayList).Cast <int>(); cell.Vertices = cellVertsIds.Select(x => vertDict[x]).ToList(); var cellEdgesIds = (cellPropDict["Edges"] as ArrayList).Cast <int>(); cell.Edges = cellEdgesIds.Select(x => edgeDict[x]).ToList(); var cellFacesIds = (cellPropDict["Faces"] as ArrayList).Cast <int>(); cell.Faces = cellFacesIds.Select(x => faceDict[x]).ToList(); cell.Centroid = PointFromDict(cellPropDict["Centroid"] as Dictionary <string, object>); cell.Dual = (cellPropDict["Dual"] as ArrayList).Cast <int>().Select(x => new PFVertex(x, Point3d.Unset)).ToList(); // list of dummy points to be changed later cell.Exterior = (bool)cellPropDict["Exterior"]; // add cell to foam.cells and cellDict foam.Cells.Add(cell); cellDict.Add(cell.Id, cell); } //populate properties of vertices foreach (var vert in foam.Vertices) { vert.Edges = vertEdgesId[vert].Select(x => edgeDict[x]).ToList(); vert.Faces = vertFacesId[vert].Select(x => faceDict[x]).ToList(); vert.Cells = vertCellsId[vert].Select(x => cellDict[x]).ToList(); } //populate properties of edges foreach (var edge in foam.Edges) { edge.Faces = edgeFaces[edge].Select(x => faceDict[x]).ToList(); edge.FaceAngle = edgeFaceAngle[edge]; } // populate the properties of faces foreach (var face in foam.Faces) { face.Cell = cellDict[faceCell[face]]; } // now deserialize all other properties foam.ExtVetices = (foamPropDict["ExtVertices"] as ArrayList).Cast <int>().Select(x => vertDict[x]).ToList(); foam.ExtEdges = (foamPropDict["ExtEdges"] as ArrayList).Cast <int>().Select(x => edgeDict[x]).ToList(); foam.ExtFaces = (foamPropDict["ExtFaces"] as ArrayList).Cast <int>().Select(x => faceDict[x]).ToList(); foam.Centroid = PointFromDict(foamPropDict["Centroid"] as Dictionary <string, object>); foam.Dual = new PFoam() // this is a dummy dual just a placeholder with Id { Id = foamPropDict["Dual"] as string }; foam.MaxDeviation = Convert.ToDouble(foamPropDict["MaxDeviation"]); // put also the edges in the vertices - use the vertObjDict for that // populate the edges and vertices in the faces return(foam); }