Commit 1310c800 authored by sumpfralle's avatar sumpfralle

fixed toolpath simulation


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@1233 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 3ddeba63
......@@ -2,31 +2,42 @@
<interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="SimulationDialog">
<property name="border_width">5</property>
<property name="title" translatable="yes">PyCAM simulation</property>
<property name="role">pycam-simulation</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox9">
<object class="GtkAdjustment" id="SimulationProgressTimelineValue">
<property name="upper">1</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="SimulationSpeedFactorValue">
<property name="lower">0.01</property>
<property name="upper">10000</property>
<property name="step_increment">0.25</property>
</object>
<object class="GtkAdjustment" id="SimulationDetailsValue">
<property name="lower">1</property>
<property name="upper">10</property>
<property name="step_increment">1</property>
</object>
<object class="GtkFrame" id="SimulationBox">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<property name="top_padding">3</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox23">
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkHBox" id="hbox20">
<property name="spacing">2</property>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<child>
<object class="GtkLabel" id="SimulationDetailsControlLabel">
<object class="GtkLabel" id="SimulationProgressTimelineLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="xpad">5</property>
<property name="label" translatable="yes">Simulation detail level (1..10):</property>
<property name="label" translatable="yes">Progress:</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -34,15 +45,12 @@
</packing>
</child>
<child>
<object class="GtkSpinButton" id="SimulationDetailsControl">
<object class="GtkLabel" id="SimulationProgressTimeDisplay">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">6</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SimulationDetailsValue</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">0:20 / 4:45</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
......@@ -53,14 +61,12 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Hint:&lt;/b&gt; take a look at the "show drill" and
"OpenGL: polygon" settings in preferences.
&lt;b&gt;Beware:&lt;/b&gt; the simulation feature is new and
experimental. Thus you will quite probably stumble
upon interesting bugs and weird results.</property>
<property name="use_markup">True</property>
<object class="GtkHScale" id="SimulationProgressTimeline">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="update_policy">delayed</property>
<property name="adjustment">SimulationProgressTimelineValue</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -68,22 +74,61 @@ upon interesting bugs and weird results.</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="SimulationProgressTimelineLabel">
<object class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Progress:</property>
<property name="spacing">3</property>
<child>
<object class="GtkButton" id="SimulationStartButton">
<property name="label">gtk-media-play</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="SimulationPauseButton">
<property name="label">gtk-media-pause</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="SimulationStopButton">
<property name="label">gtk-stop</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkHScale" id="SimulationProgressTimeline">
<object class="GtkHSeparator" id="hseparator1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">SimulationProgressTimelineValue</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -98,92 +143,43 @@ upon interesting bugs and weird results.</property>
<object class="GtkLabel" id="SimulationSpeedFactorLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Simulation speed factor:</property>
<property name="label" translatable="yes">Simulation speed:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="SimulationSpeedFactorValueLabel">
<object class="GtkSpinButton" id="SimulationSpeedFactorControl">
<property name="visible">True</property>
<property name="label" translatable="yes">1.00</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SimulationSpeedFactorValue</property>
<property name="digits">2</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkHScale" id="SimulationSpeedFactor">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">SimulationSpeedFactorValueExponential</property>
<property name="draw_value">False</property>
<property name="value_pos">bottom</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area8">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="ExitSimulationButton">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">ExitSimulationButton</action-widget>
</action-widgets>
</object>
<object class="GtkAdjustment" id="SimulationProgressTimelineValue">
<property name="upper">100</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="SimulationSpeedFactorValueExponential">
<property name="lower">-2</property>
<property name="upper">4</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="SimulationDetailsValue">
<property name="lower">1</property>
<property name="upper">10</property>
<property name="step_increment">1</property>
<child type="label">
<object class="GtkLabel" id="SimulationFrameLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Simulation&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
</interface>
......@@ -102,23 +102,6 @@ def draw_direction_cone(p1, p2, position=0.5, precision=12, size=0.1):
def draw_complete_model_view(settings):
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
# draw the material (for simulation mode)
if settings.get("show_simulation"):
obj = settings.get("simulation_object")
if not obj is None:
color = settings.get("color_material")
GL.glColor4f(color["red"], color["green"], color["blue"], color["alpha"])
# we need to wait until the color change is active
GL.glFinish()
obj.to_OpenGL()
# draw the toolpath simulation
if settings.get("show_simulation"):
moves = settings.get("simulation_toolpath_moves")
if not moves is None:
draw_toolpath(moves, settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return"),
show_directions=settings.get("show_directions"),
lighting=settings.get("view_light"))
# draw the drill
if settings.get("show_drill"):
cutter = settings.get("cutter")
......
......@@ -32,23 +32,25 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
def setup(self):
import OpenGL.GL
self._GL = OpenGL.GL
self.core.register_event("visualize-items", self.draw_toolpath)
self.core.register_event("visualize-items", self.draw_toolpaths)
self.core.get("register_color")("color_toolpath_cut", "Toolpath cut",
60)
self.core.get("register_color")("color_toolpath_return",
"Toolpath rapid", 70)
self.core.register_chain("get_draw_dimension", self.get_draw_dimension)
self.core.get("register_display_item")("show_toolpath", "Show Toolpath", 30),
self.core.set("draw_toolpath_moves_func", self._draw_toolpath_moves)
self.core.emit_event("visual-item-updated")
return True
def teardown(self):
self.core.unregister_chain("get_draw_dimension",
self.get_draw_dimension)
self.core.unregister_event("visualize-items", self.draw_toolpath)
self.core.unregister_event("visualize-items", self.draw_toolpaths)
self.core.get("unregister_color")("color_toolpath_cut")
self.core.get("unregister_color")("color_toolpath_return")
self.core.get("unregister_display_item")("show_toolpath")
self.core.remove_item("draw_toolpath_moves_func")
self.core.emit_event("visual-item-updated")
def get_draw_dimension(self, low, high):
......@@ -68,44 +70,46 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
def _is_visible(self):
return self.core.get("show_toolpath") \
and not self.core.get("toolpath_in_progress") \
and not (self.core.get("show_simulation") \
and self.core.get("simulation_toolpath_moves"))
and not self.core.get("show_simulation")
def draw_toolpath(self):
def draw_toolpaths(self):
if self._is_visible():
GL = self._GL
GL.glDisable(GL.GL_LIGHTING)
show_directions = self.core.get("show_directions")
color_rapid = self.core.get("color_toolpath_return")
color_cut = self.core.get("color_toolpath_cut")
for toolpath in self.core.get("toolpaths").get_visible():
moves = toolpath.get_moves(self.core.get("gcode_safety_height"))
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
last_position = None
last_rapid = None
GL.glBegin(GL.GL_LINE_STRIP)
for position, rapid in moves:
if last_rapid != rapid:
GL.glEnd()
if rapid:
GL.glColor4f(color_rapid["red"], color_rapid["green"],
color_rapid["blue"], color_rapid["alpha"])
else:
GL.glColor4f(color_cut["red"], color_cut["green"],
color_cut["blue"], color_cut["alpha"])
# we need to wait until the color change is active
GL.glFinish()
GL.glBegin(GL.GL_LINE_STRIP)
if not last_position is None:
GL.glVertex3f(last_position.x, last_position.y, last_position.z)
last_rapid = rapid
GL.glVertex3f(position.x, position.y, position.z)
last_position = position
self._draw_toolpath_moves(moves)
def _draw_toolpath_moves(self, moves):
GL = self._GL
GL.glDisable(GL.GL_LIGHTING)
show_directions = self.core.get("show_directions")
color_rapid = self.core.get("color_toolpath_return")
color_cut = self.core.get("color_toolpath_cut")
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
last_position = None
last_rapid = None
GL.glBegin(GL.GL_LINE_STRIP)
for position, rapid in moves:
if last_rapid != rapid:
GL.glEnd()
if show_directions:
for index in range(len(moves) - 1):
p1 = moves[index][0]
p2 = moves[index + 1][0]
pycam.Gui.OpenGLTools.draw_direction_cone(p1, p2)
if rapid:
GL.glColor4f(color_rapid["red"], color_rapid["green"],
color_rapid["blue"], color_rapid["alpha"])
else:
GL.glColor4f(color_cut["red"], color_cut["green"],
color_cut["blue"], color_cut["alpha"])
# we need to wait until the color change is active
GL.glFinish()
GL.glBegin(GL.GL_LINE_STRIP)
if not last_position is None:
GL.glVertex3f(last_position.x, last_position.y, last_position.z)
last_rapid = rapid
GL.glVertex3f(position.x, position.y, position.z)
last_position = position
GL.glEnd()
if show_directions:
for index in range(len(moves) - 1):
p1 = moves[index][0]
p2 = moves[index + 1][0]
pycam.Gui.OpenGLTools.draw_direction_cone(p1, p2)
......@@ -21,6 +21,8 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import math
import datetime
import gobject
import pycam.Plugins
# this requires ODE - we import it later, if necessary
......@@ -30,128 +32,130 @@ import pycam.Plugins
class ToolpathSimulation(pycam.Plugins.PluginBase):
UI_FILE = "toolpath_simulation.ui"
DEPENDS = ["Toolpaths", "OpenGLViewToolpath"]
CATEGORIES = ["Toolpath"]
def setup(self):
self._running = None
if self.gui:
self._gtk_handlers = []
speed_factor_widget = self.gui.get_object("SimulationSpeedFactor")
self.core.add_item("simulation_speed_factor",
lambda: pow(10, speed_factor_widget.get_value()),
lambda value: speed_factor_widget.set_value(math.log10(
max(0.001, value))))
simulation_progress = self.gui.get_object(
self._frame = self.gui.get_object("SimulationBox")
self.core.register_ui("toolpath_handling", "Simulation",
self._frame, 25)
self._speed_factor_widget = self.gui.get_object(
"SimulationSpeedFactorValue")
self._speed_factor_widget.set_value(1.0)
self._progress = self.gui.get_object(
"SimulationProgressTimelineValue")
def update_simulation_progress(widget):
if widget.get_value() == 100:
# a negative value indicates, that the simulation is finished
self.core.set("simulation_current_distance", -1)
else:
complete = self.core.get("simulation_complete_distance")
partial = widget.get_value() / 100.0 * complete
self.core.set("simulation_current_distance", partial)
self._gtk_handlers.append((simulation_progress, "value-changed",
update_simulation_progress))
# update the speed factor label
self._gtk_handlers.append((speed_factor_widget, "value-changed",
lambda widget: self.gui.get_object(
"SimulationSpeedFactorValueLabel").set_label("%.2f" % \
self.core.get("simulation_speed_factor"))))
self.simulation_window = self.gui.get_object("SimulationDialog")
self._gtk_handlers.append((self.simulation_window, "delete-event",
self.finish_toolpath_simulation))
sim_detail_obj = self.gui.get_object("SimulationDetailsValue")
self.core.add_item("simulation_details_level",
sim_detail_obj.get_value, sim_detail_obj.set_value)
self._timer_widget = self.gui.get_object(
"SimulationProgressTimeDisplay")
self.core.set("show_simulation", False)
self._toolpath_moves = None
self._start_button = self.gui.get_object("SimulationStartButton")
self._pause_button = self.gui.get_object("SimulationPauseButton")
self._stop_button = self.gui.get_object("SimulationStopButton")
for obj, handler in ((self._start_button, self._start_simulation),
(self._pause_button, self._pause_simulation),
(self._stop_button, self._stop_simulation)):
self._gtk_handlers.append((obj, "clicked", handler))
self._gtk_handlers.append((self._progress, "value-changed",
self._update_toolpath))
self.register_gtk_handlers(self._gtk_handlers)
self.core.register_event("visualize-items", self.show_simulation)
return True
def teardown(self):
if self.gui:
for name in ("simulation_speed_factor", "simulation_details_level"):
self.core.remove_item(name)
self.core.remove_item("show_simulation")
self.core.unregister_ui("toolpath_handling", self._frame)
self.core.unregister_event("visualize-items", self.show_simulation)
self.unregister_gtk_handlers(self._gtk_handlers)
def finish_toolpath_simulation(self, widget=None, data=None):
# hide the simulation tab
self.simulation_window.hide()
# enable all other tabs again
self.toggle_tabs_for_simulation(True)
self.core.set("simulation_object", None)
self.core.set("simulation_toolpath_moves", None)
self.core.set("show_simulation", False)
self.core.set("simulation_toolpath", None)
self.update_view()
# don't destroy the simulation window (for "destroy" event)
return True
def update_toolpath_simulation(self, widget=None, toolpath=None):
s = self.core
# update the GUI
while gtk.events_pending():
gtk.main_iteration()
if not s.get("show_simulation"):
# cancel
return False
safety_height = s.get("gcode_safety_height")
if not s.get("simulation_toolpath"):
# get the currently selected toolpath, if none is give
if toolpath is None:
toolpath_index = self._treeview_get_active_index(self.toolpath_table, self.toolpath)
if toolpath_index is None:
return
else:
toolpath = self.toolpath[toolpath_index]
s.set("simulation_toolpath", toolpath)
# set the current cutter
self.cutter = toolpath.toolpath_settings.get_tool()
def _update_visibility(self):
toolpaths = self.core.get("toolpaths").get_selected()
if toolpaths and (len(toolpaths) == 1):
self._frame.show()
else:
self._frame.hide()
def _start_simulation(self, widget=None):
if self._running is None:
# initial start of simulation (not just continuing)
toolpaths = self.core.get("toolpaths")
if not toolpaths:
# this should not happen
return
# we use only one toolpath
self._toolpath = toolpaths[0]
# calculate steps
s.set("simulation_machine_time",
toolpath.get_machine_time(safety_height=safety_height))
s.set("simulation_complete_distance",
toolpath.get_machine_movement_distance(
safety_height=safety_height))
s.set("simulation_current_distance", 0)
self._safety_height = self.core.get("gcode_safety_height")
self._progress.set_upper(self._toolpath.get_machine_time(
safety_height=self._safety_height))
self._progress.set_value(0)
self._distance = self._toolpath.get_machine_movement_distance(
safety_height=self._safety_height)
self._feedrate = self._toolpath.get_params().get("tool_feedrate",
300)
self._toolpath_moves = None
self.core.set("show_simulation", True)
self._running = True
interval_ms = int(1000 / self.core.get("drill_progress_max_fps"))
gobject.timeout_add(interval_ms, self._next_timestep)
else:
toolpath = s.get("simulation_toolpath")
if (s.get("simulation_current_distance") \
< s.get("simulation_complete_distance")):
if s.get("simulation_current_distance") < 0:
# "-1" -> simulation is finished
updated_distance = s.get("simulation_complete_distance")
else:
time_step = 1.0 / s.get("drill_progress_max_fps")
feedrate = toolpath.toolpath_settings.get_tool_settings(
)["feedrate"]
distance_step = s.get("simulation_speed_factor") * \
time_step * feedrate / 60
updated_distance = min(distance_step + \
s.get("simulation_current_distance"),
s.get("simulation_complete_distance"))
if updated_distance != s.get("simulation_current_distance"):
s.set("simulation_current_distance", updated_distance)
moves = toolpath.get_moves(safety_height=safety_height,
max_movement=updated_distance)
s.set("simulation_toolpath_moves", moves)
if moves:
self.cutter.moveto(moves[-1][0])
self.update_view()
progress_value_percent = 100.0 * s.get("simulation_current_distance") \
/ s.get("simulation_complete_distance")
self.gui.get_object("SimulationProgressTimelineValue").set_value(
progress_value_percent)
self._running = True
self._start_button.set_sensitive(False)
self._pause_button.set_sensitive(True)
self._stop_button.set_sensitive(True)
def _pause_simulation(self, widget=None):
self._start_button.set_sensitive(True)
self._pause_button.set_sensitive(False)
self._running = False
def _stop_simulation(self, widget=None):
self._running = None
self.core.set("show_simulation", False)
self._toolpath_moves = None
self._timer_widget.set_label("")
self._progress.set_value(0)
self._start_button.set_sensitive(True)
self._pause_button.set_sensitive(False)
self._stop_button.set_sensitive(False)
self.core.emit_event("visual-item-updated")
def _next_timestep(self):
if self._running is None:
# stop operation
return False
if not self._running:
# pause -> no change
return True
if self._progress.get_value() < self._progress.get_upper():
time_step = self._speed_factor_widget.get_value() / \
self.core.get("drill_progress_max_fps")
new_time = self._progress.get_value() + time_step
new_time = min(new_time, self._progress.get_upper())
if new_time != self._progress.get_value():
# update the visualization
self._progress.set_value(new_time)
return True
def show_toolpath_simulation(self, toolpath=None):
# disable the main controls
self.toggle_tabs_for_simulation(False)
# show the simulation controls
self.simulation_window.show()
# start the simulation
self.core.set("show_simulation", True)
time_step = int(1000 / self.core.get("drill_progress_max_fps"))
# update the toolpath simulation repeatedly
gobject.timeout_add(time_step, self.update_toolpath_simulation)
def _update_toolpath(self, widget=None):
if (not self._running is None) and (self._progress.get_upper() > 0):
fraction = self._progress.get_value() / self._progress.get_upper()
current = datetime.timedelta(
seconds=int(self._progress.get_value()))
complete = datetime.timedelta(
seconds=int(self._progress.get_upper()))
self._timer_widget.set_label("%s / %s" % (current, complete))
self._toolpath_moves = self._toolpath.get_moves(
safety_height=self._safety_height,
max_movement=self._distance * fraction)
self.core.emit_event("visual-item-updated")
def show_simulation(self):
if self._toolpath_moves and self.core.get("show_simulation"):
self.core.get("draw_toolpath_moves_func")(self._toolpath_moves)
def update_toolpath_simulation_ode(self, widget=None, toolpath=None):
import pycam.Simulation.ODEBlocks as ODEBlocks
......
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