sumolib.shapes.polygon
1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo 2# Copyright (C) 2012-2026 German Aerospace Center (DLR) and others. 3# This program and the accompanying materials are made available under the 4# terms of the Eclipse Public License 2.0 which is available at 5# https://www.eclipse.org/legal/epl-2.0/ 6# This Source Code may also be made available under the following Secondary 7# Licenses when the conditions for such availability set forth in the Eclipse 8# Public License 2.0 are satisfied: GNU General Public License, version 2 9# or later which is available at 10# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html 11# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later 12 13# @file polygon.py 14# @author Daniel Krajzewicz 15# @author Melanie Knocke 16# @author Michael Behrisch 17# @date 2012-12-04 18 19from __future__ import absolute_import 20 21from xml.sax import handler, parse 22from .. import color 23from .. import miscutils 24 25 26def getBoundingBox(shape): 27 xmin = shape[0][0] 28 xmax = shape[0][0] 29 ymin = shape[0][1] 30 ymax = shape[0][1] 31 for p in shape[1:]: 32 xmin = min(xmin, p[0]) 33 xmax = max(xmax, p[0]) 34 ymin = min(ymin, p[1]) 35 ymax = max(ymax, p[1]) 36 return xmin, ymin, xmax, ymax 37 38 39class Polygon: 40 41 def __init__(self, id, type=None, color=None, layer=None, fill=None, 42 shape=None, geo=None, angle=None, lineWidth=None, imgFile=None, color_str=None): 43 self.id = id 44 self.type = type 45 self.color = color 46 if layer is not None: 47 layer = miscutils.intIfPossible(float(layer)) 48 self.layer = layer 49 self.fill = fill 50 self.shape = shape 51 self.geo = geo 52 self.angle = angle 53 self.lineWidth = lineWidth 54 self.imgFile = imgFile 55 self.attributes = {} 56 self.color_str = color_str 57 if self.color is not None and self.color_str is None: 58 if hasattr(self.color, "toXML"): 59 self.color_str = self.color.toXML() 60 else: 61 self.color_str = self.color 62 63 def getBoundingBox(self): 64 return getBoundingBox(self.shape) 65 66 def getShapeString(self): 67 return " ".join([",".join(map(str, e)) for e in self.shape]) 68 69 def toXML(self): 70 ret = '<poly id="%s"' % self.id 71 if self.type is not None: 72 ret += ' type="%s"' % self.type 73 if self.color is not None: 74 if isinstance(self.color, color.RGBAColor): 75 ret += ' color="%s"' % self.color.toXML() 76 else: 77 ret += ' color="%s"' % self.color 78 if self.layer is not None: 79 ret += ' layer="%s"' % self.layer 80 if self.fill is not None: 81 ret += ' fill="%s"' % self.fill 82 if self.shape is not None: 83 ret += ' shape="%s"' % self.getShapeString() 84 if len(self.attributes) == 0: 85 ret += '/>' 86 else: 87 ret += '>' 88 for a in self.attributes: 89 ret += '<param key="%s" value="%s"/>' % (a, self.attributes[a]) 90 ret += '</poly>' 91 return ret 92 93 def __lt__(self, other): 94 return self.id < other.id 95 96 def __repr__(self): 97 return self.toXML() 98 99 100class PolygonReader(handler.ContentHandler): 101 102 def __init__(self, includeTaz=False): 103 self._includeTaz = includeTaz 104 self._id2poly = {} 105 self._polys = [] 106 self._lastPoly = None 107 108 def startElement(self, name, attrs): 109 if name == 'poly' or (self._includeTaz and name == 'taz'): 110 cshape = [] 111 for e in attrs['shape'].split(): 112 p = e.split(",") 113 cshape.append((float(p[0]), float(p[1]))) 114 if name == 'poly': 115 c = color.decodeXML(attrs['color']) 116 poly = Polygon(attrs['id'], attrs.get('type'), c, 117 attrs.get('layer'), attrs.get('fill'), cshape, 118 attrs.get('geo'), attrs.get('angle'), 119 attrs.get('lineWidth'), attrs.get('imgFile'), attrs.get('color')) 120 else: 121 poly = Polygon(attrs['id'], color=attrs.get('color'), shape=cshape) 122 self._id2poly[poly.id] = poly 123 self._polys.append(poly) 124 self._lastPoly = poly 125 if name == 'param' and self._lastPoly is not None: 126 self._lastPoly.attributes[attrs['key']] = attrs['value'] 127 128 def endElement(self, name): 129 if name == 'poly': 130 self._lastPoly = None 131 132 def getPolygons(self): 133 return self._polys 134 135 136def read(filenames, includeTaz=False): 137 pr = PolygonReader(includeTaz) 138 if isinstance(filenames, str): 139 filenames = [filenames] 140 for fn in filenames: 141 parse(miscutils.openz(fn), pr) 142 return pr.getPolygons()
def
getBoundingBox(shape):
class
Polygon:
40class Polygon: 41 42 def __init__(self, id, type=None, color=None, layer=None, fill=None, 43 shape=None, geo=None, angle=None, lineWidth=None, imgFile=None, color_str=None): 44 self.id = id 45 self.type = type 46 self.color = color 47 if layer is not None: 48 layer = miscutils.intIfPossible(float(layer)) 49 self.layer = layer 50 self.fill = fill 51 self.shape = shape 52 self.geo = geo 53 self.angle = angle 54 self.lineWidth = lineWidth 55 self.imgFile = imgFile 56 self.attributes = {} 57 self.color_str = color_str 58 if self.color is not None and self.color_str is None: 59 if hasattr(self.color, "toXML"): 60 self.color_str = self.color.toXML() 61 else: 62 self.color_str = self.color 63 64 def getBoundingBox(self): 65 return getBoundingBox(self.shape) 66 67 def getShapeString(self): 68 return " ".join([",".join(map(str, e)) for e in self.shape]) 69 70 def toXML(self): 71 ret = '<poly id="%s"' % self.id 72 if self.type is not None: 73 ret += ' type="%s"' % self.type 74 if self.color is not None: 75 if isinstance(self.color, color.RGBAColor): 76 ret += ' color="%s"' % self.color.toXML() 77 else: 78 ret += ' color="%s"' % self.color 79 if self.layer is not None: 80 ret += ' layer="%s"' % self.layer 81 if self.fill is not None: 82 ret += ' fill="%s"' % self.fill 83 if self.shape is not None: 84 ret += ' shape="%s"' % self.getShapeString() 85 if len(self.attributes) == 0: 86 ret += '/>' 87 else: 88 ret += '>' 89 for a in self.attributes: 90 ret += '<param key="%s" value="%s"/>' % (a, self.attributes[a]) 91 ret += '</poly>' 92 return ret 93 94 def __lt__(self, other): 95 return self.id < other.id 96 97 def __repr__(self): 98 return self.toXML()
Polygon( id, type=None, color=None, layer=None, fill=None, shape=None, geo=None, angle=None, lineWidth=None, imgFile=None, color_str=None)
42 def __init__(self, id, type=None, color=None, layer=None, fill=None, 43 shape=None, geo=None, angle=None, lineWidth=None, imgFile=None, color_str=None): 44 self.id = id 45 self.type = type 46 self.color = color 47 if layer is not None: 48 layer = miscutils.intIfPossible(float(layer)) 49 self.layer = layer 50 self.fill = fill 51 self.shape = shape 52 self.geo = geo 53 self.angle = angle 54 self.lineWidth = lineWidth 55 self.imgFile = imgFile 56 self.attributes = {} 57 self.color_str = color_str 58 if self.color is not None and self.color_str is None: 59 if hasattr(self.color, "toXML"): 60 self.color_str = self.color.toXML() 61 else: 62 self.color_str = self.color
def
toXML(self):
70 def toXML(self): 71 ret = '<poly id="%s"' % self.id 72 if self.type is not None: 73 ret += ' type="%s"' % self.type 74 if self.color is not None: 75 if isinstance(self.color, color.RGBAColor): 76 ret += ' color="%s"' % self.color.toXML() 77 else: 78 ret += ' color="%s"' % self.color 79 if self.layer is not None: 80 ret += ' layer="%s"' % self.layer 81 if self.fill is not None: 82 ret += ' fill="%s"' % self.fill 83 if self.shape is not None: 84 ret += ' shape="%s"' % self.getShapeString() 85 if len(self.attributes) == 0: 86 ret += '/>' 87 else: 88 ret += '>' 89 for a in self.attributes: 90 ret += '<param key="%s" value="%s"/>' % (a, self.attributes[a]) 91 ret += '</poly>' 92 return ret
class
PolygonReader(xml.sax.handler.ContentHandler):
101class PolygonReader(handler.ContentHandler): 102 103 def __init__(self, includeTaz=False): 104 self._includeTaz = includeTaz 105 self._id2poly = {} 106 self._polys = [] 107 self._lastPoly = None 108 109 def startElement(self, name, attrs): 110 if name == 'poly' or (self._includeTaz and name == 'taz'): 111 cshape = [] 112 for e in attrs['shape'].split(): 113 p = e.split(",") 114 cshape.append((float(p[0]), float(p[1]))) 115 if name == 'poly': 116 c = color.decodeXML(attrs['color']) 117 poly = Polygon(attrs['id'], attrs.get('type'), c, 118 attrs.get('layer'), attrs.get('fill'), cshape, 119 attrs.get('geo'), attrs.get('angle'), 120 attrs.get('lineWidth'), attrs.get('imgFile'), attrs.get('color')) 121 else: 122 poly = Polygon(attrs['id'], color=attrs.get('color'), shape=cshape) 123 self._id2poly[poly.id] = poly 124 self._polys.append(poly) 125 self._lastPoly = poly 126 if name == 'param' and self._lastPoly is not None: 127 self._lastPoly.attributes[attrs['key']] = attrs['value'] 128 129 def endElement(self, name): 130 if name == 'poly': 131 self._lastPoly = None 132 133 def getPolygons(self): 134 return self._polys
Interface for receiving logical document content events.
This is the main callback interface in SAX, and the one most important to applications. The order of events in this interface mirrors the order of the information in the document.
def
startElement(self, name, attrs):
109 def startElement(self, name, attrs): 110 if name == 'poly' or (self._includeTaz and name == 'taz'): 111 cshape = [] 112 for e in attrs['shape'].split(): 113 p = e.split(",") 114 cshape.append((float(p[0]), float(p[1]))) 115 if name == 'poly': 116 c = color.decodeXML(attrs['color']) 117 poly = Polygon(attrs['id'], attrs.get('type'), c, 118 attrs.get('layer'), attrs.get('fill'), cshape, 119 attrs.get('geo'), attrs.get('angle'), 120 attrs.get('lineWidth'), attrs.get('imgFile'), attrs.get('color')) 121 else: 122 poly = Polygon(attrs['id'], color=attrs.get('color'), shape=cshape) 123 self._id2poly[poly.id] = poly 124 self._polys.append(poly) 125 self._lastPoly = poly 126 if name == 'param' and self._lastPoly is not None: 127 self._lastPoly.attributes[attrs['key']] = attrs['value']
Signals the start of an element in non-namespace mode.
The name parameter contains the raw XML 1.0 name of the element type as a string and the attrs parameter holds an instance of the Attributes class containing the attributes of the element.
def
read(filenames, includeTaz=False):