Commit 6d9954cd authored by Whitham D. Reeve II's avatar Whitham D. Reeve II

Fixed a sluggish opengl window when a tool path is displayed.

Profiler suggests that the min/max functions for x/y/z of the Toolpath object were the main bottleneck. They iterate through all the points in each path every time they are accessed. These values are now cached which provides a huge speed boost. Originally I thought the problem was the opengl drawing code so I created a new code path that converts moves into an arrays of vertices and indices. The vertices array particularly is stored in video memory. While faster, I don't think it is all that much faster.

Whitham D. Reeve II
parent be127bc2
...@@ -23,7 +23,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -23,7 +23,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
import pycam.Plugins import pycam.Plugins
import pycam.Gui.OpenGLTools import pycam.Gui.OpenGLTools
class OpenGLViewToolpath(pycam.Plugins.PluginBase): class OpenGLViewToolpath(pycam.Plugins.PluginBase):
DEPENDS = ["OpenGLWindow", "Toolpaths"] DEPENDS = ["OpenGLWindow", "Toolpaths"]
...@@ -75,9 +74,37 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase): ...@@ -75,9 +74,37 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
def draw_toolpaths(self): def draw_toolpaths(self):
if self._is_visible(): if self._is_visible():
for toolpath in self.core.get("toolpaths").get_visible(): for toolpath in self.core.get("toolpaths").get_visible():
moves = toolpath.get_moves(self.core.get("gcode_safety_height")) moves = toolpath.get_moves_for_opengl(self.core.get("gcode_safety_height"))
self._draw_toolpath_moves(moves) self._draw_toolpath_moves2(moves)
def _draw_toolpath_moves2(self, paths):
GL = self._GL
GL.glDisable(GL.GL_LIGHTING)
color_rapid = self.core.get("color_toolpath_return")
color_cut = self.core.get("color_toolpath_cut")
show_directions = self.core.get("show_directions")
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
coords = paths[0]
try:
coords.bind()
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
GL.glVertexPointerf(coords)
for path in paths[1]:
if path[1]:
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"])
GL.glDrawElements(GL.GL_LINE_STRIP, len(path[0]), GL.GL_UNSIGNED_INT, path[0])
finally:
coords.unbind()
if show_directions:
for index in range(len(moves)):
pycam.Gui.OpenGLTools.draw_direction_cone(paths[index][0][0], paths[index + 1][0][0])
## Dead code, remove at some time
def _draw_toolpath_moves(self, moves): def _draw_toolpath_moves(self, moves):
GL = self._GL GL = self._GL
GL.glDisable(GL.GL_LIGHTING) GL.glDisable(GL.GL_LIGHTING)
...@@ -102,9 +129,9 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase): ...@@ -102,9 +129,9 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
GL.glFinish() GL.glFinish()
GL.glBegin(GL.GL_LINE_STRIP) GL.glBegin(GL.GL_LINE_STRIP)
if not last_position is None: if not last_position is None:
GL.glVertex3f(last_position[0], last_position[1], last_position[2]) GL.glVertex3f(*last_position)
last_rapid = rapid last_rapid = rapid
GL.glVertex3f(position[0], position[1], position[2]) GL.glVertex3f(*position)
last_position = position last_position = position
GL.glEnd() GL.glEnd()
if show_directions: if show_directions:
......
...@@ -22,16 +22,17 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,16 +22,17 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__ = ["simplify_toolpath", "ToolpathList", "Toolpath", "Generator"] __all__ = ["simplify_toolpath", "ToolpathList", "Toolpath", "Generator"]
import OpenGL.GL as GL
from OpenGL.arrays import vbo
import numpy
from numpy import array
from pycam.Geometry.PointUtils import * from pycam.Geometry.PointUtils import *
from pycam.Geometry.Path import Path from pycam.Geometry.Path import Path
from pycam.Geometry.Line import Line from pycam.Geometry.Line import Line
from pycam.Geometry.utils import number, epsilon from pycam.Geometry.utils import number, epsilon
import pycam.Utils.log
import random import random
import os import os
from itertools import groupby
log = pycam.Utils.log.get_logger()
def _check_colinearity(p1, p2, p3): def _check_colinearity(p1, p2, p3):
v1 = pnormalized(psub(p2, p1)) v1 = pnormalized(psub(p2, p1))
...@@ -71,6 +72,22 @@ class Toolpath(object): ...@@ -71,6 +72,22 @@ class Toolpath(object):
self.parameters = parameters self.parameters = parameters
self._max_safe_distance = 2 * parameters.get("tool_radius", 0) self._max_safe_distance = 2 * parameters.get("tool_radius", 0)
self._feedrate = parameters.get("tool_feedrate", 300) self._feedrate = parameters.get("tool_feedrate", 300)
self.opengl_safety_height = None
self._minx = None
self._maxx = None
self._miny = None
self._maxy = None
self._minz = None
self._maxz = None
def clear_cache(self):
self.opengl_safety_height = None
self._minx = None
self._maxx = None
self._miny = None
self._maxy = None
self._minz = None
self._maxz = None
def get_params(self): def get_params(self):
return dict(self.parameters) return dict(self.parameters)
...@@ -93,27 +110,39 @@ class Toolpath(object): ...@@ -93,27 +110,39 @@ class Toolpath(object):
@property @property
def minx(self): def minx(self):
return self._get_limit_generic(0, min) if self._minx == None:
self._minx = self._get_limit_generic(0, min)
return self._minx
@property @property
def maxx(self): def maxx(self):
return self._get_limit_generic(0, max) if self._maxx == None:
self._maxx = self._get_limit_generic(0, max)
return self._maxx
@property @property
def miny(self): def miny(self):
return self._get_limit_generic(1, min) if self._miny == None:
self._miny = self._get_limit_generic(1, min)
return self._miny
@property @property
def maxy(self): def maxy(self):
return self._get_limit_generic(1, max) if self._maxy == None:
self._maxy = self._get_limit_generic(1, max)
return self._maxy
@property @property
def minz(self): def minz(self):
return self._get_limit_generic(2, min) if self._minz == None:
self._minz = self._get_limit_generic(2, min)
return self._minz
@property @property
def maxz(self): def maxz(self):
return self._get_limit_generic(2, max) if self._maxz == None:
self._maxz = self._get_limit_generic(2, max)
return self._maxz
def get_meta_data(self): def get_meta_data(self):
meta = self.toolpath_settings.get_string() meta = self.toolpath_settings.get_string()
...@@ -169,8 +198,7 @@ class Toolpath(object): ...@@ -169,8 +198,7 @@ class Toolpath(object):
p_last = (p_next[0], p_next[1], safety_height) p_last = (p_next[0], p_next[1], safety_height)
if not result.append(p_last, True): if not result.append(p_last, True):
return result.moves return result.moves
if ((abs(p_last[0] - p_next[0]) > epsilon) \ if ((abs(p_last[0] - p_next[0]) > epsilon) or (abs(p_last[1] - p_next[1]) > epsilon)):
or (abs(p_last[1] - p_next[1]) > epsilon)):
# Draw the connection between the last and the next path. # Draw the connection between the last and the next path.
# Respect the safety height. # Respect the safety height.
#if (abs(p_last[2] - p_next[2]) > epsilon) or (p_last.sub(p_next).norm > self._max_safe_distance + epsilon): #if (abs(p_last[2] - p_next[2]) > epsilon) or (p_last.sub(p_next).norm > self._max_safe_distance + epsilon):
...@@ -193,6 +221,66 @@ class Toolpath(object): ...@@ -193,6 +221,66 @@ class Toolpath(object):
result.append(p_last_safety, True) result.append(p_last_safety, True)
return result.moves return result.moves
def get_moves_for_opengl(self, safety_height):
if self.opengl_safety_height != safety_height:
self.make_moves_for_opengl(safety_height)
self.make_vbo_for_moves()
return (self.opengl_coords, self.opengl_indices)
# separate vertex coordinates from line definitions and convert to indices
def make_vbo_for_moves(self):
index = 0
output = []
store_vertices = {}
vertices = []
for path in self.opengl_lines:
indices = []
for point in path[0]:
if not point in store_vertices:
store_vertices[point] = index
vertices.insert(store_vertices[point], point)
index += 1
indices.append(store_vertices[point])
#this list comprehension removes consecutive duplicate points.
indices = array([x[0] for x in groupby(indices)],dtype=numpy.int32)
output.append((indices, path[1]))
vertices = array(vertices,dtype=numpy.float32)
coords = vbo.VBO(vertices)
self.opengl_coords = coords
self.opengl_indices = output
#convert moves into lines for dispaly with opengl
def make_moves_for_opengl(self, safety_height):
working_path = []
outpaths = []
for path in self.paths:
if not path:
continue
path = path.points
if len(outpaths) != 0:
lastp = outpaths[-1][0][-1]
working_path.append((path[0][0], path[0][1], safety_height))
if ((abs(lastp[0] - path[0][0]) > epsilon) or (abs(lastp[1] - path[0][1]) > epsilon)):
if (abs(lastp[2] - path[0][2]) > epsilon) or (pnorm(psub(lastp, path[0])) > self._max_safe_distance + epsilon):
outpaths.append((working_path, True))
else:
working_path.append((0,0,0))
working_path.append((path[0][0], path[0][1], safety_height))
outpaths.append((working_path, True))
# add this move to last move if last move was not rapid
if outpaths[-1][1] == False:
outpaths[-1] = (outpaths[-1][0] + tuple(path), False)
else:
outpaths.append(((outpaths[-1][0][-1],) + tuple(path), False))
working_path = []
working_path.append(path[-1])
working_path.append((path[-1][0], path[-1][1], safety_height))
outpaths.append((working_path, True))
self.opengl_safety_height = safety_height
self.opengl_lines = outpaths
def get_machine_time(self, safety_height=0.0): def get_machine_time(self, safety_height=0.0):
""" calculate an estimation of the time required for processing the """ calculate an estimation of the time required for processing the
toolpath with the machine toolpath with the machine
...@@ -277,6 +365,7 @@ class Toolpath(object): ...@@ -277,6 +365,7 @@ class Toolpath(object):
if current_path.points: if current_path.points:
new_paths.append(current_path) new_paths.append(current_path)
self.paths = new_paths self.paths = new_paths
self.clear_cache()
class Bounds(object): class Bounds(object):
......
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