Example #1
0
def split_line_by_pattern(points, pattern):

    dg = DashGenerator(pattern)
    lines = []
    is_whitespace = False
    current_line = []

    for p in xrange(1, len(points)):
        start = vec2(points[p-1])
        end = vec2(points[p])
        normal = (end - start).normalized()
        amount_to_move = (end - start).length()

        current = start
        while amount_to_move > 0:
            l, should_flip = dg.next(amount_to_move)
            a = current
            b = current + normal * l
            current = b
            if not is_whitespace:
                if len(current_line):
                    current_line.append(b)
                else:
                    current_line.append(a)
                    current_line.append(b)
            if should_flip:
                if not is_whitespace:
                    lines.append(current_line)
                    current_line = []
                is_whitespace = not is_whitespace

            amount_to_move -= l
    if len(current_line):
        lines.append(current_line)
    return lines
Example #2
0
 def calculate_tangents(self):
     v = (self.end - self.start).normalized()
     angle = math.atan2(v.y, v.x)
     half_width = self.w * 0.5
     self.up_normal = vec2(math.cos(angle - radian(90)) * half_width,
                           math.sin(angle - radian(90)) * half_width)
     self.dn_normal = vec2(math.cos(angle + radian(90)) * half_width,
                           math.sin(angle + radian(90)) * half_width)
Example #3
0
    def _render_stroke(self):
        stroke = self.style.stroke
        stroke_width = self.style.stroke_width

        is_miter = self.style.stroke_linejoin == 'miter'

        miter_limit = self.style.stroke_miterlimit if is_miter else 0

        for loop in self.outlines:
            self.svg.n_lines += len(loop) - 1
            loop_plus = []

            for i in xrange(len(loop) - 1):
                loop_plus += [loop[i], loop[i+1]]

            if isinstance(stroke, str):
                g = self.svg._gradients[stroke]
                strokes = [g.sample(x, self) for x in loop_plus]
            else:
                strokes = [stroke for x in loop_plus]

            if len(loop_plus) == 0:
                continue

            if len(self.style.stroke_dasharray):
                ls = lines.split_line_by_pattern(loop_plus, self.style.stroke_dasharray)

                if ls[0][0] == ls[-1][-1]:
                    #if the last line end point equals the first line start point,
                    #this is a "closed" line, so combine the first and the last line
                    combined_line = ls[-1] + ls[0]
                    ls[0] = combined_line
                    del ls[-1]

                for l in ls:
                    lines.draw_polyline(
                        l,
                        stroke_width,
                        color=strokes[0],
                        line_cap=self.style.stroke_linecap,
                        join_type=self.style.stroke_linejoin,
                        miter_limit=miter_limit)

                if self.marker_start:
                    end_point = vec2(loop_plus[0])
                    almost_end_point = vec2(loop_plus[1])
                    marker = self.svg.defs[self.marker_start]
                    self._render_marker(end_point, almost_end_point, marker, True)
                if self.marker_end:
                    end_point = vec2(loop_plus[-1])
                    almost_end_point = vec2(loop_plus[-2])
                    marker = self.svg.defs[self.marker_end]
                    self._render_marker(end_point, almost_end_point, marker)

            else:
                lines.draw_polyline(
                    loop_plus,
                    stroke_width,
                    color=strokes[0],
                    line_cap=self.style.stroke_linecap,
                    join_type=self.style.stroke_linejoin,
                    miter_limit=miter_limit)

                if self.marker_start:
                    end_point = vec2(loop_plus[0])
                    almost_end_point = vec2(loop_plus[1])
                    marker = self.svg.defs[self.marker_start]
                    self._render_marker(end_point, almost_end_point, marker, True)
                if self.marker_end:
                    end_point = vec2(loop_plus[-1])
                    almost_end_point = vec2(loop_plus[-2])
                    marker = self.svg.defs[self.marker_end]
                    self._render_marker(end_point, almost_end_point, marker)
Example #4
0
def _process_joint(ln, pln, miter_limit, rounded=False):
    up_intersection, ln.upper_join = ln_intersection(pln.upper_edge, ln.upper_edge)
    lo_intersection, ln.lower_join = ln_intersection(pln.lower_edge, ln.lower_edge)

    if up_intersection and lo_intersection:
        pln.upper_v.append(pln.upper_join)
        pln.lower_v.append(pln.lower_join)
        return

    if ln.upper_join == None:
        ln.upper_join = ln.upper_edge.start

    if ln.lower_join == None:
        ln.lower_join = ln.lower_edge.start

    ml1 = line_length(ln.lower_edge.start, ln.upper_join)

    if rounded:
        pass


    if rounded and not up_intersection:
        ln.upper_join = ln.upper_edge.start
        pln.upper_v.append(pln.upper_join)
        pln.upper_v.append(pln.upper_edge.end)

        #arc to next lines upper-join
        base = pln.end
        start = pln.upper_edge.end
        target = ln.upper_join

        dist = (start-base).length()
        av = (start - base).normalized()
        bv = (target - base).normalized()

        start_angle = av.angle()
        target_angle = bv.angle()
        if start_angle > target_angle:
            start_angle -= 2.0 * math.pi

        theta = start_angle
        pln.lower_v.append(pln.lower_join)
        while theta < target_angle:
            v = base + (vec2(math.cos(theta), math.sin(theta)) * dist)
            pln.upper_v.append(v)
            pln.lower_v.append(ln.lower_join)
            theta += 0.2

        pln.upper_v.append(ln.upper_join)
        return
    elif ml1 > miter_limit and not up_intersection:
        #bevel
        ln.upper_join = ln.upper_edge.start
        pln.upper_v.append(pln.upper_join)
        pln.upper_v.append(pln.upper_edge.end)
        pln.upper_v.append(ln.upper_join)
    elif not rounded:
        pln.upper_v.append(pln.upper_join)
        pln.upper_v.append(ln.upper_join)

    ml2 = line_length(ln.upper_edge.start, ln.lower_join)

    if rounded and not lo_intersection:
        ln.lower_join = ln.lower_edge.start
        pln.upper_v.append(pln.upper_join)
        pln.lower_v.append(pln.lower_join)

        #arc to next lines upper-join
        base = pln.end
        start = pln.lower_edge.end
        target = ln.lower_join

        dist = (start-base).length()
        av = (start - base).normalized()
        bv = (target - base).normalized()

        start_angle = av.angle()
        target_angle = bv.angle()
        if start_angle < target_angle:
            start_angle += 2.0 * math.pi

        theta = start_angle
        pln.upper_v.append(ln.upper_join)

        while theta > target_angle:
            v = base + (vec2(math.cos(theta), math.sin(theta)) * dist)

            pln.lower_v.append(v)
            pln.upper_v.append(ln.upper_join)
            theta -= 0.2
        pln.lower_v.append(ln.lower_join)

    elif ml2 > miter_limit and not lo_intersection:
        #bevel
        ln.lower_join = ln.lower_edge.start
        pln.lower_v.append(pln.lower_join)
        pln.lower_v.append(pln.lower_edge.end)
        pln.lower_v.append(ln.lower_join)
    else:
        pln.lower_v.append(pln.lower_join)
        pln.lower_v.append(ln.lower_join)
Example #5
0
def calc_polyline(points, w, line_cap='butt', join_type='miter', miter_limit=4, closed=False):

    miter_length = w * miter_limit
    points = [vec2(p) for p in points]
    if closed and points[0] != points[-1]:
        points.append(vec2(points[0]))

    lines = []
    for i in range(len(points) - 1):
        lines.append(
            LineSegment(points[i], points[i+1], w))

    lines[0].upper_join = lines[0].upper_edge.start
    lines[0].lower_join = lines[0].lower_edge.start

    if line_cap == 'square' and not closed:
        ext = lines[0].direction * w * -0.5
        lines[0].upper_join = lines[0].upper_join + ext
        lines[0].lower_join = lines[0].lower_join + ext

    for i in range(1, len(lines)):
        ln, pln = lines[i], lines[i-1]
        _process_joint(ln, pln, miter_length, join_type=='round')

    ll = lines[-1]
    lf = lines[0]
    if closed:
        b_up_int, upper_join = ln_intersection(ll.upper_edge, lf.upper_edge)
        b_lo_int, lower_join = ln_intersection(ll.lower_edge, lf.lower_edge)

        if upper_join == None: upper_join = ll.upper_edge.end
        if lower_join == None: lower_join = ll.lower_edge.end

        if line_length(ll.lower_edge.end, upper_join) > miter_length and b_up_int:
            #bevel
            ll.upper_v.append(ll.upper_join)
            ll.upper_v.append(ll.upper_edge.end)
            ll.upper_v.append(lf.upper_edge.start)
        else:
            lf.upper_v[0] = upper_join
            ll.upper_v.append(ll.upper_join)
            ll.upper_v.append(upper_join)

        if line_length(ll.upper_edge.end, lower_join) > miter_length and b_lo_int:
            #bevel
            ll.lower_v.append(ll.lower_join)
            ll.lower_v.append(ll.lower_edge.end)
            ll.lower_v.append(lf.lower_edge.start)
        else:
            lf.lower_v[0] = lower_join
            ll.lower_v.append(ll.lower_join)
            ll.lower_v.append(lower_join)

    else:
        if line_cap == 'butt' or line_cap == 'round':
            ll.upper_v.append(ll.upper_join)
            ll.upper_v.append(ll.upper_edge.end)
            ll.lower_v.append(ll.lower_join)
            ll.lower_v.append(ll.lower_edge.end)
        elif line_cap == 'square':
            ext = ll.direction * w*0.5
            ll.upper_v.append(ll.upper_join)
            ll.upper_v.append(ll.upper_edge.end + ext)
            ll.lower_v.append(ll.lower_join)
            ll.lower_v.append(ll.lower_edge.end + ext)

    return lines