/// <summary> /// Creates the pair for the face /// Reverse the edge list and replace all edges with their pair /// Reverse vertex list. /// Add pair face to the edges and to the vertexes /// </summary> public void CreatePair() { PFFace pair = new PFFace(-Id) { Vertices = this.Vertices.Reverse().ToList() }; foreach (var vert in pair.Vertices) { vert.Faces.Add(pair); } pair.Edges = this.Edges.Select(x => x.Pair).Reverse().ToList(); //foreach (var edge in pair.Edges) edge.Faces.Add(pair); // this needs to be done separately after if (Normal != Vector3d.Unset) { pair.Normal = -Normal; } if (Centroid != Point3d.Unset) { pair.Centroid = Centroid; } //pair.FMesh = this.FMesh.DuplicateMesh(); //pair.FMesh?.Flip(true, true, true); pair.Pair = this; Pair = pair; }
/// <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> /// 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); }
/// <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)); }