예제 #1
0
        /// <summary>
        /// Find elements either contained, containing or intersecting polygon.
        /// <para>
        /// If no elements are found, an empty list is returned.
        /// </para>
        /// </summary>
        public IList <MeshElement> FindElements(Polygon polygon)
        {
            if (_elementSearchTree == null)
            {
                SetupElementSearch();
            }

            Envelope targetEnvelope = polygon.EnvelopeInternal;

            IList <MeshElement> potentialElmts = _elementSearchTree.Query(targetEnvelope);

            List <MeshElement> result = new List <MeshElement>();

            // Loop over all potential elements
            for (int i = 0; i < potentialElmts.Count; i++)
            {
                MeshElement element = potentialElmts[i];

                // Fast-lane check: When there is no overlap even by the envelopes
                if (!targetEnvelope.Intersects(element.EnvelopeInternal()))
                {
                    continue;
                }

                // More detailed check for actual overlap
                Polygon elementPolygon = element.ToPolygon();
                if (elementPolygon.Intersects(polygon))
                {
                    result.Add(element);
                }
            }

            return(result);
        }
예제 #2
0
        /// <summary>
        /// Find element containing (x,y) coordinate. Returns null if no element found.
        /// <para>
        /// If (x,y) is exacly on the boundary between two elements, one of them will be returned.
        /// If (x,y) is matching exacly a node coordinate, one of the elements including the node will be returned.
        /// </para>
        /// </summary>
        public MeshElement FindElement(double x, double y)
        {
            // Find potential elements for (x,y) point
            Envelope targetEnvelope = new Envelope(x, x, y, y);

#if NTS173
            IList potentialSourceElmts = _elementSearchTree.Query(targetEnvelope);
#else
            IList <MeshElement> potentialSourceElmts = _elementSearchTree.Query(targetEnvelope);
#endif

            // Loop over all potential elements
            for (int i = 0; i < potentialSourceElmts.Count; i++)
            {
#if NTS173
                MeshElement element = (MeshElement)potentialSourceElmts[i];
#else
                MeshElement element = potentialSourceElmts[i];
#endif

                // Check if element includes the (x,y) point
                if (element.Includes(x, y))
                {
                    return(element);
                }
            }

            return(null);
        }
예제 #3
0
파일: MeshData.cs 프로젝트: DHI/DHI.Mesh
        public void BuildNodeElements()
        {
            if (Nodes[0].Elements != null)
            {
                return;
            }

            // Build up element list in nodes
            for (int i = 0; i < Nodes.Count; i++)
            {
                Nodes[i].Elements = new List <MeshElement>();
            }

            for (int ielmt = 0; ielmt < Elements.Count; ielmt++)
            {
                MeshElement     element        = Elements[ielmt];
                List <MeshNode> nodeInElmt     = element.Nodes;
                int             numNodesInElmt = nodeInElmt.Count;

                for (int j = 0; j < numNodesInElmt; j++)
                {
                    MeshNode meshNode = nodeInElmt[j];
                    meshNode.Elements.Add(element);
                }
            }
        }
예제 #4
0
 /// <summary>
 /// Set a target being all elements of the <paramref name="targetMesh"/>
 /// </summary>
 public void SetTarget(MeshData targetMesh)
 {
     SetTargetSize(targetMesh.Elements.Count);
     for (int i = 0; i < targetMesh.Elements.Count; i++)
     {
         MeshElement targetElement = targetMesh.Elements[i];
         AddTarget(targetElement.XCenter, targetElement.YCenter);
     }
 }
예제 #5
0
        /// <summary>
        /// Create mesh from arrays.
        /// </summary>
        public static MeshData CreateMesh(string projection, int[] nodeIds, double[] x, double[] y, double[] z, int[] code, int[] elementIds, int[] elementTypes, int[][] connectivity, MeshUnit zUnit = MeshUnit.Meter)
        {
            MeshData meshData = new MeshData();

            meshData.Projection = projection;
            meshData.ZUnit      = zUnit;
            meshData.Nodes      = new List <MeshNode>(nodeIds.Length);
            meshData.Elements   = new List <MeshElement>(elementIds.Length);

            for (int i = 0; i < nodeIds.Length; i++)
            {
                var node = new MeshNode()
                {
                    Index    = i,
                    Id       = nodeIds[i],
                    X        = x[i],
                    Y        = y[i],
                    Z        = z[i],
                    Code     = code[i],
                    Elements = new List <MeshElement>(),
                };
                meshData.Nodes.Add(node);
            }

            for (int ielmt = 0; ielmt < elementIds.Length; ielmt++)
            {
                var element = new MeshElement()
                {
                    Index       = ielmt,
                    Id          = elementIds[ielmt],
                    ElementType = elementTypes[ielmt],
                    Nodes       = new List <MeshNode>(connectivity[ielmt].Length),
                };
                double xc = 0;
                double yc = 0;
                double zc = 0;

                for (int j = 0; j < connectivity[ielmt].Length; j++)
                {
                    MeshNode meshNode = meshData.Nodes[connectivity[ielmt][j] - 1];
                    element.Nodes.Add(meshNode);
                    meshNode.Elements.Add(element);
                    xc += meshNode.X;
                    yc += meshNode.Y;
                    zc += meshNode.Z;
                }

                element.XCenter = xc / connectivity[ielmt].Length;
                element.YCenter = yc / connectivity[ielmt].Length;
                element.ZCenter = zc / connectivity[ielmt].Length;

                meshData.Elements.Add(element);
            }

            return(meshData);
        }
예제 #6
0
        /// <summary>
        /// Create mesh from arrays.
        /// <para>
        /// Note that the <paramref name="connectivity"/> array is using zero-based indices
        /// (as compared to the <see cref="MeshFile.ElementTable"/>, which is using one-based indices)
        /// </para>
        /// </summary>
        public MeshDataBase(string projection, int[] nodeIds, double[] x, double[] y, double[] z, int[] code, int[] elementIds, int[] elementTypes, int[][] connectivity, MeshUnit zUnit = MeshUnit.Meter)
        {
            Projection = projection;
            ZUnit      = zUnit;
            Nodes      = new List <MeshNode>(nodeIds.Length);
            Elements   = new List <MeshElement>(elementIds.Length);

            for (int i = 0; i < nodeIds.Length; i++)
            {
                var node = new MeshNode()
                {
                    Index = i,
                    Id    = nodeIds[i],
                    X     = x[i],
                    Y     = y[i],
                    Z     = z[i],
                    Code  = code[i],
                };
                Nodes.Add(node);
            }

            for (int ielmt = 0; ielmt < elementIds.Length; ielmt++)
            {
                int[] nodeInElmt     = connectivity[ielmt];
                int   numNodesInElmt = nodeInElmt.Length;

                var element = new MeshElement()
                {
                    Index       = ielmt,
                    Id          = elementIds[ielmt],
                    ElementType = elementTypes[ielmt],
                    Nodes       = new List <MeshNode>(numNodesInElmt),
                };
                double xc = 0;
                double yc = 0;
                double zc = 0;

                for (int j = 0; j < numNodesInElmt; j++)
                {
                    int      nodeIndex = nodeInElmt[j];
                    MeshNode meshNode  = Nodes[nodeIndex];
                    element.Nodes.Add(meshNode);
                    xc += meshNode.X;
                    yc += meshNode.Y;
                    zc += meshNode.Z;
                }

                double inumNodesInElmt = 1.0 / numNodesInElmt;
                element.XCenter = xc * inumNodesInElmt; // / numNodesInElmt;
                element.YCenter = yc * inumNodesInElmt; // / numNodesInElmt;
                element.ZCenter = zc * inumNodesInElmt; // / numNodesInElmt;

                Elements.Add(element);
            }
        }
예제 #7
0
        /// <summary>
        /// Returns true if mesh element is a quadrilateral element
        /// </summary>
        public static bool IsQuadrilateral(this MeshElement element)
        {
            // TODO: Should probably check on type?
            int nodesCount = element.Nodes.Count;

            if (nodesCount == 4 || nodesCount == 8)
            {
                return(true);
            }
            return(false);
        }
예제 #8
0
 /// <summary>
 /// Get the other element of a <see cref="MeshFace"/>, when
 /// looking from <paramref name="element"/>.
 /// <para>
 /// For boundary faces, null is returned.
 /// </para>
 /// </summary>
 public static MeshElement OtherElement(this MeshFace face, MeshElement element)
 {
     if (ReferenceEquals(face.LeftElement, element))
     {
         return(face.RightElement);
     }
     if (ReferenceEquals(face.RightElement, element))
     {
         return(face.LeftElement);
     }
     throw new Exception("element is not part of face");
 }
예제 #9
0
        /// <summary>
        /// Setup for element-search
        /// </summary>
        public void SetupElementSearch()
        {
            _elementSearchTree = new SearchTreeType();

            for (int i = 0; i < _mesh.Elements.Count; i++)
            {
                MeshElement element = _mesh.Elements[i];
                Envelope    extent  = element.EnvelopeInternal();
                _elementSearchTree.Insert(extent, element);
            }
            // When using STRtree, call this method here
            //_elementSearchTree.Build();
        }
예제 #10
0
        /// <summary>
        /// Convert a <see cref="MeshData"/> class into a <see cref="MeshFile"/> class.
        /// </summary>
        public static MeshFile ToMeshFile(this MeshData meshData)
        {
            int numberOfNodes = meshData.Nodes.Count;

            int[]    nodeId = new int[numberOfNodes];
            double[] x      = new double[numberOfNodes];
            double[] y      = new double[numberOfNodes];
            double[] z      = new double[numberOfNodes];
            int[]    code   = new int[numberOfNodes];

            for (int i = 0; i < numberOfNodes; i++)
            {
                MeshNode node = meshData.Nodes[i];
                nodeId[i] = node.Id;
                x[i]      = node.X;
                y[i]      = node.Y;
                z[i]      = node.Z;
                code[i]   = node.Code;
            }

            int numberOfElements = meshData.Elements.Count;

            int[]   elmtId    = new int[numberOfElements];
            int[][] elmtTable = new int[numberOfElements][];
            for (int i = 0; i < numberOfElements; i++)
            {
                MeshElement elmt = meshData.Elements[i];
                elmtId[i] = elmt.Id;
                int[] elmtNodes = new int[elmt.Nodes.Count];
                elmtTable[i] = elmtNodes;
                for (int j = 0; j < elmt.Nodes.Count; j++)
                {
                    elmtNodes[j] = elmt.Nodes[j].Index + 1;
                }
            }

            MeshFileBuilder builder = new MeshFileBuilder();

            builder.SetProjection(meshData.Projection);
            builder.SetZUnit(meshData.ZUnit);
            builder.SetNodeIds(nodeId);
            builder.SetNodes(x, y, z, code);
            builder.SetElementIds(elmtId);
            builder.SetElements(elmtTable);

            MeshFile meshFile = builder.CreateMesh();

            return(meshFile);
        }
