0

I have a set of objects (triangles) in the 2D-Plane and I want to separate them by a line into two sets of about the same size.

Perfect separation line

Because normally the line will intersect with some triangles, I get three sets. One on the left side, one on the right side and one with collisions with the line.

I now want to find a good line. I figured out a cost function:

cost=-min(len(set_left), len(set_right))

Unfortunately, I can't think of a nice algorithm to solve this. I have written a python exaple to show my problem: (I use the real part for x and the imaginary part for the y coordinate)

import scipy.optimize
import numpy as np

def scalar_prod (v1, v2):
    return v1.real*v2.real + v1.imag*v2.imag

def intersect_line_triangle (line, triangle):
    point = line[0]
    dir_ = line[1]
    # calculate normal vector
    n_vec = 1j * dir_
    # Calculate signed distance of each point
    dist = tuple(scalar_prod(n_vec, p-point) for p in triangle)
    if all(d > 0 for d in dist):
        return 1 # right
    if all(d < 0 for d in dist):
        return -1 # left
    return 0 # intersecting

def split_triangles_by_line (triangles, line):
    out = {-1: [], 0:[], 1:[]}
    for tri in triangles:
        out[intersect_line_triangle(line,tri)].append(tri)
    return out

def calc_cost (triangles, line):
    split = split_triangles_by_line(triangles, line)
    cost = -(min(len(split[-1]), len(split[1])))
    return cost

def calc_line (triangles, method='Powell'):
    # TODO: think about a good algorithm!
    center_point = sum(sum(tri) for tri in triangles) / (len(triangles)*3)
    init_point = center_point
    fun = lambda args: calc_cost(triangles, (args[0] + 1j* args[1], np.exp(1j*args[2])))
    res = scipy.optimize.minimize(fun,  [init_point.real, init_point.imag, np.pi/2], method=method)
    res_line = (res.x[0]+ 1j*res.x[1], np.exp(1j*res.x[2]))
    return res_line

triangles = [(0, 3j, 2), (4, 2+2j, 6+2j),
        (4j, 3+4j, 3+7j), (4+3j, 5+3j, 4+10j),
        (-1+5j, -1+8j, 3+9j)]
line = calc_line(triangles)
sep_triangles = split_triangles_by_line(triangles, line)
print("The resulting line is {} + {} * t".format(line[0], line[1]))
print("The triangles are separated:\nleft: {}\nright: {}\nintersected: {}".format(sep_triangles[-1], sep_triangles[1], sep_triangles[0]))
print("The cost is {}".format(calc_cost(triangles, line)))

I want to replace the optimizer part by some efficient algorithm. I guess, that computer graphic experts may use similar things.

Thanks in advance!

drahnoel
  • 231
  • 1
  • 5
  • 3
    you could look at all possible pairs of points, and use those to generate all possible lines. – Rusty Rob Mar 21 '18 at 23:48
  • 1
    related to this question: https://stackoverflow.com/questions/49333960/maximum-possible-number-of-rectangles-that-can-be-crossed-with-a-single-straight – Reblochon Masque Mar 22 '18 at 04:39
  • 1
    You may also want to check the various BSP tree construction algorithms, which solve exactly this problem. However, an optimal solution is NP-hard as far as I know. – Nico Schertler Mar 22 '18 at 07:32
  • Looking to the pair of points gives a simple O(n^3) solution: – drahnoel Mar 22 '18 at 08:57

0 Answers0