/// <summary> /// If a fixed enrichment area is applied, all nodes inside a circle around the tip are enriched with tip /// functions. They can still be enriched with Heaviside functions, if they do not belong to the tip /// element(s). /// </summary> /// <param name="tipNodes"></param> /// <param name="tipElement"></param> private void ApplyFixedEnrichmentArea(CartesianPoint crackTip, XContinuumElement2D tipElement, HashSet <XNode> tipNodes, IEnrichmentItem2D tipEnrichments) { if (enrichmentRadiusOverElementSize > 0) { var outline = ConvexPolygon2D.CreateUnsafe(tipElement.Nodes); double elementArea = outline.ComputeArea(); double radius = enrichmentRadiusOverElementSize * Math.Sqrt(elementArea); var enrichmentArea = new Circle2D(crackTip, radius); foreach (var element in Mesh.FindElementsInsideCircle(enrichmentArea, tipElement)) { bool completelyInside = true; foreach (var node in element.Nodes) { CirclePointPosition position = enrichmentArea.FindRelativePositionOfPoint(node); if ((position == CirclePointPosition.Inside) || (position == CirclePointPosition.On)) { tipNodes.Add(node); } else { completelyInside = false; } } if (completelyInside) { element.EnrichmentItems.Add(tipEnrichments); } } } }
private IReadOnlyDictionary <XContinuumElement2D, double[]> FindJintegralElementsAndNodalWeights( CartesianPoint crackTip, TipCoordinateSystem tipSystem, IReadOnlyList <XContinuumElement2D> tipElements) { Circle2D outerContour = new Circle2D(crackTip, ComputeRadiusOfJintegralOuterContour(tipSystem, tipElements)); IReadOnlyList <XContinuumElement2D> intersectedElements = mesh.FindElementsIntersectedByCircle(outerContour, tipElements[0]); var elementsAndWeights = new Dictionary <XContinuumElement2D, double[]>(); foreach (var element in intersectedElements) { // The relative position of the circle and the nodes was already calculated when checking the // circle-element intersection, but that method should be decoupled from assigning the nodal // weights, even at the cost of some duplicate operations. What could be done more efficiently is // caching the nodes and weights already processed by previous elements, but even then the cost of // processing each node will be increased by the lookup. double[] nodalWeights = new double[element.Nodes.Count]; for (int nodeIdx = 0; nodeIdx < element.Nodes.Count; ++nodeIdx) { CirclePointPosition pos = outerContour.FindRelativePositionOfPoint((CartesianPoint)element.Nodes[nodeIdx]); if (pos == CirclePointPosition.Outside) { nodalWeights[nodeIdx] = 0.0; } else // Node lies inside or exactly on the circle { nodalWeights[nodeIdx] = 1.0; } } elementsAndWeights.Add(element, nodalWeights); } return(elementsAndWeights); }
/// <summary> /// Shortcut method to avoid redundant checks /// </summary> /// <param name="circle"></param> /// <returns></returns> public bool IntersectsWithCircle(Circle2D circle) { int verticesOutsideCircle = 0; int verticesInsideCircle = 0; foreach (CartesianPoint vertex in Vertices) { CirclePointPosition vertexPosition = circle.FindRelativePositionOfPoint(vertex); if (vertexPosition == CirclePointPosition.Outside) { ++verticesOutsideCircle; } else if (vertexPosition == CirclePointPosition.Inside) { ++verticesInsideCircle; } } int verticesOnCircle = Vertices.Count - verticesOutsideCircle - verticesInsideCircle; if (verticesOutsideCircle >= 1) { if ((verticesInsideCircle >= 1) || (verticesOnCircle >= 2)) { return(true); } } return(false); }
public IReadOnlyList <TNode> FindNodesInsideCircle(Circle2D circle, bool findBoundaryNodes = true, TElement startingElement = null) { var selectedNodes = new List <TNode>(); foreach (TNode node in Nodes) // O(nodesCount) { CirclePointPosition relativePosition = circle.FindRelativePositionOfPoint(new CartesianPoint(node.X, node.Y)); if ((relativePosition == CirclePointPosition.Inside) || (findBoundaryNodes && (relativePosition == CirclePointPosition.On))) { selectedNodes.Add(node); } } return(selectedNodes); }
public CirclePolygonPosition FindRelativePositionOfCircle(Circle2D circle) { int verticesOutsideCircle = 0; int verticesInsideCircle = 0; foreach (CartesianPoint vertex in Vertices) { CirclePointPosition vertexPosition = circle.FindRelativePositionOfPoint(vertex); if (vertexPosition == CirclePointPosition.Outside) { ++verticesOutsideCircle; } else if (vertexPosition == CirclePointPosition.Inside) { ++verticesInsideCircle; } } int verticesOnCircle = Vertices.Count - verticesOutsideCircle - verticesInsideCircle; if (verticesOutsideCircle == Vertices.Count) { if (IsPointInsidePolygon(circle.Center)) { return(CirclePolygonPosition.CircleInsidePolygon); } else { return(CirclePolygonPosition.Disjoint); } } else if (verticesOutsideCircle == 0) { return(CirclePolygonPosition.PolygonInsideCircle); } else if ((verticesOnCircle == 1) && (verticesInsideCircle == 0)) { return(CirclePolygonPosition.Disjoint); } else { return(CirclePolygonPosition.Intersecting); } }
/// <summary> /// If a fixed enrichment area is applied, all nodes inside a circle around the tip are enriched with tip /// functions. They can still be enriched with Heaviside functions, if they do not belong to the tip /// element(s). /// </summary> /// <param name="tipElement"></param> private void ApplyFixedEnrichmentArea(XContinuumElement2D tipElement) { if (tipEnrichmentAreaRadius > 0) { var enrichmentArea = new Circle2D(crackTip, tipEnrichmentAreaRadius); foreach (var element in Mesh.FindElementsInsideCircle(enrichmentArea, tipElement)) { bool completelyInside = true; foreach (var node in element.Nodes) { CirclePointPosition position = enrichmentArea.FindRelativePositionOfPoint(node); if ((position == CirclePointPosition.Inside) || (position == CirclePointPosition.On)) { crackTipNodesNew.Add(node); } else { completelyInside = false; } } //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. if (completelyInside) { element.EnrichmentItems.Add(CrackTipEnrichments); } } #region alternatively /* // If there wasn't a need to enrich the elements, this is more performant * foreach (var node in mesh.FindNodesInsideCircle(enrichmentArea, true, tipElement)) * { * tipNodes.Add(node); // Nodes of tip element(s) will not be included twice * } */ #endregion } }
/// <summary> /// If a fixed enrichment area is applied, all nodes inside a circle around the tip are enriched with tip /// functions. They can still be enriched with Heaviside functions, if they do not belong to the tip /// element(s). /// </summary> /// <param name="tipNodes"></param> /// <param name="tipElement"></param> private void ApplyFixedEnrichmentArea(HashSet <XNode> tipNodes, XContinuumElement2D tipElement) { if (tipEnrichmentAreaRadius > 0) { var enrichmentArea = new Circle2D(crackTip, tipEnrichmentAreaRadius); foreach (var element in Mesh.FindElementsInsideCircle(enrichmentArea, tipElement)) { bool completelyInside = true; foreach (var node in element.Nodes) { CirclePointPosition position = enrichmentArea.FindRelativePositionOfPoint(node); if ((position == CirclePointPosition.Inside) || (position == CirclePointPosition.On)) { tipNodes.Add(node); } else { completelyInside = false; } } if (completelyInside) { element.EnrichmentItems.Add(CrackTipEnrichments); } } #region alternatively /* // If there wasn't a need to enrich the elements, this is more performant * foreach (var node in mesh.FindNodesInsideCircle(enrichmentArea, true, tipElement)) * { * tipNodes.Add(node); // Nodes of tip element(s) will not be included twice * } */ #endregion } }