class StMove(object):
    """
    This Function generates the StartMove for each shape. It
    also performs the Plotting and Export of this moves. It is linked
    to the shape of its parent
    """

    # only need default arguments here because of the change of usage with super in QGraphicsLineItem
    def __init__(self, shape=None):
        if shape is None:
            return

        self.shape = shape

        self.start, self.angle = self.shape.get_start_end_points(True, True)
        self.end = self.start

        self.geos = Geos([])

        self.make_start_moves()

    def append(self, geo):
        # we don't want to additional scale / rotate the stmove geo
        # so no geo.make_abs_geo(self.shape.parentEntity)
        geo.make_abs_geo()
        self.geos.append(geo)

    def make_start_moves(self):
        """
        This function called to create the start move. It will
        be generated based on the given values for start and angle.
        """
        self.geos = Geos([])

        if g.config.machine_type == 'drag_knife':
            self.make_swivelknife_move()
            return
        elif self.shape.cut_cor != 40 and not g.config.vars.Cutter_Compensation[
                "done_by_machine"]:
            self.make_own_cutter_compensation()
            return

        # Get the start rad. and the length of the line segment at begin.
        start_rad = self.shape.parentLayer.start_radius

        # Get tool radius based on tool diameter.
        tool_rad = self.shape.parentLayer.getToolRadius()

        # Calculate the starting point with and without compensation.
        start = self.start
        angle = self.angle

        if self.shape.cut_cor == 40:
            self.append(RapidPos(start))

        # Cutting Compensation Left
        elif self.shape.cut_cor == 41:
            # Center of the Starting Radius.
            Oein = start.get_arc_point(angle + pi / 2, start_rad + tool_rad)
            # Start Point of the Radius
            Pa_ein = Oein.get_arc_point(angle + pi, start_rad + tool_rad)
            # Start Point of the straight line segment at begin.
            Pg_ein = Pa_ein.get_arc_point(angle + pi / 2, start_rad)

            # Get the dive point for the starting contour and append it.
            start_ein = Pg_ein.get_arc_point(angle, tool_rad)
            self.append(RapidPos(start_ein))

            # generate the Start Line and append it including the compensation.
            start_line = LineGeo(start_ein, Pa_ein)
            self.append(start_line)

            # generate the start rad. and append it.
            start_rad = ArcGeo(Ps=Pa_ein,
                               Pe=start,
                               O=Oein,
                               r=start_rad + tool_rad,
                               direction=1)
            self.append(start_rad)

        # Cutting Compensation Right
        elif self.shape.cut_cor == 42:
            # Center of the Starting Radius.
            Oein = start.get_arc_point(angle - pi / 2, start_rad + tool_rad)
            # Start Point of the Radius
            Pa_ein = Oein.get_arc_point(angle + pi, start_rad + tool_rad)
            # Start Point of the straight line segment at begin.
            Pg_ein = Pa_ein.get_arc_point(angle - pi / 2, start_rad)

            # Get the dive point for the starting contour and append it.
            start_ein = Pg_ein.get_arc_point(angle, tool_rad)
            self.append(RapidPos(start_ein))

            # generate the Start Line and append it including the compensation.
            start_line = LineGeo(start_ein, Pa_ein)
            self.append(start_line)

            # generate the start rad. and append it.
            start_rad = ArcGeo(Ps=Pa_ein,
                               Pe=start,
                               O=Oein,
                               r=start_rad + tool_rad,
                               direction=0)
            self.append(start_rad)

    def make_swivelknife_move(self):
        """
        Set these variables for your tool and material
        @param offset: knife tip distance from tool centerline. The radius of the
        tool is used for this.
        """
        offset = self.shape.parentLayer.getToolRadius()
        drag_angle = self.shape.drag_angle

        startnorm = offset * Point(
            1, 0)  # TODO make knife direction a config setting
        prvend, prvnorm = Point(), Point()
        first = True

        for geo in self.shape.geos.abs_iter():
            if isinstance(geo, LineGeo):
                geo_b = deepcopy(geo)
                if first:
                    first = False
                    prvend = geo_b.Ps + startnorm
                    prvnorm = startnorm
                norm = offset * (geo_b.Pe - geo_b.Ps).unit_vector()
                geo_b.Ps += norm
                geo_b.Pe += norm
                if not prvnorm == norm:
                    direction = prvnorm.to3D().cross_product(norm.to3D()).z
                    swivel = ArcGeo(Ps=prvend,
                                    Pe=geo_b.Ps,
                                    r=offset,
                                    direction=direction)
                    swivel.drag = drag_angle < abs(swivel.ext)
                    self.append(swivel)
                self.append(geo_b)

                prvend = geo_b.Pe
                prvnorm = norm
            elif isinstance(geo, ArcGeo):
                geo_b = deepcopy(geo)
                if first:
                    first = False
                    prvend = geo_b.Ps + startnorm
                    prvnorm = startnorm
                if geo_b.ext > 0.0:
                    norma = offset * Point(cos(geo_b.s_ang + pi / 2),
                                           sin(geo_b.s_ang + pi / 2))
                    norme = Point(cos(geo_b.e_ang + pi / 2),
                                  sin(geo_b.e_ang + pi / 2))
                else:
                    norma = offset * Point(cos(geo_b.s_ang - pi / 2),
                                           sin(geo_b.s_ang - pi / 2))
                    norme = Point(cos(geo_b.e_ang - pi / 2),
                                  sin(geo_b.e_ang - pi / 2))
                geo_b.Ps += norma
                if norme.x > 0:
                    geo_b.Pe = Point(
                        geo_b.Pe.x + offset / (sqrt(1 +
                                                    (norme.y / norme.x)**2)),
                        geo_b.Pe.y + (offset * norme.y / norme.x) /
                        (sqrt(1 + (norme.y / norme.x)**2)))
                elif norme.x == 0:
                    geo_b.Pe = Point(geo_b.Pe.x, geo_b.Pe.y)
                else:
                    geo_b.Pe = Point(
                        geo_b.Pe.x - offset / (sqrt(1 +
                                                    (norme.y / norme.x)**2)),
                        geo_b.Pe.y - (offset * norme.y / norme.x) /
                        (sqrt(1 + (norme.y / norme.x)**2)))
                if prvnorm != norma:
                    direction = prvnorm.to3D().cross_product(norma.to3D()).z
                    swivel = ArcGeo(Ps=prvend,
                                    Pe=geo_b.Ps,
                                    r=offset,
                                    direction=direction)
                    swivel.drag = drag_angle < abs(swivel.ext)
                    self.append(swivel)
                prvend = geo_b.Pe
                prvnorm = offset * norme
                if -pi < geo_b.ext < pi:
                    self.append(
                        ArcGeo(Ps=geo_b.Ps,
                               Pe=geo_b.Pe,
                               r=sqrt(geo_b.r**2 + offset**2),
                               direction=geo_b.ext))
                else:
                    geo_b = ArcGeo(Ps=geo_b.Ps,
                                   Pe=geo_b.Pe,
                                   r=sqrt(geo_b.r**2 + offset**2),
                                   direction=-geo_b.ext)
                    geo_b.ext = -geo_b.ext
                    self.append(geo_b)
            # TODO support different geos, or disable them in the GUI
            # else:
            #     self.append(copy(geo))
        if not prvnorm == startnorm:
            direction = prvnorm.to3D().cross_product(startnorm.to3D()).z
            self.append(
                ArcGeo(Ps=prvend,
                       Pe=prvend - prvnorm + startnorm,
                       r=offset,
                       direction=direction))

        self.geos.insert(0, RapidPos(self.geos.abs_el(0).Ps))
        self.geos[0].make_abs_geo()

    def make_own_cutter_compensation(self):
        toolwidth = self.shape.parentLayer.getToolRadius()

        geos = Geos([])

        direction = -1 if self.shape.cut_cor == 41 else 1

        if self.shape.closed:
            end, end_dir = self.shape.get_start_end_points(False, False)
            end_proj = Point(direction * end_dir.y, -direction * end_dir.x)
            prv_Pe = end + toolwidth * end_proj
        else:
            prv_Pe = None
        for geo_nr, geo in enumerate(self.shape.geos.abs_iter()):
            start, start_dir = geo.get_start_end_points(True, False)
            end, end_dir = geo.get_start_end_points(False, False)
            start_proj = Point(direction * start_dir.y,
                               -direction * start_dir.x)
            end_proj = Point(direction * end_dir.y, -direction * end_dir.x)
            Ps = start + toolwidth * start_proj
            Pe = end + toolwidth * end_proj
            if Ps == Pe:
                continue
            if prv_Pe:
                r = geo.Ps.distance(Ps)
                d = (prv_Pe - geo.Ps).to3D().cross_product(
                    (Ps - geo.Ps).to3D()).z
                if direction * d > 0 and prv_Pe != Ps:
                    geos.append(
                        ArcGeo(Ps=prv_Pe, Pe=Ps, O=geo.Ps, r=r, direction=d))
                    geos[-1].geo_nr = geo_nr
                # else:
                #     geos.append(LineGeo(Ps=prv_Pe, Pe=Ps))
            if isinstance(geo, LineGeo):
                geos.append(LineGeo(Ps, Pe))
                geos[-1].geo_nr = geo_nr
            elif isinstance(geo, ArcGeo):
                O = geo.O
                r = O.distance(Ps)
                geos.append(ArcGeo(Ps=Ps, Pe=Pe, O=O, r=r, direction=geo.ext))
                geos[-1].geo_nr = geo_nr
            # TODO other geos are not supported; disable them in gui for this option
            # else:
            #     geos.append(geo)
            prv_Pe = Pe

        tot_length = 0
        for geo in geos.abs_iter():
            tot_length += geo.length

        reorder_shape = False
        for start_geo_nr in range(len(geos)):
            # if shape is not closed we may only remove shapes from the start
            last_geo_nr = start_geo_nr if self.shape.closed else 0
            geos_adj = deepcopy(geos[start_geo_nr:]) + deepcopy(
                geos[:last_geo_nr])
            new_geos = Geos([])
            i = 0
            while i in range(len(geos_adj)):
                geo = geos_adj[i]
                intersections = []
                for j in range(i + 1, len(geos_adj)):
                    intersection = Intersect.get_intersection_point(
                        geos_adj[j], geos_adj[i])
                    if intersection and intersection != geos_adj[i].Ps:
                        intersections.append([j, intersection])
                if len(intersections) > 0:
                    intersection = intersections[-1]
                    change_end_of_geo = True
                    if i == 0 and intersection[0] >= len(geos_adj) // 2:
                        geo.update_start_end_points(True, intersection[1])
                        geos_adj[intersection[0]].update_start_end_points(
                            False, intersection[1])
                        if len(intersections) > 1:
                            intersection = intersections[-2]
                        else:
                            change_end_of_geo = False
                            i += 1
                    if change_end_of_geo:
                        geo.update_start_end_points(False, intersection[1])
                        i = intersection[0]
                        geos_adj[i].update_start_end_points(
                            True, intersection[1])
                else:
                    i += 1
                # TODO
                # if len(new_geos) > 0 and not new_geos[-1].Pe.eq(geo.Ps, g.config.fitting_tolerance):
                #     break  # geo is disconnected
                new_geos.append(geo)
                if new_geos[0].Ps == new_geos[-1].Pe:
                    break

            new_length = 0
            for geo in new_geos:
                new_length += geo.length

            if tot_length * g.config.vars.Cutter_Compensation['min_length_considered']\
                    <= new_length <= tot_length * g.config.vars.Cutter_Compensation['max_length_considered'] and\
               (not g.config.vars.Cutter_Compensation['direction_maintained'] or
                    not self.shape.closed or self.shape.isDirectionOfGeosCCW(new_geos) != self.shape.cw):
                self.append(RapidPos(new_geos[0].Ps))
                for geo in new_geos:
                    if geo.Ps != geo.Pe:
                        self.append(geo)
                reorder_shape = True
                break
        if reorder_shape and self.shape.closed:
            # we do not reorder the original shape if it's not closed
            self.shape.geos = Geos(
                self.shape.geos[geos[start_geo_nr].geo_nr:] +
                self.shape.geos[:geos[start_geo_nr].geo_nr])

        if len(self.geos) == 0:
            self.append(RapidPos(self.start))

    def make_path(self, drawHorLine, drawVerLine):
        for geo in self.geos.abs_iter():
            drawVerLine(self.shape, geo.get_start_end_points(True))
            geo.make_path(self.shape, drawHorLine)
        drawVerLine(self.shape, geo.get_start_end_points(False))
Beispiel #2
0
class StMove(object):
    """
    This Function generates the StartMove for each shape. It
    also performs the Plotting and Export of this moves. It is linked
    to the shape of its parent
    """

    # only need default arguments here because of the change of usage with super in QGraphicsLineItem
    def __init__(self, shape=None):
        if shape is None:
            return

        self.shape = shape

        self.start, self.angle = self.shape.get_start_end_points(True, True)
        self.end = self.start

        self.geos = Geos([])

        self.make_start_moves()

    def append(self, geo):
        # we don't want to additional scale / rotate the stmove geo
        # so no geo.make_abs_geo(self.shape.parentEntity)
        geo.make_abs_geo()
        self.geos.append(geo)

    def make_start_moves(self):
        """
        This function called to create the start move. It will
        be generated based on the given values for start and angle.
        """
        self.geos = Geos([])

        if g.config.machine_type == 'drag_knife':
            self.make_swivelknife_move()
            return

        # Get the start rad. and the length of the line segment at begin.
        start_rad = self.shape.parentLayer.start_radius

        # Get tool radius based on tool diameter.
        tool_rad = self.shape.parentLayer.getToolRadius()

        # Calculate the starting point with and without compensation.
        start = self.start
        angle = self.angle

        if self.shape.cut_cor == 40:
            self.append(RapidPos(start))

        elif self.shape.cut_cor != 40 and not g.config.vars.Cutter_Compensation[
                "done_by_machine"]:

            toolwidth = self.shape.parentLayer.getToolRadius()
            offtype = "in" if self.shape.cut_cor == 42 else "out"
            offshape = offShapeClass(parent=self.shape,
                                     offset=toolwidth,
                                     offtype=offtype)

            if len(offshape.rawoff) > 0:
                start, angle = offshape.rawoff[0].get_start_end_points(
                    True, True)

                self.append(RapidPos(start))
                self.geos += offshape.rawoff

        # Cutting Compensation Left
        elif self.shape.cut_cor == 41:
            # Center of the Starting Radius.
            Oein = start.get_arc_point(angle + pi / 2, start_rad + tool_rad)
            # Start Point of the Radius
            Ps_ein = Oein.get_arc_point(angle + pi, start_rad + tool_rad)
            # Start Point of the straight line segment at begin.
            Pg_ein = Ps_ein.get_arc_point(angle + pi / 2, start_rad)

            # Get the dive point for the starting contour and append it.
            start_ein = Pg_ein.get_arc_point(angle, tool_rad)
            self.append(RapidPos(start_ein))

            # generate the Start Line and append it including the compensation.
            start_line = LineGeo(start_ein, Ps_ein)
            self.append(start_line)

            # generate the start rad. and append it.
            start_rad = ArcGeo(Ps=Ps_ein,
                               Pe=start,
                               O=Oein,
                               r=start_rad + tool_rad,
                               direction=1)
            self.append(start_rad)

        # Cutting Compensation Right
        elif self.shape.cut_cor == 42:
            # Center of the Starting Radius.
            Oein = start.get_arc_point(angle - pi / 2, start_rad + tool_rad)
            # Start Point of the Radius
            Ps_ein = Oein.get_arc_point(angle + pi, start_rad + tool_rad)
            # Start Point of the straight line segment at begin.
            Pg_ein = Ps_ein.get_arc_point(angle - pi / 2, start_rad)

            # Get the dive point for the starting contour and append it.
            start_ein = Pg_ein.get_arc_point(angle, tool_rad)
            self.append(RapidPos(start_ein))

            # generate the Start Line and append it including the compensation.
            start_line = LineGeo(start_ein, Ps_ein)
            self.append(start_line)

            # generate the start rad. and append it.
            start_rad = ArcGeo(Ps=Ps_ein,
                               Pe=start,
                               O=Oein,
                               r=start_rad + tool_rad,
                               direction=0)
            self.append(start_rad)

    def make_swivelknife_move(self):
        """
        Set these variables for your tool and material
        @param offset: knife tip distance from tool centerline. The radius of the
        tool is used for this.
        """
        offset = self.shape.parentLayer.getToolRadius()
        drag_angle = self.shape.drag_angle

        startnorm = offset * Point(
            1, 0)  # TODO make knife direction a config setting
        prvend, prvnorm = Point(), Point()
        first = True

        for geo in self.shape.geos.abs_iter():
            if isinstance(geo, LineGeo):
                geo_b = deepcopy(geo)
                if first:
                    first = False
                    prvend = geo_b.Ps + startnorm
                    prvnorm = startnorm
                norm = offset * (geo_b.Pe - geo_b.Ps).unit_vector()
                geo_b.Ps += norm
                geo_b.Pe += norm
                if not prvnorm == norm:
                    direction = prvnorm.to3D().cross_product(norm.to3D()).z
                    swivel = ArcGeo(Ps=prvend,
                                    Pe=geo_b.Ps,
                                    r=offset,
                                    direction=direction)
                    swivel.drag = drag_angle < abs(swivel.ext)
                    self.append(swivel)
                self.append(geo_b)

                prvend = geo_b.Pe
                prvnorm = norm
            elif isinstance(geo, ArcGeo):
                geo_b = deepcopy(geo)
                if first:
                    first = False
                    prvend = geo_b.Ps + startnorm
                    prvnorm = startnorm
                if geo_b.ext > 0.0:
                    norma = offset * Point(cos(geo_b.s_ang + pi / 2),
                                           sin(geo_b.s_ang + pi / 2))
                    norme = Point(cos(geo_b.e_ang + pi / 2),
                                  sin(geo_b.e_ang + pi / 2))
                else:
                    norma = offset * Point(cos(geo_b.s_ang - pi / 2),
                                           sin(geo_b.s_ang - pi / 2))
                    norme = Point(cos(geo_b.e_ang - pi / 2),
                                  sin(geo_b.e_ang - pi / 2))
                geo_b.Ps += norma
                if norme.x > 0:
                    geo_b.Pe = Point(
                        geo_b.Pe.x + offset / (sqrt(1 +
                                                    (norme.y / norme.x)**2)),
                        geo_b.Pe.y + (offset * norme.y / norme.x) /
                        (sqrt(1 + (norme.y / norme.x)**2)))
                elif norme.x == 0:
                    geo_b.Pe = Point(geo_b.Pe.x, geo_b.Pe.y)
                else:
                    geo_b.Pe = Point(
                        geo_b.Pe.x - offset / (sqrt(1 +
                                                    (norme.y / norme.x)**2)),
                        geo_b.Pe.y - (offset * norme.y / norme.x) /
                        (sqrt(1 + (norme.y / norme.x)**2)))
                if prvnorm != norma:
                    direction = prvnorm.to3D().cross_product(norma.to3D()).z
                    swivel = ArcGeo(Ps=prvend,
                                    Pe=geo_b.Ps,
                                    r=offset,
                                    direction=direction)
                    swivel.drag = drag_angle < abs(swivel.ext)
                    self.append(swivel)
                prvend = geo_b.Pe
                prvnorm = offset * norme
                if -pi < geo_b.ext < pi:
                    self.append(
                        ArcGeo(Ps=geo_b.Ps,
                               Pe=geo_b.Pe,
                               r=sqrt(geo_b.r**2 + offset**2),
                               direction=geo_b.ext))
                else:
                    geo_b = ArcGeo(Ps=geo_b.Ps,
                                   Pe=geo_b.Pe,
                                   r=sqrt(geo_b.r**2 + offset**2),
                                   direction=-geo_b.ext)
                    geo_b.ext = -geo_b.ext
                    self.append(geo_b)
            # TODO support different geos, or disable them in the GUI
            # else:
            #     self.append(copy(geo))
        if not prvnorm == startnorm:
            direction = prvnorm.to3D().cross_product(startnorm.to3D()).z
            self.append(
                ArcGeo(Ps=prvend,
                       Pe=prvend - prvnorm + startnorm,
                       r=offset,
                       direction=direction))

        self.geos.insert(0, RapidPos(self.geos.abs_el(0).Ps))
        self.geos[0].make_abs_geo()

    def make_path(self, drawHorLine, drawVerLine):
        for geo in self.geos.abs_iter():
            drawVerLine(self.shape, geo.get_start_end_points(True))
            geo.make_path(self.shape, drawHorLine)
        if len(self.geos):
            drawVerLine(self.shape, geo.get_start_end_points(False))
Beispiel #3
0
class StMove(object):
    """
    This Function generates the StartMove for each shape. It
    also performs the Plotting and Export of this moves. It is linked
    to the shape of its parent
    """
    # only need default arguments here because of the change of usage with super in QGraphicsLineItem
    def __init__(self, shape=None):
        if shape is None:
            return

        self.shape = shape

        self.start, self.angle = self.shape.get_start_end_points(True, True)
        self.end = self.start

        self.geos = Geos([])

        self.make_start_moves()

    def append(self, geo):
        # we don't want to additional scale / rotate the stmove geo
        # so no geo.make_abs_geo(self.shape.parentEntity)
        geo.make_abs_geo()
        self.geos.append(geo)

    def make_start_moves(self):
        """
        This function called to create the start move. It will
        be generated based on the given values for start and angle.
        """
        self.geos = Geos([])

        if g.config.machine_type == 'drag_knife':
            self.make_swivelknife_move()
            return
        elif self.shape.cut_cor != 40 and not g.config.vars.Cutter_Compensation["done_by_machine"]:
            self.make_own_cutter_compensation()
            return

        # Get the start rad. and the length of the line segment at begin.
        start_rad = self.shape.parentLayer.start_radius

        # Get tool radius based on tool diameter.
        tool_rad = self.shape.parentLayer.getToolRadius()

        # Calculate the starting point with and without compensation.
        start = self.start
        angle = self.angle

        if self.shape.cut_cor == 40:
            self.append(RapidPos(start))

        # Cutting Compensation Left
        elif self.shape.cut_cor == 41:
            # Center of the Starting Radius.
            Oein = start.get_arc_point(angle + pi/2, start_rad + tool_rad)
            # Start Point of the Radius
            Pa_ein = Oein.get_arc_point(angle + pi, start_rad + tool_rad)
            # Start Point of the straight line segment at begin.
            Pg_ein = Pa_ein.get_arc_point(angle + pi/2, start_rad)

            # Get the dive point for the starting contour and append it.
            start_ein = Pg_ein.get_arc_point(angle, tool_rad)
            self.append(RapidPos(start_ein))

            # generate the Start Line and append it including the compensation.
            start_line = LineGeo(start_ein, Pa_ein)
            self.append(start_line)

            # generate the start rad. and append it.
            start_rad = ArcGeo(Ps=Pa_ein, Pe=start, O=Oein,
                               r=start_rad + tool_rad, direction=1)
            self.append(start_rad)

        # Cutting Compensation Right
        elif self.shape.cut_cor == 42:
            # Center of the Starting Radius.
            Oein = start.get_arc_point(angle - pi/2, start_rad + tool_rad)
            # Start Point of the Radius
            Pa_ein = Oein.get_arc_point(angle + pi, start_rad + tool_rad)
            # Start Point of the straight line segment at begin.
            Pg_ein = Pa_ein.get_arc_point(angle - pi/2, start_rad)

            # Get the dive point for the starting contour and append it.
            start_ein = Pg_ein.get_arc_point(angle, tool_rad)
            self.append(RapidPos(start_ein))

            # generate the Start Line and append it including the compensation.
            start_line = LineGeo(start_ein, Pa_ein)
            self.append(start_line)

            # generate the start rad. and append it.
            start_rad = ArcGeo(Ps=Pa_ein, Pe=start, O=Oein,
                               r=start_rad + tool_rad, direction=0)
            self.append(start_rad)

    def make_swivelknife_move(self):
        """
        Set these variables for your tool and material
        @param offset: knife tip distance from tool centerline. The radius of the
        tool is used for this.
        """
        offset = self.shape.parentLayer.getToolRadius()
        drag_angle = self.shape.drag_angle

        startnorm = offset*Point(1, 0)  # TODO make knife direction a config setting
        prvend, prvnorm = Point(), Point()
        first = True

        for geo in self.shape.geos.abs_iter():
            if isinstance(geo, LineGeo):
                geo_b = deepcopy(geo)
                if first:
                    first = False
                    prvend = geo_b.Ps + startnorm
                    prvnorm = startnorm
                norm = offset * (geo_b.Pe - geo_b.Ps).unit_vector()
                geo_b.Ps += norm
                geo_b.Pe += norm
                if not prvnorm == norm:
                    direction = prvnorm.to3D().cross_product(norm.to3D()).z
                    swivel = ArcGeo(Ps=prvend, Pe=geo_b.Ps, r=offset, direction=direction)
                    swivel.drag = drag_angle < abs(swivel.ext)
                    self.append(swivel)
                self.append(geo_b)

                prvend = geo_b.Pe
                prvnorm = norm
            elif isinstance(geo, ArcGeo):
                geo_b = deepcopy(geo)
                if first:
                    first = False
                    prvend = geo_b.Ps + startnorm
                    prvnorm = startnorm
                if geo_b.ext > 0.0:
                    norma = offset*Point(cos(geo_b.s_ang+pi/2), sin(geo_b.s_ang+pi/2))
                    norme = Point(cos(geo_b.e_ang+pi/2), sin(geo_b.e_ang+pi/2))
                else:
                    norma = offset*Point(cos(geo_b.s_ang-pi/2), sin(geo_b.s_ang-pi/2))
                    norme = Point(cos(geo_b.e_ang-pi/2), sin(geo_b.e_ang-pi/2))
                geo_b.Ps += norma
                if norme.x > 0:
                    geo_b.Pe = Point(geo_b.Pe.x+offset/(sqrt(1+(norme.y/norme.x)**2)),
                                     geo_b.Pe.y+(offset*norme.y/norme.x)/(sqrt(1+(norme.y/norme.x)**2)))
                elif norme.x == 0:
                    geo_b.Pe = Point(geo_b.Pe.x,
                                     geo_b.Pe.y)
                else:
                    geo_b.Pe = Point(geo_b.Pe.x-offset/(sqrt(1+(norme.y/norme.x)**2)),
                                     geo_b.Pe.y-(offset*norme.y/norme.x)/(sqrt(1+(norme.y/norme.x)**2)))
                if prvnorm != norma:
                    direction = prvnorm.to3D().cross_product(norma.to3D()).z
                    swivel = ArcGeo(Ps=prvend, Pe=geo_b.Ps, r=offset, direction=direction)
                    swivel.drag = drag_angle < abs(swivel.ext)
                    self.append(swivel)
                prvend = geo_b.Pe
                prvnorm = offset*norme
                if -pi < geo_b.ext < pi:
                    self.append(ArcGeo(Ps=geo_b.Ps, Pe=geo_b.Pe, r=sqrt(geo_b.r**2+offset**2), direction=geo_b.ext))
                else:
                    geo_b = ArcGeo(Ps=geo_b.Ps, Pe=geo_b.Pe, r=sqrt(geo_b.r**2+offset**2), direction=-geo_b.ext)
                    geo_b.ext = -geo_b.ext
                    self.append(geo_b)
            # TODO support different geos, or disable them in the GUI
            # else:
            #     self.append(copy(geo))
        if not prvnorm == startnorm:
            direction = prvnorm.to3D().cross_product(startnorm.to3D()).z
            self.append(ArcGeo(Ps=prvend, Pe=prvend-prvnorm+startnorm, r=offset, direction=direction))

        self.geos.insert(0, RapidPos(self.geos.abs_el(0).Ps))
        self.geos[0].make_abs_geo()

    def make_own_cutter_compensation(self):
        toolwidth = self.shape.parentLayer.getToolRadius()

        geos = Geos([])

        direction = -1 if self.shape.cut_cor == 41 else 1

        if self.shape.closed:
            end, end_dir = self.shape.get_start_end_points(False, False)
            end_proj = Point(direction * end_dir.y, -direction * end_dir.x)
            prv_Pe = end + toolwidth * end_proj
        else:
            prv_Pe = None
        for geo_nr, geo in enumerate(self.shape.geos.abs_iter()):
            start, start_dir = geo.get_start_end_points(True, False)
            end, end_dir = geo.get_start_end_points(False, False)
            start_proj = Point(direction * start_dir.y, -direction * start_dir.x)
            end_proj = Point(direction * end_dir.y, -direction * end_dir.x)
            Ps = start + toolwidth * start_proj
            Pe = end + toolwidth * end_proj
            if Ps == Pe:
                continue
            if prv_Pe:
                r = geo.Ps.distance(Ps)
                d = (prv_Pe - geo.Ps).to3D().cross_product((Ps - geo.Ps).to3D()).z
                if direction * d > 0 and prv_Pe != Ps:
                    geos.append(ArcGeo(Ps=prv_Pe, Pe=Ps, O=geo.Ps, r=r, direction=d))
                    geos[-1].geo_nr = geo_nr
                # else:
                #     geos.append(LineGeo(Ps=prv_Pe, Pe=Ps))
            if isinstance(geo, LineGeo):
                geos.append(LineGeo(Ps, Pe))
                geos[-1].geo_nr = geo_nr
            elif isinstance(geo, ArcGeo):
                O = geo.O
                r = O.distance(Ps)
                geos.append(ArcGeo(Ps=Ps, Pe=Pe, O=O, r=r, direction=geo.ext))
                geos[-1].geo_nr = geo_nr
            # TODO other geos are not supported; disable them in gui for this option
            # else:
            #     geos.append(geo)
            prv_Pe = Pe

        tot_length = 0
        for geo in geos.abs_iter():
            tot_length += geo.length

        reorder_shape = False
        for start_geo_nr in range(len(geos)):
            # if shape is not closed we may only remove shapes from the start
            last_geo_nr = start_geo_nr if self.shape.closed else 0
            geos_adj = deepcopy(geos[start_geo_nr:]) + deepcopy(geos[:last_geo_nr])
            new_geos = Geos([])
            i = 0
            while i in range(len(geos_adj)):
                geo = geos_adj[i]
                intersections = []
                for j in range(i+1, len(geos_adj)):
                    intersection = Intersect.get_intersection_point(geos_adj[j], geos_adj[i])
                    if intersection and intersection != geos_adj[i].Ps:
                        intersections.append([j, intersection])
                if len(intersections) > 0:
                    intersection = intersections[-1]
                    change_end_of_geo = True
                    if i == 0 and intersection[0] >= len(geos_adj)//2:
                        geo.update_start_end_points(True, intersection[1])
                        geos_adj[intersection[0]].update_start_end_points(False, intersection[1])
                        if len(intersections) > 1:
                            intersection = intersections[-2]
                        else:
                            change_end_of_geo = False
                            i += 1
                    if change_end_of_geo:
                        geo.update_start_end_points(False, intersection[1])
                        i = intersection[0]
                        geos_adj[i].update_start_end_points(True, intersection[1])
                else:
                    i += 1
                # TODO
                # if len(new_geos) > 0 and not new_geos[-1].Pe.eq(geo.Ps, g.config.fitting_tolerance):
                #     break  # geo is disconnected
                new_geos.append(geo)
                if new_geos[0].Ps == new_geos[-1].Pe:
                    break

            new_length = 0
            for geo in new_geos:
                new_length += geo.length

            if tot_length * g.config.vars.Cutter_Compensation['min_length_considered']\
                    <= new_length <= tot_length * g.config.vars.Cutter_Compensation['max_length_considered'] and\
               (not g.config.vars.Cutter_Compensation['direction_maintained'] or
                    not self.shape.closed or self.shape.isDirectionOfGeosCCW(new_geos) != self.shape.cw):
                self.append(RapidPos(new_geos[0].Ps))
                for geo in new_geos:
                    if geo.Ps != geo.Pe:
                        self.append(geo)
                reorder_shape = True
                break
        if reorder_shape and self.shape.closed:
            # we do not reorder the original shape if it's not closed
            self.shape.geos = Geos(self.shape.geos[geos[start_geo_nr].geo_nr:] + self.shape.geos[:geos[start_geo_nr].geo_nr])

        if len(self.geos) == 0:
            self.append(RapidPos(self.start))

    def make_path(self, drawHorLine, drawVerLine):
        for geo in self.geos.abs_iter():
            drawVerLine(self.shape, geo.get_start_end_points(True))
            geo.make_path(self.shape, drawHorLine)
        drawVerLine(self.shape, geo.get_start_end_points(False))