<jupyter_start><jupyter_text><jupyter_code>#!/usr/bin/env python
# coding: utf-8

# # Collision analysis
import pandas as pd
import numpy as np
import itertools
import numba
from numba import vectorize
import os
import time
from numba import cuda
import multiprocessing as mp
from multiprocessing import Pool
from functools import partial
from numpy.lib import recfunctions as rfn
os.environ["OMP_NUM_THREADS"] = "10"
os.environ["OPENBLAS_MAIN_FREE"] = "10"

os.environ['NUMBAPRO_LIBDEVICE'] = "/usr/local/cuda-10.0/nvvm/libdevice"
os.environ['NUMBAPRO_NVVM'] = "/usr/local/cuda-10.0/nvvm/lib64/libnvvm.so"<jupyter_output><empty_output><jupyter_text>Main run:Remember to upload the files<jupyter_code># Loger for python console 

def log(message):
	print('{} , {}'.format(time.time(), message))

@numba.jit(forceobj=True, parallel=True, nopython=True )
def FilterByBBX(Faces, line):
	maxX = line[0]
	maxY = line[1]
	maxZ = line[2]
	minX = line[3]
	minY = line[4]
	minZ = line[5]
	midX = (Faces[:,0] + Faces[:,3])/2
	mixY = (Faces[:,1] + Faces[:,4])/2
	mixZ = (Faces[:,2] + Faces[:,5])/2
	aa = np.where((midX >= minX) & ( mixY >= minY) & (mixZ >= minZ) & (midX <= maxX) & (mixY <= maxY) & (mixZ <= maxZ)   )
	return Faces[aa]


class BoundingBoxCreate():
	def __init__(self, line):

		XMax = max(line[3],line[0]) 
		YMax = max(line[4],line[1]) 
		ZMax = max(line[5],line[2]) 
		XMin = min(line[3],line[0])
		YMin = min(line[4],line[1])
		ZMin = min(line[5],line[2])
		self.box= np.array([XMax,YMax,ZMax,XMin,YMin,ZMin])

@numba.jit(nopython=True)
def split(aabb):
    minX = aabb[3]
    maxX = aabb[0]
    minY = aabb[4]
    maxY = aabb[1]
    minZ = aabb[5]
    maxZ = aabb[2]
    centerX = (minX+ maxX)/2
    centerY = (minY + maxY)/2
    centerZ = (minZ+ maxY)/2

    bbox0 = (maxX, maxY, maxZ, centerX, centerY, centerZ)
    bbox1 = (centerX, maxY,maxZ,  minX, centerY, centerZ)
    bbox2 = (maxX, centerY, maxZ, centerX, minY, centerZ)
    bbox3 = (centerX, centerY, maxZ, minX, minY, centerZ)
    bbox4 = (maxX, maxY, centerZ, centerX, centerY, minZ)
    bbox5 = (centerX, maxY,centerZ,  minX, centerY, minZ)
    bbox6 = (maxX, centerY, centerZ, centerX, minY, minZ)
    bbox7 = (centerX, centerY, centerZ, minX, minY, minZ)

    return bbox0, bbox1 , bbox2, bbox3, bbox4, bbox5, bbox6, bbox7

@numba.jit(nopython=True)
def XClipLine(d,vecMax, vecMin,  v0,  v1, f_low, f_high):
	# Method for AABB vs line took from https://github.com/BSVino/MathForGameDevelopers/tree/line-box-intersection
	# // Find the point of intersection in this dimension only as a fraction of the total vector
	
	f_dim_low = (vecMin[d] - v0[d])/(v1[d] - v0[d] + 0.0000001)
	f_dim_high = (vecMax[d] - v0[d])/(v1[d] - v0[d]+ 0.0000001)

	# // Make sure low is less than high
	if (f_dim_high < f_dim_low):
		f_dim_high, f_dim_low = f_dim_low, f_dim_high

	# // If this dimension's high is less than the low we got then we definitely missed.
	if (f_dim_high < f_low):
		return 0,0

	# // Likewise if the low is less than the high.
	if (f_dim_low > f_high):
		return 0,0

	# // Add the clip from this dimension to the previous results
	f_low = max(f_dim_low, f_low)
	f_high = min(f_dim_high, f_high)

	if (f_low > f_high):
		return 0,0

	return f_low , f_high



