Beispiel #1
0
def drawcurve(counter, pos, window):
    if counter == 1:
        pygame.draw.circle(window, (0, 255, 0), pos[0], 5)
    if counter == 2:
        line = shapely.geometry.LineString([pos[0], pos[1]])
        pygame.draw.line(window, (255, 0, 0), pos[0], pos[1])

    if counter == 3:
        pygame.draw.line(window, (255, 0, 0), pos[0], pos[1])
        pygame.draw.circle(window, (0, 255, 0), pos[2], 5)
    if counter == 0:
        pygame.draw.line(window, (255, 0, 0), pos[0], pos[1])
        pygame.draw.line(window, (255, 0, 0), pos[2], pos[3])
        rect_lol, kosmos1, kosmos2 = LLuk(pos).get_pygame_arc()
        pygame.draw.arc(window, (255, 255, 0), rect_lol, kosmos1, kosmos2)

        lines.append(Line(srumpy(pos[0]), srumpy(pos[1])))
        lines.append(Line(srumpy(pos[2]), srumpy(pos[3])))
        print(kosmos2 - kosmos1)
        if (is_right_to(kosmos1, kosmos2)):
            lines.append(
                Arc(srumpy(pos[1]), srumpy((intergreat_len, intergreat_len)),
                    0, False, False, srumpy(pos[2])))
        else:
            lines.append(
                Arc(srumpy(pos[1]), srumpy((intergreat_len, intergreat_len)),
                    0, False, True, srumpy(pos[2])))
        srodes.append(srumpy(pos[0]))
        stroke_widths.append(2)
        srodes.append(srumpy(pos[3]))
        stroke_widths.append(2)
        return "kcc"
    return ""
Beispiel #2
0
 def get_svg_arc(self):
     if (self.is_right_to(self.azimuth1, self.azimuth2)):
         return Arc(srumpy(self.arc_start),
                    srumpy((self.arc_radius, self.arc_radius)), 0, False,
                    False, srumpy(self.arc_end))
     else:
         return Arc(srumpy(self.arc_start),
                    srumpy((self.arc_radius, self.arc_radius)), 0, False,
                    True, srumpy(self.arc_end))
Beispiel #3
0
def flip_path(upside_down_path):
    path = []
    _, _, min_y, max_y = upside_down_path.bbox()
    offset = max_y + min_y
    for segment in upside_down_path._segments:
        if type(segment) is Line:
            path.append(
                Line(complex(segment.start.real, -segment.start.imag + offset),
                     complex(segment.end.real, -segment.end.imag + offset)))
        elif type(segment) is Arc:
            path.append(
                Arc(complex(segment.start.real,
                            -segment.start.imag + offset), segment.radius,
                    abs(180 - segment.rotation), segment.large_arc,
                    not segment.sweep,
                    complex(segment.end.real, -segment.end.imag + offset)))
        elif type(segment) is QuadraticBezier:
            path.append(
                QuadraticBezier(
                    complex(segment.start.real, -segment.start.imag + offset),
                    complex(segment.control.real,
                            -segment.control.imag + offset),
                    complex(segment.end.real, -segment.end.imag + offset)))
        else:
            raise ValueError(f"Unknown type: {type(segment)}")

    return Path(*path)
 def transform_seg(seg):
     if isinstance(seg, (Line, QuadraticBezier, CubicBezier)):
         return seg.__class__(
             *[transformed_points[point] for point in seg.bpoints()])
     elif isinstance(seg, Arc):
         new_start = transformed_points[seg.start]
         new_end = transformed_points[seg.end]
         new_raidus = transformed_radii[seg.radius]
         new_rotation = seg.rotation + random.uniform(
             -rotation_amplitude, rotation_amplitude)
         return Arc(new_start, new_raidus, new_rotation, seg.large_arc,
                    seg.sweep, new_end, seg.autoscale_radius)
Beispiel #5
0
def add_circle(input_file, output_file):
    """
    Adds a circle around the base icon. This will have the effect to invert
    the mask.
    """
    paths, attributes, svg_attributes = svg2paths2(input_file)
    if len(paths) > 1:
        raise NotImplementedError("Can't handle more than one path for now")
    path = paths[0]

    # Scale path down
    new_path = scale_path_to_bbox(path, (6, 6, 42, 42))

    # Add circle
    new_path.append(Arc(24 + 2j, 22 + 22j, 180, 0, 1, 24 + 46j))
    new_path.append(Arc(24 + 46j, 22 + 22j, 180, 0, 1, 24 + 2j))

    wsvg(
        [new_path],
        attributes=attributes,
        svg_attributes=svg_attributes,
        filename=output_file,
    )
    def __init__(self,
                 obliquity=23.4443291,
                 radius_capricorn=100,
                 plate_parameters=None):
        self.obliquity = obliquity
        self._obliquityRadians = math.radians(obliquity)
        self._obliquityRadiansArgument = math.radians(
            (90 - self.obliquity) / 2)
        self.RadiusCapricorn = radius_capricorn
        self.plate_parameters = self.climata
        self.plate_altitudes = list(range(0, 90, 10))
        self.plate_azimuths = list(range(10, 90, 10))

        self.tropic_arcs()
        self.plates(plate_parameters=plate_parameters)

        # Parameters for layout of graduated limb.
        self.short_tick_angles = list(range(0, 361, 1))
        self.long_tick_angles = list(range(0, 375, 15))

        self.short_tick = 5
        self.long_tick = 15
        self.ticks = {
            "inner_radius": self.RadiusCapricorn,
            "center_radius": self.RadiusCapricorn + self.short_tick,
            "outer_radius": self.RadiusCapricorn + self.long_tick,
            "short_tick_angles": self.short_tick_angles,
            "long_tick_angles": self.long_tick_angles,
        }

        # Ecliptic
        self.RadiusEcliptic = (self.RadiusCapricorn + self.RadiusCancer) / 2.0
        self.yEclipticCenter = (self.RadiusCapricorn - self.RadiusCancer) / 2.0
        self.xEclipticCenter = 0.0

        self.ecliptic_pole = self.RadiusEquator * math.tan(
            self._obliquityRadiansArgument / 2.0)
        self.ecliptic_center = self.RadiusEquator * math.tan(
            self._obliquityRadiansArgument)

        self.ecliptic = {
            "cx": self.xEclipticCenter,
            "cy": self.yEclipticCenter,
            "r": self.RadiusEcliptic,
            "width": 5,
        }

        self.ecliptic_path = Path(
            Arc(
                start=complex(0, self.ecliptic["cy"] + self.ecliptic["r"]),
                radius=(complex(self.ecliptic["r"], self.ecliptic["r"])),
                rotation=0.0,
                large_arc=True,
                sweep=False,
                end=complex(0, self.ecliptic["cy"] - self.ecliptic["r"]),
            ),
            Arc(
                start=complex(0, self.ecliptic["cy"] - self.ecliptic["r"]),
                radius=(complex(self.ecliptic["r"], self.ecliptic["r"])),
                rotation=0.0,
                large_arc=True,
                sweep=False,
                end=complex(0, self.ecliptic["cy"] + self.ecliptic["r"]),
            ),
        )
def main():

    plate_parameters = {"Hawaiian Islands": 21.3069}
    astrolabe = Astrolabe(plate_parameters=plate_parameters)
    plate = astrolabe.plates["Hawaiian Islands"]

    background_color = "#a3262a;"
    stroke_color = "#f5ac27;"
    background_color = "grey;"
    stroke_color = "#f5ac27;"
    graph_color = "navy;"

    background_color = "white;"
    graph_color = "white;"

    # Morrison Blue
    stroke_color = "#f5ac27;"
    graph_color = "#596581;"
    background_color = "#051633"

    # In order to place parts of the figure in Inkscape layers, need the attributes below.
    # This will cause errors, of course, in other renderers unless the inkscape namespace
    # (xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape") is included.

    # Use Inkscape extensions to svg to place different parts of astrolabe into their own layer.
    inkscape_attributes = {
        identifier:
        'inkscape:label="{}" inkscape:groupmode="layer"'.format(identifier)
        for identifier in identifiers
    }

    animation_parameters = {
        "from": "0",
        "to": "175",
        "begin": "0s",
        "dur": "3s"
    }

    ecliptic = {
        "cx": astrolabe.xEclipticCenter,
        "cy": astrolabe.yEclipticCenter,
        "r": astrolabe.RadiusEcliptic,
        "width": 5,
    }
    # ecliptic_center = astrolabe.RadiusEquator * math.tan(
    #     astrolabe._obliquityRadiansArgument
    # )
    outer_radius = ecliptic["r"]
    inner_radius = outer_radius - ecliptic["width"]

    top_middle_outer = {
        "x": (ecliptic["cx"]),
        "y": (ecliptic["cy"] + outer_radius)
    }
    bottom_middle_outer = {
        "x": (ecliptic["cx"]),
        "y": (ecliptic["cy"] - outer_radius)
    }

    top_middle_inner = {
        "x": (ecliptic["cx"]),
        "y": (ecliptic["cy"] + inner_radius)
    }
    bottom_middle_inner = {
        "x": (ecliptic["cx"]),
        "y": (ecliptic["cy"] - inner_radius)
    }

    aries_first_point = astrolabe.ecliptic_division(180)
    aries_first_point_angle = math.degrees(
        math.atan2(aries_first_point["y2"], aries_first_point["x2"]))

    ecliptic_divisions = []
    for angle in list(range(0, 361, 30)):
        ecliptic_divisions.append(astrolabe.ecliptic_division(angle))

    ecliptic_divisions_fine = []
    for angle in list(range(0, 361, 10)):
        ecliptic_divisions_fine.append(astrolabe.ecliptic_division(angle))

    ecliptic_divisions_extra_fine = []
    for angle in list(range(0, 361, 2)):
        ecliptic_divisions_extra_fine.append(
            astrolabe.ecliptic_division(angle))

    seasonal_arcs = []
    month_names = [
        "jan",
        "feb",
        "mar",
        "apr",
        "may",
        "june",
        "july",
        "aug",
        "sept",
        "oct",
        "nov",
        "dec",
    ]
    seasonal_names = [
        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"
    ]
    seasonal_names = [
        "pisces",
        "aquarius",
        "capricorn",
        "sagittarius",
        "scorpio",
        "libra",
        "virgo",
        "leo",
        "cancer",
        "gemini",
        "taurus",
        "aries",
    ]
    # seasonal_names = [
    #     "雨水",
    #     "大寒",
    #     "冬至",
    #     "小雪",
    #     "霜降",
    #     "秋分",
    #     "处暑",
    #     "大暑",
    #     "夏至",
    #     "小满",
    #     "谷雨",
    #     "春分",
    # ]

    angle = 0
    for n, division in enumerate(ecliptic_divisions[0:12]):
        tag = "season" + str(angle)
        angle += 30
        next_division = ecliptic_divisions[(n + 1) % 12]
        sarc = Path(
            Arc(
                start=complex(division["x2"], division["y2"]),
                radius=complex(ecliptic["r"], ecliptic["r"]),
                rotation=0.0,
                large_arc=True,
                sweep=False,
                end=complex(next_division["x2"], next_division["y2"]),
            ))
        seasonal_arcs.append({
            "tag": tag,
            "name": seasonal_names[n],
            "r": ecliptic["r"],
            "start_x": division["x2"],
            "start_y": division["y2"],
            "end_x": next_division["x2"],
            "end_y": next_division["y2"],
            "reversed": sarc.reversed().d(),
        })

    stars = [
        {
            "name": "aldebaran",
            "r": 0.7467,
            "theta": 68.98
        },
        {
            "name": "altair",
            "r": 0.8561,
            "theta": 297.69542
        },
        {
            "name": "arcturus",
            "r": 0.7109,
            "theta": 213.91500
        },
        {
            "name": "capella",
            "r": 0.4040,
            "theta": 79.17208
        },
        {
            "name": "sirius",
            "r": 1.3099,
            "theta": 101.28708
        },
        {
            "name": "procyon",
            "r": 0.9127,
            "theta": 114.82542
        },
        {
            "name": "deneb",
            "r": 0.4114,
            "theta": 310.35750
        },
        {
            "name": "castor",
            "r": 0.5556,
            "theta": 113.64958
        },
        {
            "name": "regulus",
            "r": 0.8103,
            "theta": 152.09250
        },
        {
            "name": "vega",
            "r": 0.4793,
            "theta": 279.23417
        },
        {
            "name": "betelgeuse",
            "r": 0.8784,
            "theta": 88.79292
        },
        {
            "name": "rigel",
            "r": 1.1463,
            "theta": 78.63417
        },
        {
            "name": "bellatrix",
            "r": 0.8949,
            "theta": 81.28250
        },
        {
            "name": "antares",
            "r": 1.5870,
            "theta": 247.35167
        },
        {
            "name": "spica",
            "r": 1.2096,
            "theta": 201.29792
        },
    ]

    for star in stars:
        star["cx"] = (astrolabe.RadiusEquator * star["r"] *
                      math.cos(math.radians(star["theta"])))
        star["cy"] = (astrolabe.RadiusEquator * star["r"] *
                      math.sin(math.radians(star["theta"])))

    print(astrolabe.obliquity)

    with open("calendrical_tools/astrolabe_template.svg.j2") as fp:
        template_text = fp.read()

    template = Template(template_text)
    svg = template.render(
        place_name=plate["location"],
        latitude=plate["latitude"],
        RCapricorn=astrolabe.RadiusCapricorn,
        REquator=astrolabe.RadiusEquator,
        RCancer=astrolabe.RadiusCancer,
        horiz=plate["horizon"],
        almucantar_coords=plate["almucantars"],
        almucantar_center=plate["almucantar_center"],
        azimuth_coords=plate["azimuths"],
        prime_vertical=plate["prime_vertical"],
        ticks=astrolabe.ticks,
        ecliptic=ecliptic,
        ecliptic_divisions=ecliptic_divisions,
        ecliptic_divisions_fine=ecliptic_divisions_fine,
        ecliptic_divisions_extra_fine=ecliptic_divisions_extra_fine,
        aries_first_point=aries_first_point,
        aries_first_point_angle=astrolabe.obliquity,
        top_middle_outer=top_middle_outer,
        bottom_middle_outer=bottom_middle_outer,
        outer_radius=outer_radius,
        inner_radius=inner_radius,
        top_middle_inner=top_middle_inner,
        bottom_middle_inner=bottom_middle_inner,
        # ecliptic_center=ecliptic_center,
        ecliptic_pole=astrolabe.ecliptic_pole,
        seasonal_arcs=seasonal_arcs,
        stars=stars,
        stroke_color=stroke_color,
        background_color=background_color,
        graph_color=graph_color,
        inkscape=inkscape_attributes,
        animation=animation_parameters,
        moons=[
            (44.142706092611434, 214.41520455448494),
            (-64.29833725607341, 244.05007530120906),
            (19.338217263234128, 274.11533327404277),
            (17.224801417675735, 304.36003467896535),
            (-64.16194195841945, 334.4763799297398),
            (-25.561893428663097, 4.203505420431007),
        ],
        suns=[
            214.41713740391424,
            244.05065884583018,
            274.1147430450437,
            304.35973321930214,
            334.47736243435793,
            4.204523538166541,
        ],
    )

    with open("astrolabe_generated.svg", "w") as fp:
        fp.write(svg)

    import jinja2

    # Seems like overkill, but adds "include_file" function to jinja2
    # environment in order to include raw svg into an html template.
    @jinja2.contextfunction
    def include_file(ctx, name):
        env = ctx.environment
        return jinja2.Markup(env.loader.get_source(env, name)[0])

    loader = jinja2.PackageLoader(__name__, ".")
    env = jinja2.Environment(loader=loader)
    env.globals["include_file"] = include_file
Beispiel #8
0
def parse_path(pathdef, current_pos=0j, tree_element=None):
    # In the SVG specs, initial movetos are absolute, even if
    # specified as 'm'. This is the default behavior here as well.
    # But if you pass in a current_pos variable, the initial moveto
    # will be relative to that current_pos. This is useful.
    elements = list(_tokenize_path(pathdef))
    # Reverse for easy use of .pop()
    elements.reverse()

    if tree_element is None:
        segments = Path()
    else:
        segments = Path(tree_element=tree_element)

    start_pos = None
    command = None

    while elements:

        if elements[-1] in COMMANDS:
            # New command.
            last_command = command  # Used by S and T
            command = elements.pop()
            absolute = command in UPPERCASE
            command = command.upper()
        else:
            # If this element starts with numbers, it is an implicit command
            # and we don't change the command. Check that it's allowed:
            if command is None:
                raise ValueError(
                    "Unallowed implicit command in %s, position %s" %
                    (pathdef, len(pathdef.split()) - len(elements)))

        if command == 'M':
            # Moveto command.
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if absolute:
                current_pos = pos
            else:
                current_pos += pos

            # when M is called, reset start_pos
            # This behavior of Z is defined in svg spec:
            # http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
            start_pos = current_pos

            # Implicit moveto commands are treated as lineto commands.
            # So we set command to lineto here, in case there are
            # further implicit commands after this moveto.
            command = 'L'

        elif command == 'Z':
            # Close path
            if not (current_pos == start_pos):
                segments.append(Line(current_pos, start_pos))
            segments.closed = True
            current_pos = start_pos
            command = None

        elif command == 'L':
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if not absolute:
                pos += current_pos
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'H':
            x = elements.pop()
            pos = float(x) + current_pos.imag * 1j
            if not absolute:
                pos += current_pos.real
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'V':
            y = elements.pop()
            pos = current_pos.real + float(y) * 1j
            if not absolute:
                pos += current_pos.imag * 1j
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'C':
            control1 = float(elements.pop()) + float(elements.pop()) * 1j
            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control1 += current_pos
                control2 += current_pos
                end += current_pos

            segments.append(CubicBezier(current_pos, control1, control2, end))
            current_pos = end

        elif command == 'S':
            # Smooth curve. First control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'CS':
                # If there is no previous command or if the previous command
                # was not an C, c, S or s, assume the first control point is
                # coincident with the current point.
                control1 = current_pos
            else:
                # The first control point is assumed to be the reflection of
                # the second control point on the previous command relative
                # to the current point.
                control1 = current_pos + current_pos - segments[-1].control2

            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control2 += current_pos
                end += current_pos

            segments.append(CubicBezier(current_pos, control1, control2, end))
            current_pos = end

        elif command == 'Q':
            control = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control += current_pos
                end += current_pos

            segments.append(QuadraticBezier(current_pos, control, end))
            current_pos = end

        elif command == 'T':
            # Smooth curve. Control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'QT':
                # If there is no previous command or if the previous command
                # was not an Q, q, T or t, assume the first control point is
                # coincident with the current point.
                control = current_pos
            else:
                # The control point is assumed to be the reflection of
                # the control point on the previous command relative
                # to the current point.
                control = current_pos + current_pos - segments[-1].control

            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(QuadraticBezier(current_pos, control, end))
            current_pos = end

        elif command == 'A':
            radius = float(elements.pop()) + float(elements.pop()) * 1j
            rotation = float(elements.pop())
            arc = float(elements.pop())
            sweep = float(elements.pop())
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(Arc(current_pos, radius, rotation, arc, sweep,
                                end))
            current_pos = end

    return segments
Beispiel #9
0
    def renderLabel(self, inString):
        dwg = svgwrite.Drawing()  # SVG drawing in memory
        strIdx = 0  # Used to iterate over inString
        xOffset = 100  # Cumulative character placement offset
        yOffset = 0  # Cumulative character placement offset
        charSizeX = 8  # Character size constant
        charSizeY = 8  # Character size constant
        baseline = 170  # Y value of text baseline
        glyphBounds = [
        ]  # List of boundingBox objects to track rendered character size
        finalSegments = []  # List of output paths
        escaped = False  # Track whether the current character was preceded by a '\'
        lineover = False  # Track whether the current character needs to be lined over
        lineoverList = []

        # If we can't find the typeface that the user requested, we have to quit
        try:
            face = Face(
                os.path.dirname(os.path.abspath(__file__)) + '/typeface/' +
                self.fontName + '.ttf')
            face.set_char_size(charSizeX, charSizeY, 200, 200)
        except Exception as e:
            print(e)
            print("WARN: No Typeface found with the name " + self.fontName +
                  ".ttf")
            sys.exit(0)  # quit Python

        # If the typeface that the user requested exists, but there's no position table for it, we'll continue with a warning
        try:
            table = __import__(
                'KiBuzzard.KiBuzzard.buzzard.typeface.' + self.fontName,
                globals(), locals(), ['glyphPos'])
            glyphPos = table.glyphPos
            spaceDistance = table.spaceDistance
        except:
            glyphPos = 0
            spaceDistance = 60
            print(
                "WARN: No Position Table found for this typeface. Composition will be haphazard at best."
            )

        # If there's lineover text, drop the text down to make room for the line
        dropBaseline = False
        a = False
        x = 0
        while x < len(inString):
            if x > 0 and inString[x] == '\\':
                a = True
                if x != len(inString) - 1:
                    x += 1
            if inString[x] == '!' and not a:
                dropBaseline = True
            a = False
            x += 1
        if dropBaseline:
            baseline = 190

        # Draw and compose the glyph portion of the tag
        for charIdx in range(len(inString)):
            # Check whether this character is a space
            if inString[charIdx] == ' ':
                glyphBounds.append(boundingBox(0, 0, 0, 0))
                xOffset += spaceDistance
                continue
            # Check whether this character is a backslash that isn't escaped
            # and isn't the first character (denoting a backslash-shaped tag)
            if inString[charIdx] == '\\' and charIdx > 0 and not escaped:
                glyphBounds.append(boundingBox(0, 0, 0, 0))
                escaped = True
                continue
            # If this is a non-escaped '!' mark the beginning of lineover
            if inString[charIdx] == '!' and not escaped:
                glyphBounds.append(boundingBox(0, 0, 0, 0))
                lineover = True
                # If we've hit the end of the string but not the end of the lineover
                # go ahead and finish it out
                if charIdx == len(inString) - 1 and len(lineoverList) > 0:
                    linePaths = []
                    linePaths.append(
                        Line(start=complex(lineoverList[0], 10),
                             end=complex(xOffset, 10)))
                    linePaths.append(
                        Line(start=complex(xOffset, 10),
                             end=complex(xOffset, 30)))
                    linePaths.append(
                        Line(start=complex(xOffset, 30),
                             end=complex(lineoverList[0], 30)))
                    linePaths.append(
                        Line(start=complex(lineoverList[0], 30),
                             end=complex(lineoverList[0], 10)))
                    linepath = Path(*linePaths)
                    linepath = elPath(linepath.d())
                    finalSegments.append(linepath)
                    lineover = False
                    lineoverList.clear()
                continue
            # All special cases end in 'continue' so if we've gotten here we can clear our flags
            if escaped:
                escaped = False

            face.load_char(
                inString[charIdx])  # Load character curves from font
            outline = face.glyph.outline  # Save character curves to var
            y = [t[1] for t in outline.points]
            # flip the points
            outline_points = [(p[0], max(y) - p[1]) for p in outline.points]
            start, end = 0, 0
            paths = []
            box = 0
            yOffset = 0

            for i in range(len(outline.contours)):
                end = outline.contours[i]
                points = outline_points[start:end + 1]
                points.append(points[0])
                tags = outline.tags[start:end + 1]
                tags.append(tags[0])
                segments = [
                    [
                        points[0],
                    ],
                ]
                box = boundingBox(points[0][0], points[0][1], points[0][0],
                                  points[0][1])
                for j in range(1, len(points)):
                    if not tags[j]:  # if this point is off-path
                        if tags[j - 1]:  # and the last point was on-path
                            segments[-1].append(
                                points[j])  # toss this point onto the segment
                        elif not tags[j -
                                      1]:  # and the last point was off-path
                            # get center point of two
                            newPoint = ((points[j][0] + points[j - 1][0]) /
                                        2.0,
                                        (points[j][1] + points[j - 1][1]) /
                                        2.0)
                            segments[-1].append(
                                newPoint
                            )  # toss this new point onto the segment
                            segments.append(
                                [
                                    newPoint,
                                    points[j],
                                ]
                            )  # and start a new segment with the new point and this one
                    elif tags[j]:  # if this point is on-path
                        segments[-1].append(
                            points[j])  # toss this point onto the segment
                        if j < (len(points) - 1):
                            segments.append(
                                [
                                    points[j],
                                ]
                            )  # and start a new segment with this point if we're not at the end

                for segment in segments:
                    if len(segment) == 2:
                        paths.append(
                            Line(start=tuple_to_imag(segment[0]),
                                 end=tuple_to_imag(segment[1])))

                    elif len(segment) == 3:
                        paths.append(
                            QuadraticBezier(start=tuple_to_imag(segment[0]),
                                            control=tuple_to_imag(segment[1]),
                                            end=tuple_to_imag(segment[2])))
                start = end + 1

            # Derive bounding box of character
            for segment in paths:
                i = 0
                while i < 10:
                    point = segment.point(0.1 * i)
                    if point.real > box.xMax:
                        box.xMax = point.real
                    if point.imag > box.yMax:
                        box.yMax = point.imag
                    if point.real < box.xMin:
                        box.xMin = point.real
                    if point.imag < box.yMin:
                        box.yMin = point.imag
                    i += 1

            glyphBounds.append(box)
            path = Path(*paths)
            if glyphPos != 0:
                try:
                    xOffset += glyphPos[inString[charIdx]].real
                    yOffset = glyphPos[inString[charIdx]].imag
                except:
                    pass
            if lineover and len(lineoverList) == 0:
                lineoverList.append(xOffset)
                lineover = False

            if (lineover and len(lineoverList) > 0):
                linePaths = []
                linePaths.append(
                    Line(start=complex(lineoverList[0], 10),
                         end=complex(xOffset, 10)))
                linePaths.append(
                    Line(start=complex(xOffset, 10), end=complex(xOffset, 30)))
                linePaths.append(
                    Line(start=complex(xOffset, 30),
                         end=complex(lineoverList[0], 30)))
                linePaths.append(
                    Line(start=complex(lineoverList[0], 30),
                         end=complex(lineoverList[0], 10)))
                linepath = Path(*linePaths)
                linepath = elPath(linepath.d())
                finalSegments.append(linepath)
                lineover = False
                lineoverList.clear()

            pathTransform = Matrix.translate(xOffset,
                                             baseline + yOffset - box.yMax)
            path = elPath(path.d()) * pathTransform
            path = elPath(path.d())
            finalSegments.append(path)
            xOffset += 30
            if glyphPos != 0:
                try:
                    xOffset -= glyphPos[inString[charIdx]].real
                except:
                    pass
            xOffset += (glyphBounds[charIdx].xMax - glyphBounds[charIdx].xMin)
            strIdx += 1

        if self.leftCap == '' and self.rightCap == '':
            for i in range(len(finalSegments)):
                svgObj = dwg.add(dwg.path(finalSegments[i].d()))
                svgObj['fill'] = "#000000"
        else:
            #draw the outline of the label as a filled shape and
            #subtract each latter from it
            tagPaths = []
            if self.rightCap == 'round':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Arc(start=complex(xOffset, 0),
                        radius=complex(100, 100),
                        rotation=180,
                        large_arc=1,
                        sweep=1,
                        end=complex(xOffset, 200)))
            elif self.rightCap == 'square':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 0),
                         end=complex(xOffset + 50, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'pointer':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 0),
                         end=complex(xOffset + 100, 100)))
                tagPaths.append(
                    Line(start=complex(xOffset + 100, 100),
                         end=complex(xOffset + 50, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'flagtail':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 100, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 100, 0),
                         end=complex(xOffset + 50, 100)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 100),
                         end=complex(xOffset + 100, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 100, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'fslash':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 0),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'bslash':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == '' and self.leftCap != '':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0), end=complex(xOffset, 200)))

            if self.leftCap == 'round':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Arc(start=complex(100, 200),
                        radius=complex(100, 100),
                        rotation=180,
                        large_arc=0,
                        sweep=1,
                        end=complex(100, 0)))
            elif self.leftCap == 'square':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 200)))
                tagPaths.append(
                    Line(start=complex(50, 200), end=complex(50, 0)))
                tagPaths.append(Line(start=complex(50, 0), end=complex(100,
                                                                       0)))
            elif self.leftCap == 'pointer':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 200)))
                tagPaths.append(
                    Line(start=complex(50, 200), end=complex(0, 100)))
                tagPaths.append(Line(start=complex(0, 100), end=complex(50,
                                                                        0)))
                tagPaths.append(Line(start=complex(50, 0), end=complex(100,
                                                                       0)))
            elif self.leftCap == 'flagtail':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(0, 200)))
                tagPaths.append(
                    Line(start=complex(0, 200), end=complex(50, 100)))
                tagPaths.append(Line(start=complex(50, 100), end=complex(0,
                                                                         0)))
                tagPaths.append(Line(start=complex(0, 0), end=complex(100, 0)))
            elif self.leftCap == 'fslash':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 200)))
                tagPaths.append(
                    Line(start=complex(50, 200), end=complex(100, 0)))
            elif self.leftCap == 'bslash':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 0)))
                tagPaths.append(Line(start=complex(50, 0), end=complex(100,
                                                                       0)))
            elif self.leftCap == '' and self.rightCap != '':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(100, 0)))

            path = Path(*tagPaths)
            for i in range(len(finalSegments)):
                path = elPath(path.d() + " " + finalSegments[i].reverse())
            tagObj = dwg.add(dwg.path(path.d()))
            tagObj['fill'] = "#000000"

        dwg['width'] = xOffset + 100
        dwg['height'] = 250

        #dwg.saveas('out.svg')

        print('create svg')

        return dwg