79831317

Date: 2025-11-27 04:02:56
Score: 0.5
Natty:
Report link

The answer is rather simple actually; when I was checking for intersections in triangle_triangle_partition, I was not filtering out duplicates. Now that I am, everything works as expected. The corrected function:

--- returns the partitio of the first triangle into three subtriangles, 
--- if it intersects the second, otherwise produces nil
--- @param T1 table<table<number>> the first triangle
--- @param T2 table<table<number>> the second triangle
--- @return table<table<table<number>>,table<table<number>>,table<table<number>>> table of sub triangles
local function triangle_triangle_partition(T1, T2)
    local I = triangle_triangle_intersections(T1, T2)
    if I == nil then return nil end
    if #I == 0 then return nil end
    if #I == 1 then return nil end
    -- if #I ~= 2 then  assert(false, ("I is not 2, it is instead: %f"):format(#I)) end
    
    local IO = I[1]
    local IU = vector_subtraction(I[2], IO)
    local I_basis = {IO[1], IU[1]}
    local T1A = {T1[1], T1[2]}
    local T1AU = vector_subtraction({T1A[2]}, {T1A[1]})
    local T1A_basis = {T1A[1], T1AU[1]}
    local T1B = {T1[2], T1[3]}
    local T1BU = vector_subtraction({T1B[2]}, {T1B[1]})
    local T1B_basis = {T1B[1], T1BU[1]}
    local T1C = {T1[3], T1[1]}
    local T1CU = vector_subtraction({T1C[2]}, {T1C[1]})
    local T1C_basis = {T1C[1], T1CU[1]}
    local T2A = {T2[1], T2[2]}
    local T2AU = vector_subtraction({T2A[2]}, {T2A[1]})
    local T2A_basis = {T2A[1], T2AU[1]}
    local T2B = {T2[2], T2[3]}
    local T2BU = vector_subtraction({T2B[2]}, {T2B[1]})
    local T2B_basis = {T2B[1], T2BU[1]}
    local T2C = {T2[3], T2[1]}
    local T2CU = vector_subtraction({T2C[2]}, {T2C[1]})
    local T2C_basis = {T2C[1], T2CU[1]}

    local points = {}
    local non_intersecting = nil

    local function add_unique(points, pt, eps)
        for _, p in ipairs(points) do
            if distance(p, pt) < eps then
                return false -- Not unique
            end
        end
        table.insert(points, pt)
        return true -- Unique
    end


    -- T1A
    local int1 = line_line_intersection(I_basis, T1A_basis)
    if int1 == nil then 
        int1 = {solution = {}}
    end
    if #int1.solution ~= 0 then 
        local t = int1.solution[1]
        local intersect = vector_addition(IO, scalar_multiplication(t, IU))
        if point_line_segment_intersecting(intersect, T1A) then
            if not add_unique(points, intersect, eps) then
                non_intersecting = "T1A"
            end
        else 
            non_intersecting = "T1A"
        end
    else 
        non_intersecting = "T1A"
    end

    -- T1B
    local int2 = line_line_intersection(I_basis, T1B_basis)
    if int2 == nil then 
        int2 = {solution = {}}
    end
    if #int2.solution ~= 0 then 
        local t = int2.solution[1]
        local intersect = vector_addition(IO, scalar_multiplication(t, IU))
        if point_line_segment_intersecting(intersect, T1B) then
            if not add_unique(points, intersect, eps) then
                non_intersecting = "T1B"
            end
        else 
            non_intersecting = "T1B"
        end
    else 
        non_intersecting = "T1B"
    end

    -- T1C
    local int3 = line_line_intersection(I_basis, T1C_basis)
    if int3 == nil then 
        int3 = {solution = {}}
    end
    if #int3.solution ~= 0 then 
        local t = int3.solution[1]
        local intersect = vector_addition(IO, scalar_multiplication(t, IU))
        if point_line_segment_intersecting(intersect, T1C) then
            if not add_unique(points, intersect, eps) then
                non_intersecting = "T1C"
            end
        else 
            non_intersecting = "T1C"
        end
    else 
        non_intersecting = "T1C"
    end
    if #points ~= 2 then
        -- print("Partition failure: got", #points, "points")
        -- print("Triangle 1:", T1)
        -- print("Triangle 2:", T2)
        -- return nil
    end
    
    local quad = {}
    local tri1
    local A, B = points[1], points[2]
    table.insert(quad, A[1])
    table.insert(quad, B[1])
    if non_intersecting == "T1A" then 
        table.insert(quad, T1A[1])
        table.insert(quad, T1A[2])
        tri1 = {A[1], B[1], T1B[2]}
    elseif non_intersecting == "T1B" then 
        table.insert(quad, T1B[1])
        table.insert(quad, T1B[2])
        tri1 = {A[1], B[1], T1C[2]}
    elseif non_intersecting == "T1C" then
        table.insert(quad, T1C[1])
        table.insert(quad, T1C[2])
        tri1 = {A[1], B[1], T1A[2]}
    end
    
    quad = centroid_sort(quad)
    if distance({quad[1]},{quad[3]}) > distance({quad[2]},{quad[4]}) then
        return {
            tri1 = tri1,
            tri2 = {quad[2], quad[1], quad[4]},
            tri3 = {quad[2], quad[3], quad[4]}
        }
    else
        return {
            tri1 = tri1,
            tri2 = {quad[1], quad[2], quad[3]},
            tri3 = {quad[3], quad[4], quad[1]}
        }
    end
end

output

Reasons:
  • Probably link only (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Jasper