Advertisement
Fangz17

129H - vectris.py

Jul 18th, 2013
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.32 KB | None | 0 0
  1. import math
  2.  
  3. def product(m0, m1):
  4.     'Multiplying matrices (in columns)'
  5.    
  6.     m0 = [[v[i] for v in m0] for i in range(len(m0))]
  7.     return [[dot(x,y) for x in m0] for y in m1]    
  8.  
  9. def det(m):
  10.     'Determinant of matrix m'
  11.    
  12.     if len(m) == 2:
  13.         return m[0][0]*m[1][1] - m[0][1]*m[1][0]
  14.     elif len(m) == 3:
  15.         return sum([(m[0][i]*m[1][(i+1)%3]*m[2][(i+2)%3]) -
  16.                     (m[0][i]*m[2][(i+1)%3]*m[1][(i+2)%3]) for i in range(3)])
  17.  
  18. def inverse(m):
  19.     'Inverse of matrix m, described in column vectors'
  20.    
  21.     d = det(m)
  22.     if len(m) == 2:
  23.         n = [[m[1][1]/d, -m[0][1]/d], [-m[1][0]/d, m[0][0]/d]]
  24.     elif len(m) == 3:
  25.         n = []
  26.         for i in range(3):
  27.             j = [0,1,2]
  28.             j = j[:i] + j[i+1:]
  29.             n.append([(-1)**i*x/d for x in cross(m[j[0]], m[j[1]])])
  30.     return n
  31.  
  32. def length(v):
  33.     'Length of vector'
  34.    
  35.     return sum([i**2 for i in v])**0.5
  36.    
  37. def dot(v0, v1):
  38.     'Dot product of two vectors'
  39.    
  40.     return sum([v0[i]*v1[i] for i in range(3)])
  41.  
  42. def angle(v0, v1):
  43.     'Angle between two vectors'
  44.    
  45.     return math.acos(dot(v0,v1)/(length(v0)*length(v1)))*180/math.pi
  46.  
  47. def cross(v0, v1):
  48.     'Cross product of two vectors'
  49.    
  50.     return [(-1)**i * det([v0[0:i]+v0[i+1:4], v1[0:i]+v1[i+1:4]]) for i in range(3)]
  51.  
  52. def plane_eq(*args):
  53.     'Calculates the equation of the plane with the three points in it'
  54.    
  55.     if len(args) == 1:
  56.         p0, p1, p2 = args[0]
  57.     else:
  58.         p0, p1, p2 = args
  59.     v0 = [p1[i]-p0[i] for i in range(3)]
  60.     v1 = [p2[i]-p1[i] for i in range(3)]
  61.    
  62.     normal = cross(v0, v1)
  63.     if normal[0] == 0:
  64.         if normal[1] == 0:
  65.             normal = [0.0,0.0,1.0]
  66.         else:
  67.             normal = [i/normal[1] for i in normal]
  68.     else:
  69.         normal = [i/normal[0] for i in normal]  
  70.     return [normal, dot(p0, normal)]
  71.  
  72. def solve(v0, v1, t):
  73.     'Calculates two variables s&t such that r*v0+s*v1=t'
  74.    
  75.     x = 0
  76.     while True:
  77.         y = [0,1,2]
  78.         y = y[:x]+y[x+1:]
  79.         m, n = y
  80.         if v0[n]*v1[m]-v0[m]*v1[n] != 0:
  81.             break
  82.         else:
  83.             x += 1            
  84.     r = (t[n]*v1[m]-t[m]*v1[n])/(v0[n]*v1[m]-v0[m]*v1[n])
  85.     s = (t[n]*v0[m]-t[m]*v0[n])/(v0[n]*v1[m]-v0[m]*v1[n])
  86.     return r, s
  87.  
  88. def intersect_lines(l0, l1):
  89.     'Calculates whether two lines intersect'
  90.    
  91.     plane = plane_eq(l0[0], l0[1], [l0[0][i]+l1[0][i]-l1[1][i] for i in range(3)])
  92.     if dot(plane[0], l0[0]) == plane[1]:
  93.         a = [l0[1][i]-l0[0][i] for i in range(3)]
  94.         b = [l1[0][i]-l1[1][i] for i in range(3)]
  95.         c = [l1[0][i]-l0[0][i] for i in range(3)]
  96.         r, s = solve(a, b, c)
  97.         if r < 1 and s < 1:
  98.             return True
  99.     return False
  100.  
  101. def intersect_tris(t0, t1):
  102.     'Caluculates whether two triangles intersect'
  103.    
  104.     p0 = plane_eq(t0)
  105.     p1 = plane_eq(t1)
  106.     if p0 == p1:
  107.         # If the planes are the same
  108.         a = [t0[1][i]-t0[0][i] for i in range(3)]
  109.         b = [t0[2][i]-t0[1][i] for i in range(3)]
  110.         for p in t1:
  111.             r, s = solve(a, b, p)
  112.             if r < 1 and s < r:
  113.                 return True            
  114.         a = [t1[1][i]-t1[0][i] for i in range(3)]
  115.         b = [t1[2][i]-t1[1][i] for i in range(3)]
  116.         for p in t0:
  117.             r, s = solve(a, b, p)
  118.             if r < 1 and s < r:
  119.                 return True
  120.            
  121.         for p in t0:
  122.             if p in t1:
  123.                 return False
  124.        
  125.         l0 = t0[0:2]
  126.         if intersect_lines(l0, t1[0:2]) or intersect_lines(l0, t1[1:3]):
  127.             return True      
  128.     elif p0[0] == p1[0]:
  129.         # If the normals are the same but the distances aren't
  130.         # they are parallel and don't intersect
  131.         return False
  132.     else:
  133.         # If they are not parallel
  134.         # If a point is shared, then they do not intersect
  135.         for p in t0:
  136.             if p in t1:
  137.                 return False
  138.         # Now we look at the dot products of the normal of the second plane with each point in the first
  139.         # Since it changes linearly from point to point
  140.         # If it goes from below the distance of the second plane to above
  141.         # Then it intersects within the triangle
  142.         vals0 = [dot(p, p1[0]) for p in t0]
  143.         vals1 = [dot(p, p0[0]) for p in t1]
  144.        
  145.         below = [False, False]
  146.         above = [False, False]
  147.         for v in vals0:
  148.             if v < p1[1]:
  149.                 below[0] = True
  150.             elif v > p1[1]:
  151.                 above[0] = True
  152.         for v in vals1:
  153.             if v < p0[1]:
  154.                 below[1] = True
  155.             elif v > p0[1]:
  156.                 above[0] = True
  157.  
  158.         for i in below + above:
  159.             if not i:
  160.                 return False
  161.         else:
  162.             return True
  163.  
  164. def construct(p, v, tris):
  165.     'For every tri, calculates the normal and which other tris it intersects with'
  166.    
  167.     tris2 = {}
  168.     for t in tris:
  169.         tri = (p[t[0]], p[t[1]], p[t[2]])
  170.         v0 = [tri[1][i]-tri[0][i] for i in range(3)]
  171.         v1 = [tri[2][i]-tri[1][i] for i in range(3)]
  172.         normal = cross(v0, v1)
  173.         if angle(v, normal) > 90:
  174.             normal = [-i for i in normal]
  175.         intersecting = []
  176.  
  177.         for t2 in tris2:
  178.             if intersect_tris([p[i] for i in t2], tri):
  179.                 intersecting.append(t2)
  180.                 tris2[t2][1].append(t)
  181.  
  182.         tris2[t] = [normal, intersecting]
  183.     return tris2
  184.  
  185. def find_sets(p,v):
  186.     'Calculates the possible sets that can be formed in p'
  187.    
  188.     n = len(p)
  189.     tris = []
  190.     for i in range(n):
  191.         for j in range(i+1, n):
  192.             for k in range(j+1, n):
  193.                 tris.append((i,j,k))
  194.     tris2 = construct(p, v, tris)
  195.  
  196.     sets = []
  197.     size = 0
  198.     possible_sets = []
  199.     closest = 90
  200.     closest_sets = []
  201.  
  202.     # We work through each tri
  203.     # Seeing which sets it can be added to without intersecting any other tris
  204.     for t in tris:
  205.         new_sets = []
  206.         for j in range(len(sets)):
  207.             for k in sets[j]:
  208.                 if k in tris2[t][1]:
  209.                     break
  210.             else:
  211.                 sets[j] = sets[j] + [t]
  212.                 new_sets.append(sets[j])
  213.         sets.append([t])
  214.         new_sets.append([t])
  215.  
  216.         for s in new_sets:
  217.             # Now we calculate the average normal and see what angle it forms with the target vector
  218.             norms = [tris2[i][0] for i in s]
  219.             average = [sum([norms[n][j] for n in range(len(s))]) for j in range(3)]
  220.             a = angle(average, v)
  221.             if a > 170:
  222.                 a = 180 - a
  223.             if a < 10:
  224.                 l = len(s)
  225.                 if l > size:
  226.                     size = l
  227.                     possible_sets = [s]
  228.                 elif l == size:
  229.                     possible_sets.append(s)
  230.  
  231.                 if a < closest:
  232.                     closest = a
  233.                     closest_sets = [s]
  234.                 elif a == closest:
  235.                     if l > len(closest_sets[0]):
  236.                         closest_sets = [s]
  237.                     elif l == len(closest_sets[0]):
  238.                         closest_sets.append(s)
  239.                 break
  240.  
  241.     return size, possible_sets, closest, closest_sets
  242.                
  243. def main():
  244.     raw = open('129H.txt').read().split('\n')
  245.     points = [[float(i) for i in line.split()] for line in raw[1:-1]]
  246.     vector = [float(i) for i in raw[-1].split()]
  247.  
  248.     size, possible_sets, closest, closest_sets = find_sets(points, vector)
  249.  
  250.     if possible_sets:
  251.         print("Largest sized set:", size)
  252.         print("Possible sets:", len(possible_sets))
  253.  
  254.         for s in possible_sets:
  255.             print()
  256.             for t in s:
  257.                 print(t, end = ': ')
  258.                 for p in t:
  259.                     print(tuple(points[p]), end = ' ')
  260.                 print()
  261.                
  262.     if closest_sets:
  263.         print()
  264.         print("Closest set: {0:}°".format(closest))
  265.         print("Possible sets:", len(closest_sets))
  266.  
  267.         for s in closest_sets:
  268.             print()
  269.             for t in s:
  270.                 print(t, end = ': ')
  271.                 for p in t:
  272.                     print(tuple(points[p]), end = ' ')
  273.                 print()
  274.     else:
  275.         print("No valid result found")
  276.  
  277. if __name__ == '__main__':
  278.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement