private void FindBodyAndTipNodesAndElements() //TODO: perhaps the singularity resolution should be done inside this method
        {
            foreach (var element in Mesh.Elements)
            {
                //TODO: I tried an alternative approach, ie elements access their enrichments from their nodes.
                //      My original thought that this approach (storing enrichments in elements, unless they are standard /
                //      blending) wouldn't work for blending elements, was incorrect, as elements with 0 enrichments
                //      were then examined and separated into standard / blending.
                element.EnrichmentItems.Clear(); //TODO: not too fond of saving enrichment state in elements. It should be confined in nodes

                CrackElementPosition relativePosition = meshInteraction.FindRelativePositionOf(element);
                if (relativePosition == CrackElementPosition.ContainsTip)
                {
                    tipElements.Add(element);
                    foreach (var node in element.Nodes)
                    {
                        crackTipNodesNew.Add(node);
                    }

                    element.EnrichmentItems.Add(CrackTipEnrichments);
                }
                else if (relativePosition == CrackElementPosition.Intersected)
                {
                    foreach (var node in element.Nodes)
                    {
                        bool isNew = crackBodyNodesAll.Add(node);
                        if (isNew)
                        {
                            crackBodyNodesNew.Add(node);
                        }
                    }

                    // Cut elements next to tip elements will be enriched with both Heaviside and tip functions. If all
                    // nodes were enriched with tip functions, the element would not be enriched with Heaviside, but then it
                    // would be a tip element and not fall under this case.
                    element.EnrichmentItems.Add(CrackBodyEnrichment);
                }
            }
            foreach (var node in crackTipNodesNew) // tip element's nodes are not enriched with Heaviside
            {
                crackBodyNodesAll.Remove(node);
                crackBodyNodesNew.Remove(node);
            }

            ReportTipElements(tipElements);
        }
        public SortedSet <CartesianPoint> FindTriangleVertices(XContinuumElement2D element)
        {
            var triangleVertices = new SortedSet <CartesianPoint>(element.Nodes, pointComparer);
            int nodesCount       = element.Nodes.Count;
            CrackElementPosition relativePosition = meshInteraction.FindRelativePositionOf(element);

            if (relativePosition != CrackElementPosition.Irrelevant)
            {
                // Find the intersections between element edges and the crack. TODO: See Serafeim's Msc Thesis for a correct procedure.
                for (int i = 0; i < nodesCount; ++i)
                {
                    XNode  node1     = element.Nodes[i];
                    XNode  node2     = element.Nodes[(i + 1) % nodesCount];
                    double levelSet1 = levelSetsBody[node1];
                    double levelSet2 = levelSetsBody[node2];

                    if (levelSet1 * levelSet2 < 0.0)
                    {
                        // The intersection point between these nodes can be found using the linear interpolation, see
                        // Sukumar 2001
                        double k = -levelSet1 / (levelSet2 - levelSet1);
                        double x = node1.X + k * (node2.X - node1.X);
                        double y = node1.Y + k * (node2.Y - node1.Y);

                        // TODO: For the tip element one intersection point is on the crack extension and does not
                        // need to be added. It is not wrong though.
                        triangleVertices.Add(new CartesianPoint(x, y));
                    }
                    else if (levelSet1 == 0.0)
                    {
                        triangleVertices.Add(node1);                        // TODO: perhaps some tolerance is needed.
                    }
                    else if (levelSet2 == 0.0)
                    {
                        triangleVertices.Add(node2);
                    }
                }

                if (relativePosition == CrackElementPosition.ContainsTip)
                {
                    triangleVertices.Add(crackTip);
                }
            }
            return(triangleVertices);
        }