Commit b5cbb9a3 authored by sumpfralle's avatar sumpfralle

r673@erker: lars | 2010-02-16 12:42:38 +0100

 visualize cutter movement during calculation
 use const definitions for drawing colors


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@131 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 9d6e928b
......@@ -19,6 +19,7 @@ class BaseCutter:
self.maxx = location.x+radius
self.miny = location.y-radius
self.maxy = location.y+radius
self.shape = {}
def __repr__(self):
return "BaseCutter"
......@@ -29,6 +30,8 @@ class BaseCutter:
self.maxx = location.x+self.radius
self.miny = location.y-self.radius
self.maxy = location.y+self.radius
for shape, set_pos_func, offset in self.shape.values():
set_pos_func(location.x, location.y, location.z)
def intersect(self, direction, triangle):
return (None, None, None, INFINITE)
......
......@@ -25,6 +25,15 @@ class CylindricalCutter(BaseCutter):
def __repr__(self):
return "CylindricalCutter<%s,%s>" % (self.location,self.radius)
def get_shape(self, format="ODE"):
if format == "ODE":
import ode
geom = ode.GeomCylinder(None, self.radius, self.height)
def set_position(x, y, z):
geom.setPosition((x, y, z))
self.shape[format] = (geom, set_position, (0, 0, 0.5 * self.height))
return self.shape[format]
def to_OpenGL(self):
if not GL_enabled:
return
......
......@@ -25,6 +25,15 @@ class SphericalCutter(BaseCutter):
def __repr__(self):
return "SphericalCutter<%s,%s>" % (self.location,self.radius)
def get_shape(self, format="ODE"):
if format == "ODE":
import ode
geom = ode.GeomCapsule(None, self.radius, self.height)
def set_position(x, y, z):
geom.setPosition((x, y, z))
self.shape[format] = (geom, set_position, (0, 0, 0.5 * self.height + self.radius))
return self.shape[format]
def to_OpenGL(self):
if not GL_enabled:
return
......
......@@ -30,6 +30,16 @@ class ToroidalCutter(BaseCutter):
def __repr__(self):
return "ToroidalCutter<%s,%f,R=%f,r=%f>" % (self.location,self.radius,self.majorradius,self.minorradius)
def get_shape(self, format="ODE"):
if format == "ODE":
import ode
# TODO: use an appromixated trimesh instead (ODE does not support toroidal shapes)
geom = ode.GeomCapsule(None, self.radius, self.height)
def set_position(x, y, z):
geom.setPosition((x, y, z))
self.shape[format] = (geom, set_position, (0, 0, 0.5 * self.height + self.minorradius))
return self.shape[format]
def to_OpenGL(self):
if not GL_enabled:
return
......
......@@ -257,9 +257,11 @@ class ProjectGui:
self.model = None
self.toolpath = None
self.physics = None
self.cutter = None
# add some dummies - to be implemented later ...
self.settings.add_item("model", lambda: getattr(self, "model"))
self.settings.add_item("toolpath", lambda: getattr(self, "toolpath"))
self.settings.add_item("cutter", lambda: getattr(self, "cutter"))
# TODO: replace hard-coded scale
self.settings.add_item("scale", lambda: 0.9/getattr(getattr(self, "model"), "maxsize")())
# create the unit field (the default content can't be defined via glade)
......@@ -326,10 +328,8 @@ class ProjectGui:
if self.view3d:
self.view3d.paint()
def reload_model(self, widget=None, data=None):
self.physics = GuiCommon.generate_physics(self.settings, self.physics)
if self.view3d:
self.update_view()
def update_physics(self):
self.physics = GuiCommon.generate_physics(self.settings, self.cutter, self.physics)
@gui_activity_guard
def toggle_3d_view(self, widget=None, value=None):
......@@ -467,12 +467,21 @@ class ProjectGui:
# do some initialization
self.append_to_queue(self.reset_bounds)
self.append_to_queue(self.toggle_3d_view, True)
self.append_to_queue(self.reload_model)
self.append_to_queue(self.update_view)
@gui_activity_guard
def generate_toolpath(self, widget, data=None):
start_time = time.time()
self.reload_model()
class UpdateView:
def __init__(self, func, skip=10):
self.count = 0
self.skip = skip
self.func = func
def update(self):
if self.count % self.skip == 0:
self.func()
self.count += 1
updater = UpdateView(self.update_view, 2)
radius = float(self.gui.get_object("ToolRadiusControl").get_value())
cuttername = None
for name in ("SphericalCutter", "CylindricalCutter", "ToroidalCutter"):
......@@ -490,13 +499,16 @@ class ProjectGui:
for obj, value in [("PathDirectionX", "x"), ("PathDirectionY", "y"), ("PathDirectionXY", "xy")]:
if self.gui.get_object(obj).get_active():
direction = value
cutter_height = 2 * (self.settings.get("maxz") - self.settings.get("minz"))
if cuttername == "SphericalCutter":
self.cutter = pycam.Cutters.SphericalCutter(radius)
self.cutter = pycam.Cutters.SphericalCutter(radius, height=cutter_height)
elif cuttername == "CylindricalCutter":
self.cutter = pycam.Cutters.CylindricalCutter(radius)
self.cutter = pycam.Cutters.CylindricalCutter(radius, height=cutter_height)
elif cuttername == "ToroidalCutter":
toroid = float(self.gui.get_object("TorusRadiusControl").get_value())
self.cutter = pycam.Cutters.ToroidalCutter(radius, toroid)
self.cutter = pycam.Cutters.ToroidalCutter(radius, toroid, height=cutter_height)
self.update_physics()
offset = radius/2
......@@ -524,9 +536,9 @@ class ProjectGui:
else:
dy = utils.INFINITE
if direction == "x":
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dx, dy, 0)
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dx, dy, 0, updater.update)
elif direction == "y":
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dy, dx, 1)
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dy, dx, 1, updater.update)
elif pathgenerator == "PushCutter":
if pathprocessor == "PathAccumulator":
......@@ -555,11 +567,11 @@ class ProjectGui:
else:
dz = utils.INFINITE
if direction == "x":
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, 0, dy, dz)
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, 0, dy, dz, updater.update)
elif direction == "y":
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dy, 0, dz)
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dy, 0, dz, updater.update)
elif direction == "xy":
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dy, dy, dz)
self.toolpath = self.pathgenerator.GenerateToolPath(minx, maxx, miny, maxy, minz, maxz, dy, dy, dz, updater.update)
print "Time elapsed: %f" % (time.time() - start_time)
self.update_view()
......
......@@ -16,6 +16,14 @@ MODEL_TRANSFORMATIONS = {
"y_swap_z": ((1, 0, 0, 0), (0, 0, 1, 0), (0, 1, 0, 0)),
}
COLORS = {
"model": (0.5, 0.5, 1.0),
"bounding": (0.3, 0.3, 0.3),
"cutter": (1.0, 0.2, 0.2),
"toolpath_way": (1.0, 0.5, 0.5),
"toolpath_back": (0.5, 1.0, 0.5),
}
def keep_gl_mode(func):
def wrapper(*args, **kwargs):
prev_mode = GL.glGetDoublev(GL.GL_MATRIX_MODE)
......@@ -83,7 +91,7 @@ def draw_axes(settings):
@keep_matrix
def draw_bounding_box(minx, miny, minz, maxx, maxy, maxz):
color = [0.3, 0.3, 0.3]
color = COLORS["bounding"]
p1 = [minx, miny, minz]
p2 = [minx, maxy, minz]
p3 = [maxx, maxy, minz]
......@@ -103,6 +111,13 @@ def draw_bounding_box(minx, miny, minz, maxx, maxy, maxz):
GL.glVertex3f(*(corner_pair[1]))
GL.glEnd()
@keep_gl_mode
@keep_matrix
def draw_cutter(cutter):
if not cutter is None:
GL.glColor3f(*COLORS["cutter"])
cutter.to_OpenGL()
@keep_gl_mode
@keep_matrix
def draw_complete_model_view(settings):
......@@ -115,10 +130,12 @@ def draw_complete_model_view(settings):
float(settings.get("minz")), float(settings.get("maxx")),
float(settings.get("maxy")), float(settings.get("maxz")))
# draw the model
GL.glColor3f(0.5, 0.5, 1)
GL.glColor3f(*COLORS["model"])
settings.get("model").to_OpenGL()
# draw the toolpath
draw_toolpath(settings.get("toolpath"))
# draw the drill
draw_cutter(settings.get("cutter"))
@keep_gl_mode
@keep_matrix
......@@ -129,13 +146,13 @@ def draw_toolpath(toolpath):
last = None
for path in toolpath:
if last:
GL.glColor3f(0.5, 1, 0.5)
GL.glColor3f(*COLORS["toolpath_back"])
GL.glBegin(GL.GL_LINES)
GL.glVertex3f(last.x, last.y, last.z)
last = path.points[0]
GL.glVertex3f(last.x, last.y, last.z)
GL.glEnd()
GL.glColor3f(1, 0.5, 0.5)
GL.glColor3f(*COLORS["toolpath_way"])
GL.glBegin(GL.GL_LINE_STRIP)
for point in path.points:
GL.glVertex3f(point.x, point.y, point.z)
......@@ -162,15 +179,17 @@ def scale_model(model, scale):
matrix = ((scale, 0, 0, 0), (0, scale, 0, 0), (0, 0, scale, 0))
model.transform(matrix)
def generate_physics(settings, physics=None):
def generate_physics(settings, cutter, physics=None):
if physics is None:
physics = ode_objects.PhysicalWorld()
physics.reset()
physics.add_mesh((0, 0, 0), settings.get("model").triangles())
radius = settings.get("tool_radius")
#radius = settings.get("tool_radius")
# weird: the normal length of the drill causes the detection to fail at high points of the object
height = 2 * (settings.get("maxz") - settings.get("minz"))
#height = 2 * (settings.get("maxz") - settings.get("minz"))
#physics.set_drill(ode_objects.ShapeCylinder(radius, height), (settings.get("minx"), settings.get("miny"), settings.get("maxz")))
physics.set_drill(ode_objects.ShapeCylinder(radius, height), (0, 0, height/2.0))
#physics.set_drill(ode_objects.ShapeCylinder(radius, height), (0, 0, height/2.0))
shape_info = cutter.get_shape("ODE")
physics.set_drill(shape_info[0], shape_info[2])
return physics
......@@ -37,7 +37,7 @@ class DropCutter:
self.processor = PathProcessor
self.physics = physics
def GenerateToolPath(self, minx, maxx, miny, maxy, z0, z1, d0, d1, direction):
def GenerateToolPath(self, minx, maxx, miny, maxy, z0, z1, d0, d1, direction, draw_callback=None):
if self.processor:
pa = self.processor
else:
......@@ -68,8 +68,6 @@ class DropCutter:
while dims[0].check_bounds():
p = Point(dims[x].get(), dims[y].get(), dim_height.get())
self.cutter.moveto(p)
low, high = z0, z1
trip_start = 20
safe_z = None
......@@ -97,11 +95,16 @@ class DropCutter:
self.physics.set_drill_position((dims[x].get(), dims[y].get(), z1))
if self.physics.check_collision():
# the object fills the whole range of z0..z1 - we should issue a warning
pa.append(Point(dims[x].get(), dims[y].get(), INFINITE))
next_point = Point(dims[x].get(), dims[y].get(), INFINITE)
else:
pa.append(Point(dims[x].get(), dims[y].get(), z1))
next_point = Point(dims[x].get(), dims[y].get(), z1)
else:
pa.append(Point(dims[x].get(), dims[y].get(), safe_z))
next_point = Point(dims[x].get(), dims[y].get(), safe_z)
pa.append(next_point)
self.cutter.moveto(next_point)
if draw_callback:
draw_callback()
"""
height_max = -INFINITE
......
......@@ -26,7 +26,7 @@ class PushCutter:
self.model = model
self.pa = pathextractor
def GenerateToolPath(self, minx, maxx, miny, maxy, minz, maxz, dx, dy, dz):
def GenerateToolPath(self, minx, maxx, miny, maxy, minz, maxz, dx, dy, dz, draw_callback=None):
if dx != 0:
self.pa.dx = dx
else:
......@@ -237,6 +237,10 @@ class PushCutter:
print "C ", begin, " - ", end
self.pa.append(begin)
self.pa.append(end)
self.cutter.moveto(begin)
self.cutter.moveto(end)
if draw_callback:
draw_callback()
if DEBUG_PUSHCUTTER3:
self.svg.stroke("red' stroke-width='0.1")
self.svg.AddLine(begin.x, z-0.1, end.x, z-0.1)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment