Commit 60549c42 authored by sumpfralle's avatar sumpfralle

added an option for using fixed precision numbers instead of floats

 * only useful for debugging (toolpath generation slows down by a factor of 40)


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@567 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 648901e5
......@@ -23,6 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import number
class BaseCutter(object):
......@@ -35,7 +36,8 @@ class BaseCutter(object):
self.location = location
if height is None:
height = 10
self.height = height
radius = number(radius)
self.height = number(height)
self.id = BaseCutter.id
BaseCutter.id += 1
self.radius = radius
......@@ -80,7 +82,7 @@ class BaseCutter(object):
def set_required_distance(self, value):
if value >= 0:
self.required_distance = value
self.required_distance = number(value)
self.distance_radius = self.radius + self.get_required_distance()
self.distance_radiussq = self.distance_radius * self.distance_radius
......
......@@ -21,14 +21,13 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry.utils import INFINITE
from pycam.Geometry.utils import INFINITE, sqrt
from pycam.Geometry.Point import Point
from pycam.Geometry.intersection import intersect_circle_plane, \
intersect_circle_point, intersect_circle_line, \
intersect_cylinder_point, intersect_cylinder_line
from pycam.Cutters.BaseCutter import BaseCutter
import math
try:
import OpenGL.GL as GL
......@@ -64,7 +63,7 @@ class CylindricalCutter(BaseCutter):
additional_distance = self.get_required_distance()
radius = self.distance_radius
height = self.height + additional_distance
center_height = 0.5 * height - additional_distance
center_height = height / 2 - additional_distance
geom = ode.GeomTransform(None)
geom_drill = ode.GeomCylinder(None, radius, height)
geom_drill.setPosition((0, 0, center_height))
......@@ -77,7 +76,7 @@ class CylindricalCutter(BaseCutter):
def extend_shape(diff_x, diff_y, diff_z):
reset_shape()
# see http://mathworld.wolfram.com/RotationMatrix.html
hypotenuse = math.sqrt(diff_x * diff_x + diff_y * diff_y)
hypotenuse = sqrt(diff_x * diff_x + diff_y * diff_y)
# Some paths contain two identical points (e.g. a "touch" of
# the PushCutter) We don't need any extension for these.
if hypotenuse == 0:
......@@ -96,20 +95,20 @@ class CylindricalCutter(BaseCutter):
geom_connect_transform = ode.GeomTransform(geom.space)
geom_connect_transform.setBody(geom.getBody())
geom_connect = ode_physics.get_parallelepiped_geom(
(Point(-hypotenuse / 2.0, radius, -diff_z / 2.0),
Point(hypotenuse / 2.0, radius, diff_z / 2.0),
Point(hypotenuse / 2.0, -radius, diff_z / 2.0),
Point(-hypotenuse / 2.0, -radius, -diff_z / 2.0)),
(Point(-hypotenuse / 2.0, radius,
self.height - diff_z / 2.0),
Point(hypotenuse / 2.0,
radius, self.height + diff_z / 2.0),
Point(hypotenuse / 2.0, -radius,
self.height + diff_z / 2.0),
Point(-hypotenuse / 2.0, -radius,
self.height - diff_z / 2.0)))
(Point(-hypotenuse / 2, radius, -diff_z / 2),
Point(hypotenuse / 2, radius, diff_z / 2),
Point(hypotenuse / 2, -radius, diff_z / 2),
Point(-hypotenuse / 2, -radius, -diff_z / 2)),
(Point(-hypotenuse / 2, radius,
self.height - diff_z / 2),
Point(hypotenuse / 2,
radius, self.height + diff_z / 2),
Point(hypotenuse / 2, -radius,
self.height + diff_z / 2),
Point(-hypotenuse / 2, -radius,
self.height - diff_z / 2)))
geom_connect.setRotation(rot_matrix_box)
geom_connect.setPosition((hypotenuse / 2.0, 0, radius))
geom_connect.setPosition((hypotenuse / 2, 0, radius))
geom_connect_transform.setGeom(geom_connect)
# sort the geoms in order of collision probability
geom.children.extend([geom_connect_transform,
......
......@@ -23,13 +23,12 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry import Matrix
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import INFINITE, epsilon
from pycam.Geometry.utils import INFINITE, epsilon, sqrt
from pycam.Geometry.intersection import intersect_sphere_plane, \
intersect_sphere_point, intersect_sphere_line, \
intersect_cylinder_point, intersect_cylinder_line
from pycam.Cutters.BaseCutter import BaseCutter
import math
try:
import OpenGL.GL as GL
......@@ -45,7 +44,7 @@ class SphericalCutter(BaseCutter):
BaseCutter.__init__(self, radius, **kwargs)
self.axis = Point(0, 0, 1)
self.center = Point(self.location.x, self.location.y,
self.location.z + radius)
self.location.z + self.radius)
def __repr__(self):
return "SphericalCutter<%s,%s>" % (self.location, self.radius)
......@@ -56,7 +55,7 @@ class SphericalCutter(BaseCutter):
import pycam.Physics.ode_physics as ode_physics
additional_distance = self.get_required_distance()
radius = self.radius + additional_distance
center_height = 0.5 * self.height + radius - additional_distance
center_height = self.height / 2 + radius - additional_distance
geom = ode.GeomTransform(None)
geom_drill = ode.GeomCapsule(None, radius, self.height)
geom_drill.setPosition((0, 0, center_height))
......@@ -69,7 +68,7 @@ class SphericalCutter(BaseCutter):
def extend_shape(diff_x, diff_y, diff_z):
reset_shape()
# see http://mathworld.wolfram.com/RotationMatrix.html
hypotenuse = math.sqrt(diff_x * diff_x + diff_y * diff_y)
hypotenuse = sqrt(diff_x * diff_x + diff_y * diff_y)
# Some paths contain two identical points (e.g. a "touch" of the
# PushCutter). We don't need any extension for these.
if hypotenuse == 0:
......@@ -88,20 +87,20 @@ class SphericalCutter(BaseCutter):
geom_connect_transform = ode.GeomTransform(geom.space)
geom_connect_transform.setBody(geom.getBody())
geom_connect = ode_physics.get_parallelepiped_geom((
Point(-hypotenuse / 2.0, radius, -diff_z / 2.0),
Point(hypotenuse / 2.0, radius, diff_z / 2.0),
Point(hypotenuse / 2.0, -radius, diff_z / 2.0),
Point(-hypotenuse / 2.0, -radius, -diff_z / 2.0)),
(Point(-hypotenuse / 2.0, radius,
self.height - diff_z / 2.0),
Point(hypotenuse / 2.0, radius,
self.height + diff_z / 2.0),
Point(hypotenuse / 2.0, -radius,
self.height + diff_z / 2.0),
Point(-hypotenuse / 2.0, -radius,
self.height - diff_z / 2.0)))
Point(-hypotenuse / 2, radius, -diff_z / 2),
Point(hypotenuse / 2, radius, diff_z / 2),
Point(hypotenuse / 2, -radius, diff_z / 2),
Point(-hypotenuse / 2, -radius, -diff_z / 2)),
(Point(-hypotenuse / 2, radius,
self.height - diff_z / 2),
Point(hypotenuse / 2, radius,
self.height + diff_z / 2),
Point(hypotenuse / 2, -radius,
self.height + diff_z / 2),
Point(-hypotenuse / 2, -radius,
self.height - diff_z / 2)))
geom_connect.setRotation(rot_matrix_box)
geom_connect.setPosition((hypotenuse / 2.0, 0, radius))
geom_connect.setPosition((hypotenuse / 2, 0, radius))
geom_connect_transform.setGeom(geom_connect)
# Create a cylinder, that connects the two half spheres at the
# lower end of both drills.
......@@ -116,7 +115,7 @@ class SphericalCutter(BaseCutter):
cyl_original_vector, cyl_destination_vector))
# The rotation is around the center - thus we ignore negative
# diff values.
geom_cyl.setPosition((abs(diff_x / 2.0), abs(diff_y / 2.0),
geom_cyl.setPosition((abs(diff_x / 2), abs(diff_y / 2),
radius - additional_distance))
geom_cyl_transform.setGeom(geom_cyl)
# sort the geoms in order of collision probability
......
......@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import INFINITE
from pycam.Geometry.utils import INFINITE, number
from pycam.Geometry.intersection import intersect_torus_plane, \
intersect_torus_point, intersect_circle_plane, intersect_circle_point, \
intersect_cylinder_point, intersect_cylinder_line, intersect_circle_line
......@@ -42,7 +42,8 @@ class ToroidalCutter(BaseCutter):
def __init__(self, radius, minorradius, **kwargs):
BaseCutter.__init__(self, radius, **kwargs)
self.majorradius = radius-minorradius
minorradius = number(minorradius)
self.majorradius = self.radius - minorradius
self.minorradius = minorradius
self.axis = Point(0, 0, 1)
self.center = Point(self.location.x, self.location.y,
......
......@@ -24,7 +24,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry import TransformableContainer
from pycam.Geometry.Point import Point
from pycam.Geometry.Plane import Plane
from pycam.Geometry.utils import epsilon
from pycam.Geometry.utils import epsilon, sqrt
import math
......@@ -97,7 +97,7 @@ class Line(TransformableContainer):
return p.sub(self.closest_point(p)).normsq
def dist_to_point(self, p):
return math.sqrt(self.dist_to_point_sq(p))
return sqrt(self.dist_to_point_sq(p))
def is_point_in_line(self, p):
return abs(p.sub(self.p1).norm + p.sub(self.p2).norm - self.len) < epsilon
......@@ -116,8 +116,8 @@ class Line(TransformableContainer):
ortho = (0.0, 1.0)
else:
ortho = (1.0 / line[0], -1.0 / line[1])
line_size = math.sqrt((line[0] ** 2) + (line[1] ** 2))
ortho_size = math.sqrt((ortho[0] ** 2) + (ortho[1] ** 2))
line_size = sqrt((line[0] ** 2) + (line[1] ** 2))
ortho_size = sqrt((ortho[0] ** 2) + (ortho[1] ** 2))
ortho_dest_size = line_size / 10.0
ortho = (ortho[0] * ortho_dest_size / ortho_size,
ortho[1] * ortho_dest_size / ortho_size)
......
......@@ -24,6 +24,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import sqrt, number
import math
......@@ -80,7 +81,7 @@ def get_length(vector):
@return: the length of a vector is the square root of the dot product
of the vector with itself
"""
return math.sqrt(get_dot_product(vector, vector))
return sqrt(get_dot_product(vector, vector))
def get_rotation_matrix_from_to(v_orig, v_dest):
""" calculate the rotation matrix used to transform one vector into another
......@@ -149,8 +150,8 @@ def get_rotation_matrix_axis_angle(rot_axis, rot_angle):
@rtype: tuple(float)
@return: the roation
"""
sin = math.sin(rot_angle)
cos = math.cos(rot_angle)
sin = number(math.sin(rot_angle))
cos = number(math.cos(rot_angle))
return ((cos + rot_axis[0]*rot_axis[0]*(1-cos),
rot_axis[0]*rot_axis[1]*(1-cos) - rot_axis[2]*sin,
rot_axis[0]*rot_axis[2]*(1-cos) + rot_axis[1]*sin),
......@@ -172,7 +173,13 @@ def multiply_vector_matrix(v, m):
@return: a tuple of 3 floats as the matrix product
"""
if len(m) == 9:
m = [number(value) for value in m]
m = ((m[0], m[1], m[2]), (m[3], m[4], m[5]), (m[6], m[7], m[8]))
else:
new_m = []
for column in m:
new_m.append([number(value) for value in column])
v = [number(value) for value in v]
return (v[0] * m[0][0] + v[1] * m[0][1] + v[2] * m[0][2],
v[0] * m[1][0] + v[1] * m[1][1] + v[2] * m[1][2],
v[0] * m[2][0] + v[1] * m[2][1] + v[2] * m[2][2])
......
......@@ -21,7 +21,8 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import math
from pycam.Geometry.utils import sqrt, number
from decimal import Decimal
def _is_near(x, y):
return abs(x - y) < 1e-6
......@@ -33,9 +34,9 @@ class Point:
def __init__(self, x, y, z):
self.id = Point.id
Point.id += 1
self.x = float(x)
self.y = float(y)
self.z = float(z)
self.x = number(x)
self.y = number(y)
self.z = number(z)
self.reset_cache()
def __repr__(self):
......@@ -74,13 +75,14 @@ class Point:
def reset_cache(self):
self.normsq = self.dot(self)
self.norm = math.sqrt(self.normsq)
self.norm = sqrt(self.normsq)
def mul(self, c):
c = number(c)
return Point(self.x * c, self.y * c, self.z * c)
def div(self, c):
c = float(c)
c = number(c)
return Point(self.x / c, self.y / c, self.z / c)
def add(self, p):
......
......@@ -24,6 +24,7 @@ from pycam.Geometry.Line import Line
from pycam.Geometry.Point import Point
from pycam.Geometry.Plane import Plane
from pycam.Geometry import TransformableContainer
from pycam.Geometry.utils import number
import pycam.Geometry.Matrix as Matrix
import math
......@@ -123,7 +124,7 @@ class Polygon(TransformableContainer):
p1 = self._points[index]
p2 = self._points[(index + 1) % len(self._points)]
value += p1.x * p2.y - p2.x * p1.y
return value / 2.0
return value / 2
def get_max_inside_distance(self):
""" calculate the maximum distance between two points of the polygon
......@@ -188,8 +189,11 @@ class Polygon(TransformableContainer):
or (len(self) != len(self._lines_cache)):
# recalculate the line cache
lines = []
for index in range(len(self._points)):
lines.append(Line(self._points[index], self._points[(index + 1) % len(self._points)]))
for index in range(len(self._points) - 1):
lines.append(Line(self._points[index], self._points[index + 1]))
# connect the last point with the first only if the polygon is closed
if self._is_closed:
lines.append(Line(self._points[-1], self._points[0]))
self._lines_cache = lines
return self._lines_cache[:]
......@@ -345,6 +349,7 @@ class Polygon(TransformableContainer):
return [new_group]
else:
return None
offset = number(offset)
if offset == 0:
return [self]
if offset * 2 >= self.get_max_inside_distance():
......
......@@ -20,11 +20,10 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from math import sqrt
#import pycam.Geometry
from pycam.Utils.polynomials import poly4_roots
from pycam.Geometry.utils import INFINITE
from pycam.Geometry.utils import INFINITE, sqrt
from pycam.Geometry.Plane import Plane
from pycam.Geometry.Line import Line
from pycam.Geometry.Point import Point
......
......@@ -20,6 +20,32 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import decimal
import math
INFINITE = 10000
epsilon = 0.0001
# use the "decimal" module for fixed precision numbers (only for debugging)
_use_precision = False
def sqrt(value):
# support precision libraries like "decimal" (built-in)
if hasattr(value, "sqrt"):
return value.sqrt()
else:
return math.sqrt(value)
def ceil(value):
if hasattr(value, "next_minus"):
return int((value + number(1).next_minus()) // 1)
else:
return int(math.ceil(value))
def number(value):
if _use_precision:
return decimal.Decimal(str(value))
else:
return float(value)
......@@ -22,6 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry.Point import Point
import pycam.Geometry.Matrix as Matrix
from pycam.Geometry.utils import sqrt, number
import pycam.Utils.log
import OpenGL.GL as GL
import OpenGL.GLU as GLU
......@@ -94,7 +95,7 @@ class Camera:
v["distance"][2]).normalized()
# The multiplier "2.0" is based on: sqrt(2) + margin -- the squre root
# makes sure, that the the diagonal fits.
distv = distv.mul((max_dim * 2.0) / math.sin(v["fovy"]/2))
distv = distv.mul((max_dim * 2) / number(math.sin(v["fovy"] / 2)))
self.view["distance"] = (distv.x, distv.y, distv.z)
# Adjust the "far" distance for the camera to make sure, that huge
# models (e.g. x=1000) are still visible.
......@@ -102,6 +103,7 @@ class Camera:
def scale_distance(self, scale):
if scale != 0:
scale = number(scale)
dist = self.view["distance"]
self.view["distance"] = (scale * dist[0], scale * dist[1],
scale * dist[2])
......@@ -128,21 +130,22 @@ class Camera:
factors_x, factors_y = self._get_axes_vectors()
width, height = self._get_screen_dimensions()
# relation of x/y movement to the respective screen dimension
win_x_rel = ((-2.0 * x_move) / width) / math.sin(self.view["fovy"])
win_y_rel = ((-2.0 * y_move) / height) / math.sin(self.view["fovy"])
win_x_rel = (-2 * x_move) / float(width) / math.sin(self.view["fovy"])
win_y_rel = (-2 * y_move) / float(height) / math.sin(self.view["fovy"])
# This code is completely arbitrarily based on trial-and-error for
# finding a nice movement speed for all distances.
# Anyone with a better approach should just fix this.
distance_vector = self.get("distance")
distance = math.sqrt(sum([dim ** 2 for dim in distance_vector]))
distance = float(sqrt(sum([dim ** 2 for dim in distance_vector])))
win_x_rel *= math.cos(win_x_rel / distance) ** 20
win_y_rel *= math.cos(win_y_rel / distance) ** 20
# update the model position that should be centered on the screen
old_center = self.view["center"]
new_center = []
for i in range(3):
new_center.append(old_center[i] + max_model_shift \
* (win_x_rel * factors_x[i] + win_y_rel * factors_y[i]))
new_center.append(old_center[i] \
+ max_model_shift * (number(win_x_rel) * factors_x[i] \
+ number(win_y_rel) * factors_y[i]))
self.view["center"] = tuple(new_center)
def rotate_camera_by_screen(self, start_x, start_y, end_x, end_y):
......@@ -212,7 +215,7 @@ class Camera:
# The "up" vector defines, in what proportion each axis of the model is
# in line with the screen's y axis.
v_up = self.view["up"]
factors_y = (v_up[0], v_up[1], v_up[2])
factors_y = (number(v_up[0]), number(v_up[1]), number(v_up[2]))
# Calculate the proportion of each model axis according to the x axis of
# the screen.
distv = self.view["distance"]
......@@ -638,10 +641,10 @@ def draw_axes(settings):
size_x = abs(settings.get("maxx"))
size_y = abs(settings.get("maxy"))
size_z = abs(settings.get("maxz"))
size = 1.7 * max(size_x, size_y, size_z)
size = number(1.7) * max(size_x, size_y, size_z)
# the divider is just based on playing with numbers
scale = size/1500.0
string_distance = 1.1 * size
scale = size / number(1500.0)
string_distance = number(1.1) * size
GL.glBegin(GL.GL_LINES)
GL.glColor3f(1, 0, 0)
GL.glVertex3f(0, 0, 0)
......
......@@ -30,6 +30,7 @@ import pycam.Toolpath.Generator
import pycam.Toolpath
import pycam.Importers
import pycam.Utils.log
from pycam.Geometry.utils import sqrt
from pycam.Gui.OpenGLTools import ModelViewWindowGL
from pycam.Toolpath import Bounds
from pycam import VERSION
......@@ -39,7 +40,6 @@ import pycam.Physics.ode_physics
import gtk
import webbrowser
import ConfigParser
import math
import time
import logging
import datetime
......@@ -2260,8 +2260,8 @@ class ProjectGui:
# proportion = dimension_x / dimension_y
proportion = (bounding_box["maxx"] - bounding_box["minx"]) \
/ (bounding_box["maxy"] - bounding_box["miny"])
x_steps = int(math.sqrt(grid_size) * proportion)
y_steps = int(math.sqrt(grid_size) / proportion)
x_steps = int(sqrt(grid_size) * proportion)
y_steps = int(sqrt(grid_size) / proportion)
simulation_backend = ODEBlocks.ODEBlocks(toolpath.get_tool_settings(),
toolpath.get_bounding_box(), x_steps=x_steps, y_steps=y_steps)
self.settings.set("simulation_object", simulation_backend)
......
......@@ -20,6 +20,8 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry.utils import sqrt
import math
import sys
......@@ -215,10 +217,10 @@ def mouseMoved(x, y):
x = float(x)
y = float(y)
a1 = math.atan2(mouseState.y-height/2.0, mouseState.x-width/2.0)
r1 = math.sqrt((mouseState.y - height / 2.0) ** 2 \
r1 = sqrt((mouseState.y - height / 2.0) ** 2 \
+ (mouseState.x - width / 2.0) ** 2)
a2 = math.atan2(y-height/2.0, x-width/2.0)
r2 = math.sqrt((y - height / 2.0) ** 2 + (x - width / 2.0) ** 2)
r2 = sqrt((y - height / 2.0) ** 2 + (x - width / 2.0) ** 2)
if (mouseState.button == GLUT.GLUT_LEFT_BUTTON) \
or (mouseState.button == GLUT.GLUT_RIGHT_BUTTON):
a3 = math.acos(mouseState.x/width-0.5)
......
......@@ -22,11 +22,10 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry import Point
from pycam.Geometry.utils import INFINITE
from pycam.Geometry.utils import INFINITE, ceil
from pycam.PathGenerators import get_max_height_triangles, get_max_height_ode
from pycam.Utils import ProgressCounter
import pycam.Utils.log
import math
log = pycam.Utils.log.get_logger()
......@@ -78,8 +77,8 @@ class DropCutter:
direction, draw_callback=None):
quit_requested = False
# determine step size
num_of_x_lines = 1 + int(math.ceil(abs(maxx - minx) / d0))
num_of_y_lines = 1 + int(math.ceil(abs(maxy - miny) / d1))
num_of_x_lines = 1 + ceil(abs(maxx - minx) / d0)
num_of_y_lines = 1 + ceil(abs(maxy - miny) / d1)
x_step = abs(maxx - minx) / max(1, (num_of_x_lines - 1))
y_step = abs(maxy - miny) / max(1, (num_of_y_lines - 1))
x_steps = [(minx + i * x_step) for i in range(num_of_x_lines)]
......@@ -113,8 +112,7 @@ class DropCutter:
last_position = None
if draw_callback and draw_callback(text="DropCutter: processing " \
+ "line %d/%d" % (current_line, num_of_lines),
percent=(100.0 * current_line / num_of_lines)):
+ "line %d/%d" % (current_line, num_of_lines)):
# cancel requested
quit_requested = True
break
......
......@@ -23,12 +23,11 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
import pycam.PathProcessors.PathAccumulator
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import INFINITE
from pycam.Geometry.utils import INFINITE, ceil
from pycam.PathGenerators import get_max_height_triangles, get_max_height_ode, \
get_free_paths_ode, get_free_paths_triangles
from pycam.Utils import ProgressCounter
import pycam.Utils.log
import math
log = pycam.Utils.log.get_logger()
......@@ -51,7 +50,7 @@ class EngraveCutter:
def GenerateToolPath(self, minz, maxz, horiz_step, dz, draw_callback=None):
quit_requested = False
# calculate the number of steps
num_of_layers = 1 + int(math.ceil(abs(maxz - minz) / dz))
num_of_layers = 1 + ceil(abs(maxz - minz) / dz)
if num_of_layers > 1:
z_step = abs(maxz - minz) / (num_of_layers - 1)
z_steps = [(maxz - i * z_step) for i in range(num_of_layers)]
......@@ -78,7 +77,7 @@ class EngraveCutter:
break
for line_group in line_groups:
for line in line_group.next():
for line in line_group.get_lines():
self.GenerateToolPathLinePush(self.pa_push, line, z,
draw_callback)
if progress_counter.increment():
......@@ -150,7 +149,7 @@ class EngraveCutter:
p2 = Point(line.p2.x, line.p2.y, minz)
distance = line.len
# we want to have at least five steps each
num_of_steps = max(5, 1 + int(math.ceil(distance / horiz_step)))
num_of_steps = max(5, 1 + ceil(distance / horiz_step))
# steps may be negative
x_step = (p2.x - p1.x) / (num_of_steps - 1)
y_step = (p2.y - p1.y) / (num_of_steps - 1)
......
......@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry.Point import Point
from pycam.PathGenerators import get_free_paths_ode, get_free_paths_triangles
from pycam.Geometry.utils import epsilon
from pycam.Geometry.utils import epsilon, ceil
from pycam.Utils import ProgressCounter
import math
......@@ -45,16 +45,16 @@ class PushCutter:
diff_z = 0
else:
diff_z = abs(maxz - minz)
num_of_layers = 1 + int(math.ceil(diff_z / dz))
num_of_layers = 1 + ceil(diff_z / dz)
z_step = diff_z / max(1, (num_of_layers - 1))
lines_per_layer = 0
if dx != 0:
x_lines_per_layer = 1 + int(math.ceil(abs(maxx - minx) / dx))
x_lines_per_layer = 1 + ceil(abs(maxx - minx) / dx)
x_step = abs(maxx - minx) / max(1, (x_lines_per_layer - 1))
lines_per_layer += x_lines_per_layer
if dy != 0:
y_lines_per_layer = 1 + int(math.ceil(abs(maxy - miny) / dy))
y_lines_per_layer = 1 + ceil(abs(maxy - miny) / dy)
y_step = abs(maxy - miny) / max(1, (y_lines_per_layer - 1))
lines_per_layer += y_lines_per_layer
......@@ -98,17 +98,17 @@ class PushCutter:
# calculate the required number of steps in each direction
if dx > 0:
depth_x = math.log(accuracy * abs(maxx - minx) / dx) / math.log(2)
depth_x = max(int(math.ceil(depth_x)), 4)
depth_x = max(ceil(depth_x), 4)
depth_x = min(depth_x, max_depth)
num_of_x_lines = 1 + int(math.ceil(abs(maxx - minx) / dx))
num_of_x_lines = 1 + ceil(abs(maxx - minx) / dx)
x_step = abs(maxx - minx) / max(1, (num_of_x_lines - 1))
x_steps = [minx + i * x_step for i in range(num_of_x_lines)]
y_steps = [None] * num_of_x_lines
else:
depth_y = math.log(accuracy * abs(maxy - miny) / dy) / math.log(2)
depth_y = max(int(math.ceil(depth_y)), 4)
depth_y = max(ceil(depth_y), 4)
depth_y = min(depth_y, max_depth)
num_of_y_lines = 1 + int(math.ceil(abs(maxy - miny) / dy))
num_of_y_lines = 1 + ceil(abs(maxy - miny) / dy)
y_step = abs(maxy - miny) / max(1, (num_of_y_lines - 1))
y_steps = [miny + i * y_step for i in range(num_of_y_lines)]
x_steps = [None] * num_of_y_lines
......
......@@ -22,9 +22,8 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__ = ["DropCutter", "PushCutter", "EngraveCutter"]
from pycam.Geometry.utils import INFINITE, epsilon
from pycam.Geometry.utils import INFINITE, epsilon, sqrt
from pycam.Geometry.Point import Point
import math
class Hit:
......@@ -43,7 +42,7 @@ def get_free_paths_triangles(model, cutter, p1, p2):
x_dist = p2.x - p1.x
y_dist = p2.y - p1.y
z_dist = p2.z - p1.z
xyz_dist = math.sqrt(x_dist * x_dist + y_dist * y_dist + z_dist * z_dist)
xyz_dist = sqrt(x_dist * x_dist + y_dist * y_dist + z_dist * z_dist)
x_frac = x_dist / xyz_dist
y_frac = y_dist / xyz_dist
z_frac = z_dist / xyz_dist
......@@ -134,9 +133,9 @@ def get_free_paths_ode(physics, p1, p2, depth=8):
if physics.check_collision():
# collision detected
if depth > 0:
middle_x = (p1.x + p2.x) / 2.0
middle_y = (p1.y + p2.y) / 2.0
middle_z = (p1.z + p2.z) / 2.0
middle_x = (p1.x + p2.x) / 2
middle_y = (p1.y + p2.y) / 2
middle_z = (p1.z + p2.z) / 2
p_middle = Point(middle_x, middle_y, middle_z)
group1 = get_free_paths_ode(physics, p1, p_middle, depth - 1)
group2 = get_free_paths_ode(physics, p_middle, p2, depth - 1)
......@@ -186,7 +185,7 @@ def get_max_height_ode(physics, x, y, minz, maxz, order=None):
trips = 0
safe_z = minz
while trips > 0:
current_z = (low + high) / 2.0
current_z = (low + high) / 2
physics.set_drill_position((x, y, current_z))
if physics.check_collision():
low = current_z
......
......@@ -21,6 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.utils import number
try:
import ode
......@@ -146,7 +147,7 @@ class PhysicalWorld:
# the cutters' "extend" functions
shape.space = self._space
self._add_geom(shape, position, append=False)
self._drill_offset = position
self._drill_offset = [number(value) for value in position]
self._drill = shape
self.reset_drill()
......
......@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import math
from pycam.Geometry.utils import sqrt
from pycam.Geometry.Point import Point
import ctypes
......@@ -93,10 +93,10 @@ class ZBuffer:
def add_wave(self, freq=8, damp=3.0):
self.changed = True
rmax = math.sqrt(self.y[0]*self.y[0]+self.x[0]*self.x[0])
rmax = sqrt(self.y[0]*self.y[0]+self.x[0]*self.x[0])
for y in range(0, self.yres):
for x in range(0, self.xres):
r = math.sqrt(self.y[y]*self.y[y]+self.x[x]*self.x[x])
r = sqrt(self.y[y]*self.y[y]+self.x[x]*self.x[x])
self.buf[y][x].z = 1 + math.cos(r / rmax * r / rmax * math.pi \
* freq) / (1 + damp * (r / rmax))
self.buf[y][x].changed = True
......
......@@ -21,6 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.PathGenerators import DropCutter, PushCutter, EngraveCutter
from pycam.Geometry.utils import number
import pycam.PathProcessors
import pycam.Cutters
import pycam.Toolpath.SupportGrid
......@@ -57,8 +58,8 @@ def generate_toolpath_from_settings(model, tp_settings, callback=None):
def generate_toolpath(model, tool_settings=None,
bounds_low=None, bounds_high=None, direction="x",
path_generator="DropCutter", path_postprocessor="ZigZagCutter",
material_allowance=0.0, safety_height=None, overlap=0.0, step_down=0.0,
engrave_offset=0.0, support_grid_distance_x=None,
material_allowance=0, safety_height=None, overlap=0, step_down=0,
engrave_offset=0, support_grid_distance_x=None,
support_grid_distance_y=None, support_grid_thickness=None,
support_grid_height=None, support_grid_offset_x=None,
support_grid_offset_y=None, support_grid_adjustments_x=None,
......@@ -116,16 +117,20 @@ def generate_toolpath(model, tool_settings=None,
@return: the resulting toolpath object or an error string in case of invalid
arguments
"""
overlap = number(overlap)
step_down = number(step_down)
safety_height = number(safety_height)
engrave_offset = number(engrave_offset)
if bounds_low is None:
# no bounds were given - we use the boundaries of the model
minx, miny, minz = (model.minx, model.miny, model.minz)
else:
minx, miny, minz = bounds_low
minx, miny, minz = [number(value) for value in bounds_low]
if bounds_high is None:
# no bounds were given - we use the boundaries of the model
maxx, maxy, maxz = (model.maxx, model.maxy, model.maxz)
else:
maxx, maxy, maxz = bounds_high
maxx, maxy, maxz = [number(value) for value in bounds_high]
# trimesh model or contour model?
if isinstance(model, pycam.Geometry.Model.Model):
# trimesh model
......@@ -136,7 +141,7 @@ def generate_toolpath(model, tool_settings=None,
trimesh_model = pycam.Geometry.Model.Model()
contour_model = model
# material allowance is ignored for engraving
material_allowance = 0.0
material_allowance = 0
# create the grid model if requested
if (((not support_grid_distance_x is None) \
or (not support_grid_distance_y is None)) \
......@@ -220,7 +225,7 @@ def generate_toolpath(model, tool_settings=None,
if (overlap < 0) or (overlap >= 1):
return "Invalid overlap value (%f): should be greater or equal 0 " \
+ "and lower than 1"
effective_toolradius = tool_settings["tool_radius"] * (1.0 - overlap)
effective_toolradius =number(tool_settings["tool_radius"]) * (1 - overlap)
if path_generator == "DropCutter":
if direction == "x":
direction_param = 0
......@@ -230,6 +235,7 @@ def generate_toolpath(model, tool_settings=None,
return "Invalid direction value (%s): not one of %s" \
% (direction, DIRECTIONS)
if safety_height < maxz:
print "%s / %s / %s / %s" % (safety_height, maxz, type(safety_height), type(maxz))
return ("Safety height (%.4f) is within the bounding box height " \
+ "(%.4f) - this can cause collisions of the tool with " \
+ "the material.") % (safety_height, maxz)
......
......@@ -24,6 +24,7 @@ from pycam.Geometry.Point import Point
from pycam.Geometry.Line import Line
from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.Model import Model
from pycam.Geometry.utils import number
def _add_cuboid_to_model(minx, maxx, miny, maxy, minz, maxz):
......@@ -88,16 +89,21 @@ def get_support_grid_locations(minx, maxx, miny, maxy, dist_x, dist_y,
# remove lines that are out of range (e.g. due to a huge offset)
lines = [line for line in lines if min_value < line < max_value]
return lines
center_x = (maxx + minx) / 2.0 + offset_x
center_y = (maxy + miny) / 2.0 + offset_y
# convert all inputs to the type defined in "number"
dist_x = number(dist_x)
dist_y = number(dist_y)
offset_x = number(offset_x)
offset_y = number(offset_y)
center_x = (maxx + minx) / 2 + offset_x
center_y = (maxy + miny) / 2 + offset_y
lines_x = get_lines(center_x, dist_x, minx, maxx)
lines_y = get_lines(center_y, dist_y, miny, maxy)
if adjustments_x:
for index in range(min(len(lines_x), len(adjustments_x))):
lines_x[index] += adjustments_x[index]
lines_x[index] += number(adjustments_x[index])
if adjustments_y:
for index in range(min(len(lines_y), len(adjustments_y))):
lines_y[index] += adjustments_y[index]
lines_y[index] += number(adjustments_y[index])
return lines_x, lines_y
def get_support_grid(minx, maxx, miny, maxy, z_plane, dist_x, dist_y, thickness,
......@@ -107,8 +113,11 @@ def get_support_grid(minx, maxx, miny, maxy, z_plane, dist_x, dist_y, thickness,
dist_y, offset_x, offset_y, adjustments_x, adjustments_y)
# create all x grid lines
grid_model = Model()
# convert all inputs to "number"
thickness = number(thickness)
height = number(height)
# helper variables
thick_half = thickness / 2.0
thick_half = thickness / 2
length_extension = max(thickness, height)
for line_x in lines_x:
# we make the grid slightly longer (by thickness) than necessary
......
......@@ -23,6 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__ = ["simplify_toolpath", "ToolPathList", "ToolPath", "Generator"]
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import number
import pycam.Utils.log
import random
import os
......@@ -113,7 +114,7 @@ class ToolPath:
settings = self.toolpath_settings
if start_position is None:
start_position = Point(0, 0, 0)
feedrate = settings.get_tool_settings()["feedrate"]
feedrate = number(settings.get_tool_settings()["feedrate"])
result = {}
result["time"] = 0
result["position"] = start_position
......@@ -121,7 +122,7 @@ class ToolPath:
result["time"] += new_pos.sub(result["position"]).norm / feedrate
result["position"] = new_pos
# move to safey height at the starting position
safety_height = settings.get_process_settings()["safety_height"]
safety_height = number(settings.get_process_settings()["safety_height"])
move(Point(start_position.x, start_position.y, safety_height))
for path in self.get_path():
# go to safety height (horizontally from the previous x/y location)
......@@ -214,14 +215,14 @@ class Bounds:
raise ValueError, "lower bounds should be supplied as a " \
+ "tuple/list of 3 items - but %d were given" % len(low)
else:
self.bounds_low = list(low[:])
self.bounds_low = [number(value) for value in low]
if not high is None:
if len(high) != 3:
raise ValueError, "upper bounds should be supplied as a " \
+ "tuple/list of 3 items - but %d were given" \
% len(high)
else:
self.bounds_high = list(high[:])
self.bounds_high = [number(value) for value in high]
def get_absolute_limits(self, reference=None):
""" calculate the current absolute limits of the Bounds instance
......@@ -262,8 +263,8 @@ class Bounds:
high[index] = ref_high[index] + self.bounds_high[index]
elif self.bounds_type == Bounds.TYPE_CUSTOM:
for index in range(3):
low[index] = self.bounds_low[index]
high[index] = self.bounds_high[index]
low[index] = number(self.bounds_low[index])
high[index] = number(self.bounds_high[index])
else:
# this should not happen
raise NotImplementedError, "the function 'get_absolute_limits' is" \
......
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