示例#1
0
def _flat_segment(p0, p1, p2, p3, tlr):
    p4 = midpoint(p0, p1)
    p5 = midpoint(p1, p2)
    p6 = midpoint(p2, p3)
    p7 = midpoint(p4, p5)
    p8 = midpoint(p5, p6)
    p9 = midpoint(p7, p8)

    b = sub_points(p3, p0)
    s = sub_points(p9, p0)
    c1 = sub_points(p1, p0)
    c2 = sub_points(p2, p3)

    if abs_point(c1) > abs_point(b) or abs_point(c2) > abs_point(b):
        return _flat_segment(p0, p4, p7, p9, tlr) + _flat_segment(p9, p8, p6, p3, tlr)

    elif abs_point(b) < tlr / 2.0:
        return [p9, p3]
    else:
        N = normalize_point(b)
        if (
            (mult_points(c1, N)) < -tlr
            or (mult_points(c2, N)) > tlr
            or cr_points(c1, b) * cr_points(c2, b) < 0
            or abs(cr_points(N, s)) > tlr
        ):
            return _flat_segment(p0, p4, p7, p9, tlr) + _flat_segment(p9, p8, p6, p3, tlr)
        else:
            return [p9, p3]
示例#2
0
文件: contour.py 项目: Scrik/sk1-wx
def create_stroke_outline (path, radius, linejoin=sk2_const.JOIN_MITER,
						captype=sk2_const.CAP_BUTT, miter_limit=MITER_LIMIT):
	"""
	Outlines a single stroke. Returns two lists of lists of bezier
	segments for both sides of the stroke.
	"""
	fw_segments = []
	bw_segments = []

	last_point = None

	segs = [path[0], ] + path[1]
	startpoint = [] + path[0]
	for i in range (len(segs)):
		segment = unpack_seg(segs[i], startpoint)
		startpoint = bezier_base_point(segs[i])
		if not segment[0]:
			if last_point:
				c1 = sub_points(segment[2], last_point)
				if not c1 == [0.0]:
					t1 = mult_point(normalize(c1), radius)
					fw_segments.append(
								[add_points(last_point, [t1[1], -t1[0]]),
								 add_points(segment[2], [t1[1], -t1[0]])])
					bw_segments.insert(0,
								[sub_points(segment[2], [t1[1], -t1[0]]),
								 sub_points(last_point, [t1[1], -t1[0]])])
			last_point = segment[2]

		else:
			segments = build_parallel([last_point, segment[1][0],
										segment[1][1], segment[2]], radius)
			fw_segments.append(segments)

			segments = build_parallel([segment[2], segment[1][1],
										segment[1][0], last_point], radius)
			bw_segments.insert(0, segments)
			last_point = segment[2]

	# Connect segments if necessary
	for item in [fw_segments, bw_segments]:
		join_segs(item, radius, linejoin, miter_limit,
				path[2] == sk2_const.CURVE_CLOSED)

	# Set caps for unclosed paths
	if not path[2] == sk2_const.CURVE_CLOSED:
		fw_segments.insert(0, get_cap_segment (bw_segments[-1][-1],
									fw_segments[0][0], captype))
		bw_segments.insert(0, get_cap_segment (fw_segments[-1][-1],
									bw_segments[0][0], captype))

	return fw_segments, bw_segments
示例#3
0
文件: contour.py 项目: Scrik/sk1-wx
def build_parallel(p, radius, recursionlimit=6):
	"""
	This builds a list of bezier segments that are "sufficiently"
	close to a given source segment. It recursively subdivides, if
	the check for parallelity fails.	
	"""
	# find tangent to calculate orthogonal neighbor of endpoint
	for i in p[1:]:
		c1 = sub_points(i, p[0])
		if c1: break

	if c1 == [0, 0]: return []

	t1 = mult_point(normalize(c1), radius)
	p0 = add_points(p[0], [t1[1], -t1[0]])
	c1 = sub_points(p[1], p[0])

	for i in [p[2], p[1], p[0]]:
		c2 = sub_points(p[3], i)
		if not c2 == [0, 0]: break

	t2 = mult_point(normalize(c2), radius)
	p3 = add_points(p[3], [t2[1], -t2[0]])
	c2 = sub_points(p[3], p[2])

	sd = subdivide_seg(p)
	center = sd[3]
	ccenter = mult_point(normalize(sub_points(sd[4], sd[3])), radius)

	new_center = add_points(center, [ccenter[1], -ccenter[0]])
	seg = [p0, add_points(p0, c1), sub_points(p3, c2), p3]
	now_center = subdivide_seg(seg)[3]

	offset = mult_point(sub_points(new_center, now_center), 8.0 / 3)

	det = c1[0] * c2[1] - c1[1] * c2[0]
	if det:
		ndet = det / length(c1) / length(c2)
	else:
		ndet = 0

	if math.fabs(ndet) >= 0.1:
		# "sufficiently" linear independent, cramers rule:
		oc1 = mult_point(c1, ((offset[0] * c2[1] - offset[1] * c2[0]) / det))
		oc2 = mult_point(c2, ((c1[0] * offset[1] - c1[1] * offset[0]) / det))
	else:
		# don't bother to try to correct the error, will figure out
		# soon if subdivision is necessary.
		oc1 = [0.0, 0.0]
		oc2 = [0.0, 0.0]

	new_p1 = add_points(add_points(p0, c1), oc1)
	new_p2 = add_points(sub_points(p3, c2), oc2)
	proposed_segment = [p0, new_p1, new_p2, p3]
	if check_parallel (p, proposed_segment, radius) or recursionlimit <= 0:
		return proposed_segment
	else:
		# "Not parallel enough" - subdivide.
		return (build_parallel (sd[:4], radius, recursionlimit - 1) +
				  build_parallel (sd[3:], radius, recursionlimit - 1)[1:])
示例#4
0
文件: contour.py 项目: Scrik/sk1-wx
def build_parallel(p, radius, recursionlimit=6):
    """
	This builds a list of bezier segments that are "sufficiently"
	close to a given source segment. It recursively subdivides, if
	the check for parallelity fails.	
	"""
    # find tangent to calculate orthogonal neighbor of endpoint
    for i in p[1:]:
        c1 = sub_points(i, p[0])
        if c1: break

    if c1 == [0, 0]: return []

    t1 = mult_point(normalize(c1), radius)
    p0 = add_points(p[0], [t1[1], -t1[0]])
    c1 = sub_points(p[1], p[0])

    for i in [p[2], p[1], p[0]]:
        c2 = sub_points(p[3], i)
        if not c2 == [0, 0]: break

    t2 = mult_point(normalize(c2), radius)
    p3 = add_points(p[3], [t2[1], -t2[0]])
    c2 = sub_points(p[3], p[2])

    sd = subdivide_seg(p)
    center = sd[3]
    ccenter = mult_point(normalize(sub_points(sd[4], sd[3])), radius)

    new_center = add_points(center, [ccenter[1], -ccenter[0]])
    seg = [p0, add_points(p0, c1), sub_points(p3, c2), p3]
    now_center = subdivide_seg(seg)[3]

    offset = mult_point(sub_points(new_center, now_center), 8.0 / 3)

    det = c1[0] * c2[1] - c1[1] * c2[0]
    if det:
        ndet = det / length(c1) / length(c2)
    else:
        ndet = 0

    if math.fabs(ndet) >= 0.1:
        # "sufficiently" linear independent, cramers rule:
        oc1 = mult_point(c1, ((offset[0] * c2[1] - offset[1] * c2[0]) / det))
        oc2 = mult_point(c2, ((c1[0] * offset[1] - c1[1] * offset[0]) / det))
    else:
        # don't bother to try to correct the error, will figure out
        # soon if subdivision is necessary.
        oc1 = [0.0, 0.0]
        oc2 = [0.0, 0.0]

    new_p1 = add_points(add_points(p0, c1), oc1)
    new_p2 = add_points(sub_points(p3, c2), oc2)
    proposed_segment = [p0, new_p1, new_p2, p3]
    if check_parallel(p, proposed_segment, radius) or recursionlimit <= 0:
        return proposed_segment
    else:
        # "Not parallel enough" - subdivide.
        return (build_parallel(sd[:4], radius, recursionlimit - 1) +
                build_parallel(sd[3:], radius, recursionlimit - 1)[1:])
示例#5
0
def flat_path(path, tlr=0.5):
    result = [[] + path[0]]
    start = [] + path[0]
    for point in path[1]:
        if len(point) == 2:
            result.append([] + point)
            start = [] + point
        else:
            p0 = sub_points(point[0], start)
            p1 = sub_points(point[1], start)
            p2 = sub_points(point[2], start)
            points = _flat_segment([0.0, 0.0], p0, p1, p2, tlr)
            for item in points:
                p = add_points(item, start)
                result.append(p)
            start = [] + point[2]
    return [result[0], result[1:], path[2]]
示例#6
0
文件: contour.py 项目: Scrik/sk1-wx
def check_parallel(source, parallel, radius, tolerance=0.01):
	"""
	This function checks, if two bezier segments are "sufficiently"
	parallel. It checks, if the points for the parameters 0.25, 0.5
	and 0.75 of the tested segment are orthogonal to the resp.
	points of the source segment. 1% tolerance is default.
	
	It does not check the start and endpoints, since they are
	assumed to be correct by construction.
	"""
	for t0 in [0.25, 0.5, 0.75]:
		s = subdivide_seg(source, t0)
		t = subdivide_seg(parallel, t0)
		ccenter = mult_point(normalize(sub_points(s[4], s[3])), radius)
		orig = add_points(s[3], [ccenter[1], -ccenter[0]])
		if length(sub_points(orig, t[3])) >= tolerance * radius: return False
	return True
示例#7
0
文件: contour.py 项目: Scrik/sk1-wx
def check_parallel(source, parallel, radius, tolerance=0.01):
    """
	This function checks, if two bezier segments are "sufficiently"
	parallel. It checks, if the points for the parameters 0.25, 0.5
	and 0.75 of the tested segment are orthogonal to the resp.
	points of the source segment. 1% tolerance is default.
	
	It does not check the start and endpoints, since they are
	assumed to be correct by construction.
	"""
    for t0 in [0.25, 0.5, 0.75]:
        s = subdivide_seg(source, t0)
        t = subdivide_seg(parallel, t0)
        ccenter = mult_point(normalize(sub_points(s[4], s[3])), radius)
        orig = add_points(s[3], [ccenter[1], -ccenter[0]])
        if length(sub_points(orig, t[3])) >= tolerance * radius: return False
    return True
示例#8
0
def flat_path(path, tlr=0.5):
    result = []
    result.append([] + path[0])
    start = [] + path[0]
    for point in path[1]:
        if len(point) == 2:
            result.append([] + point)
            start = [] + point
        else:
            p0 = sub_points(point[0], start)
            p1 = sub_points(point[1], start)
            p2 = sub_points(point[2], start)
            points = _flat_segment([0.0, 0.0], p0, p1, p2, tlr)
            for item in points:
                p = add_points(item, start)
                result.append(p)
            start = [] + point[2]
    return [result[0], result[1:], path[2]]
示例#9
0
文件: contour.py 项目: sahwar/sk1-wx
def get_cap_segment(startpoint, endpoint, captype):
    """
    This returns a list of bezier segments that form the end cap of
    a line. Valid captypes are: CAP_BUTT, CAP_ROUND, CAP_SQUARE	
    """

    #  =====|
    if captype == sk2const.CAP_BUTT:
        return [startpoint, endpoint]

    # =====)
    elif captype == sk2const.CAP_ROUND:
        f = CIRCLE_CONSTANT
        d = mult_point(sub_points(endpoint, startpoint), 0.5)
        o = [d[1], -d[0]]

        new_p1 = add_points(startpoint, o)
        new_p2 = mult_point(o, f)

        return [
            startpoint,
            add_points(startpoint, new_p2),
            add_points(new_p1, mult_point(d, 1 - f)),
            add_points(new_p1, d),
            add_points(new_p1, mult_point(d, 1 + f)),
            add_points(endpoint, new_p2), endpoint
        ]

    # =====]
    elif captype == sk2const.CAP_SQUARE:
        d = mult_point(sub_points(endpoint, startpoint), 0.5)
        o = [d[1], -d[0]]

        new_p1 = add_points(startpoint, o)
        new_p2 = add_points(endpoint, o)

        return [
            startpoint, startpoint, new_p1, new_p1, new_p1, new_p2, new_p2,
            new_p2, endpoint, endpoint
        ]

    else:
        raise 'Unknown captype %d' % captype
示例#10
0
文件: contour.py 项目: Scrik/sk1-wx
def get_cap_segment (startpoint, endpoint, captype):
	"""
	This returns a list of bezier segments that form the end cap of
	a line. Valid captypes are: CAP_BUTT, CAP_ROUND, CAP_SQUARE	
	"""

	#  =====|
	if captype == sk2_const.CAP_BUTT:
		return [startpoint, endpoint]

	#  =====)
	elif captype == sk2_const.CAP_ROUND:
		f = CIRCLE_CONSTANT
		d = mult_point(sub_points(endpoint, startpoint), 0.5)
		o = [d[1], -d[0]]

		new_p1 = add_points(startpoint, o)
		new_p2 = mult_point(o, f)

		return [startpoint,
				add_points(startpoint, new_p2),
				add_points(new_p1, mult_point(d, 1 - f)),
				add_points(new_p1, d),
				add_points(new_p1, mult_point(d, 1 + f)),
				add_points(endpoint, new_p2),
				endpoint]

	#  =====]
	elif captype == sk2_const.CAP_SQUARE:
		d = mult_point(sub_points(endpoint, startpoint), 0.5)
		o = [d[1], -d[0]]

		new_p1 = add_points(startpoint, o)
		new_p2 = add_points(endpoint, o)

		return [startpoint, startpoint, new_p1, new_p1, new_p1,
				new_p2, new_p2, new_p2, endpoint, endpoint]

	else:
		raise "Unknown captype %d" % captype
示例#11
0
文件: contour.py 项目: sahwar/sk1-wx
def create_stroke_outline(path,
                          radius,
                          linejoin=sk2const.JOIN_MITER,
                          captype=sk2const.CAP_BUTT,
                          miter_limit=MITER_LIMIT):
    """
    Outlines a single stroke. Returns two lists of lists of bezier
    segments for both sides of the stroke.
    """
    fw_segments = []
    bw_segments = []

    last_point = None

    segs = [
        path[0],
    ] + path[1]
    startpoint = [] + path[0]
    for i in range(len(segs)):
        segment = unpack_seg(segs[i], startpoint)
        startpoint = bezier_base_point(segs[i])
        if not segment[0]:
            if last_point:
                c1 = sub_points(segment[2], last_point)
                if not c1 == [0.0]:
                    t1 = mult_point(normalize(c1), radius)
                    fw_segments.append([
                        add_points(last_point, [t1[1], -t1[0]]),
                        add_points(segment[2], [t1[1], -t1[0]])
                    ])
                    bw_segments.insert(0, [
                        sub_points(segment[2], [t1[1], -t1[0]]),
                        sub_points(last_point, [t1[1], -t1[0]])
                    ])
            last_point = segment[2]

        else:
            segments = build_parallel(
                [last_point, segment[1][0], segment[1][1], segment[2]], radius)
            fw_segments.append(segments)

            segments = build_parallel(
                [segment[2], segment[1][1], segment[1][0], last_point], radius)
            bw_segments.insert(0, segments)
            last_point = segment[2]

    # Connect segments if necessary
    for item in [fw_segments, bw_segments]:
        join_segs(item, radius, linejoin, miter_limit,
                  path[2] == sk2const.CURVE_CLOSED)

    # Set caps for unclosed paths
    if not path[2] == sk2const.CURVE_CLOSED:
        fw_segments.insert(
            0, get_cap_segment(bw_segments[-1][-1], fw_segments[0][0],
                               captype))
        bw_segments.insert(
            0, get_cap_segment(fw_segments[-1][-1], bw_segments[0][0],
                               captype))

    return fw_segments, bw_segments
示例#12
0
文件: contour.py 项目: sahwar/sk1-wx
def get_join_segment(startpoint,
                     endpoint,
                     radius,
                     jointype,
                     miter_limit=MITER_LIMIT):
    """
    This returns a list of bezier segments that joins two points
    with a given radius (fails if the radius is smaller than the
    distance between startpoint) and endpoint). 
    jointype is one of 	JOIN_MITER, JOIN_ROUND, JOIN_BEVEL	
    """

    if jointype == sk2const.JOIN_MITER:
        d = mult_point(sub_points(endpoint, startpoint), 0.5)

        if d == [0, 0]:
            return []

        o = normalize([d[1], -d[0]])

        if radius < length(d):
            return [startpoint, endpoint]

        h = math.sqrt(radius**2 - length(d)**2)

        h2 = length(d)**2 / h

        if h2 + h > miter_limit * radius:
            # Hit miter limit
            return [startpoint, endpoint]

        edge = add_points(add_points(startpoint, d), mult_point(o, h2))
        new_seg1 = line_to_curve(startpoint, edge)
        new_seg2 = line_to_curve(edge, endpoint)
        return [
            startpoint,
        ] + new_seg1 + new_seg2

    elif jointype == sk2const.JOIN_ROUND:
        f = CIRCLE_CONSTANT
        d = mult_point(sub_points(endpoint, startpoint), 0.5)

        if d == [0, 0]:
            return []

        o = mult_point(normalize([d[1], -d[0]]), radius)

        if radius < length(d):
            return [startpoint, endpoint]

        h = math.sqrt(radius**2 - length(d)**2) / radius

        center = sub_points(add_points(startpoint, d), mult_point(o, h))
        d = mult_point(normalize(d), radius)

        t0 = circleparam(h)
        quadseg = [
            sub_points(center, d),
            add_points(sub_points(center, d), mult_point(o, f)),
            add_points(sub_points(center, mult_point(d, f)), o),
            add_points(center, o)
        ]
        ret = [startpoint] + list(subdivide_seg(quadseg, t0)[4:])

        quadseg = [
            add_points(center, o),
            add_points(add_points(center, o), mult_point(d, f)),
            add_points(add_points(center, d), mult_point(o, f)),
            add_points(center, d)
        ]
        ret = ret + list(subdivide_seg(quadseg, 1 - t0)[1:3]) + [endpoint]

        return ret

    elif jointype == sk2const.JOIN_BEVEL:
        return [startpoint, endpoint]

    else:
        raise "Unknown join type %d" % jointype
示例#13
0
文件: contour.py 项目: Scrik/sk1-wx
def get_join_segment(startpoint, endpoint, radius, jointype,
					miter_limit=MITER_LIMIT):
	"""
	This returns a list of bezier segments that joins two points
	with a given radius (fails if the radius is smaller than the
	distance between startpoint) and endpoint). 
	jointype is one of 	JOIN_MITER, JOIN_ROUND, JOIN_BEVEL	
	"""

	if jointype == sk2_const.JOIN_MITER:
		d = mult_point(sub_points(endpoint, startpoint), 0.5)

		if d == [0, 0]: return []

		o = normalize([d[1], -d[0]])
		h = math.sqrt(radius ** 2 - length(d) ** 2)

		h2 = length(d) ** 2 / h

		if h2 + h > miter_limit * radius:
			# Hit miter limit
			return [startpoint, endpoint]

		edge = add_points(add_points(startpoint, d), mult_point(o, h2))
		new_seg1 = line_to_curve(startpoint, edge)
		new_seg2 = line_to_curve(edge, endpoint)
		return [startpoint, ] + new_seg1 + new_seg2

	elif jointype == sk2_const.JOIN_ROUND:
		f = CIRCLE_CONSTANT
		d = mult_point(sub_points(endpoint, startpoint), 0.5)

		if d == [0, 0]: return []

		o = mult_point(normalize([d[1], -d[0]]), radius)

		h = math.sqrt(radius ** 2 - length(d) ** 2) / radius

		center = sub_points(add_points(startpoint, d), mult_point(o, h))
		d = mult_point(normalize(d), radius)

		t0 = circleparam(h)
		quadseg = [sub_points(center, d),
					add_points(sub_points(center, d), mult_point(o, f)),
					add_points(sub_points(center, mult_point(d, f)), o),
					add_points(center, o)]
		ret = [startpoint] + list (subdivide_seg(quadseg, t0)[4:])

		quadseg = [add_points(center, o),
					add_points(add_points(center, o), mult_point(d, f)),
					add_points(add_points(center, d), mult_point(o, f)),
					add_points(center, d)]
		ret = ret + list (subdivide_seg(quadseg, 1 - t0)[1:3]) + [endpoint]

		return ret

	elif jointype == sk2_const.JOIN_BEVEL:
		return [startpoint, endpoint]

	else:
		raise "Unknown join type %d" % jointype