Пример #1
0
 def _get_crosses(self, p0, p1):
     Point_to_Point2D = self.rfcontext.Point_to_Point2D
     dist = self.rfcontext.drawing.scale(options['knife snap dist'])
     crosses = set()
     touched = set()
     #p0 = Point_to_Point2D(p0)
     #p1 = Point_to_Point2D(p1)
     v01 = Vec2D(p1 - p0)
     lv01 = max(v01.length, 0.00001)
     d01 = v01 / lv01
     def add(p, e):
         if e in touched: return
         p.freeze()
         touched.add(e)
         crosses.add((p, e, d01.dot(p - p0) / lv01))
     p0v = self.rfcontext.accel_nearest2D_vert(point=p0, max_dist=options['knife snap dist'])[0]
     if p0v and not p0v.link_edges:
         add(p0, p0v)
     for e in self.vis_edges:
         v0, v1 = e.verts
         c0, c1 = Point_to_Point2D(v0.co), Point_to_Point2D(v1.co)
         i = intersect2d_segment_segment(p0, p1, c0, c1)
         clc0 = closest2d_point_segment(c0, p0, p1)
         clc1 = closest2d_point_segment(c1, p0, p1)
         clp0 = closest2d_point_segment(p0, c0, c1)
         clp1 = closest2d_point_segment(p1, c0, c1)
         if   (clc0 - c0).length <= dist: add(c0,   v0)
         elif (clc1 - c1).length <= dist: add(c1,   v1)
         elif (clp0 - p0).length <= dist: add(clp0, e)
         elif (clp1 - p1).length <= dist: add(clp1, e)
         elif i:                          add(Point2D(i), e)
     crosses = sorted(crosses, key=lambda cross: cross[2])
     return crosses
Пример #2
0
    def draw_postpixel(self):
        # TODO: put all logic into set_next_state(), such as vertex snapping, edge splitting, etc.

        #if self.rfcontext.nav or self.mode != 'main': return
        if not self.actions.using_onlymods({'insert', 'insert alt1'}): return
        hit_pos = self.actions.hit_pos
        if not hit_pos: return

        self.set_next_state()

        bgl.glEnable(bgl.GL_BLEND)
        CC_DRAW.stipple(pattern=[4, 4])
        CC_DRAW.point_size(8)
        CC_DRAW.line_width(2)

        if self.next_state == 'knife selected edge':
            bmv1, bmv2 = self.nearest_edge.verts
            faces = self.nearest_edge.link_faces
            if faces:
                for f in faces:
                    lco = []
                    for v0, v1 in iter_pairs(f.verts, True):
                        lco.append(v0.co)
                        if (v0 == bmv1 and v1 == bmv2) or (v0 == bmv2
                                                           and v1 == bmv1):
                            lco.append(hit_pos)
                    self.draw_lines(lco)
            else:
                self.draw_lines([bmv1.co, hit_pos])
                self.draw_lines([bmv2.co, hit_pos])

        elif self.next_state == 'new vertex':
            p0 = hit_pos
            e1, d = self.rfcontext.nearest2D_edge(edges=self.vis_edges)
            if e1:
                bmv1, bmv2 = e1.verts
                if d is not None and d < self.rfcontext.drawing.scale(15):
                    f = next(iter(e1.link_faces), None)
                    if f:
                        lco = []
                        for v0, v1 in iter_pairs(f.verts, True):
                            lco.append(v0.co)
                            if (v0 == bmv1 and v1 == bmv2) or (v0 == bmv2
                                                               and v1 == bmv1):
                                lco.append(p0)
                        self.draw_lines(lco)
                    else:
                        self.draw_lines([bmv1.co, hit_pos])
                        self.draw_lines([bmv2.co, hit_pos])
                else:
                    self.draw_lines([hit_pos])
            else:
                self.draw_lines([hit_pos])

        elif self.next_state in {'vert-edge', 'vert-edge-vert'}:
            sel_verts = self.sel_verts
            bmv0 = next(iter(sel_verts))
            if self.nearest_vert:
                p0 = self.nearest_vert.co
            elif self.next_state == 'vert-edge':
                p0 = hit_pos
                e1, d = self.rfcontext.nearest2D_edge(edges=self.vis_edges)
                if e1:
                    bmv1, bmv2 = e1.verts
                    if d is not None and d < self.rfcontext.drawing.scale(15):
                        f = next(iter(e1.link_faces), None)
                        if f:
                            lco = []
                            for v0, v1 in iter_pairs(f.verts, True):
                                lco.append(v0.co)
                                if (v0 == bmv1
                                        and v1 == bmv2) or (v0 == bmv2
                                                            and v1 == bmv1):
                                    lco.append(p0)
                            self.draw_lines(lco)
                        else:
                            self.draw_lines([bmv1.co, p0])
                            self.draw_lines([bmv2.co, p0])
            elif self.next_state == 'vert-edge-vert':
                p0 = hit_pos
            else:
                return
            self.draw_lines([bmv0.co, p0])

        elif self.actions.shift and not self.actions.ctrl:
            if self.next_state in [
                    'edge-face', 'edge-quad', 'edge-quad-snap', 'tri-quad'
            ]:
                nearest_vert, _ = self.rfcontext.nearest2D_vert(
                    verts=self.sel_verts,
                    max_dist=options['polypen merge dist'])
                if nearest_vert:
                    self.draw_lines([nearest_vert.co, hit_pos])

        elif not self.actions.shift and self.actions.ctrl:
            if self.next_state == 'edge-face':
                e0, _ = self.rfcontext.nearest2D_edge(
                    edges=self.sel_edges)  #next(iter(self.sel_edges))
                if not e0: return
                e1, d = self.rfcontext.nearest2D_edge(edges=self.vis_edges)
                if e1 and d < self.rfcontext.drawing.scale(15) and e0 == e1:
                    bmv1, bmv2 = e1.verts
                    p0 = hit_pos
                    f = next(iter(e1.link_faces), None)
                    if f:
                        lco = []
                        for v0, v1 in iter_pairs(f.verts, True):
                            lco.append(v0.co)
                            if (v0 == bmv1 and v1 == bmv2) or (v0 == bmv2
                                                               and v1 == bmv1):
                                lco.append(p0)
                        self.draw_lines(lco)
                    else:
                        self.draw_lines([bmv1.co, hit_pos])
                        self.draw_lines([bmv2.co, hit_pos])
                else:
                    # self.draw_lines([hit_pos])
                    bmv1, bmv2 = e0.verts
                    if self.nearest_vert and not self.nearest_vert.select:
                        p0 = self.nearest_vert.co
                    else:
                        p0 = hit_pos
                    self.draw_lines([p0, bmv1.co, bmv2.co])

            elif self.next_state == 'edge-quad':
                # a Desmos construction of how this works: https://www.desmos.com/geometry/bmmx206thi
                xy0, xy1, xy2, xy3 = self._get_edge_quad_verts()
                if xy0 is None: return
                co0 = self.rfcontext.raycast_sources_Point2D(xy0)[0]
                co1 = self.rfcontext.raycast_sources_Point2D(xy1)[0]
                co2 = self.rfcontext.raycast_sources_Point2D(xy2)[0]
                co3 = self.rfcontext.raycast_sources_Point2D(xy3)[0]
                self.draw_lines([co1, co2, co3, co0])

            elif self.next_state == 'edge-quad-snap':
                e0, _ = self.rfcontext.nearest2D_edge(edges=self.sel_edges)
                e1 = self.nearest_edge
                if not e0 or not e1: return
                bmv0, bmv1 = e0.verts
                bmv2, bmv3 = e1.verts
                p0, p1 = self.rfcontext.Point_to_Point2D(
                    bmv0.co), self.rfcontext.Point_to_Point2D(bmv1.co)
                p2, p3 = self.rfcontext.Point_to_Point2D(
                    bmv2.co), self.rfcontext.Point_to_Point2D(bmv3.co)
                if intersect2d_segment_segment(p1, p2, p3, p0):
                    bmv2, bmv3 = bmv3, bmv2
                # if e0.vector2D(self.rfcontext.Point_to_Point2D).dot(e1.vector2D(self.rfcontext.Point_to_Point2D)) > 0:
                #     bmv2,bmv3 = bmv3,bmv2
                self.draw_lines([bmv0.co, bmv1.co, bmv2.co, bmv3.co])

            elif self.next_state == 'tri-quad':
                if self.nearest_vert and not self.nearest_vert.select:
                    p0 = self.nearest_vert.co
                else:
                    p0 = hit_pos
                e1, _ = self.rfcontext.nearest2D_edge(edges=self.sel_edges)
                if not e1: return
                bmv1, bmv2 = e1.verts
                f = next(iter(e1.link_faces), None)
                if not f: return
                lco = []
                for v0, v1 in iter_pairs(f.verts, True):
                    lco.append(v0.co)
                    if (v0 == bmv1 and v1 == bmv2) or (v0 == bmv2
                                                       and v1 == bmv1):
                        lco.append(p0)
                self.draw_lines(lco)