@numba.jit(nopython=True)
def LineAABBIntersection(aabbBox,line):
	# Method for AABB vs line took from https://github.com/BSVino/MathForGameDevelopers/tree/line-box-intersection
	f_low = 0
	f_high = 1
	v0, v1 = (line[0], line[1], line[2]), (line[3], line[4], line[5])
	vecMax =  aabbBox[:3]
	vecMin = aabbBox[-3:]
	x = XClipLine(0, vecMax, vecMin , v0, v1, f_low, f_high)
	if not x:
		return False
	

	x = XClipLine(1, vecMax, vecMin , v0, v1, x[0], x[1])
	if  x == (0,0) :
		return False
	x = XClipLine(2, vecMax, vecMin , v0, v1, x[0], x[1])
	if x == (0,0):
		return False

	return True

# @numba.jit(forceobj=True, parallel=True)
def checkFaces(Faces, line):

	for f in Faces:
		if LineAABBIntersection(f,line):
			return True
	return False



# @numba.jit(forceobj=True, parallel=True)
def checklines(meshes, line):

    global count
    global totalLines

    if (count % 10) == 0:
        # print("=", end ="")
        print("\r {} of {} total lines".format( str(count),totalLines ), end ="")
    count = count + 1
    for b in meshes:
        #check if line line intersect with mesh
        bbx = b.boundingBox
        if LineAABBIntersection(bbx, line):
            
            #if true split bbx in 4
            splitted  = b.parts
            for s in splitted:
                for ss in s.parts:
                    if LineAABBIntersection( ss.boundingBox , line):
                        for sss in ss.parts:
                            check = checkFaces(sss.faces,line)
                            if check:
                                return True

    return False





from google.colab import drive
drive.mount('/content/drive')<jupyter_output>Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6qk8qdgf4n4g3pfee6491hc0brc4i.apps.googleusercontent.com&redirect_uri=urn%3aietf%3awg%3aoauth%3a2.0%3aoob&response_type=code&scope=email%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdocs.test%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive.photos.readonly%20https%3a%2f%2fwww.googleapis.com%2fauth%2fpeopleapi.readonly

Enter your authorization code:
··········
Mounted at /content/drive<jupyter_text>Mesh class<jupyter_code>class Mesh():

  def __init__(self, mesh, faces):
    self.Id = mesh[6]
    self.boundingBox = BoundingBoxCreate(mesh).box
    self.parts = [MeshPart(self.Id, x, faces ) for x in split(self.boundingBox) ]




class MeshPart():
  def __init__(self,Id, boundingBox,faces):
    self.boundingBox = BoundingBoxCreate(boundingBox).box
    ff = faces[faces[:,6] == Id]
    filteredFaces = FilterByBBX(ff, boundingBox)
    drop = np.delete(filteredFaces, np.s_[6:], axis=1)
    self.parts = []
    if drop.any():
        self.parts = [MeshSubPart(Id, x, faces ) for x in split(self.boundingBox) ]

class MeshSubPart():
  def __init__(self,Id, boundingBox,faces):
    self.boundingBox = BoundingBoxCreate(boundingBox).box
    ff = faces[faces[:,6] == Id]
    filteredFaces = FilterByBBX(ff, boundingBox)
    drop = np.delete(filteredFaces, np.s_[6:], axis=1)
    self.parts = []
    if drop.any():
        self.parts = [MeshSubSubPart(Id, x, faces ) for x in split(self.boundingBox) ]

class MeshSubSubPart():
  def __init__(self,Id, boundingBox,faces):
    self.boundingBox = BoundingBoxCreate(boundingBox).box
    ff = faces[faces[:,6] == Id]
    filteredFaces = FilterByBBX(ff, boundingBox)
    drop = np.delete(filteredFaces, np.s_[6:], axis=1)
    self.faces =[ BoundingBoxCreate(d).box for d in drop]
    

