Beispiel #1
0
 /// <summary>
 /// Get the other node of a <see cref="MeshFace"/>, when
 /// looking from <paramref name="fromNode"/>.
 /// </summary>
 public static MeshNode ToNode(this MeshFace face, MeshNode fromNode)
 {
     if (ReferenceEquals(face.FromNode, fromNode))
     {
         return(face.ToNode);
     }
     return(face.FromNode);
 }
Beispiel #2
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");
 }
Beispiel #3
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);
            }
        }
Beispiel #4
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);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Build list of face boundaries of <paramref name="mesh"/>
        /// </summary>
        public static List <MeshBoundary> BuildBoundaryList(MeshData mesh)
        {
            if (mesh.Faces == null)
            {
                mesh.BuildDerivedData();
            }

            // Sort all faces on boundary code
            Dictionary <int, List <MeshFace> > bcs = new Dictionary <int, List <MeshFace> >();

            for (int i = 0; i < mesh.Faces.Count; i++)
            {
                MeshFace meshFace = mesh.Faces[i];
                if (meshFace.IsBoundaryFace())
                {
                    List <MeshFace> boundaryFaces;
                    if (!bcs.TryGetValue(meshFace.Code, out boundaryFaces))
                    {
                        boundaryFaces = new List <MeshFace>();
                        bcs.Add(meshFace.Code, boundaryFaces);
                    }
                    boundaryFaces.Add(meshFace);
                }
            }

            List <MeshBoundary> boundaries = new List <MeshBoundary>();

            // For each boundary code, find segments
            foreach (KeyValuePair <int, List <MeshFace> > bfkvp in bcs)
            {
                int             code  = bfkvp.Key;
                List <MeshFace> faces = bfkvp.Value;

                // Sort faces on FromNode index
                faces.Sort((f1, f2) => f1.FromNode.Index.CompareTo(f2.FromNode.Index));

                // Create searchable array of FromNode indices
                int[] fromNodes = faces.Select(f => f.FromNode.Index).ToArray();

                // Matching array telling which boundary segment a given face belongs to
                int[] faceSegmentIndex = new int[faces.Count];
                for (int ii = 0; ii < faceSegmentIndex.Length; ii++)
                {
                    faceSegmentIndex[ii] = -1;
                }

                // All segments with this boundary code
                List <LinkedList <int> > segments = new List <LinkedList <int> >();

                // Make sure to visit all faces
                for (int i = 0; i < faces.Count; i++)
                {
                    // Check if this face has already been visited.
                    if (faceSegmentIndex[i] >= 0)
                    {
                        continue;
                    }

                    // Start new boundary segment with face i
                    int currentSegmentIndex         = segments.Count;
                    int currentFaceIndex            = i;
                    LinkedList <int> currentSegment = new LinkedList <int>();
                    // Add current face to segment
                    currentSegment.AddLast(currentFaceIndex);
                    faceSegmentIndex[currentFaceIndex] = currentSegmentIndex;

                    while (true)
                    {
                        // Try find next face, which is the face with fromNode matching currentFace.ToNode
                        MeshFace currentFace   = faces[currentFaceIndex];
                        int      nextFaceIndex = Array.BinarySearch(fromNodes, currentFace.ToNode.Index);

                        if (nextFaceIndex < 0)
                        {
                            // No to-node, we are done with this segment
                            segments.Add(currentSegment);
                            break;
                        }

                        // Check if the next face is already part of a segment
                        if (faceSegmentIndex[nextFaceIndex] >= 0)
                        {
                            if (faceSegmentIndex[nextFaceIndex] == currentSegmentIndex)
                            {
                                // Circular boundary - we are done with this segment
                                segments.Add(currentSegment);
                                break;
                            }

                            // Now: nextSegment is not the same as the currentSection,
                            // but they should be - move entire current segment to the
                            // start of the nextFace segment

                            int nextFaceSegment = faceSegmentIndex[nextFaceIndex];
                            // Move all from current segment to
                            LinkedListNode <int> thisSegmentListNode = currentSegment.Last;
                            while (thisSegmentListNode != null)
                            {
                                int faceToMoveIndex = thisSegmentListNode.Value;
                                segments[nextFaceSegment].AddFirst(faceToMoveIndex);
                                faceSegmentIndex[faceToMoveIndex] = nextFaceSegment;
                                thisSegmentListNode = thisSegmentListNode.Previous;
                            }
                            break; // Break out of while (true) loop
                        }

                        // Make nextFace to currentFace - add it to the list of current segments.
                        currentFaceIndex = nextFaceIndex;
                        currentSegment.AddLast(currentFaceIndex);
                        faceSegmentIndex[currentFaceIndex] = currentSegmentIndex;
                    }
                }

                MeshBoundary meshBoundary = new MeshBoundary()
                {
                    Code = code
                };
                foreach (LinkedList <int> segment in segments)
                {
                    if (segment == null)
                    {
                        continue;
                    }
                    List <MeshFace> segmentFaces = new List <MeshFace>(segment.Count);
                    foreach (int currentFace in segment)
                    {
                        segmentFaces.Add(faces[currentFace]);
                    }
                    meshBoundary.Segments.Add(segmentFaces);
                }

                boundaries.Add(meshBoundary);
            }

            boundaries.Sort((mb1, mb2) => mb1.Code.CompareTo(mb2.Code));
            return(boundaries);
        }
Beispiel #6
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);
        }
Beispiel #7
0
 /// <summary>
 /// Returns true if the face is a boundary face.
 /// </summary>
 public static bool IsBoundaryFace(this MeshFace face)
 {
     return(face.RightElement == null);
 }