예제 #11
0
        private static void CreateAddElementFaces(CMeshData meshData, List <CMeshFace>[] facesFromNode, int ielmt, bool checkAllFaces)
        {
            MeshElement     elmt      = meshData.Elements[ielmt];
            List <MeshNode> elmtNodes = elmt.Nodes;

            for (int j = 0; j < elmtNodes.Count; j++)
            {
                MeshNode fromNode = elmtNodes[j];
                MeshNode toNode   = elmtNodes[(j + 1) % elmtNodes.Count];
                if (checkAllFaces || fromNode.Code > 0 && toNode.Code > 0)
                {
                    MeshData.AddFace(elmt, fromNode, toNode, facesFromNode);
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Create an envelop around from a mesh element.
        /// </summary>
        public static Envelope EnvelopeInternal(this MeshElement element)
        {
            List <MeshNode> elementNodes = element.Nodes;
            double          minx         = elementNodes[0].X;
            double          miny         = elementNodes[0].Y;
            double          maxx         = elementNodes[0].X;
            double          maxy         = elementNodes[0].Y;

            for (int i = 1; i < elementNodes.Count; i++)
            {
                minx = minx < elementNodes[i].X ? minx : elementNodes[i].X;
                maxx = maxx > elementNodes[i].X ? maxx : elementNodes[i].X;
                miny = miny < elementNodes[i].Y ? miny : elementNodes[i].Y;
                maxy = maxy > elementNodes[i].Y ? maxy : elementNodes[i].Y;
            }
            return(new Envelope(minx, maxx, miny, maxy));
        }
예제 #13
0
        /// <summary>
        /// Returns true if coordinate (x,y) is inside element
        /// </summary>
        public static bool Includes(this MeshElement element, double x, double y, double tolerance)
        {
            bool isQuad = element.IsQuadrilateral();

            List <MeshNode> elementNodes = element.Nodes;

            if (!isQuad)
            {
                return
                    (LeftDistance(x, y, elementNodes[0], elementNodes[1]) >= -tolerance &&
                     LeftDistance(x, y, elementNodes[1], elementNodes[2]) >= -tolerance &&
                     LeftDistance(x, y, elementNodes[2], elementNodes[0]) >= -tolerance);
            }
            return
                (LeftDistance(x, y, elementNodes[0], elementNodes[1]) >= -tolerance &&
                 LeftDistance(x, y, elementNodes[1], elementNodes[2]) >= -tolerance &&
                 LeftDistance(x, y, elementNodes[2], elementNodes[3]) >= -tolerance &&
                 LeftDistance(x, y, elementNodes[3], elementNodes[0]) >= -tolerance);
        }
예제 #14
0
        /// <summary>
        /// Create a polygon from a mesh element.
        /// </summary>
        public static Polygon ToPolygon(this MeshElement element, GeometryFactory geomFactory)
        {
            List <CoordinateZ> coordinates = new List <CoordinateZ>(element.Nodes.Count);

            MeshNode node;

            for (int i = 0; i < element.Nodes.Count; i++)
            {
                node = element.Nodes[i];
                coordinates.Add(new CoordinateZ(node.X, node.Y, node.Z));
            }
            // Add the first node again, to close the polygon
            node = element.Nodes[0];
            coordinates.Add(new CoordinateZ(node.X, node.Y, node.Z));

            Polygon elementPolygon = geomFactory.CreatePolygon(coordinates.ToArray());

            return(elementPolygon);
        }
예제 #15
0
파일: MeshData.cs 프로젝트: DHI/DHI.Mesh
        /// <summary>
        /// Create and add a face.
        /// <para>
        /// A face is only "added once", i.e. when two elements share the face, it is found twice,
        /// once defined as "toNode"-"fromNode" and once as "fromNode"-"toNode". The second time,
        /// the existing face is being reused, and the element is added as the <see cref="CMeshFace.RightElement"/>
        /// </para>
        /// <para>
        /// The <see cref="CMeshFace"/> is added to the global list of faces, and also to tne nodes list of faces.
        /// </para>
        /// </summary>
        private void AddFace(MeshElement element, MeshNode fromNode, MeshNode toNode)
        {
            List <CMeshFace> fromNodeFaces = fromNode.Faces;
            List <CMeshFace> toNodeFaces   = toNode.Faces;

            // Try find "reverse face" going from to-node to from-node.
            // The FindIndex with delegate is 10+ times slower than the tight loop below.
            //int reverseFaceIndex = toNodeFaces.FindIndex(mf => mf.ToNode == fromNode);
            int reverseToNodeFaceIndex = -1;

            // Look in all faces starting from toNode
            for (int i = 0; i < toNodeFaces.Count; i++)
            {
                // Check if the face goes to fromNode
                if (toNodeFaces[i].ToNode == fromNode)
                {
                    reverseToNodeFaceIndex = i;
                    break;
                }
            }

            if (reverseToNodeFaceIndex >= 0)
            {
                // Found reverse face, reuse it and add the element as the RightElement
                CMeshFace reverseFace = toNodeFaces[reverseToNodeFaceIndex];
                reverseFace.RightElement = element;
            }
            else
            {
                // Found new face, set element as LeftElement and add it to both from-node and to-node
                CMeshFace meshFace = new CMeshFace(fromNode, toNode)
                {
                    LeftElement = element,
                };

                Faces.Add(meshFace);
                fromNodeFaces.Add(meshFace);
                // Adding to toNodeFaces is not required for the algorithm to work,
                // however, it is required in order to get NodesFaces lists right
                toNodeFaces.Add(meshFace);
            }
        }
예제 #16
0
        /// <summary>
        /// Setup for element-search
        /// </summary>
        public void SetupElementSearch()
        {
#if NTS173
            _elementSearchTree = new STRtree();
#else
            _elementSearchTree = new STRtree <MeshElement>();
#endif
            for (int i = 0; i < _mesh.Elements.Count; i++)
            {
                MeshElement element = _mesh.Elements[i];
                double      x       = element.Nodes[0].X;
                double      y       = element.Nodes[0].Y;
                Envelope    extent  = new Envelope(x, x, y, y);
                for (int j = 1; j < element.Nodes.Count; j++)
                {
                    extent.ExpandToInclude(element.Nodes[j].X, element.Nodes[j].Y);
                }
                _elementSearchTree.Insert(extent, element);
            }
        }
예제 #17
0
        /// <summary>
        /// Set a target being all elements of the <paramref name="targetMesh"/>
        /// </summary>
        public void SetTarget(MeshData targetMesh, MeshValueType targetType)
        {
            if (targetType == MeshValueType.Elements)
            {
                SetTargetSize(targetMesh.NumberOfElements);
                for (int i = 0; i < targetMesh.NumberOfElements; i++)
                {
                    MeshElement targetMeshElement = targetMesh.Elements[i];
                    AddTarget(targetMeshElement.XCenter, targetMeshElement.YCenter);
                }
            }
            else
            {
                SetTargetSize(targetMesh.NumberOfNodes);

                for (int i = 0; i < targetMesh.NumberOfNodes; i++)
                {
                    MeshNode targetMeshNode = targetMesh.Nodes[i];
                    AddTarget(targetMeshNode.X, targetMeshNode.Y);
                }
            }
        }
예제 #18
0
        /// <summary>
        /// Find element containing (x,y) coordinate. Returns null if no element found.
        /// <para>
        /// If (x,y) is exactly on the boundary between two elements, one of them will be returned.
        /// If (x,y) is matching exacly a node coordinate, one of the elements including the node will be returned.
        /// </para>
        /// </summary>
        public MeshElement FindElement(double x, double y)
        {
            // Find potential elements for (x,y) point
            Envelope targetEnvelope = new Envelope(x, x, y, y);

            IList <MeshElement> potentialSourceElmts = _elementSearchTree.Query(targetEnvelope);

            // Loop over all potential elements
            for (int i = 0; i < potentialSourceElmts.Count; i++)
            {
                MeshElement element = potentialSourceElmts[i];

                // Check if element includes the (x,y) point
                if (element.Includes(x, y))
                {
                    return(element);
                }
            }

            if (Tolerance <= 0)
            {
                return(null);
            }

            // Try again, now with tolerance
            for (int i = 0; i < potentialSourceElmts.Count; i++)
            {
                MeshElement element = potentialSourceElmts[i];

                // Check if element includes the (x,y) point
                if (element.Includes(x, y, Tolerance))
                {
                    return(element);
                }
            }

            return(null);
        }
예제 #19
0
파일: MeshData.cs 프로젝트: DHI/DHI.Mesh
        /// <summary>
        /// Determines whether the specified mesh geometry is equal to the current mesh's geometry.
        /// The order of the nodes and elements in the mesh must equal.
        /// <para>
        /// This only checks the geometry, i.e. node coordinates, node boundary codes and element connectivity.
        /// The Id's in the mesh may differ.
        /// </para>
        /// </summary>
        /// <param name="other"></param>
        /// <param name="tolerance"></param>
        public bool EqualsGeometry(MeshData other, double tolerance = 1e-3)
        {
            if (this.Nodes.Count != other.Nodes.Count ||
                this.Elements.Count != other.Elements.Count)
            {
                return(false);
            }

            for (int i = 0; i < this.Nodes.Count; i++)
            {
                MeshNode nt = this.Nodes[i];
                MeshNode no = other.Nodes[i];
                if (Math.Abs(nt.X - no.X) > tolerance ||
                    Math.Abs(nt.Y - no.Y) > tolerance ||
                    nt.Code != no.Code)
                {
                    return(false);
                }
            }

            for (int i = 0; i < this.Elements.Count; i++)
            {
                MeshElement et = this.Elements[i];
                MeshElement eo = other.Elements[i];
                if (et.Nodes.Count != eo.Nodes.Count)
                {
                    return(false);
                }
                for (int j = 0; j < et.Nodes.Count; j++)
                {
                    if (et.Nodes[j].Index != eo.Nodes[j].Index)
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
예제 #20
0
        /// <summary>
        /// Convert a <see cref="MeshData"/> class into a <see cref="SMeshData"/> class.
        /// </summary>
        public static SMeshData ToSMesh(this MeshData meshData)
        {
            int numberOfNodes = meshData.Nodes.Count;

            int[]    nodeId = new int[numberOfNodes];
            double[] x      = new double[numberOfNodes];
            double[] y      = new double[numberOfNodes];
            double[] z      = new double[numberOfNodes];
            int[]    code   = new int[numberOfNodes];

            for (int i = 0; i < numberOfNodes; i++)
            {
                MeshNode node = meshData.Nodes[i];
                nodeId[i] = node.Id;
                x[i]      = node.X;
                y[i]      = node.Y;
                z[i]      = node.Z;
                code[i]   = node.Code;
            }

            int numberOfElements = meshData.Elements.Count;

            int[]   elmtId    = new int[numberOfElements];
            int[][] elmtTable = new int[numberOfElements][];
            for (int i = 0; i < numberOfElements; i++)
            {
                MeshElement elmt = meshData.Elements[i];
                elmtId[i] = elmt.Id;
                int[] elmtNodes = new int[elmt.Nodes.Count];
                elmtTable[i] = elmtNodes;
                for (int j = 0; j < elmt.Nodes.Count; j++)
                {
                    elmtNodes[j] = elmt.Nodes[j].Index;
                }
            }

            return(new SMeshData(meshData.Projection, nodeId, x, y, z, code, elmtId, null, elmtTable, meshData.ZUnit));
        }
예제 #21
0
        /// <summary>
        /// Create and add a face.
        /// <para>
        /// A face is only "added once", i.e. when two elements share the face, it is found twice,
        /// once defined as "toNode"-"fromNode" and once as "fromNode"-"toNode". The second time,
        /// the existing face is being reused, and the element is added as the <see cref="MeshFace.RightElement"/>
        /// </para>
        /// <para>
        /// The <see cref="MeshFace"/> is added to the global list of faces, and also to tne nodes list of faces.
        /// </para>
        /// </summary>
        private void AddFace(MeshElement element, MeshNode fromNode, MeshNode toNode)
        {
            List <MeshFace> fromNodeFaces = fromNode.Faces;
            List <MeshFace> toNodeFaces   = toNode.Faces;

            if (fromNodeFaces.FindIndex(mf => mf.ToNode == toNode) >= 0)
            {
                throw new Exception(string.Format("Invalid mesh: Double face, from node {0} to node {1}. " +
                                                  "Hint: Probably too many nodes was merged into one of the two face nodes." +
                                                  "Try decrease node merge tolerance value",
                                                  fromNode.Index + 1, toNode.Index + 1));
            }

            // Try find "reverse face" going from from-node to to-node.
            int reverseFaceIndex = toNodeFaces.FindIndex(mf => mf.ToNode == fromNode);

            if (reverseFaceIndex >= 0)
            {
                // Found reverse face, reuse it and add the elment as the RightElement
                MeshFace reverseFace = toNodeFaces[reverseFaceIndex];
                reverseFace.RightElement = element;
            }
            else
            {
                // Found new face, set element as LeftElement and add it to both from-node and to-node
                MeshFace meshFace = new MeshFace()
                {
                    FromNode    = fromNode,
                    ToNode      = toNode,
                    LeftElement = element,
                };

                Faces.Add(meshFace);
                fromNodeFaces.Add(meshFace);
                toNodeFaces.Add(meshFace);
            }
        }
예제 #22
0
파일: MeshData.cs 프로젝트: DHI/DHI.Mesh
        /// <summary>
        /// Create and add a face - special version for <see cref="MeshBoundaryExtensions.GetBoundaryFaces(MeshData)"/>
        /// <para>
        /// A face is only "added once", i.e. when two elements share the face, it is found twice,
        /// once defined as "toNode"-"fromNode" and once as "fromNode"-"toNode". The second time,
        /// the existing face is being reused, and the element is added as the <see cref="CMeshFace.RightElement"/>
        /// </para>
        /// <para>
        /// The <see cref="CMeshFace"/> is added to the global list of faces, and also to tne nodes list of faces.
        /// </para>
        /// </summary>
        internal static void AddFace(MeshElement element, MeshNode fromNode, MeshNode toNode, List <CMeshFace>[] nodeFaces)
        {
            List <CMeshFace> fromNodeFaces = nodeFaces[fromNode.Index];
            List <CMeshFace> toNodeFaces   = nodeFaces[toNode.Index];

            // Try find "reverse face" going from from-node to to-node.
            // The FindIndex with delegate is 10+ times slower than the tight loop below.
            //int reverseFaceIndex = toNodeFaces.FindIndex(mf => mf.ToNode == fromNode);
            int reverseFaceIndex = -1;

            for (int i = 0; i < toNodeFaces.Count; i++)
            {
                if (toNodeFaces[i].ToNode == fromNode)
                {
                    reverseFaceIndex = i;
                    break;
                }
            }

            if (reverseFaceIndex >= 0)
            {
                // Found reverse face, reuse it and add the element as the RightElement
                CMeshFace reverseFace = toNodeFaces[reverseFaceIndex];
                reverseFace.RightElement = element;
            }
            else
            {
                // Found new face, set element as LeftElement and add it to both from-node and to-node
                CMeshFace meshFace = new CMeshFace(fromNode, toNode)
                {
                    LeftElement = element,
                };

                fromNodeFaces.Add(meshFace);
            }
        }
예제 #23
0
        /// <summary>
        /// Find elements either contained, containing or intersecting the polygon.
        /// <para>
        /// This method can be used if only some elements of the mesh is to be included
        /// in the weight calculations.
        /// </para>
        /// <para>
        /// If polygon is totally contained within one mesh element, then 1 element is returned.
        /// If polygon partially falls outside of the grid, only elements within grid are returned.
        /// </para>
        /// <param name="polygon">Polygon or multi-polygon</param>
        /// <param name="elements">List of elements</param>
        /// </summary>
        public List <ElementWeight> CalculateWeights(Geometry polygon, IList <MeshElement> elements)
        {
            Envelope targetEnvelope = polygon.EnvelopeInternal;

            //// It should be faster to use than the polygon directly?
            //PreparedPolygon prepolygon = new PreparedPolygon(polygon);

            List <ElementWeight> result = new List <ElementWeight>();

            // Total intersecting area
            double totalArea = 0;

            // Loop over all potential elements
            for (int i = 0; i < elements.Count; i++)
            {
                MeshElement element = elements[i];

                // Fast-lane check: When there is no overlap even by the envelopes
                if (!targetEnvelope.Intersects(element.EnvelopeInternal()))
                {
                    continue;
                }

                Polygon elementPolygon = element.ToPolygon();

                Geometry intersection = elementPolygon.Intersection(polygon);
                if (!intersection.IsEmpty)
                {
                    // Target polygon and element polygon has an overlap.
                    // If target  polygon fully contains the element polygon, this is the element area
                    // If element polygon fully contains the target  polygon, this is the polygon area
                    double intersectingArea = intersection.Area;
                    totalArea += intersectingArea;
                    if (WeightType == WeightType.Fraction)
                    {
                        result.Add(new ElementWeight(element, intersectingArea / elementPolygon.Area));
                    }
                    else
                    {
                        result.Add(new ElementWeight(element, intersectingArea));
                    }
                }
            }

            IntersectionArea = totalArea;

            if (result.Count == 0 || totalArea == 0)
            {
                return(null);
            }

            // When Weight-based calculations, weight with the total intersecting area
            if (WeightType == WeightType.Weight)
            {
                for (int i = 0; i < result.Count; i++)
                {
                    ElementWeight elmtWeight = result[i];
                    elmtWeight.Weight /= totalArea;
                    result[i]          = elmtWeight;
                }
            }

            return(result);
        }
예제 #24
0
        /// <summary>
        /// Add a target, by specifying its (x,y) coordinate.
        /// </summary>
        public void AddTarget(double x, double y)
        {
            if (_mesh == null)
            {
                AddSTarget(x, y);
                return;
            }

            // Find element that includes the (x,y) coordinate
            MeshElement element = _searcher.FindElement(x, y);

            // Setup interpolation from node values
            if (NodeValueInterpolation)
            {
                InterpNodeData interp;
                // Check if element has been found, i.e. includes the (x,y) point
                if (element != null)
                {
                    var nodes = element.Nodes;
                    if (nodes.Count == 3)
                    {
                        var weights = InterpTriangle.InterpolationWeights(x, y, nodes);
                        interp = new InterpNodeData(element.Index, weights.w1, weights.w2, weights.w3);
                    }
                    else if (nodes.Count == 4)
                    {
                        var weights = InterpQuadrangle.InterpolationWeights(x, y, nodes);
                        interp = new InterpNodeData(element.Index, weights.dx, weights.dy);
                    }
                    else
                    {
                        interp = InterpNodeData.Undefined();
                    }
                }
                else
                {
                    interp = InterpNodeData.Undefined();
                }

                if (_targetsNode == null)
                {
                    _targetsNode = new List <InterpNodeData>();
                }
                _targetsNode.Add(interp);
            }

            // Setup interpolation from element+node values
            if (ElmtNodeValueInterpolation)
            {
                InterpElmtNode.Weights weights;
                // Check if element has been found, i.e. includes the (x,y) point
                if (element != null)
                {
                    weights = InterpElmtNode.InterpolationWeights(x, y, element);
                }
                else
                {
                    weights = InterpElmtNode.Undefined();
                }

                if (_targetsElmtNode == null)
                {
                    _targetsElmtNode = new List <InterpElmtNode.Weights>();
                }
                _targetsElmtNode.Add(weights);
            }
        }
예제 #25
0
 /// <summary>
 /// Create a polygon from a mesh element
 /// </summary>
 public static Polygon ToPolygon(this MeshElement element)
 {
     return(element.ToPolygon(GeomFactory));
 }
예제 #26
0
        /// <summary>
        /// Add a target, by specifying its (x,y) coordinate.
        /// </summary>
        public void AddTarget(double x, double y)
        {
            if (_targets == null)
            {
                _targets = new List <InterPData>();
            }
            if (_searcher == null)
            {
                _searcher = new MeshSearcher(_mesh);
                _searcher.SetupElementSearch();
            }

            InterPData interpData = new InterPData();

            // Setting "out-of-bounds" index
            interpData.Element1Index = -1;

            // Find element that includes the (x,y) coordinate
            MeshElement element = _searcher.FindElement(x, y);

            // Check if element has been found, i.e. includes the (x,y) point
            if (element != null)
            {
                bool found = false;
                interpData.Element1Index = element.Index;

                // Check which face the point belongs to, and which "side" of the face
                bool isQuad   = element.IsQuadrilateral();
                int  numFaces = isQuad ? 4 : 3;
                for (int j = 0; j < numFaces; j++)
                {
                    MeshFace elementFace = element.Faces[j];
                    // From the element (x,y), looking towards the face,
                    // figure out wich node is right and which is left.
                    MeshNode rightNode, leftNode;
                    if (elementFace.LeftElement == element)
                    {
                        rightNode = elementFace.FromNode;
                        leftNode  = elementFace.ToNode;
                    }
                    else
                    {
                        rightNode = elementFace.ToNode;
                        leftNode  = elementFace.FromNode;
                    }

                    // Find also the element on the other side of the face
                    double      otherElementX, otherElementY;
                    MeshElement otherElement = elementFace.OtherElement(element);
                    if (otherElement != null)
                    {
                        otherElementX            = otherElement.XCenter;
                        otherElementY            = otherElement.YCenter;
                        interpData.Element2Index = otherElement.Index;
                    }
                    else
                    {
                        // No other element - boundary face, use center of face.
                        otherElementX = 0.5 * (rightNode.X + leftNode.X);
                        otherElementY = 0.5 * (rightNode.Y + leftNode.Y);
                        // Use "itself" as element-2
                        interpData.Element2Index = element.Index;
                    }


                    // Check if point is on the right side of the line between element and other-element
                    if (MeshExtensions.IsPointInsideLines(x, y, element.XCenter, element.YCenter, rightNode.X, rightNode.Y, otherElementX, otherElementY))
                    {
                        (double w1, double w2, double w3) = MeshExtensions.InterpolationWeights(x, y, element.XCenter, element.YCenter, rightNode.X, rightNode.Y, otherElementX, otherElementY);
                        interpData.NodeIndex      = rightNode.Index;
                        interpData.Element1Weight = w1;
                        interpData.NodeWeight     = w2;
                        interpData.Element2Weight = w3;
                        found = true;
                        break;
                    }
                    // Check if point is on the left side of the line between element and other-element
                    if (MeshExtensions.IsPointInsideLines(x, y, element.XCenter, element.YCenter, otherElementX, otherElementY, leftNode.X, leftNode.Y))
                    {
                        (double w1, double w2, double w3) = MeshExtensions.InterpolationWeights(x, y, element.XCenter, element.YCenter, otherElementX, otherElementY, leftNode.X, leftNode.Y);
                        interpData.NodeIndex      = leftNode.Index;
                        interpData.Element1Weight = w1;
                        interpData.Element2Weight = w2;
                        interpData.NodeWeight     = w3;
                        found = true;
                        break;
                    }
                }

                if (!found) // Should never happen, but just in case
                {
                    interpData.Element1Weight = 1;
                    interpData.Element2Weight = 0;
                    interpData.NodeWeight     = 0;
                    interpData.Element2Index  = element.Index;
                    interpData.NodeIndex      = element.Nodes[0].Index;
                }
            }
            _targets.Add(interpData);
        }
예제 #27
0
        /// <summary>
        /// Build derived mesh data, especially the <see cref="MeshFace"/> lists.
        /// </summary>
        public void BuildDerivedData()
        {
            Faces = new List <MeshFace>();

            // Preallocate list of face on all nodes - used in next loop
            for (int i = 0; i < Nodes.Count; i++)
            {
                Nodes[i].Faces = new List <MeshFace>();
            }

            // Create all faces.
            for (int ielmt = 0; ielmt < Elements.Count; ielmt++)
            {
                MeshElement element = Elements[ielmt];
                element.Faces = new List <MeshFace>();
                List <MeshNode> elmtNodes = element.Nodes;
                for (int j = 0; j < elmtNodes.Count; j++)
                {
                    MeshNode fromNode = elmtNodes[j];
                    MeshNode toNode   = elmtNodes[(j + 1) % elmtNodes.Count];
                    AddFace(element, fromNode, toNode);
                }
            }

            // Figure out boundary code
            for (int i = 0; i < Faces.Count; i++)
            {
                MeshFace face = Faces[i];

                // If the RightElement exists, this face is an internal face
                if (face.RightElement != null)
                {
                    continue;
                }

                // RightElement does not exist, so it is a boundary face.
                int fromCode = face.FromNode.Code;
                int toCode   = face.ToNode.Code;

                // True if "invalid" boundary face, then set it as internal face.
                bool internalFace = false;

                if (fromCode == 0)
                {
                    internalFace = true;
                    throw new Exception(string.Format("Invalid mesh: Boundary face, from node {0} to node {1} is missing a boundary code on node {0}. " +
                                                      "Hint: Modify boundary code for node {0}",
                                                      face.FromNode.Index + 1, face.ToNode.Index + 1));
                }
                if (toCode == 0)
                {
                    internalFace = true;
                    throw new Exception(string.Format("Invalid mesh: Boundary face, from node {0} to node {1} is missing a boundary code on node {1}. " +
                                                      "Hint: Modify boundary code for node {1}",
                                                      face.FromNode.Index + 1, face.ToNode.Index + 1));
                }

                int faceCode;

                // Find face code:
                // 1) In case any of the nodes is a land node (code value 1) then the
                //    boundary face is a land face, given boundary code value 1.
                // 2) For boundary faces (if both fromNode and toNode have code values larger than 1),
                //    the face code is the boundary code value of toNode.
                if (fromCode == 1 || toCode == 1)
                {
                    faceCode = 1;
                }
                else
                {
                    faceCode = toCode;
                }

                if (!internalFace)
                {
                    face.Code = faceCode;
                }
            }

            // Add face to the elements list of faces
            for (int i = 0; i < Faces.Count; i++)
            {
                MeshFace face = Faces[i];
                face.LeftElement.Faces.Add(face);
                face.RightElement?.Faces.Add(face);
            }
        }
예제 #28
0
 public ElementWeight(MeshElement element, double weight)
 {
     ElementIndex = element.Index;
     Weight       = weight;
 }
예제 #29
0
        /// <summary>
        /// Calculate interpolation weights for interpolating a value at the provided <paramref name="node"/>
        /// from the surrounding element center values.
        /// </summary>
        /// <param name="node">Node to setup interpolation for</param>
        public Interpolator.InterPData SetupNodeInterpolation(MeshNode node)
        {
            Interpolator.InterPData interpData = new Interpolator.InterPData()
            {
                Indices = new int[node.Elements.Count],
                Weights = new double[node.Elements.Count],
            };

            double Ixx      = 0;
            double Iyy      = 0;
            double Ixy      = 0;
            double Rx       = 0;
            double Ry       = 0;
            double omegaTot = 0;

            for (int i = 0; i < node.Elements.Count; i++)
            {
                MeshElement element = node.Elements[i];
                double      dx      = element.XCenter - node.X;
                double      dy      = element.YCenter - node.Y;

                Ixx += dx * dx;
                Iyy += dy * dy;
                Ixy += dx * dy;
                Rx  += dx;
                Ry  += dy;

                interpData.Indices[i] = element.Index;
            }

            double lambda = Ixx * Iyy - Ixy * Ixy;

            if (lambda > 1e-10 * (Ixx * Iyy))
            {
                // Standard case - Pseudo Laplacian

                for (int i = 0; i < node.Elements.Count; i++)
                {
                    MeshElement element = node.Elements[i];
                    double      dx      = element.XCenter - node.X;
                    double      dy      = element.YCenter - node.Y;

                    double lambda_x = (Ixy * Ry - Iyy * Rx) / lambda;
                    double lambda_y = (Ixy * Rx - Ixx * Ry) / lambda;

                    double omega = 1.0 + lambda_x * dx + lambda_y * dy;
                    if (!_allowExtrapolation)
                    {
                        if (omega < 0)
                        {
                            omega = 0;
                        }
                        else if (omega > 2)
                        {
                            omega = 2;
                        }
                    }

                    interpData.Weights[i] = omega;
                    omegaTot += omega;
                }
            }

            if (omegaTot <= 0)
            {
                // We did not succeed using pseudo laplace procedure,
                // use inverse distance instead
                omegaTot = 0;
                for (int i = 0; i < node.Elements.Count; i++)
                {
                    MeshElement element = node.Elements[i];
                    double      dx      = element.XCenter - node.X;
                    double      dy      = element.YCenter - node.Y;

                    // Inverse distance weighted interpolation weight
                    double omega = 1 / Math.Sqrt(dx * dx + dy * dy);

                    interpData.Weights[i] = omega;
                    omegaTot += omega;
                }
            }

            // Scale to 1
            if (omegaTot != 0)
            {
                for (int i = 0; i < interpData.Weights.Length; i++)
                {
                    interpData.Weights[i] /= omegaTot;
                }
            }
            else
            {
                for (int i = 0; i < interpData.Weights.Length; i++)
                {
                    interpData.Weights[i] = 0;
                }
            }

            //double sum = 0;
            //for (int i = 0; i < interpData.Weights.Length; i++)
            //{
            //  sum += interpData.Weights[i];
            //}
            //if (Math.Abs(sum - 1) > 1e-12)
            //  Console.Out.WriteLine("Duh!!!: "+node.Index);

            return(interpData);
        }
예제 #30
0
파일: MeshData.cs 프로젝트: DHI/DHI.Mesh
        /// <summary>
        /// Build up the list of <see cref="Faces"/>
        /// </summary>
        /// <param name="elmtFaces">Also build up <see cref="MeshElement.Faces"/></param>
        public List <string> BuildFaces(bool elmtFaces = false)
        {
            List <string> errors = new List <string>();

            int numberOfNodes    = NumberOfNodes;
            int numberOfElements = NumberOfElements;

            bool hasElementFaces = Elements[0].Faces != null;

            //System.Diagnostics.Stopwatch timer = MeshExtensions.StartTimer();

            if (Faces == null)
            {
                // Build up face lists
                // The exact number of faces is: NumberOfElements+NumberOfNodes + numberOfSubMeshes - numberOfHoles
                Faces = new List <CMeshFace>((int)((numberOfElements + numberOfNodes) * 1.01));

                // Preallocate list of face on all nodes - used in next loop
                for (int i = 0; i < Nodes.Count; i++)
                {
                    Nodes[i].Faces = new List <CMeshFace>();
                }
                //timer.ReportAndRestart("Prealloc nodeface");

                //watch.Start();
                // Create all faces.
                for (int ielmt = 0; ielmt < Elements.Count; ielmt++)
                {
                    MeshElement     element   = Elements[ielmt];
                    List <MeshNode> elmtNodes = element.Nodes;
                    if (elmtFaces)
                    {
                        element.Faces = new List <CMeshFace>(elmtNodes.Count);
                    }
                    for (int j = 0; j < elmtNodes.Count; j++)
                    {
                        MeshNode fromNode = elmtNodes[j];
                        MeshNode toNode   = elmtNodes[(j + 1) % elmtNodes.Count];
                        AddFace(element, fromNode, toNode);
                    }
                }
                //timer.ReportAndRestart("Create faces "+Faces.Count);

                // Figure out boundary code
                for (int i = 0; i < Faces.Count; i++)
                {
                    CMeshFace face = Faces[i];
                    face.SetBoundaryCode(errors);
                }
                //timer.ReportAndRestart("Set Boundary Code");
            }

            if (elmtFaces && !hasElementFaces)
            {
                // If not already created, create the lists
                if (Elements[0].Faces == null)
                {
                    for (int ielmt = 0; ielmt < numberOfElements; ielmt++)
                    {
                        Elements[ielmt].Faces = new List <CMeshFace>();
                    }
                }

                // Add face to the elements list of faces
                for (int i = 0; i < Faces.Count; i++)
                {
                    CMeshFace face = Faces[i];
                    face.LeftElement.Faces.Add(face);
                    if (face.RightElement != null)
                    {
                        face.RightElement.Faces.Add(face);
                    }
                }
            }
            //timer.ReportAndRestart("Create element faces");

            return(errors);
        }