public SortedSet <CartesianPoint> FindTriangleVertices(XContinuumElement2D element) { var polygon = ConvexPolygon2D.CreateUnsafe(element.Nodes); var triangleVertices = new SortedSet <CartesianPoint>(element.Nodes, pointComparer); int nodesCount = element.Nodes.Count; foreach (var vertex in Vertices) { PolygonPointPosition position = polygon.FindRelativePositionOfPoint(vertex); if (position == PolygonPointPosition.Inside || position == PolygonPointPosition.OnEdge || position == PolygonPointPosition.OnVertex) { triangleVertices.Add(vertex); } } foreach (var crackSegment in Segments) { var segment = new LineSegment2D(crackSegment.Start, crackSegment.End); IReadOnlyList <CartesianPoint> intersections = segment.IntersectionWith(polygon); foreach (var point in intersections) { triangleVertices.Add(point); } } return(triangleVertices); }
private bool IsCutElement(XContinuumElement2D element) { var polygon = ConvexPolygon2D.CreateUnsafe(element.Nodes); // Look at each segment foreach (var crackSegment in Segments) { var segment = new LineSegment2D(crackSegment.Start, crackSegment.End); CartesianPoint intersectionPoint; foreach (var edge in polygon.Edges) { LineSegment2D.SegmentSegmentPosition position = segment.IntersectionWith(edge, out intersectionPoint); if (position == LineSegment2D.SegmentSegmentPosition.Intersecting) { // TODO: Perhaps the element should not be flagged as a Heaviside element, if the segment passes // through 1 node only. To detect this, check if the intersection point coincides with an element // node. If it does store it and go to the next edge. If a second intersection point (that does // not coincide with the stored one) is found then it is a Heaviside element. return(true); } else if (position == LineSegment2D.SegmentSegmentPosition.Overlapping) { return(true); } } } // Look at the vertices // (if a segment is entirely inside an element, it will not be caught by checking the segment itself) bool previousVertexOnEdge = false; LinkedListNode <CartesianPoint> currentNode = Vertices.First.Next; LinkedListNode <CartesianPoint> lastNode = Vertices.Last; while (currentNode != lastNode) { PolygonPointPosition position = polygon.FindRelativePositionOfPoint(currentNode.Value); if (position == PolygonPointPosition.Inside) { return(true); } else if (position == PolygonPointPosition.OnEdge || position == PolygonPointPosition.OnVertex) { if (previousVertexOnEdge) { return(true); } else { previousVertexOnEdge = true; } } else { previousVertexOnEdge = false; } currentNode = currentNode.Next; } return(false); }
/// <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); } } } }
public List <XContinuumElement2D> FindElementsThatContains(IEnumerable <XContinuumElement2D> elements, CartesianPoint point) { var result = new List <XContinuumElement2D>(); foreach (var element in elements) { var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes); PolygonPointPosition position = outline.FindRelativePositionOfPoint(point); if (position == PolygonPointPosition.Inside) { result.Add(element); break; } else if ((position == PolygonPointPosition.OnEdge) || (position == PolygonPointPosition.OnVertex)) { result.Add(element); } } if (result.Count == 0) { throw new KeyNotFoundException("No element containing the point " + point + "was found"); } return(result); }
public IReadOnlyList <GaussPoint> GenerateIntegrationPoints(XContinuumElement2D element) { SortedSet <CartesianPoint> cartesianDelaunyPoints = crack.FindTriangleVertices(element); IReadOnlyList <NaturalPoint> naturalDelaunyPoints = FindNaturalPointsForTriangulation(element, cartesianDelaunyPoints); IReadOnlyList <Triangle2D <NaturalPoint> > subtriangles; if (double.IsPositiveInfinity(triangleOverElementArea)) { subtriangles = triangulator.CreateMesh(naturalDelaunyPoints); } else { double elementArea = (ConvexPolygon2D.CreateUnsafe(element.Nodes)).ComputeArea(); subtriangles = triangulator.CreateMesh(naturalDelaunyPoints, triangleOverElementArea * elementArea); } var integrationPoints = new List <GaussPoint>(); foreach (Triangle2D <NaturalPoint> triangle in subtriangles) { integrationPoints.AddRange(GenerateIntegrationPointsOfTriangle(triangle)); } return(integrationPoints); }
/// <summary> /// 生成外轮廓多边形 /// </summary> /// <param name="grid"></param> /// <param name="me"></param> /// <param name="startSearchPoint"></param> /// <param name="limitDistance"></param> /// <param name="isBlockOutPoly">是否为挡格的轮廓多边形,是的时候需要倒序处理</param> /// <returns></returns> private static ContourPoly GeneralOutPoly(RLEGridMap grid, MapElement me, Float2 startSearchPoint, float limitDistance, bool isBlockOutPoly) { ContourPoly poly = new ContourPoly(); List <Double2> points = me.GetContourPoints(grid, startSearchPoint); if (isBlockOutPoly == true) { points.Reverse(); } List <int> listIndex = ConvexPolygon2D.GenerateConvexPolygonIndex(points.ToArray()); List <Double2> polys = new List <Double2>(); for (int i = 0; i < listIndex.Count; i++) { if (i < listIndex.Count - 1) { OptimizationContourConvexLine(listIndex[i], listIndex[i + 1], false, limitDistance, points, ref polys); } else { OptimizationContourConvexLine(listIndex[i], listIndex[0], true, limitDistance, points, ref polys); } } poly.InitData(polys); return(poly); }
public CrackElementPosition FindRelativePositionOf(XContinuumElement2D element) { CartesianPoint crackTip = lsm.GetCrackTip(CrackTipPosition.Single); double minBodyLevelSet = double.MaxValue; double maxBodyLevelSet = double.MinValue; double minTipLevelSet = double.MaxValue; double maxTipLevelSet = double.MinValue; foreach (XNode node in element.Nodes) { double bodyLevelSet = lsm.LevelSetsBody[node]; double tipLevelSet = lsm.LevelSetsTip[node]; if (bodyLevelSet < minBodyLevelSet) { minBodyLevelSet = bodyLevelSet; } if (bodyLevelSet > maxBodyLevelSet) { maxBodyLevelSet = bodyLevelSet; } if (tipLevelSet < minTipLevelSet) { minTipLevelSet = tipLevelSet; } if (tipLevelSet > maxTipLevelSet) { maxTipLevelSet = tipLevelSet; } } //Warning: this might actually be worse than Stolarska's criterion. At least that one enriched the dubious //intersected elements with tip enrichments. This one just ignores them. if (minBodyLevelSet * maxBodyLevelSet <= 0.0) { if (minTipLevelSet * maxTipLevelSet <= 0) { var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes); if (outline.IsPointInsidePolygon(crackTip)) { return(CrackElementPosition.ContainsTip); } } else if (maxTipLevelSet < 0) { return(CrackElementPosition.Intersected); } } return(CrackElementPosition.Irrelevant); }
public IReadOnlyList <TElement> FindElementsIntersectedByCircle(Circle2D circle, TElement startingElement = null) { var intersectedElements = new List <TElement>(); foreach (TElement element in Elements) { var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes.ToCartesianPoints()); CirclePolygonPosition relativePosition = outline.FindRelativePositionOfCircle(circle); if (relativePosition == CirclePolygonPosition.Intersecting) { intersectedElements.Add(element); } } return(intersectedElements); }
// TODO: handle cases where more the point lies on an element edge or node. public IReadOnlyList <TElement> FindElementsContainingPoint(CartesianPoint point, TElement startingElement = null) { var containingElements = new List <TElement>(); foreach (TElement element in Elements) // O(elementsCount) { var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes.ToCartesianPoints()); PolygonPointPosition pos = outline.FindRelativePositionOfPoint(point); if ((pos == PolygonPointPosition.Inside) || (pos == PolygonPointPosition.OnEdge) || (pos == PolygonPointPosition.OnVertex)) { containingElements.Add(element); } } return(containingElements); }
// TODO: This method should directly return the elements and take care of cases near the domain boundaries (see Ahmed) // TODO: The J-integral radius should not exceed the last crack segment's length public double ComputeRadiusOfJintegralOuterContour(TipCoordinateSystem tipSystem, IReadOnlyList <XContinuumElement2D> tipElements) { double maxTipElementArea = -1.0; foreach (var element in tipElements) { var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes.Select(node => (CartesianPoint)node).ToArray()); double elementArea = outline.ComputeArea(); if (elementArea > maxTipElementArea) { maxTipElementArea = elementArea; } } return(magnificationOfJintegralRadius * Math.Sqrt(maxTipElementArea)); }
//TODO: replace this with the Faster~() version public CrackElementPosition FindRelativePositionOf(XContinuumElement2D element) { CartesianPoint crackTip = lsm.GetCrackTip(CrackTipPosition.Single); double minBodyLevelSet = double.MaxValue; double maxBodyLevelSet = double.MinValue; double minTipLevelSet = double.MaxValue; double maxTipLevelSet = double.MinValue; foreach (XNode node in element.Nodes) { double bodyLevelSet = lsm.LevelSetsBody[node]; double tipLevelSet = lsm.LevelSetsTip[node]; if (bodyLevelSet < minBodyLevelSet) { minBodyLevelSet = bodyLevelSet; } if (bodyLevelSet > maxBodyLevelSet) { maxBodyLevelSet = bodyLevelSet; } if (tipLevelSet < minTipLevelSet) { minTipLevelSet = tipLevelSet; } if (tipLevelSet > maxTipLevelSet) { maxTipLevelSet = tipLevelSet; } } // Warning: This criterion might give false positives for tip elements (see Serafeim's thesis for details) if (minBodyLevelSet * maxBodyLevelSet <= 0.0) { var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes); if (outline.IsPointInsidePolygon(crackTip)) { return(CrackElementPosition.ContainsTip); } else if (maxTipLevelSet < 0) { return(CrackElementPosition.Intersected); } } return(CrackElementPosition.Irrelevant); }
private bool IsTipElement(XContinuumElement2D element, CrackTipPosition tipPosition) { CartesianPoint crackTip, adjacentVertex; if (tipPosition == CrackTipPosition.Start) { crackTip = Vertices.First.Value; adjacentVertex = Vertices.First.Next.Value; } else if (tipPosition == CrackTipPosition.End) { crackTip = Vertices.Last.Value; adjacentVertex = Vertices.Last.Previous.Value; } else { throw new ArgumentException("Tip position can be either start or end"); } var polygon = ConvexPolygon2D.CreateUnsafe(element.Nodes); PolygonPointPosition relativeTipPos = polygon.FindRelativePositionOfPoint(crackTip); if (relativeTipPos == PolygonPointPosition.Inside || relativeTipPos == PolygonPointPosition.OnEdge || relativeTipPos == PolygonPointPosition.OnVertex) { PolygonPointPosition previousVertexPos = polygon.FindRelativePositionOfPoint(adjacentVertex); if (previousVertexPos == PolygonPointPosition.Inside) { throw new NotImplementedException("Problem with blending elements, if the tip element is also " + "enriched with Heaviside. What happens after the crack tip? Based on the LSM, the signed " + "distance of the blending element after the crack tip should have a positive and negative " + "region, however that element is not split by the crack and thus should not have " + "discontinuity in the displacement field"); //return ElementEnrichmentType.Both; } return(true); } return(false); }
/// <summary> /// /// </summary> /// <param name="allVertices"></param> /// <param name="boundaryVertices">If the all vertices are boundary, then this list needs to start and end with the same /// vertex.</param> public PolygonalRegion(IReadOnlyList <CartesianPoint> allVertices, HashSet <LineSegment2D> boundaries) { this.polygon = ConvexPolygon2D.CreateUnsafe(allVertices); this.boundaries = boundaries; }
public Polygonal2DBoundary(IReadOnlyList <CartesianPoint> vertices) { polygon = ConvexPolygon2D.CreateUnsafe(vertices); }
private ElementEnrichmentType CharacterizeElementEnrichment(XContinuumElement2D element) { var polygon = ConvexPolygon2D.CreateUnsafe(element.Nodes); int tipIndex = Vertices.Count - 1; // Check tip element PolygonPointPosition tipPosition = polygon.FindRelativePositionOfPoint(Vertices[tipIndex]); if (tipPosition == PolygonPointPosition.Inside || tipPosition == PolygonPointPosition.OnEdge || tipPosition == PolygonPointPosition.OnVertex) { PolygonPointPosition previousVertexPos = polygon.FindRelativePositionOfPoint(Vertices[tipIndex - 1]); if (previousVertexPos == PolygonPointPosition.Inside) { // Problem with blending elements, if the tip element is also enriched with Heaviside. What happens // after the crack tip? Based on the LSM, the signed distance of the blending element after the // crack tip should have a positive and negative region, however that element is not split by the // crack and thus should not have discontinuity in the displacement field. var builder = new StringBuilder(); builder.Append("Crack tip "); builder.Append(Vertices[Vertices.Count - 1].ToString()); builder.Append(" and kink point "); builder.Append(Vertices[Vertices.Count - 2].ToString()); builder.Append(" inside the same element with nodes: "); foreach (var node in element.Nodes) { builder.Append(node.ToString()); builder.Append(' '); } throw new ArgumentException(builder.ToString()); //return ElementEnrichmentType.Both; } else { return(ElementEnrichmentType.Tip); } } // Look at the other vertices // (if a segment is inside an element, it will not be caught by checking the segment itself) bool previousVertexOnEdge = false; for (int v = 0; v < tipIndex; ++v) { PolygonPointPosition position = polygon.FindRelativePositionOfPoint(Vertices[v]); if (position == PolygonPointPosition.Inside) { return(ElementEnrichmentType.Heaviside); } else if (position == PolygonPointPosition.OnEdge || position == PolygonPointPosition.OnVertex) { if (previousVertexOnEdge) { return(ElementEnrichmentType.Heaviside); } else { previousVertexOnEdge = true; } } else { previousVertexOnEdge = false; } } // Look at each segment foreach (var crackSegment in Segments) { var segment = new LineSegment2D(crackSegment.Start, crackSegment.End); CartesianPoint intersectionPoint; foreach (var edge in polygon.Edges) { LineSegment2D.SegmentSegmentPosition position = segment.IntersectionWith(edge, out intersectionPoint); if (position == LineSegment2D.SegmentSegmentPosition.Intersecting) { // TODO: Perhaps the element should not be flagged as a Heaviside element, if the segment passes // through 1 node only. To detect this, check if the intersection point coincides with an element // node. If it does store it and go to the next edge. If a second intersection point (that does // not coincide with the stored one) is found then it is a Heaviside element. return(ElementEnrichmentType.Heaviside); } else if (position == LineSegment2D.SegmentSegmentPosition.Overlapping) { return(ElementEnrichmentType.Heaviside); } } } // Then it must be a standard element return(ElementEnrichmentType.Standard); }