Пример #3
0
    def _insert(self):
        self.last_delta = None
        self.move_done_pressed = None
        self.move_done_released = 'insert'
        self.move_cancelled = 'cancel'

        if self.actions.shift and not self.actions.ctrl and not self.next_state in [
                'new vertex', 'vert-edge'
        ]:
            self.next_state = 'vert-edge'
            nearest_vert, _ = self.rfcontext.nearest2D_vert(
                verts=self.sel_verts, max_dist=options['polypen merge dist'])
            self.rfcontext.select(nearest_vert)

        sel_verts = self.sel_verts
        sel_edges = self.sel_edges
        sel_faces = self.sel_faces

        if self.next_state == 'knife selected edge':  # overriding: if hovering over a selected edge, knife it!
            # self.nearest_edge and self.nearest_edge.select:
            #print('knifing selected, hovered edge')
            bmv = self.rfcontext.new2D_vert_mouse()
            if not bmv:
                self.rfcontext.undo_cancel()
                return 'main'
            bme0, bmv2 = self.nearest_edge.split()
            bmv.merge(bmv2)
            self.rfcontext.select(bmv)
            self.mousedown = self.actions.mousedown
            xy = self.rfcontext.Point_to_Point2D(bmv.co)
            if not xy:
                #print('Could not insert: ' + str(bmv.co))
                self.rfcontext.undo_cancel()
                return 'main'
            self.bmverts = [(bmv, xy)] if bmv else []
            self.set_vis_bmverts()
            return 'move'

        if self.next_state in {'vert-edge', 'vert-edge-vert'}:
            bmv0 = next(iter(sel_verts))

            if self.next_state == 'vert-edge':
                nearest_vert, dist = self.rfcontext.nearest2D_vert(
                    verts=self.vis_verts,
                    max_dist=options['polypen merge dist'])
                if nearest_vert:
                    bmv1 = nearest_vert
                    lbmf = bmv0.shared_faces(bmv1)
                    if len(lbmf) == 1 and not bmv0.share_edge(bmv1):
                        # split face
                        bmf = lbmf[0]
                        bmf.split(bmv0, bmv1)
                        self.rfcontext.select(bmv1)
                        return 'main'

                nearest_edge, dist = self.rfcontext.nearest2D_edge(
                    edges=self.vis_edges)
                bmv1 = self.rfcontext.new2D_vert_mouse()
                if not bmv1:
                    self.rfcontext.undo_cancel()
                    return 'main'
                if dist is not None and dist < self.rfcontext.drawing.scale(
                        15):
                    if bmv0 in nearest_edge.verts:
                        # selected vert already part of edge; split
                        bme0, bmv2 = nearest_edge.split()
                        bmv1.merge(bmv2)
                        self.rfcontext.select(bmv1)
                    else:
                        bme0, bmv2 = nearest_edge.split()
                        bmv1.merge(bmv2)
                        bmf = next(iter(bmv0.shared_faces(bmv1)), None)
                        if bmf:
                            if not bmv0.share_edge(bmv1):
                                bmf.split(bmv0, bmv1)
                        if not bmv0.share_face(bmv1):
                            bme = self.rfcontext.new_edge((bmv0, bmv1))
                            self.rfcontext.select(bme)
                        self.rfcontext.select(bmv1)
                else:
                    bme = self.rfcontext.new_edge((bmv0, bmv1))
                    self.rfcontext.select(bme)

            elif self.next_state == 'vert-edge-vert':
                if self.nearest_vert:
                    bmv1 = self.nearest_vert
                else:
                    bmv1 = self.rfcontext.new2D_vert_mouse()
                    if not bmv1:
                        self.rfcontext.undo_cancel()
                        return 'main'
                bme = bmv0.shared_edge(bmv1) or self.rfcontext.new_edge(
                    (bmv0, bmv1))
                self.rfcontext.select(bmv1)

            else:
                return 'main'

            self.mousedown = self.actions.mousedown
            xy = self.rfcontext.Point_to_Point2D(bmv1.co)
            if not xy:
                dprint('Could not insert: ' + str(bmv1.co))
                self.rfcontext.undo_cancel()
                return 'main'
            self.bmverts = [(bmv1, xy)] if bmv1 else []
            self.set_vis_bmverts()
            return 'move'

        if self.next_state == 'edge-face':
            bme, _ = self.rfcontext.nearest2D_edge(edges=self.sel_edges)
            if not bme: return
            bmv0, bmv1 = bme.verts

            if self.nearest_vert and not self.nearest_vert.select:
                bmv2 = self.nearest_vert
                bmf = self.rfcontext.new_face([bmv0, bmv1, bmv2])
                self.rfcontext.clean_duplicate_bmedges(bmv2)
            else:
                bmv2 = self.rfcontext.new2D_vert_mouse()
                if not bmv2:
                    self.rfcontext.undo_cancel()
                    return 'main'
                bmf = self.rfcontext.new_face([bmv0, bmv1, bmv2])

            self.rfcontext.select(bmf)
            self.mousedown = self.actions.mousedown
            xy = self.rfcontext.Point_to_Point2D(bmv2.co)
            if not xy:
                dprint('Could not insert: ' + str(bmv2.co))
                self.rfcontext.undo_cancel()
                return 'main'
            self.bmverts = [(bmv2, xy)] if bmv2 else []
            self.set_vis_bmverts()
            return 'move'

        if self.next_state == 'edge-quad':
            xy0, xy1, xy2, xy3 = self._get_edge_quad_verts()
            if xy0 is None or xy1 is None or xy2 is None or xy3 is None: return
            # a Desmos construction of how this works: https://www.desmos.com/geometry/bmmx206thi
            e0, _ = self.rfcontext.nearest2D_edge(edges=self.sel_edges)
            if not e0: return
            bmv0, bmv1 = e0.verts

            bmv2, _ = self.rfcontext.nearest2D_vert(
                point=xy2,
                verts=self.vis_verts,
                max_dist=options['polypen merge dist'])
            if not bmv2: bmv2 = self.rfcontext.new2D_vert_point(xy2)
            bmv3, _ = self.rfcontext.nearest2D_vert(
                point=xy3,
                verts=self.vis_verts,
                max_dist=options['polypen merge dist'])
            if not bmv3: bmv3 = self.rfcontext.new2D_vert_point(xy3)
            if not bmv2 or not bmv3:
                self.rfcontext.undo_cancel()
                return 'main'
            e1 = bmv2.shared_edge(bmv3)
            if not e1: e1 = self.rfcontext.new_edge([bmv2, bmv3])
            bmf = self.rfcontext.new_face([bmv0, bmv1, bmv2, bmv3])
            bmes = [
                bmv1.shared_edge(bmv2),
                bmv0.shared_edge(bmv3),
                bmv2.shared_edge(bmv3)
            ]
            self.rfcontext.select(bmes, subparts=False)
            self.mousedown = self.actions.mousedown
            self.bmverts = []
            if bmv2:
                self.bmverts.append(
                    (bmv2, self.rfcontext.Point_to_Point2D(bmv2.co)))
            if bmv3:
                self.bmverts.append(
                    (bmv3, self.rfcontext.Point_to_Point2D(bmv3.co)))
            self.set_vis_bmverts()
            return 'move'

        if self.next_state == 'edge-quad-snap':
            e0, _ = self.rfcontext.nearest2D_edge(edges=self.sel_edges)
            e1 = self.nearest_edge
            if not e0 or not e1: return
            bmv0, bmv1 = e0.verts
            bmv2, bmv3 = e1.verts
            p0, p1 = self.rfcontext.Point_to_Point2D(
                bmv0.co), self.rfcontext.Point_to_Point2D(bmv1.co)
            p2, p3 = self.rfcontext.Point_to_Point2D(
                bmv2.co), self.rfcontext.Point_to_Point2D(bmv3.co)
            if intersect2d_segment_segment(p1, p2, p3, p0):
                bmv2, bmv3 = bmv3, bmv2
            # if e0.vector2D(self.rfcontext.Point_to_Point2D).dot(e1.vector2D(self.rfcontext.Point_to_Point2D)) > 0:
            #     bmv2,bmv3 = bmv3,bmv2
            bmf = self.rfcontext.new_face([bmv0, bmv1, bmv2, bmv3])
            # select all non-manifold edges that share vertex with e1
            bmes = [
                e for e in bmv2.link_edges + bmv3.link_edges
                if not e.is_manifold and not e.share_face(e1)
            ]
            if not bmes:
                bmes = [bmv1.shared_edge(bmv2), bmv0.shared_edge(bmv3)]
            self.rfcontext.select(bmes, subparts=False)
            return 'main'

        if self.next_state == 'tri-quad':
            hit_pos = self.actions.hit_pos
            if not hit_pos:
                self.rfcontext.undo_cancel()
                return 'main'
            if not self.sel_edges:
                return 'main'
            bme0, _ = self.rfcontext.nearest2D_edge(edges=self.sel_edges)
            if not bme0: return
            bmv0, bmv2 = bme0.verts
            bme1, bmv1 = bme0.split()
            bme0.select = True
            bme1.select = True
            self.rfcontext.select(bmv1.link_edges)
            if self.nearest_vert and not self.nearest_vert.select:
                self.nearest_vert.merge(bmv1)
                bmv1 = self.nearest_vert
                self.rfcontext.clean_duplicate_bmedges(bmv1)
                for bme in bmv1.link_edges:
                    bme.select &= len(bme.link_faces) == 1
                bme01, bme12 = bmv0.shared_edge(bmv1), bmv1.shared_edge(bmv2)
                if len(bme01.link_faces) == 1: bme01.select = True
                if len(bme12.link_faces) == 1: bme12.select = True
            else:
                bmv1.co = hit_pos
            self.mousedown = self.actions.mousedown
            self.rfcontext.select(bmv1, only=False)
            xy = self.rfcontext.Point_to_Point2D(bmv1.co)
            if not xy:
                dprint('Could not insert: ' + str(bmv3.co))
                self.rfcontext.undo_cancel()
                return 'main'
            self.bmverts = [(bmv1, xy)] if bmv1 else []
            self.set_vis_bmverts()
            return 'move'

        nearest_edge, d = self.rfcontext.nearest2D_edge(edges=self.vis_edges)
        bmv = self.rfcontext.new2D_vert_mouse()
        if not bmv:
            self.rfcontext.undo_cancel()
            return 'main'
        if d is not None and d < self.rfcontext.drawing.scale(15):
            bme0, bmv2 = nearest_edge.split()
            bmv.merge(bmv2)
        self.rfcontext.select(bmv)
        self.mousedown = self.actions.mousedown
        xy = self.rfcontext.Point_to_Point2D(bmv.co)
        if not xy:
            dprint('Could not insert: ' + str(bmv.co))
            self.rfcontext.undo_cancel()
            return 'main'
        self.bmverts = [(bmv, xy)] if bmv else []
        self.set_vis_bmverts()
        return 'move'