Added "split plate" function to project planner, which cuts an STL file up into seperate pieces. Useful to print items with the project planner that are only distributed in plate form.
parent
daa2066a64
commit
16c043e469
|
@ -157,9 +157,11 @@ class projectPlanner(wx.Frame):
|
||||||
toolbarUtil.RadioButton(self.toolbar, group, 'object-3d-on.png', 'object-3d-off.png', '3D view', callback=self.On3DClick)
|
toolbarUtil.RadioButton(self.toolbar, group, 'object-3d-on.png', 'object-3d-off.png', '3D view', callback=self.On3DClick)
|
||||||
toolbarUtil.RadioButton(self.toolbar, group, 'object-top-on.png', 'object-top-off.png', 'Topdown view', callback=self.OnTopClick).SetValue(True)
|
toolbarUtil.RadioButton(self.toolbar, group, 'object-top-on.png', 'object-top-off.png', 'Topdown view', callback=self.OnTopClick).SetValue(True)
|
||||||
self.toolbar.AddSeparator()
|
self.toolbar.AddSeparator()
|
||||||
toolbarUtil.NormalButton(self.toolbar, self.OnQuit, 'exit.png', 'Close project planner')
|
|
||||||
self.toolbar.AddSeparator()
|
|
||||||
toolbarUtil.NormalButton(self.toolbar, self.OnPreferences, 'preferences.png', 'Project planner preferences')
|
toolbarUtil.NormalButton(self.toolbar, self.OnPreferences, 'preferences.png', 'Project planner preferences')
|
||||||
|
self.toolbar.AddSeparator()
|
||||||
|
toolbarUtil.NormalButton(self.toolbar, self.OnCutMesh, 'cut-mesh.png', 'Cut a plate STL into multiple STL files, and add those files to the project.\nNote: Splitting up plates sometimes takes a few minutes.')
|
||||||
|
self.toolbar.AddSeparator()
|
||||||
|
toolbarUtil.NormalButton(self.toolbar, self.OnQuit, 'exit.png', 'Close project planner')
|
||||||
|
|
||||||
self.toolbar.Realize()
|
self.toolbar.Realize()
|
||||||
|
|
||||||
|
@ -252,6 +254,23 @@ class projectPlanner(wx.Frame):
|
||||||
prefDialog.Centre()
|
prefDialog.Centre()
|
||||||
prefDialog.Show(True)
|
prefDialog.Show(True)
|
||||||
|
|
||||||
|
def OnCutMesh(self, e):
|
||||||
|
dlg=wx.FileDialog(self, "Open file to cut", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
|
||||||
|
dlg.SetWildcard("STL files (*.stl)|*.stl;*.STL")
|
||||||
|
if dlg.ShowModal() == wx.ID_OK:
|
||||||
|
filename = dlg.GetPath()
|
||||||
|
parts = stl.stlModel().load(filename).splitToParts()
|
||||||
|
for part in parts:
|
||||||
|
partFilename = filename[:filename.rfind('.')] + "_part%d.stl" % (parts.index(part))
|
||||||
|
stl.saveAsSTL(part, partFilename)
|
||||||
|
item = ProjectObject(self, partFilename)
|
||||||
|
self.list.append(item)
|
||||||
|
self.selection = item
|
||||||
|
self._updateListbox()
|
||||||
|
self.OnListSelect(None)
|
||||||
|
self.preview.Refresh()
|
||||||
|
dlg.Destroy()
|
||||||
|
|
||||||
def OnSaveProject(self, e):
|
def OnSaveProject(self, e):
|
||||||
dlg=wx.FileDialog(self, "Save project file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
|
dlg=wx.FileDialog(self, "Save project file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
|
||||||
dlg.SetWildcard("Project files (*.curaproject)|*.curaproject")
|
dlg.SetWildcard("Project files (*.curaproject)|*.curaproject")
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import __init__
|
import __init__
|
||||||
|
|
||||||
import sys
|
import sys, math, re, os, struct, time
|
||||||
import math
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import struct
|
|
||||||
|
|
||||||
from util import util3d
|
from util import util3d
|
||||||
|
|
||||||
|
@ -19,12 +15,12 @@ class mesh(object):
|
||||||
self.vertexes = []
|
self.vertexes = []
|
||||||
|
|
||||||
def addFace(self, v0, v1, v2):
|
def addFace(self, v0, v1, v2):
|
||||||
self.faces.append(meshFace(v0, v1, v2))
|
|
||||||
self.vertexes.append(v0)
|
self.vertexes.append(v0)
|
||||||
self.vertexes.append(v1)
|
self.vertexes.append(v1)
|
||||||
self.vertexes.append(v2)
|
self.vertexes.append(v2)
|
||||||
|
self.faces.append(meshFace(v0, v1, v2))
|
||||||
|
|
||||||
def _createOrigonalVertexCopy(self):
|
def _postProcessAfterLoad(self):
|
||||||
self.origonalVertexes = list(self.vertexes)
|
self.origonalVertexes = list(self.vertexes)
|
||||||
for i in xrange(0, len(self.origonalVertexes)):
|
for i in xrange(0, len(self.origonalVertexes)):
|
||||||
self.origonalVertexes[i] = self.origonalVertexes[i].copy()
|
self.origonalVertexes[i] = self.origonalVertexes[i].copy()
|
||||||
|
@ -96,6 +92,81 @@ class mesh(object):
|
||||||
v.y -= minV.y + (maxV.y - minV.y) / 2
|
v.y -= minV.y + (maxV.y - minV.y) / 2
|
||||||
self.getMinimumZ()
|
self.getMinimumZ()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def splitToParts(self):
|
||||||
for filename in sys.argv[1:]:
|
t0 = time.time()
|
||||||
stlModel().load(filename)
|
|
||||||
|
print "%f: " % (time.time() - t0), "Splitting a model with %d vertexes." % (len(self.vertexes))
|
||||||
|
removeDict = {}
|
||||||
|
tree = util3d.AABBTree()
|
||||||
|
off = util3d.Vector3(0.0001,0.0001,0.0001)
|
||||||
|
newVertexList = []
|
||||||
|
for v in self.vertexes:
|
||||||
|
e = util3d.AABB(v-off, v+off)
|
||||||
|
q = tree.query(e)
|
||||||
|
if len(q) < 1:
|
||||||
|
e.vector = v
|
||||||
|
tree.insert(e)
|
||||||
|
newVertexList.append(v)
|
||||||
|
else:
|
||||||
|
removeDict[v] = q[0].vector
|
||||||
|
print "%f: " % (time.time() - t0), "Marked %d duplicate vertexes for removal." % (len(removeDict))
|
||||||
|
|
||||||
|
#Make facelists so we can quickly remove all the vertexes.
|
||||||
|
for v in self.vertexes:
|
||||||
|
v.faceList = []
|
||||||
|
for f in self.faces:
|
||||||
|
f.v[0].faceList.append(f)
|
||||||
|
f.v[1].faceList.append(f)
|
||||||
|
f.v[2].faceList.append(f)
|
||||||
|
|
||||||
|
self.vertexes = newVertexList
|
||||||
|
for v1 in removeDict.iterkeys():
|
||||||
|
v0 = removeDict[v1]
|
||||||
|
for f in v1.faceList:
|
||||||
|
if f.v[0] == v1:
|
||||||
|
f.v[0] = v0
|
||||||
|
if f.v[1] == v1:
|
||||||
|
f.v[1] = v0
|
||||||
|
if f.v[2] == v1:
|
||||||
|
f.v[2] = v0
|
||||||
|
print "%f: " % (time.time() - t0), "Building face lists after vertex removal."
|
||||||
|
for v in self.vertexes:
|
||||||
|
v.faceList = []
|
||||||
|
for f in self.faces:
|
||||||
|
f.v[0].faceList.append(f)
|
||||||
|
f.v[1].faceList.append(f)
|
||||||
|
f.v[2].faceList.append(f)
|
||||||
|
|
||||||
|
print "%f: " % (time.time() - t0), "Building parts."
|
||||||
|
partList = []
|
||||||
|
doneSet = set()
|
||||||
|
for f in self.faces:
|
||||||
|
if not f in doneSet:
|
||||||
|
partList.append(self._createPartFromFacewalk(f, doneSet))
|
||||||
|
print "%f: " % (time.time() - t0), "Split into %d parts" % (len(partList))
|
||||||
|
return partList
|
||||||
|
|
||||||
|
def _createPartFromFacewalk(self, startFace, doneSet):
|
||||||
|
m = mesh()
|
||||||
|
todoList = [startFace]
|
||||||
|
doneSet.add(startFace)
|
||||||
|
while len(todoList) > 0:
|
||||||
|
f = todoList.pop()
|
||||||
|
m._partAddFacewalk(f, doneSet, todoList)
|
||||||
|
return m
|
||||||
|
|
||||||
|
def _partAddFacewalk(self, f, doneSet, todoList):
|
||||||
|
self.addFace(f.v[0], f.v[1], f.v[2])
|
||||||
|
for f1 in f.v[0].faceList:
|
||||||
|
if f1 not in doneSet:
|
||||||
|
todoList.append(f1)
|
||||||
|
doneSet.add(f1)
|
||||||
|
for f1 in f.v[1].faceList:
|
||||||
|
if f1 not in doneSet:
|
||||||
|
todoList.append(f1)
|
||||||
|
doneSet.add(f1)
|
||||||
|
for f1 in f.v[2].faceList:
|
||||||
|
if f1 not in doneSet:
|
||||||
|
todoList.append(f1)
|
||||||
|
doneSet.add(f1)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import __init__
|
import __init__
|
||||||
|
|
||||||
import sys
|
import sys, math, re, os, struct, time
|
||||||
import math
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import struct
|
|
||||||
|
|
||||||
from util import util3d
|
from util import util3d
|
||||||
from util import mesh
|
from util import mesh
|
||||||
|
@ -25,7 +21,8 @@ class stlModel(mesh.mesh):
|
||||||
self._loadBinary(f)
|
self._loadBinary(f)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
self._createOrigonalVertexCopy()
|
self._postProcessAfterLoad()
|
||||||
|
return self
|
||||||
|
|
||||||
def _loadAscii(self, f):
|
def _loadAscii(self, f):
|
||||||
cnt = 0
|
cnt = 0
|
||||||
|
@ -54,7 +51,30 @@ class stlModel(mesh.mesh):
|
||||||
v2 = util3d.Vector3(data[9], data[10], data[11])
|
v2 = util3d.Vector3(data[9], data[10], data[11])
|
||||||
self.addFace(v0, v1, v2)
|
self.addFace(v0, v1, v2)
|
||||||
|
|
||||||
|
def saveAsSTL(mesh, filename):
|
||||||
|
f = open(filename, 'wb')
|
||||||
|
#Write the STL binary header. This can contain any info, except for "SOLID" at the start.
|
||||||
|
f.write(("CURA BINARY STL EXPORT. " + time.strftime('%a %d %b %Y %H:%M:%S')).ljust(80, '\000'))
|
||||||
|
#Next follow 4 binary bytes containing the amount of faces, and then the face information.
|
||||||
|
f.write(struct.pack("<I", len(mesh.faces)))
|
||||||
|
for face in mesh.faces:
|
||||||
|
v1 = face.v[0]
|
||||||
|
v2 = face.v[1]
|
||||||
|
v3 = face.v[2]
|
||||||
|
normal = (v2 - v1).cross(v3 - v1)
|
||||||
|
normal.normalize()
|
||||||
|
f.write(struct.pack("<fff", normal.x, normal.y, normal.z))
|
||||||
|
f.write(struct.pack("<fff", v1.x, v1.y, v1.z))
|
||||||
|
f.write(struct.pack("<fff", v2.x, v2.y, v2.z))
|
||||||
|
f.write(struct.pack("<fff", v3.x, v3.y, v3.z))
|
||||||
|
f.write(struct.pack("<H", 0))
|
||||||
|
f.close()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
for filename in sys.argv[1:]:
|
for filename in sys.argv[1:]:
|
||||||
stlModel().load(filename)
|
m = stlModel().load(filename)
|
||||||
|
print "Loaded %d faces" % (len(m.faces))
|
||||||
|
parts = m.splitToParts()
|
||||||
|
for p in parts:
|
||||||
|
saveAsSTL(p, "export_%i.stl" % parts.index(p))
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class Vector3(object):
|
||||||
return Vector3(self.x, self.y, self.z)
|
return Vector3(self.x, self.y, self.z)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s, %s, %s' % ( self.x, self.y, self.z )
|
return '[%s, %s, %s]' % ( self.x, self.y, self.z )
|
||||||
|
|
||||||
def __add__(self, v):
|
def __add__(self, v):
|
||||||
return Vector3( self.x + v.x, self.y + v.y, self.z + v.z )
|
return Vector3( self.x + v.x, self.y + v.y, self.z + v.z )
|
||||||
|
@ -56,6 +56,9 @@ class Vector3(object):
|
||||||
self.z /= v
|
self.z /= v
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def almostEqual(self, v):
|
||||||
|
return (abs(self.x - v.x) + abs(self.y - v.y) + abs(self.z - v.z)) < 0.00001
|
||||||
|
|
||||||
def cross(self, v):
|
def cross(self, v):
|
||||||
return Vector3(self.y * v.z - self.z * v.y, -self.x * v.z + self.z * v.x, self.x * v.y - self.y * v.x)
|
return Vector3(self.y * v.z - self.z * v.y, -self.x * v.z + self.z * v.x, self.x * v.y - self.y * v.x)
|
||||||
|
|
||||||
|
@ -75,3 +78,240 @@ class Vector3(object):
|
||||||
def max(self, v):
|
def max(self, v):
|
||||||
return Vector3(max(self.x, v.x), max(self.y, v.y), max(self.z, v.z))
|
return Vector3(max(self.x, v.x), max(self.y, v.y), max(self.z, v.z))
|
||||||
|
|
||||||
|
class AABB(object):
|
||||||
|
def __init__(self, vMin, vMax):
|
||||||
|
self.vMin = vMin
|
||||||
|
self.vMax = vMax
|
||||||
|
|
||||||
|
def getPerimeter(self):
|
||||||
|
return (self.vMax.x - self.vMax.x) + (self.vMax.y - self.vMax.y) + (self.vMax.z - self.vMax.z)
|
||||||
|
|
||||||
|
def combine(self, aabb):
|
||||||
|
return AABB(self.vMin.min(aabb.vMin), self.vMax.max(aabb.vMax))
|
||||||
|
|
||||||
|
def overlap(self, aabb):
|
||||||
|
if aabb.vMin.x - self.vMax.x > 0.0 or aabb.vMin.y - self.vMax.y > 0.0 or aabb.vMin.z - self.vMax.z > 0.0:
|
||||||
|
return False
|
||||||
|
if self.vMin.x - aabb.vMax.x > 0.0 or self.vMin.y - aabb.vMax.y > 0.0 or self.vMin.z - aabb.vMax.z > 0.0:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "AABB:%s - %s" % (str(self.vMin), str(self.vMax))
|
||||||
|
|
||||||
|
class _AABBNode(object):
|
||||||
|
def __init__(self, aabb):
|
||||||
|
self.child1 = None
|
||||||
|
self.child2 = None
|
||||||
|
self.parent = None
|
||||||
|
self.height = 0
|
||||||
|
self.aabb = aabb
|
||||||
|
|
||||||
|
def isLeaf(self):
|
||||||
|
return self.child1 == None
|
||||||
|
|
||||||
|
class AABBTree(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.root = None
|
||||||
|
|
||||||
|
def insert(self, aabb):
|
||||||
|
newNode = _AABBNode(aabb)
|
||||||
|
if self.root == None:
|
||||||
|
self.root = newNode
|
||||||
|
return
|
||||||
|
|
||||||
|
node = self.root
|
||||||
|
while not node.isLeaf():
|
||||||
|
child1 = node.child1
|
||||||
|
child2 = node.child2
|
||||||
|
|
||||||
|
area = node.aabb.getPerimeter()
|
||||||
|
combinedAABB = node.aabb.combine(aabb)
|
||||||
|
combinedArea = combinedAABB.getPerimeter()
|
||||||
|
|
||||||
|
cost = 2.0 * combinedArea
|
||||||
|
inheritanceCost = 2.0 * (combinedArea - area)
|
||||||
|
|
||||||
|
if child1.isLeaf():
|
||||||
|
cost1 = aabb.combine(child1.aabb).getPerimeter() + inheritanceCost
|
||||||
|
else:
|
||||||
|
oldArea = child1.aabb.getPerimeter()
|
||||||
|
newArea = aabb.combine(child1.aabb).getPerimeter()
|
||||||
|
cost1 = (newArea - oldArea) + inheritanceCost
|
||||||
|
|
||||||
|
if child2.isLeaf():
|
||||||
|
cost2 = aabb.combine(child1.aabb).getPerimeter() + inheritanceCost
|
||||||
|
else:
|
||||||
|
oldArea = child2.aabb.getPerimeter()
|
||||||
|
newArea = aabb.combine(child2.aabb).getPerimeter()
|
||||||
|
cost2 = (newArea - oldArea) + inheritanceCost
|
||||||
|
|
||||||
|
if cost < cost1 and cost < cost2:
|
||||||
|
break
|
||||||
|
|
||||||
|
if cost1 < cost2:
|
||||||
|
node = child1
|
||||||
|
else:
|
||||||
|
node = child2
|
||||||
|
|
||||||
|
sibling = node
|
||||||
|
|
||||||
|
# Create a new parent.
|
||||||
|
oldParent = sibling.parent
|
||||||
|
newParent = _AABBNode(aabb.combine(sibling.aabb))
|
||||||
|
newParent.parent = oldParent
|
||||||
|
newParent.height = sibling.height + 1
|
||||||
|
|
||||||
|
if oldParent != None:
|
||||||
|
# The sibling was not the root.
|
||||||
|
if oldParent.child1 == sibling:
|
||||||
|
oldParent.child1 = newParent
|
||||||
|
else:
|
||||||
|
oldParent.child2 = newParent
|
||||||
|
|
||||||
|
newParent.child1 = sibling
|
||||||
|
newParent.child2 = newNode
|
||||||
|
sibling.parent = newParent
|
||||||
|
newNode.parent = newParent
|
||||||
|
else:
|
||||||
|
# The sibling was the root.
|
||||||
|
newParent.child1 = sibling
|
||||||
|
newParent.child2 = newNode
|
||||||
|
sibling.parent = newParent
|
||||||
|
newNode.parent = newParent
|
||||||
|
self.root = newParent
|
||||||
|
|
||||||
|
# Walk back up the tree fixing heights and AABBs
|
||||||
|
node = newNode.parent
|
||||||
|
while node != None:
|
||||||
|
node = self._balance(node)
|
||||||
|
|
||||||
|
child1 = node.child1
|
||||||
|
child2 = node.child2
|
||||||
|
|
||||||
|
node.height = 1 + max(child1.height, child2.height)
|
||||||
|
node.aabb = child1.aabb.combine(child2.aabb)
|
||||||
|
|
||||||
|
node = node.parent
|
||||||
|
|
||||||
|
def _balance(self, A):
|
||||||
|
if A.isLeaf() or A.height < 2:
|
||||||
|
return A
|
||||||
|
|
||||||
|
B = A.child1
|
||||||
|
C = A.child2
|
||||||
|
|
||||||
|
balance = C.height - B.height
|
||||||
|
|
||||||
|
# Rotate C up
|
||||||
|
if balance > 1:
|
||||||
|
F = C.child1;
|
||||||
|
G = C.child2;
|
||||||
|
|
||||||
|
# Swap A and C
|
||||||
|
C.child1 = A;
|
||||||
|
C.parent = A.parent;
|
||||||
|
A.parent = C;
|
||||||
|
|
||||||
|
# A's old parent should point to C
|
||||||
|
if C.parent != None:
|
||||||
|
if C.parent.child1 == A:
|
||||||
|
C.parent.child1 = C
|
||||||
|
else:
|
||||||
|
C.parent.child2 = C
|
||||||
|
else:
|
||||||
|
self.root = C
|
||||||
|
|
||||||
|
# Rotate
|
||||||
|
if F.height > G.height:
|
||||||
|
C.child2 = F
|
||||||
|
A.child2 = G
|
||||||
|
G.parent = A
|
||||||
|
A.aabb = B.aabb.combine(G.aabb)
|
||||||
|
C.aabb = A.aabb.combine(F.aabb)
|
||||||
|
|
||||||
|
A.height = 1 + Math.max(B.height, G.height)
|
||||||
|
C.height = 1 + Math.max(A.height, F.height)
|
||||||
|
else:
|
||||||
|
C.child2 = G
|
||||||
|
A.child2 = F
|
||||||
|
F.parent = A
|
||||||
|
A.aabb = B.aabb.combine(F.aabb)
|
||||||
|
C.aabb = A.aabb.combine(G.aabb)
|
||||||
|
|
||||||
|
A.height = 1 + max(B.height, F.height)
|
||||||
|
C.height = 1 + max(A.height, G.height)
|
||||||
|
|
||||||
|
return C;
|
||||||
|
|
||||||
|
# Rotate B up
|
||||||
|
if balance < -1:
|
||||||
|
D = B.child1
|
||||||
|
E = B.child2
|
||||||
|
|
||||||
|
# Swap A and B
|
||||||
|
B.child1 = A
|
||||||
|
B.parent = A.parent
|
||||||
|
A.parent = B
|
||||||
|
|
||||||
|
# A's old parent should point to B
|
||||||
|
if B.parent != None:
|
||||||
|
if B.parent.child1 == A:
|
||||||
|
B.parent.child1 = B
|
||||||
|
else:
|
||||||
|
B.parent.child2 = B
|
||||||
|
else:
|
||||||
|
self.root = B
|
||||||
|
|
||||||
|
# Rotate
|
||||||
|
if D.height > E.height:
|
||||||
|
B.child2 = D
|
||||||
|
A.child1 = E
|
||||||
|
E.parent = A
|
||||||
|
A.aabb = C.aabb.combine(E.aabb)
|
||||||
|
B.aabb = A.aabb.combine(D.aabb)
|
||||||
|
|
||||||
|
A.height = 1 + max(C.height, E.height)
|
||||||
|
B.height = 1 + max(A.height, D.height)
|
||||||
|
else:
|
||||||
|
B.child2 = E
|
||||||
|
A.child1 = D
|
||||||
|
D.parent = A
|
||||||
|
A.aabb = C.aabb.combine(D.aabb)
|
||||||
|
B.aabb = A.aabb.combine(E.aabb)
|
||||||
|
|
||||||
|
A.height = 1 + max(C.height, D.height)
|
||||||
|
B.height = 1 + max(A.height, E.height)
|
||||||
|
|
||||||
|
return B
|
||||||
|
|
||||||
|
return A
|
||||||
|
|
||||||
|
def query(self, aabb):
|
||||||
|
resultList = []
|
||||||
|
if self.root != None:
|
||||||
|
self._query(self.root, aabb, resultList)
|
||||||
|
return resultList
|
||||||
|
|
||||||
|
def _query(self, node, aabb, resultList):
|
||||||
|
if not aabb.overlap(node.aabb):
|
||||||
|
return
|
||||||
|
if node.isLeaf():
|
||||||
|
resultList.append(node.aabb)
|
||||||
|
else:
|
||||||
|
self._query(node.child1, aabb, resultList)
|
||||||
|
self._query(node.child2, aabb, resultList)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
s = "AABBTree:\n"
|
||||||
|
s += str(self.root.aabb)
|
||||||
|
return s
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
tree = AABBTree()
|
||||||
|
tree.insert(AABB(Vector3(0,0,0), Vector3(0,0,0)))
|
||||||
|
tree.insert(AABB(Vector3(1,1,1), Vector3(1,1,1)))
|
||||||
|
tree.insert(AABB(Vector3(0.5,0.5,0.5), Vector3(0.5,0.5,0.5)))
|
||||||
|
print tree
|
||||||
|
print tree.query(AABB(Vector3(0,0,0), Vector3(0,0,0)))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue