Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mesh refinement around line segment and points #48

Open
mustbau opened this issue Aug 19, 2024 · 9 comments
Open

Mesh refinement around line segment and points #48

mustbau opened this issue Aug 19, 2024 · 9 comments

Comments

@mustbau
Copy link

mustbau commented Aug 19, 2024

Hi,
i am struggling to achieve mesh refinement around a line segment and around some points inside a polygon. i used this code below to define the geometry for the PSLG for meshing, i have a n Ellipse and a line segment inside the Polygon and some points. i want to refine the mesh around all of them, here is my code:

`
var p = new TriangleNet.Geometry.Polygon();

        //first add the outer boundry points (taken from the modellines) to the polygon p
        p.Add(new Contour(boundary.Select(px => new Vertex(px.X, px.Y, 1)), 1));

        //Add borehole points
       p.Points.AddRange(boreholepts.Select(qy => new Vertex(qy.X, qy.Y, 1)));

        // Add ellipse segments to the main geometry PSLG
        List<XYZ> ellipse = AddEllipse(boreholepts[4], 1, 1);
        p.Add(new Contour(ellipse.Select(px => new Vertex(px.X, px.Y, 1)), 1));


        // Add line segment, where mesh is to be refined to the main geometry PSLG
        List<XYZ> linesegment = new List<XYZ> { boreholepts[0], boreholepts[1] };
        p.Add(new Contour(linesegment.Select(px => new Vertex(px.X, px.Y, 1)), 1));
        p.Regions.Add(new RegionPointer(linesegment[0].X, linesegment[0].Y, 11, 0.5));

       

        // Define regions in polygon where mesh must be refined.
        for (int i =0;i<boreholepts.Count;i++) 
        {
            //Add refinement region for each borehole point
            p.Regions.Add(new RegionPointer(boreholepts[i].X, boreholepts[i].Y,i,0.5)) ;
        }
       

        var options = new ConstraintOptions() { ConformingDelaunay = true };

        var triQuality = new QualityOptions()
        {
            MinimumAngle = 30,
           
            MaximumArea = MaxArea
        };

        // The aCute refinement algorithm might fail when used with variable
        // area constraints, so we use Ruppert's refinement algorithm here.
        triQuality.UseLegacyRefinement = true;


        //var mesh = p.Triangulate(new ConstraintOptions() { Convex = true });
        var mesh = p.Triangulate(options, triQuality);//,triQuality`

the mesh does refine around the ellipse but not around the borehole points and the line segment. Any idea whats missing in the geometry description. Thanks in Advance.

@mustbau mustbau changed the title Mesh refinement around line segment Mesh refinement around line segment and points Aug 19, 2024
@wo80
Copy link
Owner

wo80 commented Aug 19, 2024

I'm afraid there is no easy way to directly refine a mesh around points or a line. Region pointers are exactly what the name says: a pointer to a region which is enclosed by a contour (i.e. a region has an area > 0). A simple point doesn't fit into that category, neither does a line.

A possible solution might be to post-process the mesh, setting the triangle area for all triangles connected to the borehole points (using the VertexCirculator class) and then refining with triQuality.VariableArea = true.

@wo80
Copy link
Owner

wo80 commented Aug 19, 2024

Here's an example:

using System.Collections.Generic;
using TriangleNet;
using TriangleNet.Geometry;
using TriangleNet.Meshing;
using TriangleNet.Meshing.Iterators;

public class Issue48
{
    public static void Test()
    {
        var poly = new Polygon(6);

        // Outer contour
        poly.Add(new Contour([
            new Vertex(0.0, 0.0, 1),
            new Vertex(1.0, 0.0, 1),
            new Vertex(1.0, 1.0, 1),
            new Vertex(0.0, 1.0, 1)],
        1, true));

        var boreholepoints = new List<Vertex>()
        {
            new Vertex(0.4, 0.4, 2),
            new Vertex(0.9, 0.9, 2)
        };

        poly.Points.AddRange(boreholepoints);

        var options = new QualityOptions()
        {
            MinimumAngle = 30,
            MaximumArea = 0.05
        };

        var m = poly.Triangulate(options);

        var c = new VertexCirculator((Mesh)m);

        // Set area constraint around borehole points
        foreach (var p in boreholepoints)
        {
            foreach (var tri in c.EnumerateTriangles(p))
            {
                tri.Area = 0.002;
            }
        }

        options.VariableArea = true;

        m.Refine(options, true);
    }
}

mesh-1

@wo80
Copy link
Owner

wo80 commented Aug 20, 2024

Another option: add extra points around borehole points before triangulation. Of course you must make sure that those extra points do not introduce any unwanted features. Additionally, you could subdivide the line segments before triangulation.

Example:

public static void Test()
{
    var poly = new Polygon(6);

    // Outer contour
    poly.Add(new Contour([
        new Vertex(0.0, 0.0, 1),
        new Vertex(1.0, 0.0, 1),
        new Vertex(1.0, 1.0, 1),
        new Vertex(0.0, 1.0, 1)],
    1, true));

    var boreholepoints = new List<Vertex>()
    {
        new Vertex(0.4, 0.4, 2),
        new Vertex(0.9, 0.9, 2)
    };

    poly.Points.AddRange(boreholepoints);

    var options = new QualityOptions()
    {
        MinimumAngle = 30,
        MaximumArea = 0.05
    };

    // Add extra points in vicinity of borehole points
    foreach (var p in boreholepoints)
    {
        // Using negative of original label to identify extra points.
        poly.Points.AddRange(Circle(6, p, 0.01, -p.Label));
    }

    var m = poly.Triangulate(options);
}

static IEnumerable<Vertex> Circle(int n, Vertex center, double radius, int label = 0)
{
    double x = center.X;
    double y = center.Y;

    double dphi = 2 * Math.PI / n;

    for (int i = 0; i < n; i++)
    {
        yield return new Vertex(x + radius * Math.Cos(i * dphi), y + radius * Math.Sin(i * dphi), label);
    }
}

mesh-0

@mustbau
Copy link
Author

mustbau commented Aug 20, 2024

Hi Christian,
Thanks for the examples, i found the first example to be suitable, i have tried the 2nd example before. it works when i add an ellipse or circle beforehand, but the refinement is only bound inside/adjecent to the ellipse/circle contours.

I would like to continue with the post refinement technique in your first example. i tried it but somehow
the function "c.EnumerateTriangles(pt) " throws null exception. Although the mesh is full of triangles.

here the full post refinement code:

`
var mesh = p.Triangulate(options, triQuality);//,triQuality
TriangleNet.Mesh m = (TriangleNet.Mesh)mesh;
var c = new TriangleNet.Meshing.Iterators.VertexCirculator(m);

        // Set area constraint around borehole points
        int indexer = 0;
        foreach (var pt in boreholepts)
        {
            var vert = new Vertex(pt.X, pt.Y, indexer);

            foreach (var tri in c.EnumerateTriangles(vert))
            {
                tri.Area = 0.5;
            }
            indexer++;  
        }

        triQuality.VariableArea = true;

        mesh.Refine(triQuality, true);`

@wo80
Copy link
Owner

wo80 commented Aug 20, 2024

Are there by any chance duplicate vertices in your input? Please check with PolygonValidator and also take a look at the log.

@mustbau
Copy link
Author

mustbau commented Aug 20, 2024

hi, thanks for fast reply.
No, i tested it with a single internal point, still throwing: System.NullReferenceException: “The object reference was not set to an object instance.", ill try to check with Validator.

@wo80
Copy link
Owner

wo80 commented Aug 20, 2024

That's strange. Can you post the full stack trace and maybe a small, but complete (code and input data) test case that reproduces the error?

@wo80
Copy link
Owner

wo80 commented Aug 20, 2024

Ok, I see the problem. Take a look at the VertexCirculator. It relies on the internal Vertex.tri. This means you cannot do

var vert = new Vertex(pt.X, pt.Y, indexer);
foreach (var tri in c.EnumerateTriangles(vert))
    //...

since that newly created vertex won't have the tri field set (that's an implementation detail of the mesh topology you don't have access to).

To make this work with your original code example, you have to have access to the borehole vertices:

//Add borehole points
var boreholevertices = boreholepts.Select(qy => new Vertex(qy.X, qy.Y, 1));
p.Points.AddRange(boreholevertices);
//...
foreach (var p in boreholevertices)
{
    foreach (var tri in c.EnumerateTriangles(p))
    //...

@mustbau
Copy link
Author

mustbau commented Aug 20, 2024

Hi, i now tried to use the older vertices which were added to the polygon itself for post refinement, but i get the same System.NullReferenceException: “The object reference was not set to an object instance.",

Here the new try code (ill add the data together with error log after another try at it. ill try to use some other points first):
`
var p = new TriangleNet.Geometry.Polygon();

        //creat vertices from boreholpts
        var bvert = new List<Vertex>();

        foreach (XYZ pt in boreholepts) 
        {
            Vertex vert = new Vertex(pt.X, pt.Y, 1);
            bvert.Add(vert);
        }

        //first add the outer boundry points (taken from the modellines) to the polygon p
        p.Add(new Contour(boundary.Select(px => new Vertex(px.X, px.Y, 1)), 1));
      
        // now add internal vertices 
        p.Points.AddRange(bvert);

        var options = new ConstraintOptions() { ConformingDelaunay = true };

        var triQuality = new QualityOptions()
        {
            MinimumAngle = 30,
            //VariableArea = true,
            MaximumArea = MaxArea
        };
        
        var mesh = p.Triangulate(options, triQuality);//,triQuality
        TriangleNet.Mesh m = (TriangleNet.Mesh)mesh;
        var c = new TriangleNet.Meshing.Iterators.VertexCirculator(m);
       

        // Set area constraint around borehole points
        
        foreach (var pt in bvert)
        {
          

            foreach (var tri in c.EnumerateTriangles(pt))
            {
                tri.Area = 0.5;
            }
             
        }

        triQuality.VariableArea = true;

        mesh.Refine(triQuality, true);

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants