示例#1
0
def createSVG(filename, tool, points):
  # Generate the paths
  allPoints = list()
  paths = list()
  t = Template(PATH_TEMPLATE)
  for point in points:
    allPoints.extend(point)
    path = Path()
    lx, ly = point[0]
    pc = 0
    for p in point[1:]:
      l = mkLine(lx, ly, p[0], p[1])
      if l is not None:
        path.append(l)
        pc = pc + 1
      lx = p[0]
      ly = p[1]
    path.closed = True
    paths.append(t.safe_substitute({ 'strokeWidth': tool, 'path': path.d() }))
    print "Generated path with %d points." % pc
  # Build the final output
  v = { 
    'xmin': min([ x for x, y in allPoints ]) - (tool / 2),
    'ymin': min([ y for x, y in allPoints ]) - (tool / 2),
    'xmax': max([ x for x, y in allPoints ]) + (tool / 2),
    'ymax': max([ y for x, y in allPoints ]) + (tool / 2)
    }
  v['width'] = abs(v['xmax'] - v['xmin'])
  v['height'] = abs(v['ymax'] - v['ymin'])
  v['path'] = "\n".join(paths)
  out = Template(SVG_TEMPLATE).substitute(v).strip()
  # And write the file
  with open(filename, "w") as svg:
    svg.write(out)
示例#2
0
def breakIntoLines(segment):

    #I may need to check if it is a move command and do nothing...

    #for now I am just going to hardcode this but it is possible that I will make it dynamic in the future
    numberOfSegments = 20
    baseSegmentStep = 1 / (numberOfSegments)
    segmentStep = 1 / (numberOfSegments)
    k = 0
    linesOnlySegment = Path()

    initialPoint = segment.point(0.0)

    while (k <= numberOfSegments):
        currentPoint = segment.point(segmentStep)
        if (k == 0):
            returnedLine = createLineSegment(currentPoint, initialPoint)
        else:
            returnedLine = createLineSegment(currentPoint, lastPoint)

        linesOnlySegment.append(returnedLine)
        lastPoint = segment.point(segmentStep)

        k = k + 1
        segmentStep = baseSegmentStep * k

    return linesOnlySegment
示例#3
0
文件: path.py 项目: asteinh/sympathor
    def __init__(self, path):
        Path.__init__(self)
        elements.SymbolicMixin.__init__(self)

        # build path from segments
        for seg in path._segments:
            clss = 'Symbolic' + seg.__class__.__name__
            self._segments.append(getattr(elements, clss)(seg))

        self.__symbolic_setup()
示例#4
0
def test_Path_close_adds_a_close_path_command_to_the_path():
    path = Path((0, 1)).v_line(-1.2, relative=True)
    path.h_line(2.5, relative=True)
    path.close()
    assert str(path) == '<path d="M 0 1 v -1.2 h 2.5 Z"/>\n'

    path = Path((0, 2)).h_line(2.5, relative=True).close()
    assert str(path) == '<path d="M 0 2 h 2.5 Z"/>\n'
示例#5
0
    def test_get_path_not_starting_at_0(self):
        test_path = Path(Line(start=(0 + 0j), end=(2 + 2j)),
                         Line(start=(2 + 2j), end=(7 + 1j)),
                         Line(start=(7 + 1j), end=(0 + 0j)))

        expected_result = Trajectory.discretize(
            Path(Line(start=(2 + 2j), end=(7 + 1j)),
                 Line(start=(7 + 1j), end=(0 + 0j)),
                 Line(start=(0 + 0j), end=(2 + 2j))), 1)

        traj = Trajectory()
        traj.paths.append(test_path)
        result = traj.get_path(0, 1, 1)

        self.assertEqual(result, expected_result)
示例#6
0
def createPathObject(numberOfFiles):
    k = 0
    while (k < numberOfFiles):
        parsedPath = Path()
        individualSegmentCommand = []
        individualSegmentCollection = []

        f = open("onlyCurves" + str(k) + ".txt", "r")

        pathToFormString = str(f.readline())

        f.close()

        listOfSegments = re.split("M|m|L|l|H|h|V|v|C|c|S|s|Q|q|T|t|A|a|Z|z",
                                  pathToFormString)
        svgCommands = re.findall("M|m|L|l|H|h|V|v|C|c|S|s|Q|q|T|t|A|a|Z|z",
                                 pathToFormString)

        for x in range(len(svgCommands)):
            individualSegmentCommand.append(
                (svgCommands[x] + listOfSegments[x + 1]).strip())
        individualSegmentCollection.append(individualSegmentCommand)

        # for y in range(len(individualSegmentCollection[0])):
        #     # parsedPath.append(individualSegmentCollection[0][y])
        #     parsedPath = Path(individualSegmentCollection[0])

        f = open("onlyCurves" + str(k) + ".txt", "w")

        f.write(str(individualSegmentCollection[0]))

        f.close()

        k = k + 1
示例#7
0
    def add_highlight_lines(self, lines):
        for line in lines:
            new_path_node = self.dom.createElement("path")

            new_path_node.setAttribute('d', Path(line).d())
            new_path_node.setAttribute('fill', 'none')
            new_path_node.setAttribute('stroke', '#FF0000')
            new_path_node.setAttribute('stroke-width', '1')

            self.svg_node.appendChild(new_path_node)
示例#8
0
文件: path.py 项目: asteinh/sympathor
    def length(self):
        """
        Compute overall length of path.

        Returns
        -------
        length : numpy.float
            Length of path

        """
        return np.float(Path.length(self))
示例#9
0
    def test_path_is_homogeneously_sampled(self):
        test_path = Path(Line(start=(0 + 0j), end=(5 + 0j)))
        expected_result = [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0)]

        traj = Trajectory()
        traj.paths.append(test_path)
        result = traj.get_path(0, 0, 1)

        for (x1, y1), (x2, y2) in zip(result, expected_result):
            self.assertAlmostEqual(x1, x2, delta=0.01)
            self.assertAlmostEqual(y1, y2, delta=0.01)
示例#10
0
    def test_get_normalized_path(self):
        traj = Trajectory()

        test_path = Path(Line(start=(0 + 0j), end=(2 + 2j)),
                         Line(start=(2 + 2j), end=(7 + 1j)),
                         Line(start=(7 + 1j), end=(0 + 0j)))

        expected_path = Trajectory.scale(
            Trajectory.discretize(
                Path(Line(start=(0 + 0j), end=(2 + 2j)),
                     Line(start=(2 + 2j), end=(7 + 1j)),
                     Line(start=(7 + 1j), end=(0 + 0j))), 1), 1 / 7.0, 1 / 2.0)

        traj.paths.append(test_path)
        normalized_trajectory = traj.get_normalized_path(0)

        self.assertGreater(len(normalized_trajectory), 3)

        for (x1, y1), (x2, y2) in zip(normalized_trajectory, expected_path):
            self.assertAlmostEqual(x1, x2, delta=0.01)
            self.assertAlmostEqual(y1, y2, delta=0.01)
示例#11
0
def path_to_polygon(path):
    polygon = []
    global max_x, max_y, min_x, min_y
    new_path = Path()
    for segment in parse_path(path):
        new_path.append(Line(segment.start, segment.end))
    new_path.closed = True
    raw_path = new_path.d()

    # search for compound path bits and remove them
    path_bits = re.findall('M.+?[ZM]', raw_path)
    if len(path_bits) > 0:
        raw_path = path_bits[0]
        raw_path_size = len(re.findall(',', raw_path))
        for bit in path_bits:
            bit_size = len(re.findall(',', bit))
            if bit_size > raw_path_size:
                raw_path = bit
                raw_path_size = bit_size

    # convert to simple list of nodes
    nodes = re.findall('[ML]\s*(\d+\.*\d*,\d+\.*\d*)\s*', raw_path)
    for n in nodes:
        coords = n.split(',')
        if max_x < int(coords[0]):
            max_x = int(coords[0])
        if max_y < int(coords[1]):
            max_y = int(coords[1])
        if min_x > int(coords[0]):
            min_x = int(coords[0])
        if min_y > int(coords[1]):
            min_y = int(coords[1])
        polygon.append([int(coords[0]), int(coords[1])])
    polygon.pop()
    return polygon
示例#12
0
def _get_closed_subpaths(path):
    '''
    Generates all closed subpaths raises error if open subpaths exist.

    Credit to @tatarize:
    https://github.com/regebro/svg.path/issues/54#issuecomment-570101018
    '''
    segments = None
    for p in path:
        if isinstance(p, Move):
            if segments is not None:
                raise RuntimeError("Only closed shapes accepted.")
            segments = []

        segments.append(p)

        if isinstance(p, Close):
            yield Path(*segments)
            segments = None
示例#13
0
def createSVG(filename, tool, points):
    # Generate the paths
    allPoints = list()
    paths = list()
    t = Template(PATH_TEMPLATE)
    for point in points:
        allPoints.extend(point)
        path = Path()
        lx, ly = point[0]
        pc = 0
        for p in point[1:]:
            l = mkLine(lx, ly, p[0], p[1])
            if l is not None:
                path.append(l)
                pc = pc + 1
            lx = p[0]
            ly = p[1]
        path.closed = True
        paths.append(t.safe_substitute({
            'strokeWidth': tool,
            'path': path.d()
        }))
        print "Generated path with %d points." % pc
    # Build the final output
    v = {
        'xmin': min([x for x, y in allPoints]) - (tool / 2),
        'ymin': min([y for x, y in allPoints]) - (tool / 2),
        'xmax': max([x for x, y in allPoints]) + (tool / 2),
        'ymax': max([y for x, y in allPoints]) + (tool / 2)
    }
    v['width'] = abs(v['xmax'] - v['xmin'])
    v['height'] = abs(v['ymax'] - v['ymin'])
    v['path'] = "\n".join(paths)
    out = Template(SVG_TEMPLATE).substitute(v).strip()
    # And write the file
    with open(filename, "w") as svg:
        svg.write(out)
示例#14
0
'''

SVG2 = '''  </g>
</svg>
'''

svgpath1 = '''<path
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       d="'''
svgpath2 = ''' Z"/>
'''

all_paths = []
print(SVG1)
for p in paths:
    new_path = Path()
    path = parse_path(p.attrib["d"])
    all_paths.append(svgpath1 + path.d() + svgpath2)

mul = sys.argv[2]
count = 0
MAX = 43330
for x in range(int(mul)):
    if (count >= MAX):
        break

    for p in all_paths:
        if (count >= MAX):
            break

        print(p)
def get_paths(edges, nodes, node_type, extra_nodes, pos, label, label_size, pathway, cofactors = None, min_path_length = 10, max_bend = 40, prevent_overlap = True, direction_default = 'v', reverse_cofactor_direction = []):
	"""
	Get svg-paths for the metabolic map.
	INPUT:
	'edges': 				a list of edges; i.e. (reaction node, species node) tuples.
	'nodes': 				a list of nodes. 
	'node_type': 			a dictionary with node types; keys are nodes and values are 
							the type of node, being either 'reaction' or 'species'.
	'extra_nodes':			a dictionary with nodes that are not representative of reactions
							or species, but help with drawing svg-paths by giving extra 
							points through which the path must be drawn.
	'pos':					a dictionary with coordinates of the nodes; keys are nodes and
							values are (x,y) tuples.
	'label':				a dictionary with labels; keys are nodes and values are metabolite
							or reaction names.
	'label_size': 			a dictionary with node label size; keys are nodes and values are 
							[width, height] tuples
	'pathway':				a dictionary with pathways; keys are nodes and values are pathways
							(if 'cycle' is in the pathway name and the node is on a circle of 
							nodes in the same pathway, paths will be drawn as arcs instead of
							bezier curves).
	'cofactors'				a dictionary with cofactors; keys are reactions and values are species.
	'min_path_length':		minimal length of paths.
	'max_bend': 			curvature of the paths.
	'prevent_overlap':		prevent overlap of paths and labels.
	'direction_default':	default direction of paths at reaction nodes.
	'reverse_cofactors':	list of reactions in which cofactors must be placed in opposite order
	
	OUTPUT:
	A dictionary with the svg-paths; keys are edges and values are svg paths (svg path 'd' attribute)	
	"""

	if direction_default:
		direction_default = direction_default[0].lower()
	s_nodes = set()
	r_nodes = []
	for n in nodes:
		if node_type[n] == 'reaction':
			r_nodes.append(n)
		else:
			s_nodes.add(n)

	# get circular paths, exclude edges with circular paths from further editing
	arc_paths = {} # svg arcs

	# find cycles
	cyclic_pathways = set([pw for pw in pathway.values() if 'cycle' in pw.lower()])
	for pw in cyclic_pathways:
		circle_nodes = [n for n in nodes if pathway[n] == pw]

		# get nodes that are placed on a circle
		circle_nodes = get_nodes_on_circle(pos, circle_nodes)
		
		# get center coordinates of circle
		cx = sum([pos[n][0] for n in circle_nodes])/len(circle_nodes)
		cy = sum([pos[n][1] for n in circle_nodes])/len(circle_nodes)
		
		# find closest node pairs for each source node
		sourcenodes = [n for n in circle_nodes if node_type[n]=='reaction']
		potential_edges = []
		for sn in sourcenodes:
			# get distances for all nodes on circle
			dist = [eucdist((pos[sn][0], pos[sn][1]), (pos[n][0], pos[n][1])) for n in circle_nodes]
			# sort nodes based on distance
			sorted_n = [n for (dst,n) in sorted(zip(dist, circle_nodes))] 
			# get edges with closest nodes
			potential_edges += [(sn, tn) for tn in sorted_n[1:]][:2]

		# get edges that are part of circle
		circle_edges = [e for e in edges if e in potential_edges]
		
		# get arc paths
		for e in circle_edges:
			x0, y0 = pos[e[0]][0], pos[e[0]][1] # reaction node
			x, y = pos[e[1]][0], pos[e[1]][1]	# species node
			w, h = label_size[e[1]]
			r = math.sqrt((x - cx)**2 + (y - cy)**2)
			# get the 2 intersections of the circle with the rectangular label 'bounding box'
			intersections = intersect_circ_rect(cx, cy, r, x, y, w, h)
			# get the intersection closest to reaction node, this will be the path end
			dist = [eucdist((x0, y0), intrsc) for intrsc in intersections]
			intrsc = intersections[dist.index(min(dist))]
			# determine sweep-flag for the svg arc
			angle0 = np.angle(complex((x0-cx),(y0-cy)))
			angle1 = np.angle(complex((intrsc[0]-cx),(intrsc[1]-cy)))
			if angle1-angle0 < 0:
				swp = 0 # anti-clockwise
			else:
				swp = 1 # clockwise
			arc_paths[e] = arc_path(x0, y0, r, swp, *intrsc)
			edges.remove(e)

	v_nodes={}
	for r in r_nodes: v_nodes[r] = [] # voter nodes for reaction direction

	p_nodes={} # path nodes coordinates (by edge)
	p_nodes_flat = [] # list of path nodes coordinates
	direction = {}
	for e in edges:
		p_nodes[e]=[pos[e[0]]] + extra_nodes[e] + [pos[e[1]]]
		p_nodes_flat += p_nodes[e]
		v_nodes[e[0]].append(p_nodes[e][1])
		if 'cycle' in pathway[e[0]].lower() or not direction_default:
			direction[e]=['h']*len(p_nodes[e])
		else:	
			direction[e]=[direction_default]*len(p_nodes[e])

	cof_adj = {}.fromkeys(edges, 0)
	if cofactors:
		for e in edges:
			if len(cofactors[e[0]])>0:
				cof_adj[e] = 1.5*min_path_length # reserve space for cofactors
	else:
		cofactors = {}.fromkeys(r_nodes, {})

	path_end = {}
	for e in edges: path_end[e[1]] = {}


	for e in edges:
		# determine curve direction of path at reaction node
		if 'cycle' in pathway[e[0]].lower() or not direction_default:
			direction[e][0] = path_node_direction(pos[e[0]], v_nodes[e[0]])

		# get cofactor positions and paths
		if e[0] in reverse_cofactor_direction:
			dst = (min_path_length, -1.5*min_path_length)
		else:
			dst = (min_path_length, 1.5*min_path_length)

		cofactors[e[0]] = get_cofactors_layout(pos[e[0]], cofactors[e[0]], direction[e][0], label, label_size, dist=dst)
		for s in cofactors[e[0]]:
			s_nodes.add(str(s)+str(e[0]))
			label_size[str(s)+str(e[0])] = label_size[s]
			pos[str(s)+str(e[0])] = cofactors[e[0]][s]['pos']
		
		# determine curve direction of path at helper nodes
		for i in range(1, len(p_nodes[e])-1):
			n = p_nodes[e][i]
			direction[e][i] = path_node_direction(n, [p_nodes[e][i-1], p_nodes[e][i+1]])
		
		# determine curve direction of path at species node
		dx = pos[e[1]][0] - p_nodes[e][-2][0]
		dy = pos[e[1]][1] - p_nodes[e][-2][1]
		direction[e][-1] = path_direction_end(dx, dy, direction[e][-1], label_size[e[1]], min_length = min_path_length)
		
		if not 'cycle' in pathway[e[0]].lower() and direction_default == 'v' and direction[e][-1] == 'h' and (p_nodes[e][-2][0], pos[e[1]][1]) in p_nodes_flat:
			direction[e][-1] = 'v'

		# determine endpoint of path at species node
		p_nodes[e][-1] = path_position_end(pos[e[1]], dx, dy, direction[e][-1], label_size[e[1]])

		# collect path ends for duplicates adjustment
		path_end[e[1]][e[0]] = p_nodes[e][-1]

	# adjust horizontal path ends (no more than 1 on each side of species label)
	max_hz = 1 # maximum number of horizontal path ends
	for s in path_end:
		left = []
		right = []

		for r in path_end[s]:
			if path_end[s][r][1] == pos[s][1]:
				if path_end[s][r][0] < pos[s][0]:
					left.append(r)
				else:
					right.append(r)
		for rns in [left, right]:
			if len(rns) > max_hz:
				rns.sort(key = lambda r: abs(pos[s][1] - pos[r][1])) # sort on y-distance to reaction node
				for r in rns[1:]:
					e = (r,s)
					dx = pos[s][0] - p_nodes[e][-2][0]
					dy = pos[s][1] - p_nodes[e][-2][1]
					direction[e][-1] = 'v'
					p_nodes[e][-1] = path_position_end(pos[e[1]], dx, dy, direction[e][-1], label_size[e[1]])
					path_end[s][r] = p_nodes[e][-1]

	# adjust duplicate path ends
	for s in path_end:
		path_end[s] = adjust_duplicate_path_ends(s, path_end[s], pos[s], p_nodes)
	for e in edges:
		p_nodes[e][-1] = path_end[e[1]][e[0]]


	# get path segments
	path_segs = {}
	for e in edges:
		path_segs[e]=[]
		for i in range(len(p_nodes[e])-1):
			# get list of path segments
			segs = get_path_segments(
				start = complex(*p_nodes[e][i]), 
				end = complex(*p_nodes[e][i+1]), 
				start_direction = direction[e][i], 
				end_direction = direction[e][i+1],
				max_bend = max_bend,
				adjust = [cof_adj[e],0])
			path_segs[e].append(segs)

	
	if not prevent_overlap:
		# return paths if no overlap prevention
		svg_paths = arc_paths
		for e in edges:
			p = []
			for segs in path_segs[e]:
				p+=segs
			svg_paths[e] = Path(*p).d()
		for r in cofactors:
			for s in cofactors[r]:
				svg_paths[(r,s)] = cofactors[r][s]['path']

		return svg_paths, pos
	
	###############################################
	########## adjust path/label overlap ########## 
	
	# change path segment basic shape if overlapping with labels
	print 'checking path/label overlap...'
	for e in edges:
		for i in range(len(path_segs[e])):
			seg = path_segs[e][i]

			p = Path(*seg)
			# get 100 (x + yj) points on the path
			points = [p.point(t) for t in [k/100. for k in range(101)]]
			for n in s_nodes.difference({e[1]}):
				# check if any points are inside species labels
				if overlapping(points, pos[n], label_size[n]):
					# change j shape to s shape
					print 'changing path {} shape to prevent {} label overlap...'.format(e, n)
					direction[e][i+1] = direction[e][i]
					break
		
		# determine new path ends
		dx = pos[e[1]][0] - p_nodes[e][-2][0]
		dy = pos[e[1]][1] - p_nodes[e][-2][1]
		p_nodes[e][-1] = path_position_end(pos[e[1]], dx, dy, direction[e][-1], label_size[e[1]])

		# collect path ends for duplicates adjustment
		path_end[e[1]][e[0]] = p_nodes[e][-1]


	# adjust horizontal path ends 
	max_hz =1 # (no more than 1 path end on each side of species label)
	for s in path_end:
		left = []
		right = []
		for r in path_end[s]:
			if path_end[s][r][1] == pos[s][1]:
				if path_end[s][r][0] < pos[s][0]:
					left.append(r)
				else:
					right.append(r)
		for rns in [left, right]:
			if len(rns) > max_hz:
				rns.sort(key = lambda r: abs(pos[s][1] - pos[r][1])) # sort on y-distance to reaction node
				for r in rns[1:]:
					e = (r,s)
					dx = pos[s][0] - p_nodes[e][-2][0]
					dy = pos[s][1] - p_nodes[e][-2][1]
					direction[e][-1] = 'v'
					p_nodes[e][-1] = path_position_end(pos[e[1]], dx, dy, direction[e][-1], label_size[e[1]])
					path_end[s][r] = p_nodes[e][-1]	
	
	# adjust duplicate path ends
	for s in path_end:
		path_end[s] = adjust_duplicate_path_ends(s, path_end[s], pos[s], p_nodes)
	for e in edges:
		p_nodes[e][-1] = path_end[e[1]][e[0]]

	# get new path segments
	vv_shaped=[]
	hh_shaped=[]
	path_segs = {}
	for e in edges:
		path_segs[e]=[]
		for i in range(len(p_nodes[e])-1):
			# get list of path segments
			adj = [cof_adj[e],0]
			start = complex(*p_nodes[e][i])
			end = complex(*p_nodes[e][i+1])
			segs = get_path_segments(
				start,
				end,
				start_direction = direction[e][i], 
				end_direction = direction[e][i+1],
				max_bend = max_bend,
				adjust = adj)
			path_segs[e].append(segs)

			# collect information for finding and adjusting path/path overlap
			if direction[e][i] == direction[e][i+1] == 'v':
				dx = end.real - start.real
				dy = end.imag - start.imag
				y = start.imag + 0.5*dy + adj[0]*dy/abs(dy)
				info = {'y':y, 'dx':dx, 'dy':dy, 'start':start, 'end':end, 'e,i':(e,i)}
				vv_shaped.append(info)
			if direction[e][i] == direction[e][i+1] == 'h':
				dx = end.real - start.real
				dy = end.imag - start.imag
				x = start.real + 0.5*dx + adj[0]*dx/abs(dx)
				info = {'x':x, 'dx':dx, 'dy':dy, 'start':start, 'end':end, 'e,i':(e,i)}
				hh_shaped.append(info)

	print 'adjusting path/path overlap'
	
	vv_shaped.sort(key = lambda k:k['y']) # sort by midpoint y-coordinate
	for y, info in groupby(vv_shaped, key = lambda k:k['y']):
		# determine overlap for all path segments with same midpoint y-coordinate
		segs_to_adjust = []
		for c in combinations(list(info), 2):
			min_x1 = min(c[0]['start'].real, c[0]['end'].real)
			max_x1 = max(c[0]['start'].real, c[0]['end'].real)
			min_x2 = min(c[1]['start'].real, c[1]['end'].real)
			max_x2 = max(c[1]['start'].real, c[1]['end'].real)
			if max(min_x1, min_x2) < min(max_x1, max_x2):
				# paths have overlap!
				if len(segs_to_adjust) == 0:
					segs_to_adjust.append(list(c))
				else:
					for lst in segs_to_adjust:
						if c[0] in lst and not c[1] in lst:
							lst.append(c[1])
							break
						elif c[1] in lst and not c[0] in lst:	
							lst.append(c[0])
							break
					else: # if neither c[0] or c[1] in any lst:
						segs_to_adjust.append(list(c))
		for lst in segs_to_adjust:
			lst.sort(key = lambda k:k['start'].imag)
			lst.sort(key = lambda k:k['start'].real*-k['dx']/abs(k['dx']))
			l = len(lst)
			mp_adj = [(l*-5 +5) + i*10 for i in range(l)] # e.g. [-10, 0, 10] for l = 3
			for n in range(l):
				dy = lst[n]['dy']
				e, i = lst[n]['e,i']
				start = lst[n]['start']
				end = lst[n]['end']
				adj = [cof_adj[e], 0, 0.5*abs(dy) -cof_adj[e] + mp_adj[n]]
				segs = get_path_segments(start,	end, 'v', 'v', max_bend, adj)
				path_segs[e][i] = segs

	hh_shaped.sort(key = lambda k:k['x']) # sort by midpoint y-coordinate
	for x, info in groupby(hh_shaped, key = lambda k:k['x']):
		# determine overlap for all path segments with same midpoint y-coordinate
		segs_to_adjust = []
		for c in combinations(list(info), 2):
			min_y1 = min(c[0]['start'].imag, c[0]['end'].imag)
			max_y1 = max(c[0]['start'].imag, c[0]['end'].imag)
			min_y2 = min(c[1]['start'].imag, c[1]['end'].imag)
			max_y2 = max(c[1]['start'].imag, c[1]['end'].imag)
			if max(min_y1, min_y2) < min(max_y1, max_y2):
				# paths have overlap!
				if len(segs_to_adjust) == 0:
					segs_to_adjust.append(list(c))
				else:
					for lst in segs_to_adjust:
						if c[0] in lst and not c[1] in lst:
							lst.append(c[1])
							break
						elif c[1] in lst and not c[0] in lst:
							lst.append(c[0])
							break
					else: # if neither c[0] or c[1] in any lst:
						segs_to_adjust.append(list(c))
		for lst in segs_to_adjust:
			lst.sort(key = lambda k:k['start'].real)
			l = len(lst)
			mp_adj = [(l*-5 +5) + i*10 for i in range(l)] # e.g. [-10, 0, 10] when l = 3
			for n in range(l):
				dx = lst[n]['dx']
				e, i = lst[n]['e,i']
				start = lst[n]['start']
				end = lst[n]['end']
				adj = [cof_adj[e], 0, 0.5*abs(dy) -cof_adj[e] + mp_adj[n]]
				segs = get_path_segments(start,	end, 'h', 'h', max_bend, adj)
				path_segs[e][i] = segs

	# check if still overlap
	# if overlap, try to adjust path midpoint until there is no overlap
	print 'checking path/label overlap...'

	for e in edges:
		for i in range(len(path_segs[e])):
			seg = path_segs[e][i]

			p = Path(*seg)
			# get 100 (x + yj) points on the path
			points = [p.point(t) for t in [k/100. for k in range(101)]]
			overlap =[]
			for n in s_nodes.difference({e[1]}):
				# check if any points are inside species labels
				overlap.append(overlapping(points, pos[n], label_size[n]))
			if any(overlap):
				start = complex(*p_nodes[e][i])
				end = complex(*p_nodes[e][i+1])
				if direction[e][i] == 'v' and start.real==end.real or direction[e][i] == 'h' and start.imag == end.imag:
					print 'could not find non-overlapping path for {}'.format(e)
				elif direction[e][i] == direction[e][i+1]:
					print 'adjusting path {} to prevent path/label overlap...'.format(e)
					adjustments = []
					if direction[e][i] == 'h':
						len_seg = 0.5*abs(end.real - start.real)
					else:
						len_seg = 0.5*abs(end.imag - start.imag)

					len_seg = len_seg - cof_adj[e]

					for k in range(1, int(2*len_seg/30)+1):
						adjustments.append(30*k)

					for dn in range(2,6):
						# move middle path segments toward reaction node 
						for nm in range(1, dn):
							adj = nm*(len_seg/dn)
							if adj not in adjustments:
								adjustments.append(adj)
					for dn in range(2,6):
						# move middle path segments toward species node 
						for nm in range(1, dn):
							adj = len_seg + (dn-nm)*(len_seg/dn)
							if adj not in adjustments:
								adjustments.append(adj)

					# adjust, calculate new path and check for overlap
					adjusted_paths = []
					num_overlap = []
					for adj in adjustments:
						print '.',
						sys.stdout.flush()
						new_segs = get_path_segments(start, end, direction[e][i], direction[e][i+1], max_bend, adjust=[0,0,adj])
						p = Path(*new_segs)
						points = [p.point(t) for t in [k/100. for k in range(101)]]
						overlap = []
						for n in s_nodes.difference({e[1]}):
							overlap.append(overlapping(points, pos[n], label_size[n]))
						num_overlap.append(sum(overlap))
						adjusted_paths.append(new_segs)
						if not any(overlap):
							print 'ok'
							path_segs[e][i] = new_segs
							break
					else:
						print 'could not find non-overlapping path'
						path_segs[e][i] = adjusted_paths[num_overlap.index(min(num_overlap))]

	svg_paths = arc_paths
	for e in edges:
		p = []
		for segs in path_segs[e]:
			p+=segs
		svg_paths[e] = Path(*p).d()
	for r in cofactors:
		for s in cofactors[r]:
			svg_paths[(r,s)] = cofactors[r][s]['path']

	return svg_paths, pos
示例#16
0
SVG2 = '''  </g>
</svg>
'''

svgpath1 = '''<path
       style="fill:none;fill-rule:evenodd;stroke:#{0:02x}{1:02x}{2:02x};stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       d="'''
svgpath2 = ''' Z"/>
'''

print(SVG1)
for p in paths:
	path     = parse_path(p.attrib["d"])
	start    = None
	myrange  = list(frange(0, 1, decimal.Decimal('0.01')))
	mycolors = list(red.range_to(blue, len(myrange)))
	
	for i, px in enumerate(myrange):
		new_path = Path()
		if start is None:
			start = path.point(float(px))
		else:
			end   = path.point(float(px))
			new_path.append(Line(start, end))
			start = end
			color = mycolors[i]
			r = int(color.red * 255)
			g = int(color.green * 255)
			b = int(color.blue * 255)
			print((svgpath1 + new_path.d() + svgpath2).format(clamp(r), clamp(g), clamp(b)))
print(SVG2)
示例#17
0
def test_Path_q_bezier_adds_relative_quadratic_bezier_command():
    path = Path((0, 1), style='xyz')
    path.q_bezier((3, 4), (5, 6), relative=True)
    assert str(path) == '<path d="M 0 1 q 3 4, 5 6" style="xyz"/>\n'
示例#18
0
def test_Path_c_bezier_adds_relative_smooth_bezier_command_if_no_first_point():
    path = Path((0, 1), style='xyz').c_bezier(None, (3, 4), (5, 6),
                                              relative=True)
    assert str(path) == '<path d="M 0 1 s 3 4, 5 6" style="xyz"/>\n'
示例#19
0
def test_Path_line_to_adds_a_relative_line_command_to_the_path():
    path = Path((0, 1), style="xyz").line_to((2, 3), relative=True)
    assert str(path) == '<path d="M 0 1 l 2 3" style="xyz"/>\n'
示例#20
0
    def remove_redundant_lines(self):
        eps = 0.001

        def get_slope_intersect(p1, p2):
            if abs(p1.real - p2.real) < eps:
                # Vertical; no slope and return x-intercept
                return None, p1.real
            m = (p2.imag - p1.imag) / (p2.real - p1.real)
            b1 = p1.imag - m * p1.real
            b2 = p2.imag - m * p2.real
            assert abs(b1 - b2) < eps
            return m, b1

        lines_bucketed_by_slope_intersect = defaultdict(list)
        paths = self.svg_node.getElementsByTagName('path')
        overall_index = 0
        for path_index, path in enumerate(paths):
            path_text = path.attributes['d'].value
            path_obj = parse_path(path_text)
            for line_index, line in enumerate(path_obj):
                slope, intersect = get_slope_intersect(line.start, line.end)
                if slope is not None:
                    slope = round(slope, ndigits=3)
                intersect = round(intersect, ndigits=3)
                lines_bucketed_by_slope_intersect[(slope, intersect)].append({
                    'overall_index': overall_index,
                    'path_index': path_index,
                    'line_index': line_index,
                    'line': line,
                })
                overall_index += 1

        to_remove = {}
        for slope_intersect, lines in lines_bucketed_by_slope_intersect.items():
            # Naive N^2 search for overlapping lines within a slope-intersect bucket
            for i in range(len(lines)):
                line1 = lines[i]['line']
                eq1 = get_slope_intersect(line1.start, line1.end)
                for j in range(i + 1, len(lines)):
                    line2 = lines[j]['line']
                    eq2 = get_slope_intersect(line2.start, line2.end)

                    # Compare slopes
                    if (eq1[0] is None and eq2[0] is None) \
                            or (eq1[0] is not None and eq2[0] is not None and abs(eq1[0] - eq2[0]) < eps):
                        # Compare intersects
                        if abs(eq1[1] - eq2[1]) < eps:
                            # Must be collinear, check for overlap
                            l1x1 = min(line1.start.real, line1.end.real)
                            l1x2 = max(line1.start.real, line1.end.real)
                            l1y1 = min(line1.start.imag, line1.end.imag)
                            l1y2 = max(line1.start.imag, line1.end.imag)

                            l2x1 = min(line2.start.real, line2.end.real)
                            l2x2 = max(line2.start.real, line2.end.real)
                            l2y1 = min(line2.start.imag, line2.end.imag)
                            l2y2 = max(line2.start.imag, line2.end.imag)

                            if l1x1 <= l2x1 + eps and l1x2 + eps >= l2x2 and l1y1 <= l2y1 + eps and l1y2 + eps >= l2y2:
                                # Overlapping, line 1 is bigger
                                assert line1.length() + eps >= line2.length()
                                to_remove[lines[j]['overall_index']] = (lines[j]['path_index'], lines[j]['line_index'], line2)
                            elif l1x1 + eps >= l2x1 and l1x2 <= l2x2 + eps and l1y1 + eps >= l2y1 and l1y2 <= l2y2 + eps:
                                # Overlapping, line 2 is bigger
                                assert line2.length() + eps >= line1.length()
                                to_remove[lines[i]['overall_index']] = (lines[i]['path_index'], lines[i]['line_index'], line1)

        # Reconstruct the paths, but excluding the redundant lines we just identified
        i = 0
        removed = 0
        removed_length = 0
        kept = 0
        kept_length = 0
        for path_index, path in enumerate(paths):
            path_text = path.attributes['d'].value
            path_obj = parse_path(path_text)

            filtered_path = Path()

            for line_index, line in enumerate(path_obj):
                if i in to_remove:
                    assert path_index == to_remove[i][0]
                    assert line_index == to_remove[i][1]
                    assert line == to_remove[i][2]
                    removed += 1
                    removed_length += line.length()
                else:
                    filtered_path.append(line)
                    kept += 1
                    kept_length += line.length()
                i += 1

            # Update the path data with the filtered path data
            path.attributes['d'] = filtered_path.d()

        print 'Removed {} lines ({} length) and kept {} lines ({} length)'.format(
            removed,
            removed_length,
            kept,
            kept_length,
        )

        return [to_remove[k][2] for k in to_remove]
