Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'io_import_dxf/dxfimport/convert.py')
-rw-r--r--io_import_dxf/dxfimport/convert.py287
1 files changed, 287 insertions, 0 deletions
diff --git a/io_import_dxf/dxfimport/convert.py b/io_import_dxf/dxfimport/convert.py
new file mode 100644
index 00000000..64df5c35
--- /dev/null
+++ b/io_import_dxf/dxfimport/convert.py
@@ -0,0 +1,287 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import itertools
+from . import is_
+from .fake_entities import ArcEntity
+from mathutils import Vector, Matrix, Euler, Color
+from math import pi, radians, floor, ceil, degrees
+from copy import deepcopy
+
+
+class ShortVec(Vector):
+ def __str__(self):
+ return "Vec" + str((round(self.x, 2), round(self.y, 2), round(self.z, 2)))
+
+ def __repr__(self):
+ return self.__str__()
+
+
+def bspline_to_cubic(do, en, curve, errors=None):
+ """
+ do: an instance of Do()
+ en: a DXF entity
+ curve: Blender geometry data of type "CURVE"
+ inserts knots until every knot has multiplicity of 3; returns new spline controlpoints
+ if degree of the spline is > 3 "None" is returned
+ """
+ def clean_knots():
+ start = knots[:degree + 1]
+ end = knots[-degree - 1:]
+
+ if start.count(start[0]) < degree + 1:
+ maxa = max(start)
+ for i in range(degree + 1):
+ knots[i] = maxa
+
+ if end.count(end[0]) < degree + 1:
+ mina = min(end)
+ lenk = len(knots)
+ for i in range(lenk - degree - 1, lenk):
+ knots[i] = mina
+
+ def insert_knot(t, k, p):
+ """ http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/NURBS-knot-insert.html """
+ def a(t, ui, uip):
+ if uip == ui:
+ print("zero!")
+ return 0
+ return (t - ui) / (uip - ui)
+
+ new_spline = spline.copy()
+ for pp in range(p, 1, -1):
+ i = k - pp + 1
+ ai = a(t, knots[i], knots[i + p])
+ new_spline[i] = (1 - ai) * spline[i - 1] + ai * spline[i]
+
+ ai = a(t, knots[k], knots[k + p])
+ new_spline.insert(k, (1 - ai) * spline[k - 1] + ai * spline[k % len(spline)])
+ knots.insert(k, t)
+
+ return new_spline
+
+ knots = list(en.knots)
+ spline = [ShortVec(cp) for cp in en.controlpoints]
+ degree = len(knots) - len(spline) - 1
+ if degree <= 3:
+ clean_knots()
+ k = 1
+ st = 1
+ while k < len(knots) - 1:
+ t = knots[k]
+ multilen = knots[st:-st].count(t)
+ if multilen < degree:
+ before = multilen
+ while multilen < degree:
+ spline = insert_knot(t, k, degree)
+ multilen += 1
+ k += 1
+ k += before
+ else:
+ k += degree
+
+ if degree <= 2:
+ return quad_to_cube(spline)
+
+ # the ugly truth
+ if len(spline) % 3 == 0:
+ spline.append([spline[-1]])
+ errors.add("Cubic spline: Something went wrong with knot insertion")
+ return spline
+
+
+def quad_to_cube(spline):
+ """
+ spline: list of (x,y,z)-tuples)
+ Converts quad bezier to cubic bezier curve.
+ """
+ s = []
+ for i, p in enumerate(spline):
+ if i % 2 == 1:
+ before = Vector(spline[i - 1])
+ after = Vector(spline[(i + 1) % len(spline)])
+ s.append(before + 2 / 3 * (Vector(p) - before))
+ s.append(after + 2 / 3 * (Vector(p) - after))
+ else:
+ s.append(p)
+
+ # degree == 1
+ if len(spline) == 2:
+ s.append(spline[-1])
+ return s
+
+
+def bulge_to_arc(point, next, bulge):
+ """
+ point: start point of segment in lwpolyline
+ next: end point of segment in lwpolyline
+ bulge: number between 0 and 1
+ Converts a bulge of lwpolyline to an arc with a bulge describing the amount of how much a straight segment should
+ be bended to an arc. With the bulge one can find the center point of the arc that replaces the segment.
+ """
+
+ rot = Matrix(((0, -1, 0), (1, 0, 0), (0, 0, 1)))
+ section = next - point
+ section_length = section.length / 2
+ direction = -bulge / abs(bulge)
+ correction = 1
+ sagitta_len = section_length * abs(bulge)
+ radius = (sagitta_len**2 + section_length**2) / (2 * sagitta_len)
+ if sagitta_len < radius:
+ cosagitta_len = radius - sagitta_len
+ else:
+ cosagitta_len = sagitta_len - radius
+ direction *= -1
+ correction *= -1
+ center = point + section / 2 + section.normalized() * cosagitta_len * rot * direction
+ cp = point - center
+ cn = next - center
+ cr = cp.to_3d().cross(cn.to_3d()) * correction
+ start = Vector((1, 0))
+ if cr[2] > 0:
+ angdir = 0
+ startangle = -start.angle_signed(cp.to_2d())
+ endangle = -start.angle_signed(cn.to_2d())
+ else:
+ angdir = 1
+ startangle = start.angle_signed(cp.to_2d())
+ endangle = start.angle_signed(cn.to_2d())
+ return ArcEntity(startangle, endangle, center.to_3d(), radius, angdir)
+
+
+def bulgepoly_to_cubic(do, lwpolyline):
+ """
+ do: instance of Do()
+ lwpolyline: DXF entity of type polyline
+ Bulges define how much a straight segment of a polyline should be transformed to an arc. Hence do.arc() is called
+ for segments with a bulge and all segments are being connected to a cubic bezier curve in the end.
+ Reference: http://www.afralisp.net/archive/lisp/Bulges1.htm
+ """
+ def handle_segment(last, point, bulge):
+ if bulge != 0 and (point - last).length != 0:
+ arc = bulge_to_arc(last, point, bulge)
+ cubic_bezier = do.arc(arc, None, aunits=1, angdir=arc.angdir, angbase=0)
+ else:
+ la = last.to_3d()
+ po = point.to_3d()
+ section = point - last
+ cubic_bezier = [la, la + section * 1 / 3, la + section * 2 / 3, po]
+ return cubic_bezier
+
+ points = lwpolyline.points
+ bulges = lwpolyline.bulge
+ lenpo = len(points)
+ spline = []
+ for i in range(1, lenpo):
+ spline += handle_segment(Vector(points[i - 1]), Vector(points[i]), bulges[i - 1])[:-1]
+
+ if lwpolyline.is_closed:
+ spline += handle_segment(Vector(points[-1]), Vector(points[0]), bulges[-1])
+ else:
+ spline.append(points[-1])
+ return spline
+
+
+def bulgepoly_to_lenlist(lwpolyline):
+ """
+ returns a list with the segment lengths of a lwpolyline
+ """
+ def handle_segment(last, point, bulge):
+ seglen = (point - last).length
+ if bulge != 0 and seglen != 0:
+ arc = bulge_to_arc(last, point, bulge)
+ if arc.startangle > arc.endangle:
+ arc.endangle += 2 * pi
+ angle = arc.endangle - arc.startangle
+ lenlist.append(abs(arc.radius * angle))
+ else:
+ lenlist.append(seglen)
+
+ points = lwpolyline.points
+ bulges = lwpolyline.bulge
+ lenpo = len(points)
+ lenlist = []
+ for i in range(1, lenpo):
+ handle_segment(Vector(points[i - 1][:2]), Vector(points[i][:2]), bulges[i - 1])
+
+ if lwpolyline.is_closed:
+ handle_segment(Vector(points[-1][:2]), Vector(points[0][:2]), bulges[-1])
+
+ return lenlist
+
+
+def extrusion_to_matrix(entity):
+ """
+ Converts an extrusion vector to a rotation matrix that denotes the transformation between world coordinate system
+ and the entity's own coordinate system (described by the extrusion vector).
+ """
+ def arbitrary_x_axis(extrusion_normal):
+ world_y = Vector((0, 1, 0))
+ world_z = Vector((0, 0, 1))
+ if abs(extrusion_normal[0]) < 1 / 64 and abs(extrusion_normal[1]) < 1 / 64:
+ a_x = world_y.cross(extrusion_normal)
+ else:
+ a_x = world_z.cross(extrusion_normal)
+ a_x.normalize()
+ return a_x, extrusion_normal.cross(a_x)
+
+ az = Vector(entity.extrusion)
+ ax, ay = arbitrary_x_axis(az)
+ return Matrix((ax, ay, az)).inverted()
+
+
+def split_by_width(entity):
+ """
+ Used to split a curve (polyline, lwpolyline) into smaller segments if their width is varying in the overall curve.
+ """
+ class WidthTuple:
+ def __init__(self, w):
+ self.w1 = w[0]
+ self.w2 = w[1]
+
+ def __eq__(self, other):
+ return self.w1 == other.w1 and self.w2 == other.w2 and self.w1 == self.w2
+
+ if is_.varying_width(entity):
+ entities = []
+ en_template = deepcopy(entity)
+ en_template.points = []
+ en_template.bulge = []
+ en_template.width = []
+ en_template.tangents = []
+ en_template.is_closed = False
+
+ i = 0
+ for pair, same_width in itertools.groupby(entity.width, key=lambda w: WidthTuple(w)):
+ en = deepcopy(en_template)
+ for segment in same_width:
+ en.points.append(entity.points[i])
+ en.points.append(entity.points[(i + 1) % len(entity.points)])
+ en.bulge.append(entity.bulge[i])
+ en.width.append(entity.width[i])
+ i += 1
+ entities.append(en)
+
+ if not entity.is_closed:
+ entities.pop(-1)
+ return entities
+
+ else:
+ return [entity]