Пример #1
0
        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);
        }
Пример #2
0
        /// <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));
        }
Пример #3
0
        /// <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;
        }
Пример #4
0
        /// <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;
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }
Пример #8
0
        /// <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
            });
        }
Пример #9
0
        /// <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;
        }
Пример #10
0
        /// <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));
        }
Пример #11
0
        /// <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);
        }
Пример #12
0
        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);
        }
Пример #13
0
        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);
        }
Пример #14
0
        //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();
        }
Пример #15
0
        /// <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);
        }
Пример #16
0
        /// <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);
        }
Пример #17
0
        /// <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);
        }