0
\$\begingroup\$

I’ve been working on a GDscript to draw isolines (contours). I’m using the Meandering Triangles algorithm from https://blog.bruce-hill.com/meandering-triangles, and it works pretty well! The problem is I don’t know how to do Step 4, which is where all the little individual lines that make up the contour lines are joined together, so that I have a set of points describing an entire isoline which I can then drop into a Line2D.points.

Bruce wrote his code in Python, which I’ve yet to learn, and I just don’t quite get how the joining works under the hood. That is, I understand the principle—find a segment which touches the current segment, and join them together, then do it again and again—but I don’t understand how the code makes that happen. And thus I haven’t been able figure out how to make it work in GDscript, let alone do so performantly. I feel like I really should do this, as the current implementation, where all the lines are still their own Line2D nodes, creates 3,000-5,000 such nodes. Turning those into, say, a couple dozen Line2Ds really feels like a good idea.

Below is the code the generates the several thousand tiny lines; apologies if I wrote awful code (looking at you, var offset) but I’m only two weeks into GDscript and, as I said, no weeks into Python. cols and rows are defined earlier in the script, and are at present in the 50-100 range. Any help will be greatly appreciated!

func contourDraw(isorange = Vector3(0,0,0), xmin = 0, xmax = cols, ymin = 0, ymax = rows):
    var triangles = []
    for x in range(xmin, xmax - 1):
        for y in range(ymin, ymax - 1):
            triangles.append([Vector2(x,y), Vector2(x+1,y), Vector2(x,y+1)])
            triangles.append([Vector2(x+1,y), Vector2(x,y+1), Vector2(x+1,y+1)])

    var contour_segments = []
    for triangle in triangles:
        for isocheck in range(isorange.x, floor(isorange.y /isorange.z)):
            var isoline = isocheck * isorange.z
            var below = []
            var above = []
            for vertex in triangle:
                if matrix[vertex.x][vertex.y].strength < isoline: below.append(vertex)
                if matrix[vertex.x][vertex.y].strength >= isoline: above.append(vertex)
            if below.size() == 0 or above.size() == 0:
                continue
    
            var minority = above if above.size() < below.size() else below
            var majority = above if above.size() > below.size() else below
        
            var contour_points = []
            var crossed_edges = [[minority[0], majority[0]], [minority[0], majority[1]]]
    
            for triangle_edge in crossed_edges:
                var offset = ( ( isoline - matrix[triangle_edge[1].x][triangle_edge[1].y].strength ) / ( matrix[triangle_edge[0].x][triangle_edge[0].y].strength - matrix[triangle_edge[1].x][triangle_edge[1].y].strength ) )
                var crossing_point = Vector2(
                    (offset * triangle_edge[0][0]) + ((1 - offset) * triangle_edge[1][0]),
                    (offset * triangle_edge[0][1]) + ((1 - offset) * triangle_edge[1][1])
                )
                contour_points.append(crossing_point * grid_space)
            contour_segments.append(contour_points)

    var counter = 0
    for segment in contour_segments:
        var line = Line2D.new()
        line.default_color = Color.from_hsv(0.58,0.5,0.5)
        line.width = 1
        line.antialiased = true
        line.points = segment
        $Contours.add_child(line)
        counter += 1
    print(counter)
    pass
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.