Commit 51b188e7 authored by sumpfralle's avatar sumpfralle

added bezier style polylines for DXF importer (not finished)


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@1207 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 9c4e1e1d
...@@ -120,6 +120,60 @@ def get_points_of_arc(center, radius, a1, a2, plane=None, cords=32): ...@@ -120,6 +120,60 @@ def get_points_of_arc(center, radius, a1, a2, plane=None, cords=32):
points.append(get_angle_point(a1 + angle_segment * (index + 1))) points.append(get_angle_point(a1 + angle_segment * (index + 1)))
return points return points
def get_bezier_lines(points_with_bulge, segments=32):
# TODO: add a recursive algorithm for more than two points
if len(points_with_bulge) != 2:
return []
else:
result_points = []
p1, bulge1 = points_with_bulge[0]
p2, bulge2 = points_with_bulge[1]
if not bulge1 and not bulge2:
# straight line
return [Line.Line(p1, p2)]
straight_dir = p2.sub(p1).normalized()
bulge1 = max(-1.0, min(1.0, bulge1))
# bulge=1 -> 90 degree; bulge: -1..1
angle = -90 * bulge1
rot_matrix = Matrix.get_rotation_matrix_axis_angle((0, 0, 1),
angle, use_radians=False)
dir1_mat = Matrix.multiply_vector_matrix((straight_dir.x,
straight_dir.y, straight_dir.z), rot_matrix)
dir1 = Point.Vector(dir1_mat[0], dir1_mat[1], dir1_mat[2])
if bulge2 is None:
bulge2 = bulge1
bulge2 = max(-1.0, min(1.0, bulge2))
angle = 90 * bulge2
rot_matrix = Matrix.get_rotation_matrix_axis_angle((0, 0, 1),
angle, use_radians=False)
dir2_mat = Matrix.multiply_vector_matrix((straight_dir.x,
straight_dir.y, straight_dir.z), rot_matrix)
dir2 = Point.Vector(dir2_mat[0], dir2_mat[1], dir2_mat[2])
# this length calculation for the tangents results from a bit of try-and-error
alpha = math.atan(bulge1) * 4
dist = p2.sub(p1).norm / 2.0
radius = abs(dist / math.sin(alpha / 2.0))
factor = math.sqrt(2) * 2 * (radius ** 2 - dist ** 2)
if factor < epsilon:
factor = 4 * dist
dir1 = dir1.mul(factor)
dir2 = dir2.mul(factor)
for index in range(segments + 1):
# t: 0..1
t = float(index) / segments
# see: http://en.wikipedia.org/wiki/Cubic_Hermite_spline
p = p1.mul(2 * t ** 3 - 3 * t ** 2 + 1).add(
dir1.mul(t ** 3 - 2 * t ** 2 + t).add(
p2.mul(-2 * t ** 3 + 3 * t ** 2).add(
dir2.mul(t ** 3 - t ** 2))))
result_points.append(p)
# create lines
result = []
for index in range(len(result_points) - 1):
result.append(Line.Line(result_points[index],
result_points[index + 1]))
return result
class TransformableContainer(object): class TransformableContainer(object):
""" a base class for geometrical objects containing other elements """ a base class for geometrical objects containing other elements
......
...@@ -35,6 +35,7 @@ import os ...@@ -35,6 +35,7 @@ import os
log = pycam.Utils.log.get_logger() log = pycam.Utils.log.get_logger()
def _unescape_control_characters(text): def _unescape_control_characters(text):
# see http://www.kxcad.net/autodesk/autocad/AutoCAD_2008_Command_Reference/d0e73428.htm # see http://www.kxcad.net/autodesk/autocad/AutoCAD_2008_Command_Reference/d0e73428.htm
# and QCad: qcadlib/src/filters/rs_filterdxf.cpp # and QCad: qcadlib/src/filters/rs_filterdxf.cpp
...@@ -71,15 +72,18 @@ class DXFParser(object): ...@@ -71,15 +72,18 @@ class DXFParser(object):
"RADIUS": 40, "RADIUS": 40,
"TEXT_HEIGHT": 40, "TEXT_HEIGHT": 40,
"TEXT_WIDTH_FINAL": 41, "TEXT_WIDTH_FINAL": 41,
"VERTEX_BULGE": 42,
"ANGLE_START": 50, "ANGLE_START": 50,
"TEXT_ROTATION": 50, "TEXT_ROTATION": 50,
"ANGLE_END": 51, "ANGLE_END": 51,
"TEXT_SKEW_ANGLE": 51, "TEXT_SKEW_ANGLE": 51,
"COLOR": 62, "COLOR": 62,
"VERTEX_FLAGS": 70,
"TEXT_MIRROR_FLAGS": 71, "TEXT_MIRROR_FLAGS": 71,
"MTEXT_ALIGNMENT": 71, "MTEXT_ALIGNMENT": 71,
"TEXT_ALIGN_HORIZONTAL": 72, "TEXT_ALIGN_HORIZONTAL": 72,
"TEXT_ALIGN_VERTICAL": 73, "TEXT_ALIGN_VERTICAL": 73,
"CURVE_TYPE": 75,
} }
IGNORE_KEYS = ("DICTIONARY", "VPORT", "LTYPE", "STYLE", "APPID", "DIMSTYLE", IGNORE_KEYS = ("DICTIONARY", "VPORT", "LTYPE", "STYLE", "APPID", "DIMSTYLE",
...@@ -104,6 +108,7 @@ class DXFParser(object): ...@@ -104,6 +108,7 @@ class DXFParser(object):
self._fonts_cache = fonts_cache self._fonts_cache = fonts_cache
self._open_sequence = None self._open_sequence = None
self._open_sequence_items = [] self._open_sequence_items = []
self._open_sequence_params = {}
# run the parser # run the parser
self.parse_content() self.parse_content()
self.optimize_line_order() self.optimize_line_order()
...@@ -184,7 +189,7 @@ class DXFParser(object): ...@@ -184,7 +189,7 @@ class DXFParser(object):
if line1 in [self.KEYS[key] for key in ("P1_X", "P1_Y", "P1_Z", if line1 in [self.KEYS[key] for key in ("P1_X", "P1_Y", "P1_Z",
"P2_X", "P2_Y", "P2_Z", "RADIUS", "ANGLE_START", "ANGLE_END", "P2_X", "P2_Y", "P2_Z", "RADIUS", "ANGLE_START", "ANGLE_END",
"TEXT_HEIGHT", "TEXT_WIDTH_FINAL", "TEXT_ROTATION", "TEXT_HEIGHT", "TEXT_WIDTH_FINAL", "TEXT_ROTATION",
"TEXT_SKEW_ANGLE")]: "TEXT_SKEW_ANGLE", "VERTEX_BULGE")]:
try: try:
line2 = float(line2) line2 = float(line2)
except ValueError: except ValueError:
...@@ -194,7 +199,7 @@ class DXFParser(object): ...@@ -194,7 +199,7 @@ class DXFParser(object):
line2 = None line2 = None
elif line1 in [self.KEYS[key] for key in ("COLOR", "TEXT_MIRROR_FLAGS", elif line1 in [self.KEYS[key] for key in ("COLOR", "TEXT_MIRROR_FLAGS",
"TEXT_ALIGN_HORIZONTAL", "TEXT_ALIGN_VERTICAL", "TEXT_ALIGN_HORIZONTAL", "TEXT_ALIGN_VERTICAL",
"MTEXT_ALIGNMENT")]: "MTEXT_ALIGNMENT", "CURVE_TYPE", "VERTEX_FLAGS")]:
try: try:
line2 = int(line2) line2 = int(line2)
except ValueError: except ValueError:
...@@ -273,6 +278,7 @@ class DXFParser(object): ...@@ -273,6 +278,7 @@ class DXFParser(object):
start_line = self.line_number start_line = self.line_number
point = [None, None, 0] point = [None, None, 0]
color = None color = None
bulge = None
key, value = self._read_key_value() key, value = self._read_key_value()
while (not key is None) and (key != self.KEYS["MARKER"]): while (not key is None) and (key != self.KEYS["MARKER"]):
if key == self.KEYS["P1_X"]: if key == self.KEYS["P1_X"]:
...@@ -283,6 +289,8 @@ class DXFParser(object): ...@@ -283,6 +289,8 @@ class DXFParser(object):
point[2] = value point[2] = value
elif key == self.KEYS["COLOR"]: elif key == self.KEYS["COLOR"]:
color = value color = value
elif key == self.KEYS["VERTEX_BULGE"]:
bulge = value
else: else:
pass pass
key, value = self._read_key_value() key, value = self._read_key_value()
...@@ -297,33 +305,51 @@ class DXFParser(object): ...@@ -297,33 +305,51 @@ class DXFParser(object):
"between line %d and %d" % (start_line, end_line)) "between line %d and %d" % (start_line, end_line))
else: else:
self._open_sequence_items.append( self._open_sequence_items.append(
Point(point[0], point[1], point[2])) (Point(point[0], point[1], point[2]), bulge))
def parse_polyline(self, init): def parse_polyline(self, init):
start_line = self.line_number start_line = self.line_number
params = self._open_sequence_params
if init: if init:
self._open_sequence = "POLYLINE" self._open_sequence = "POLYLINE"
self._open_sequence_items = [] self._open_sequence_items = []
key, value = self._read_key_value() key, value = self._read_key_value()
while (not key is None) and (key != self.KEYS["MARKER"]): while (not key is None) and (key != self.KEYS["MARKER"]):
if key == self.KEYS["CURVE_TYPE"]:
if value == 8:
params["CURVE_TYPE"] = "BEZIER"
elif key == self.KEYS["VERTEX_FLAGS"]:
if value == 1:
params["VERTEX_FLAGS"] = "EXTRA_VERTEX"
key, value = self._read_key_value() key, value = self._read_key_value()
if not key is None: if not key is None:
self._push_on_stack(key, value) self._push_on_stack(key, value)
else: else:
# closing # closing
points = self._open_sequence_items if ("CURVE_TYPE" in params) and (params["CURVE_TYPE"] == "BEZIER"):
self.lines.extend(pycam.Geometry.get_bezier_lines(
self._open_sequence_items))
if ("VERTEX_FLAGS" in params) and \
(params["VERTEX_FLAGS"] == "EXTRA_VERTEX"):
# repeat the same polyline on the other side
self._open_sequence_items.reverse()
self.lines.extend(pycam.Geometry.get_bezier_lines(
self._open_sequence_items))
else:
points = [p for p, bulge in self._open_sequence_items]
for index in range(len(points) - 1): for index in range(len(points) - 1):
point = points[index] point = points[index]
next_point = points[index + 1] next_point = points[index + 1]
if point != next_point: if point != next_point:
self.lines.append(Line(point, next_point)) self.lines.append(Line(point, next_point))
self._open_sequence_items = [] self._open_sequence_items = []
self._open_sequence_params = {}
self._open_sequence = None self._open_sequence = None
def parse_lwpolyline(self): def parse_lwpolyline(self):
start_line = self.line_number start_line = self.line_number
points = [] points = []
def add_point(p_array): def add_point(p_array, bulge):
# fill all "None" values with zero # fill all "None" values with zero
for index in range(len(p_array)): for index in range(len(p_array)):
if p_array[index] is None: if p_array[index] is None:
...@@ -332,8 +358,10 @@ class DXFParser(object): ...@@ -332,8 +358,10 @@ class DXFParser(object):
"date in line %d: %s" % \ "date in line %d: %s" % \
(self.line_number, p_array)) (self.line_number, p_array))
p_array[index] = 0 p_array[index] = 0
points.append(Point(p_array[0], p_array[1], p_array[2])) points.append((Point(p_array[0], p_array[1], p_array[2]), bulge))
current_point = [None, None, None] current_point = [None, None, None]
bulge = None
extra_vertex_flag = False
key, value = self._read_key_value() key, value = self._read_key_value()
while (not key is None) and (key != self.KEYS["MARKER"]): while (not key is None) and (key != self.KEYS["MARKER"]):
if key == self.KEYS["P1_X"]: if key == self.KEYS["P1_X"]:
...@@ -346,6 +374,13 @@ class DXFParser(object): ...@@ -346,6 +374,13 @@ class DXFParser(object):
# interpret the color as the height # interpret the color as the height
axis = 2 axis = 2
value = float(value) / 255 value = float(value) / 255
elif key == self.KEYS["VERTEX_BULGE"]:
bulge = value
axis = None
elif key == self.KEYS["VERTEX_FLAGS"]:
if value == 1:
extra_vertex_flag = True
axis = None
else: else:
axis = None axis = None
if not axis is None: if not axis is None:
...@@ -354,9 +389,10 @@ class DXFParser(object): ...@@ -354,9 +389,10 @@ class DXFParser(object):
current_point[axis] = value current_point[axis] = value
else: else:
# The current point seems to be complete. # The current point seems to be complete.
add_point(current_point) add_point(current_point, bulge)
current_point = [None, None, None] current_point = [None, None, None]
current_point[axis] = value current_point[axis] = value
bulge = None
key, value = self._read_key_value() key, value = self._read_key_value()
end_line = self.line_number end_line = self.line_number
# The last lines were not used - they are just the marker for the next # The last lines were not used - they are just the marker for the next
...@@ -365,16 +401,24 @@ class DXFParser(object): ...@@ -365,16 +401,24 @@ class DXFParser(object):
self._push_on_stack(key, value) self._push_on_stack(key, value)
# check if there is a remaining item in "current_point" # check if there is a remaining item in "current_point"
if len(current_point) != current_point.count(None): if len(current_point) != current_point.count(None):
add_point(current_point) add_point(current_point, bulge)
if len(points) < 2: if len(points) < 2:
# too few points for a polyline # too few points for a polyline
log.warn("DXFImporter: Empty LWPOLYLINE definition between line " \ log.warn("DXFImporter: Empty LWPOLYLINE definition between line " \
+ "%d and %d" % (start_line, end_line)) + "%d and %d" % (start_line, end_line))
else: else:
for index in range(len(points) - 1): for index in range(len(points) - 1):
point = points[index] point, bulge = points[index]
next_point = points[index + 1] next_point, next_bulge = points[index + 1]
if point != next_point: if point != next_point:
if bulge or next_bulge:
self.lines.extend(pycam.Geometry.get_bezier_lines(
((point, bulge), (next_point, next_bulge))))
if extra_vertex_flag:
self.lines.extend(pycam.Geometry.get_bezier_lines(
((next_point, next_bulge), (point, bulge))))
else:
# straight line
self.lines.append(Line(point, next_point)) self.lines.append(Line(point, next_point))
else: else:
log.warn("DXFImporter: Ignoring zero-length LINE " \ log.warn("DXFImporter: Ignoring zero-length LINE " \
......
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