示例#21
0
def test_Path_q_bezier_adds_smooth_quadratic_bezier_command_if_no_ctrl_pt():
    path = Path((0, 1), style='xyz')
    path.q_bezier(None, (5, 6))
    assert str(path) == '<path d="M 0 1 T 5 6" style="xyz"/>\n'
示例#22
0
def test_Path_v_line_to_adds_a_relative_vertical_line_command_to_the_path():
    path = Path((0, 1), style="xyz")
    path.v_line(-1.2, relative=True)
    assert str(path) == '<path d="M 0 1 v -1.2" style="xyz"/>\n'
示例#23
0
def test_Path_v_line_to_adds_a_vertical_line_command_to_the_path():
    path = Path((0, 1), style="xyz")
    path.v_line(3.11)
    assert str(path) == '<path d="M 0 1 V 3.11" style="xyz"/>\n'
示例#24
0
def test_Path_h_line_to_adds_a_relative_horizontal_line_command_to_the_path():
    path = Path((0, 1), style="xyz")
    path.h_line(7, relative=True)
    assert str(path) == '<path d="M 0 1 h 7" style="xyz"/>\n'
示例#25
0
def test_Path_q_bezier_adds_relative_smooth_quad_bezier_cmd_if_no_ctrl_pt():
    path = Path((0, 1), style='xyz').q_bezier(None, (5, 6), relative=True)
    assert str(path) == '<path d="M 0 1 t 5 6" style="xyz"/>\n'