def createObjects(meshes, faces):
  objects = []
  for m in meshes:
    objects.append(Mesh(m, faces))
  return objects


count = 0

if __name__ is  '__main__':

    start= time.time()
    pov_ = pd.read_csv(r"/content/pov_.csv",header=None )
    pov_.columns = ["x","y","z" ]
    print('{} Points of View'.format(len(pov_)))
    pov_.head(10)

    # ## Reading targets (points over meshes)

    target_ = pd.read_csv(r"/content/targets_.csv",header=None )
    target_.columns = ["x1","y1","z1" ]
    print('{} targets or points of interest'.format(len(target_)))
    target_.head()


    # ## Reading meshes bounding box
    meshes_ = pd.read_csv(r"/content/context_.csv",header=None, index_col=0  )
    meshes_.columns = ["xMax","yMax","zMax","xMin","yMin","zMin","id" ]
    print('{} meshes in context set'.format(len(meshes_)))
    meshes_.head()


    # ## Reading meshes faces
    mesh_faces = pd.read_csv(r"/content/mesh_faces.csv",header=None  )
    mesh_faces.columns = ["xMax","yMax","zMax","xMin","yMin","zMin", "id" ]
    print('{} meshes faces in set'.format(len(mesh_faces)))
    mesh_faces.head()

    # ## Creating all cross product of points vs targets to represent the lines of view
    lines = pov_
    lines = lines.assign(foo=1).merge(target_.assign(foo=1)).drop('foo', 1)
    lines = lines.drop_duplicates()
    lines = lines.reset_index()
    lines = lines.drop(['index'], axis=1)
    totalLines = len(lines)
    print('{} lines between POV and targets'.format(len(lines)))


    # ## Finding mesh intersection
    
    result = createObjects(meshes_.values, mesh_faces.values)
    # funB = partial(checklines, result) # total time 211.28 seconds
    # resultsB = pool.map(funB,lines.values)
    resultsB = [checklines(result, x) for x in  lines.values] # total time 192.399 seconds | 1378 lines between POV and targets
    

    print("")
    lines['hits']= resultsB
    positive = len(lines[lines['hits'] == False])
    print('{} lines with clean sight from POV to targets'.format(positive))
    negative = len(lines[lines['hits'] == True])
    print('{} lines with possible context intersection'.format(negative))


    # ## Saving lines with no intersection
    lines[ lines['hits'] == False].to_csv('miss.csv')

    # ## Saving lines with possible intersection

    lines[ lines['hits'] == True].to_csv('hits.csv')
    end = time.time()
    print('total time {} seconds'.format(round(end-start, 3)))
    print('{},{},{},{},{},{},{},{},{} '.format("POV","Target","Meshes","Meshes faces", "Lines of sight", "Hits", "Miss","time", "Comments"))
    data = '{},{},{},{},{},{},{},{},{}'.format(len(pov_), len(target_), len(meshes_), len(mesh_faces), len(lines), positive, negative,  round(end-start, 3), "3 Level nesting + numba" )
    with open('/content/drive/My Drive/sightlinelog.csv','a') as fd:
        fd.write(data + "\n")
    print(data)<jupyter_output>18 Points of View
5052 targets or points of interest
4 meshes in context set
192088 meshes faces in set
49518 lines between POV and targets
 49510 of 49518 total lines
16417 lines with clean sight from POV to targets
33101 lines with possible context intersection
total time 290.483 seconds
POV,Target,Meshes,Meshes faces,Lines of sight,Hits,Miss,time,Comments 
18,5052,4,192088,49518,16417,33101,290.483,3 Level nesting + numba
{'fraction_non_alphanumeric': 0.15000495392846527, 'fraction_numerical': 0.030417120776775983, 'mean_word_length': 3.7434210526315788, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 16, 'https://': 3, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '21185', 'license': 'MIT', 'n_tokens_mistral': 3982, 'n_tokens_neox': 3764, 'n_words': 878, 'path': 'Sightline.ipynb', 'repo_name': 'pabloderen/Blender_SighlineStudy', 'size': '10093'}