From fde9aa0a3fe223e7f2eb03010faf626bac925780 Mon Sep 17 00:00:00 2001 From: Stephen Leger Date: Thu, 3 Aug 2017 15:59:40 +0200 Subject: archipack: Fix issue with curved segments in walls/slab/floor --- archipack/archipack_2d.py | 39 ++++++++++++++++++++++++++++--- archipack/archipack_cutter.py | 30 ++++++++++++++++++------ archipack/archipack_fence.py | 16 +++++++++---- archipack/archipack_floor.py | 25 ++++++++++++++++---- archipack/archipack_slab.py | 53 +++++++++++++++++++++++++------------------ archipack/archipack_wall2.py | 47 +++++++++++++++++++++++++++++++++----- archipack/panel.py | 4 ++-- 7 files changed, 165 insertions(+), 49 deletions(-) (limited to 'archipack') diff --git a/archipack/archipack_2d.py b/archipack/archipack_2d.py index fcd578da..4bf0d1f1 100644 --- a/archipack/archipack_2d.py +++ b/archipack/archipack_2d.py @@ -116,6 +116,7 @@ class Line(Projection): else: self.p = Vector((0, 0)) self.v = Vector((0, 0)) + self.line = None @property def copy(self): @@ -161,6 +162,10 @@ class Line(Projection): """ return atan2(self.v.y, self.v.x) + @property + def a0(self): + return self.angle + @property def angle_normal(self): """ @@ -365,7 +370,7 @@ class Line(Projection): if hasattr(last, "r"): res, d, t = line.point_sur_segment(last.c) c = (last.r * last.r) - (d * d) - print("t:%s" % t) + # print("t:%s" % t) if c <= 0: # no intersection ! p0 = line.lerp(t) @@ -455,8 +460,6 @@ class Arc(Circle): """ Represent a 2d Arc TODO: - Add some sugar here - like being able to set p0 and p1 of line make it possible to define an arc by start point end point and center """ def __init__(self, c, radius, a0, da): @@ -473,6 +476,7 @@ class Arc(Circle): stored internally as radians """ Circle.__init__(self, Vector(c).to_2d(), radius) + self.line = None self.a0 = a0 self.da = da @@ -575,6 +579,15 @@ class Arc(Circle): """ return self.r * abs(self.da) + @property + def oposite(self): + a0 = self.a0 + self.da + if a0 > pi: + a0 -= 2 * pi + if a0 < -pi: + a0 += 2 * pi + return Arc(self.c, self.r, a0, -self.da) + def normal(self, t=0): """ Perpendicular line starting at t @@ -628,6 +641,26 @@ class Arc(Circle): steps = max(1, round(abs(self.da) / step_angle, 0)) return 1.0 / steps, int(steps) + def as_lines(self, steps): + """ + convert Arc to lines + """ + res = [] + p0 = self.lerp(0) + for step in range(steps): + p1 = self.lerp((step + 1) / steps) + s = Line(p0=p0, p1=p1) + res.append(s) + p0 = p1 + + if self.line is not None: + p0 = self.line.lerp(0) + for step in range(steps): + p1 = self.line.lerp((step + 1) / steps) + res[step].line = Line(p0=p0, p1=p1) + p0 = p1 + return res + def offset(self, offset): """ Offset circle diff --git a/archipack/archipack_cutter.py b/archipack/archipack_cutter.py index 69bd16c2..b5a64776 100644 --- a/archipack/archipack_cutter.py +++ b/archipack/archipack_cutter.py @@ -62,7 +62,7 @@ class CutterSegment(Line): def offset(self, offset): s = self.copy - s.p += offset * self.cross_z.normalized() + s.p += self.sized_normal(0, offset).v return s @property @@ -206,6 +206,18 @@ class CutAblePolygon(): - holes - convex """ + def as_lines(self, step_angle=0.104): + """ + Convert curved segments to straight lines + """ + segs = [] + for s in self.segs: + if "Curved" in type(s).__name__: + dt, steps = s.steps_by_angle(step_angle) + segs.extend(s.as_lines(steps)) + else: + segs.append(s) + self.segs = segs def inside(self, pt, segs=None): """ @@ -471,8 +483,9 @@ class CutAbleGenerator(): of = offset[s.type] else: of = offset['DEFAULT'] - p0 = s.p0 + s.cross_z.normalized() * of - self.bissect(bm, p0.to_3d(), s.cross_z.to_3d(), clear_outer=False) + n = s.sized_normal(0, 1).v + p0 = s.p0 + n * of + self.bissect(bm, p0.to_3d(), n.to_3d(), clear_outer=False) # compute boundary with offset new_s = None @@ -495,7 +508,8 @@ class CutAbleGenerator(): else: for s in hole.segs: if s.length > 0: - self.bissect(bm, s.p0.to_3d(), s.cross_z.to_3d(), clear_outer=False) + n = s.sized_normal(0, 1).v + self.bissect(bm, s.p0.to_3d(), n.to_3d(), clear_outer=False) # use hole boundary segs = hole.segs if len(segs) > 0: @@ -518,12 +532,14 @@ class CutAbleGenerator(): of = offset[s.type] else: of = offset['DEFAULT'] - p0 = s.p0 + s.cross_z.normalized() * of - self.bissect(bm, p0.to_3d(), s.cross_z.to_3d(), clear_outer=cutable.convex) + n = s.sized_normal(0, 1).v + p0 = s.p0 + n * of + self.bissect(bm, p0.to_3d(), n.to_3d(), clear_outer=cutable.convex) else: for s in cutable.segs: if s.length > 0: - self.bissect(bm, s.p0.to_3d(), s.cross_z.to_3d(), clear_outer=cutable.convex) + n = s.sized_normal(0, 1).v + self.bissect(bm, s.p0.to_3d(), n.to_3d(), clear_outer=cutable.convex) if not cutable.convex: f_geom = [f for f in bm.faces diff --git a/archipack/archipack_fence.py b/archipack/archipack_fence.py index 7006b3b1..0f5f3b37 100644 --- a/archipack/archipack_fence.py +++ b/archipack/archipack_fence.py @@ -52,7 +52,6 @@ class Fence(): self.t_end = 0 self.dz = 0 self.z0 = 0 - self.a0 = 0 def set_offset(self, offset, last=None): """ @@ -622,12 +621,19 @@ def update_type(self, context): else: w = w0.curved_fence(part.a0, part.da, part.radius) else: - g = FenceGenerator(None) - g.add_part(self) - w = g.segs[0] + if "C_" in self.type: + p = Vector((0, 0)) + v = self.length * Vector((cos(self.a0), sin(self.a0))) + w = StraightFence(p, v) + a0 = pi / 2 + else: + c = -self.radius * Vector((cos(self.a0), sin(self.a0))) + w = CurvedFence(c, self.radius, self.a0, pi) - # w0 - w - w1 + # not closed, see wall + # for closed ability dp = w.p1 - w.p0 + if "C_" in self.type: part.radius = 0.5 * dp.length part.da = pi diff --git a/archipack/archipack_floor.py b/archipack/archipack_floor.py index 634c2130..8664b637 100644 --- a/archipack/archipack_floor.py +++ b/archipack/archipack_floor.py @@ -246,6 +246,13 @@ class FloorGenerator(CutAblePolygon, CutAbleGenerator): def limits(self): x_size = [s.p0.x for s in self.segs] y_size = [s.p0.y for s in self.segs] + for s in self.segs: + if "Curved" in type(s).__name__: + x_size.append(s.c.x + s.r) + x_size.append(s.c.x - s.r) + y_size.append(s.c.y + s.r) + y_size.append(s.c.y - s.r) + self.xmin = min(x_size) self.xmax = max(x_size) self.xsize = self.xmax - self.xmin @@ -258,6 +265,7 @@ class FloorGenerator(CutAblePolygon, CutAbleGenerator): either external or holes cuts """ self.limits() + self.as_lines() self.is_convex() for b in o.children: d = archipack_floor_cutter.datablock(b) @@ -857,12 +865,21 @@ def update_type(self, context): else: w = w0.curved_floor(part.a0, part.da, part.radius) else: - g = FloorGenerator(None) - g.add_part(self) - w = g.segs[0] + if "C_" in self.type: + p = Vector((0, 0)) + v = self.length * Vector((cos(self.a0), sin(self.a0))) + w = StraightFloor(p, v) + a0 = pi / 2 + else: + c = -self.radius * Vector((cos(self.a0), sin(self.a0))) + w = CurvedFloor(c, self.radius, self.a0, pi) # w0 - w - w1 - dp = w.p1 - w.p0 + if idx + 1 == d.n_parts: + dp = - w.p0 + else: + dp = w.p1 - w.p0 + if "C_" in self.type: part.radius = 0.5 * dp.length part.da = pi diff --git a/archipack/archipack_slab.py b/archipack/archipack_slab.py index 9f8a2947..9059f269 100644 --- a/archipack/archipack_slab.py +++ b/archipack/archipack_slab.py @@ -247,6 +247,10 @@ class SlabGenerator(CutAblePolygon, CutAbleGenerator): either external or holes cuts """ self.limits() + + self.as_lines(step_angle=0.0502) + # self.segs = [s.line for s in self.segs] + for b in o.children: d = archipack_slab_cutter.datablock(b) if d is not None: @@ -382,12 +386,21 @@ def update_type(self, context): else: w = w0.curved_slab(part.a0, part.da, part.radius) else: - g = SlabGenerator(None) - g.add_part(self) - w = g.segs[0] + if "C_" in self.type: + p = Vector((0, 0)) + v = self.length * Vector((cos(self.a0), sin(self.a0))) + w = StraightSlab(p, v) + a0 = pi / 2 + else: + c = -self.radius * Vector((cos(self.a0), sin(self.a0))) + w = CurvedSlab(c, self.radius, self.a0, pi) # w0 - w - w1 - dp = w.p1 - w.p0 + if idx + 1 == d.n_parts: + dp = - w.p0 + else: + dp = w.p1 - w.p0 + if "C_" in self.type: part.radius = 0.5 * dp.length part.da = pi @@ -494,22 +507,15 @@ class ArchipackSegment(): def draw(self, context, layout, index): box = layout.box() - row = box.row() - row.prop(self, "type", text=str(index + 1)) + box.prop(self, "type", text=str(index + 1)) self.draw_insert(context, box, index) if self.type in ['C_SEG']: - row = box.row() - row.prop(self, "radius") - row = box.row() - row.prop(self, "da") + box.prop(self, "radius") + box.prop(self, "da") else: - row = box.row() - row.prop(self, "length") - row = box.row() - row.prop(self, "a0") - row = box.row() - row.prop(self, "offset") - # row.prop(self, "linked_idx") + box.prop(self, "length") + box.prop(self, "a0") + # box.prop(self, "offset") class archipack_slab_part(ArchipackSegment, PropertyGroup): @@ -823,6 +829,7 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): # start and shared: update rotation a = seg.angle - w.segs[idx].angle + if abs(a) > 0.00001: w.rotate(idx, a) @@ -831,7 +838,7 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): if next_idx > -1: - if idx + 1 == next_idx: + if (idx + 1 == next_idx) or (next_idx == 0 and i + 1 == self.n_parts): # shared: should move last point # and apply to next segments # this is overriden for common segs @@ -854,11 +861,13 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): last_idx = next_idx - 1 # update d from og + last_seg = None for i, seg in enumerate(w.segs): - if i > 0: - d.parts[i].a0 = seg.delta_angle(w.segs[i - 1]) - else: - d.parts[i].a0 = seg.angle + + d.parts[i].a0 = seg.delta_angle(last_seg) + + last_seg = seg + if "C_" in d.parts[i].type: d.parts[i].radius = seg.r d.parts[i].da = seg.da diff --git a/archipack/archipack_wall2.py b/archipack/archipack_wall2.py index f52233a5..92172eb1 100644 --- a/archipack/archipack_wall2.py +++ b/archipack/archipack_wall2.py @@ -577,11 +577,21 @@ def update_type(self, context): else: w = w0.curved_wall(self.a0, self.da, self.radius, d.z, self.z, self.t) else: - g = WallGenerator(None) - g.add_part(self, d.z, d.flip) - w = g.segs[0] + if "C_" in self.type: + p = Vector((0, 0)) + v = self.length * Vector((cos(self.a0), sin(self.a0))) + w = StraightWall(p, v, d.z, self.z, self.t, d.flip) + a0 = pi / 2 + else: + c = -self.radius * Vector((cos(self.a0), sin(self.a0))) + w = CurvedWall(c, self.radius, self.a0, pi, d.z, self.z, self.t, d.flip) + # w0 - w - w1 - dp = w.p1 - w.p0 + if d.closed and idx == d.n_parts: + dp = - w.p0 + else: + dp = w.p1 - w.p0 + if "C_" in self.type: self.radius = 0.5 * dp.length self.da = pi @@ -1088,13 +1098,37 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): def reverse(self, context, o): g = self.get_generator() + + self.auto_update = False + pts = [seg.p0.to_3d() for seg in g.segs] + if not self.closed: + g.segs.pop() + + g_segs = list(reversed(g.segs)) + + last_seg = None + + for i, seg in enumerate(g_segs): + + s = seg.oposite + if "Curved" in type(seg).__name__: + self.parts[i].type = "C_WALL" + self.parts[i].radius = s.r + self.parts[i].da = s.da + else: + self.parts[i].type = "S_WALL" + self.parts[i].length = s.length + + self.parts[i].a0 = s.delta_angle(last_seg) + + last_seg = s + if self.closed: pts.append(pts[0]) pts = list(reversed(pts)) - self.auto_update = False # location wont change for closed walls if not self.closed: @@ -1107,7 +1141,8 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): [0, 0, 0, 1], ]) - self.from_points(pts, self.closed) + # self.from_points(pts, self.closed) + g = self.get_generator() self.setup_childs(o, g) diff --git a/archipack/panel.py b/archipack/panel.py index c8898fe5..4a472362 100644 --- a/archipack/panel.py +++ b/archipack/panel.py @@ -703,8 +703,8 @@ class Panel(): n_profil_faces = self.profil_faces idmat = [] for i in range(n_path_faces): - for mat in range(n_profil_faces): - idmat.append(self.idmat[mat]) + for f in range(n_profil_faces): + idmat.append(self.idmat[f]) if self.side_cap_front > -1: idmat.append(cap_front_id) if self.side_cap_back > -1: -- cgit v1.2.3