示例#26
0
def test_Path_init_makes_path_tag_with_starting_point_and_additional_params():
    path = Path((5, 15), style="xyz")
    assert str(path) == '<path d="M 5 15" style="xyz"/>\n'
示例#27
0
def parse_polygon(points: str) -> Path:
    coordinates = [tuple(map(float, c.split(','))) for c in points.split()]
    path = Path()
    for a, b in pairwise(coordinates):
        path.append(Line(complex(*a), complex(*b)))
    return path
示例#28
0
def test_Path_c_bezier_adds_a_relative_cubic_bezier_command_to_the_path():
    path = Path((0, 1), style='xyz')
    path.c_bezier((1, 2), (3, 4), (5, 6), relative=True)
    assert str(path) == '<path d="M 0 1 c 1 2, 3 4, 5 6" style="xyz"/>\n'
示例#29
0
def test_Path_move_to_adds_a_move_command_to_the_path():
    path = Path((0, 1), style="xyz")
    path.move_to((2, 3))
    assert str(path) == '<path d="M 0 1 M 2 3" style="xyz"/>\n'
示例#30
0
def test_Path_h_line_to_adds_a_horizontal_line_command_to_the_path():
    path = Path((0, 1), style="xyz")
    path.h_line(5)
    assert str(path) == '<path d="M 0 1 H 5" style="xyz"/>\n'
示例#31
0
def test_Path_arc_to_adds_relative_arc_command_to_the_path():
    path = Path((0, 1), style='xyz')
    path.arc_to((13, 14), -30, False, False, (15, 16), relative=True)
    assert str(path) == '<path d="M 0 1 a 13 14 -30 0 0 15 16" style="xyz"/>\n'
    path = Path((0, 1), style='xyz')
    path.arc_to((13, 14), -30, False, True, (15, 16), relative=True)
    assert str(path) == '<path d="M 0 1 a 13 14 -30 0 1 15 16" style="xyz"/>\n'
    path = Path((0, 1), style='xyz')
    path.arc_to((13, 14), -30, True, False, (15, 16), relative=True)
    assert str(path) == '<path d="M 0 1 a 13 14 -30 1 0 15 16" style="xyz"/>\n'
    path = Path((0, 1), style='xyz').arc_to((13, 14),
                                            -30,
                                            True,
                                            True, (15, 16),
                                            relative=True)
    assert str(path) == '<path d="M 0 1 a 13 14 -30 1 1 15 16" style="xyz"/>\n'