def startElement(self, name, attrs): '''FIXME''' #self.padding_level = self.padding_level + 1 #self.current_element = name #self.padded_print(self.current_element) self.got_all_info = False # set True when we have all required info for builder # Allow most elements through; builders must be turned into solids. if name != 'builder' and name != 'shape': self.passthrough = True # allow these elements through unaltered elif name == 'builder': self.passthrough = False self.builder_info = attrs elif name == 'shape': self.passthrough = False self.shape_info = attrs # Now we (hopefully) have builder and shape info... self.got_all_info = True else: ldl.error('unknown element type' + name) if self.passthrough: self._downstream.startElement(name, attrs) else: if self.got_all_info: self.dispatch_macro(self.builder_info, self.shape_info) self.got_all_info = False self.builder_info = None self.shape_info = None else: pass # wait for more info
def dispatch_macro(self, bi, si): '''Call the appropriate Macro''' type = si['type'] if type == ldl.ST_STAIRS: self.macro_stairs(bi, si) elif type == ldl.ST_PLAT: self.macro_plat(bi, si) else: ldl.error('unkown macro type ' + type)
def macro_plat(self, bi, si): '''Make a plat Note that we don't specify the size of plat here as later we need to make it either at the top or the bottom of the larger brush.''' origin = ldl.getPoint(bi['origin']) size = ldl.getPoint(bi['extent']) if bi.has_key('texture'): texture = 'texture=\'' + bi['texture'] + '\' ' else: texture = '' if si.has_key('position'): pos = si['position'] # DCP_UP or DCP_DOWN (top or bottomw else: ldl.error('plat given without a position (up or down)') print "<solid origin='" + str(origin) + "' extent='" + str(size) + "' " + texture + "type='plat' position='" + pos + "' />"
def _macro_stairs_match(self, full, individual): '''Take in the dimension of the whole staircase and that of an individual step; check that they divide w/o a remainder (i.e. the steps of length/height x fit an integer numer of times) If they don't, find another value for the dimension of the individual step that allows a whole number of steps to fit in. We allow a tollerance of 0.01.''' tolerance = 0.01 difference = 1 # start high to get the loop going decrement = 0.01 lower_bound = individual / 2 # abort if it reduces to this value if full/individual != int(full/individual): while individual > lower_bound and difference > tolerance: individual = individual - decrement difference = abs(full/individual - int(full/individual)) if individual > lower_bound: return individual else: ldl.error('couldn\'t find a suitable step dimension') else: return individual
def processNode(doc, parent, worldspawn, s, offset, node): global paddinglevel name = node.localName paddinglevel = paddinglevel + 1 # for i in range(paddinglevel): # ldl.uprint(padding, True) # # if name: # ldl.uprint(name) # else: # ldl.uprint('(no name -- comment)') if node.localName == 'hollow': processHollow(doc, parent, worldspawn, s, offset, node) elif node.localName == 'solid': processSolid(doc, parent, worldspawn, s, offset, node) elif node.localName == 'entity': processEntity(doc, parent, offset, node) elif node.localName == None: pass # comment node else: ldl.error('unknown element type ' + node.localName + '.\n') paddinglevel = paddinglevel - 1
def processInfo(doc, map): info = map.firstChild for property in info.childNodes: # FIXME we assume all children of info are property elements ptype = property.getAttribute('name') if ptype == 'mapname': mapname = property.getAttribute('value') elif ptype == 'worldtype': worldtype = property.getAttribute('value') if ldl.worldtypes.has_key(worldtype): worldtype_num = ldl.worldtypes[worldtype] else: ldl.error('Invalid worldtype ' + worldtype + ' specified.') else: ldl.error('Invalid map info property ' + ptype + ' specified.') worldspawn = doc.createElement('entity') worldspawn.appendChild(ldl.createProperty(doc, 'classname', 'worldspawn')) worldspawn.appendChild(ldl.createProperty(doc, 'worldtype', str(worldtype_num))) worldspawn.appendChild(ldl.createProperty(doc, 'message', mapname)) worldspawn.appendChild(ldl.createProperty(doc, 'wad', ldl.wadfile)) map.replaceChild(worldspawn, info) return worldspawn
def splitWall(brush, holes): '''Splits a brush up in 2D so that it appears to have a hole in it. This is achieved by taking the full brush size and the holes list and splitting the brush up into multiple parts.''' if not holes: return [brush] parts = [] # stores 2D parts returned by the main function finalparts = [] # stores expanded 3D parts extent2d = ldl.Point2D(brush.extent.x, brush.extent.y) # Sort holes by x start coord, then width... sortedholes = qsortHoles(holes) # Check for errors and add doors into the returned list of parts, as they need to be built... for hole in sortedholes: # FIXME check for other errors -- backtrack? if hole.origin.y + hole.extent.y > extent2d.y: #ldl.error('Hole is taller than containing wall.\n\thole.origin.y: ' + str(hole.origin.y) + '\n\thole.extent.y: ' + str(hole.extent.y) + '\n\textent2d.y: ' + str(extent2d.y)) ldl.error('Hole is taller than containing wall.\n\thole: ' + str(hole) + '\n\textent2d: ' + str(extent2d)) if hole.type == ldl.RT_DOOR: finalparts.append(ldl.Region2D( ldl.Point2D( brush.origin.x+hole.origin.x, brush.origin.y+hole.origin.y), ldl.Point2D( hole.extent.x, hole.extent.y), hole.type, hole.props )) # Go to main function... # FIXME this should not assume the origin is (0,0) but it doesn't work if we don't make this true... parts = splitWallCore(ldl.Chunk2D(ldl.Point2D(0, 0), extent2d), sortedholes) # Take list of brushes and add the z coord back on... for p in parts: finalparts.append(ldl.Region2D( ldl.Point2D(brush.origin.x+p.origin.x, brush.origin.y+p.origin.y), ldl.Point2D(p.extent.x, p.extent.y), p.type, p.props )) # Now we can return them... return finalparts
def processInfo(doc, map): info = map.firstChild for property in info.childNodes: # FIXME we assume all children of info are property elements ptype = property.getAttribute('name') if ptype == 'mapname': mapname = property.getAttribute('value') elif ptype == 'worldtype': worldtype = property.getAttribute('value') if ldl.worldtypes.has_key(worldtype): worldtype_num = ldl.worldtypes[worldtype] else: ldl.error('Invalid worldtype ' + worldtype + ' specified.') else: ldl.error('Invalid map info property ' + ptype + ' specified.') worldspawn = doc.createElement('entity') worldspawn.appendChild(ldl.createProperty(doc, 'classname', 'worldspawn')) worldspawn.appendChild( ldl.createProperty(doc, 'worldtype', str(worldtype_num))) worldspawn.appendChild(ldl.createProperty(doc, 'message', mapname)) worldspawn.appendChild(ldl.createProperty(doc, 'wad', ldl.wadfile)) map.replaceChild(worldspawn, info) return worldspawn
def splitWall(brush, holes): '''Splits a brush up in 2D so that it appears to have a hole in it. This is achieved by taking the full brush size and the holes list and splitting the brush up into multiple parts.''' if not holes: return [brush] parts = [] # stores 2D parts returned by the main function finalparts = [] # stores expanded 3D parts extent2d = ldl.Point2D(brush.extent.x, brush.extent.y) # Sort holes by x start coord, then width... sortedholes = qsortHoles(holes) # Check for errors and add doors into the returned list of parts, as they need to be built... for hole in sortedholes: # FIXME check for other errors -- backtrack? if hole.origin.y + hole.extent.y > extent2d.y: #ldl.error('Hole is taller than containing wall.\n\thole.origin.y: ' + str(hole.origin.y) + '\n\thole.extent.y: ' + str(hole.extent.y) + '\n\textent2d.y: ' + str(extent2d.y)) ldl.error('Hole is taller than containing wall.\n\thole: ' + str(hole) + '\n\textent2d: ' + str(extent2d)) if hole.type == ldl.RT_DOOR: finalparts.append( ldl.Region2D( ldl.Point2D(brush.origin.x + hole.origin.x, brush.origin.y + hole.origin.y), ldl.Point2D(hole.extent.x, hole.extent.y), hole.type, hole.props)) # Go to main function... # FIXME this should not assume the origin is (0,0) but it doesn't work if we don't make this true... parts = splitWallCore(ldl.Chunk2D(ldl.Point2D(0, 0), extent2d), sortedholes) # Take list of brushes and add the z coord back on... for p in parts: finalparts.append( ldl.Region2D( ldl.Point2D(brush.origin.x + p.origin.x, brush.origin.y + p.origin.y), ldl.Point2D(p.extent.x, p.extent.y), p.type, p.props)) # Now we can return them... return finalparts
def processSolid(doc, parent, worldspawn, sf, offset, solid): '''Note: uses style set in parent hollow.''' global style o = ldl.getPoint(solid.getAttribute('origin')) + offset e = ldl.getPoint(solid.getAttribute('extent')) t = solid.getAttribute('texture') type = solid.getAttribute('type') if not t: if not type: ldl.error('solid with no type also has no texture attribute set') f = solid.getAttribute('holeface') # Get holes info... # FIXME this is repeated code from the hollow one -- any way we can refactor it? props = {} holes = [] # Check if the solid has children (holes). # If so, split it up. # If not, just add it. if solid.hasChildNodes(): for hole in solid.childNodes: ho_x, ho_y = hole.getAttribute('origin').split() he_x, he_y = hole.getAttribute('extent').split() type = hole.getAttribute('type') if not type: pass elif type == ldl.RT_DOOR: props[ldl.PROPS_K_KEY] = hole.getAttribute('key') else: ldl.warning( 'only doors allowed as hole types; not plats or others.') # FIXME deal with other types holes.append( ldl.Hole2D(ldl.Point2D(float(ho_x), float(ho_y)), ldl.Point2D(float(he_x), float(he_y)), type, props)) # Built split (2D) parts into 3D brushes; mapping of coords to 3D depends on which direction/face the hole was constructed in. if f == ldl.DCP_NORTH: parts = split.splitWall( ldl.Region2D(ldl.Point2D(o.x, o.z), ldl.Point2D(e.x, e.z)), holes) for part in parts: part3d = ldl.addDim(part, ldl.DIM_Y, o.y, e.y) #ldl.uprint('Part: ' + str(part) + '\nPart3D: ' + str(part3d)) ldl.makeBrush(doc, worldspawn, sf, style, part3d, f, t) elif f == ldl.DCP_UP: parts = split.splitWall( ldl.Region2D(ldl.Point2D(o.x, o.y), ldl.Point2D(e.x, e.y)), holes) for part in parts: part3d = ldl.addDim(part, ldl.DIM_Z, o.z + ldl.lip_small, e.z - ldl.lip_small * 2) #ldl.uprint('Part: ' + str(part) + '\nPart3D: ' + str(part3d)) ldl.makeBrush(doc, worldspawn, sf, style, part3d, f, t) else: ldl.error('Unsupported holeface ' + f + ' requested for hole in solid.') else: # Doesn't have child nodes... if not type or type == ldl.RT_STEP: pass # no properties to set elif type == ldl.RT_DOOR: props[ldl.PROPS_K_KEY] = solid.getAttribute('key') elif type == ldl.RT_PLAT: props[ldl.PROPS_K_POS] = solid.getAttribute('position') else: ldl.warning('unknown type ' + type + ' specifed.') brush = ldl.Region3D(Point(o.x, o.y, o.z), Point(e.x, e.y, e.z), type, props) ldl.makeBrush(doc, worldspawn, sf, style, brush, type, t) # We can't remove the child or we screw over tree traversal (urgh)... ldl.insertPlaceholder(doc, parent, solid)
def processSolid(doc, parent, worldspawn, sf, offset, solid): '''Note: uses style set in parent hollow.''' global style o = ldl.getPoint(solid.getAttribute('origin')) + offset e = ldl.getPoint(solid.getAttribute('extent')) t = solid.getAttribute('texture') type = solid.getAttribute('type') if not t: if not type: ldl.error('solid with no type also has no texture attribute set') f = solid.getAttribute('holeface') # Get holes info... # FIXME this is repeated code from the hollow one -- any way we can refactor it? props = {} holes = [] # Check if the solid has children (holes). # If so, split it up. # If not, just add it. if solid.hasChildNodes(): for hole in solid.childNodes: ho_x, ho_y = hole.getAttribute('origin').split() he_x, he_y = hole.getAttribute('extent').split() type = hole.getAttribute('type') if not type: pass elif type == ldl.RT_DOOR: props[ldl.PROPS_K_KEY] = hole.getAttribute('key') else: ldl.warning('only doors allowed as hole types; not plats or others.') # FIXME deal with other types holes.append(ldl.Hole2D(ldl.Point2D(float(ho_x), float(ho_y)), ldl.Point2D(float(he_x), float(he_y)), type, props)) # Built split (2D) parts into 3D brushes; mapping of coords to 3D depends on which direction/face the hole was constructed in. if f == ldl.DCP_NORTH: parts = split.splitWall( ldl.Region2D( ldl.Point2D(o.x, o.z), ldl.Point2D(e.x, e.z) ), holes) for part in parts: part3d = ldl.addDim(part, ldl.DIM_Y, o.y, e.y) #ldl.uprint('Part: ' + str(part) + '\nPart3D: ' + str(part3d)) ldl.makeBrush(doc, worldspawn, sf, style, part3d, f, t) elif f == ldl.DCP_UP: parts = split.splitWall( ldl.Region2D( ldl.Point2D(o.x, o.y), ldl.Point2D(e.x, e.y) ), holes) for part in parts: part3d = ldl.addDim(part, ldl.DIM_Z, o.z+ldl.lip_small, e.z-ldl.lip_small*2) #ldl.uprint('Part: ' + str(part) + '\nPart3D: ' + str(part3d)) ldl.makeBrush(doc, worldspawn, sf, style, part3d, f, t) else: ldl.error('Unsupported holeface ' + f + ' requested for hole in solid.') else: # Doesn't have child nodes... if not type or type == ldl.RT_STEP: pass # no properties to set elif type == ldl.RT_DOOR: props[ldl.PROPS_K_KEY] = solid.getAttribute('key') elif type == ldl.RT_PLAT: props[ldl.PROPS_K_POS] = solid.getAttribute('position') else: ldl.warning('unknown type ' + type + ' specifed.') brush = ldl.Region3D( Point(o.x, o.y, o.z), Point(e.x, e.y, e.z), type, props ) ldl.makeBrush(doc, worldspawn, sf, style, brush, type, t) # We can't remove the child or we screw over tree traversal (urgh)... ldl.insertPlaceholder(doc, parent, solid)
def splitWallCore(chunk, holes): '''Take a given area of the face to be split and split it.''' global splitWallCoreLevel splitWallCoreLevel = splitWallCoreLevel + 1 parts = [] if len(holes) == 0: paddedPrint('sWC: 0. chunk:' + str(chunk)) parts.append(chunk) elif len(holes) == 1: hole = holes.pop() paddedPrint('sWC: 1. chunk: ' + str(chunk) + ' holes: ' + str(hole)) if hole.end.x < chunk.end.x: # The hole is not flush with one side of this chunk; split the chunk so it is. # We do this by splitting the chunk so that the hole touches its east side. # Anything left over after the east side is a single whole chunk. paddedPrint('sWC: 1. hole.end.x (' + str(hole.end.x) + ') < chunk.end.x (' + str(chunk.end.x) + ').') # Process part of chunk with hole in it... paddedPrint('sWC: 1. hole.end.x < chunk.end.x. HOLE CHUNK') addparts = splitWallCore( ldl.Chunk2D( chunk.origin, ldl.Point2D(hole.end.x - chunk.origin.x, chunk.extent.y)), [hole]) for ap in addparts: parts.append(ap) # Process the bit left at the east side... paddedPrint('sWC: 1. hole.end.x < chunk.end.x. SOLID CHUNK') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(hole.end.x, chunk.origin.y), ldl.Point2D(chunk.end.x - hole.end.x, chunk.extent.y)), []) for ap in addparts: parts.append(ap) else: # The end x-points of hole and chunk must be equal. # Add some parts around the hole... paddedPrint('sWC: 1. split flush.') # Under hole if (hole.origin.y - chunk.origin.y) > 0: parts.append( ldl.Chunk2D( chunk.origin, ldl.Point2D(hole.end.x - chunk.origin.x, hole.origin.y - chunk.origin.y))) # Left of hole if (hole.origin.x - chunk.origin.x) > 0: parts.append( ldl.Chunk2D( chunk.origin + ldl.Point2D(0, hole.origin.y - chunk.origin.y), ldl.Point2D(hole.origin.x - chunk.origin.x, hole.extent.y))) # Above hole if (chunk.end.y - hole.end.y) > 0: parts.append( ldl.Chunk2D( chunk.origin + ldl.Point2D(0, hole.end.y - chunk.origin.y), ldl.Point2D(hole.end.x - chunk.origin.x, chunk.end.y - hole.end.y))) paddedPrint('sWC: 1. split flush. results: ' + str([str(p) for p in parts])) else: # len(holes) > 1 paddedPrint('sWC: n. chunk: ' + str(chunk) + ' holes: ' + str([str(h) for h in holes])) '''Compare first two holes. If they do not overlap x-wise, split the chunk at the x value that represents the end of the first hole. If they do overlap x-wise, see if they overlap y-wise too. If they do, we're screwed (can't handle this yet). If they overlap y-wise See if there are any more nodes. If no, then we can just split this chunk at a given y-value to keep the holes seperate. If yes, then we need to see if we can split this chunk into two: one split vertically (at an x-value just after the 2nd hole) to seperate our two x-overlapping holes from the next one. and one split horizontally (at a y-value) to separate our overlapping holes ''' holeA = holes[0] holeB = holes[1] if holeA.end.x < holeB.origin.x: paddedPrint('sWC: n. holeA.end.x (' + str(holeA.end.x) + ') < holeB.origin.x (' + str(holeB.origin.x) + ')') # Our holes do not overlap x-wise; # split our chunk into two: # one chunk containing the first hole (flush to the edge) # another chunk containing all the other holes paddedPrint('sWC: n. holeA.end.x < holeB.origin.x. singleton') addparts = splitWallCore( ldl.Chunk2D( chunk.origin, ldl.Point2D(holeA.end.x - chunk.origin.x, chunk.extent.y)), [holeA]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. holeA.end.x < holeB.origin.x. the rest') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(holeA.end.x, chunk.origin.y), ldl.Point2D(chunk.end.x - holeA.end.x, chunk.extent.y)), holes[1:]) for ap in addparts: parts.append(ap) elif holeA.origin.y >= holeB.end.y or holeB.origin.y >= holeA.end.y: paddedPrint('sWC: n. Y. holeA.origin.y (' + str(holeA.origin.y) + ' >= holeB.end.y (' + str(holeB.end.y) + ')') # Our holes overlap x-wise, but they don't overlap y-wise. # Which one is on top? if holeA.origin.y >= holeB.origin.y: upper = holeA lower = holeB else: upper = holeB lower = holeA # Are there more holes? if not len(holes) > 2: paddedPrint('sWC: n. Y. no more holes') # No more holes; just split this chunk y-wise... paddedPrint('sWC: n. Y. no more holes. LOWER.') addparts = splitWallCore( ldl.Chunk2D(chunk.origin, ldl.Point2D(chunk.extent.x, upper.origin.y)), [lower]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. Y. no more holes. UPPER.') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(chunk.origin.x, upper.origin.y), ldl.Point2D(chunk.extent.x, chunk.extent.y - upper.origin.y)), [upper]) for ap in addparts: parts.append(ap) else: # There are more holes; split both y- and x-wise. # Use the x-value of the next hole (FIXME could break things?) xcutoff = holes[2].origin.x - chunk.origin.x paddedPrint('sWC: n. Y. more holes; xcutoff = ' + str(xcutoff)) paddedPrint('sWC: n. Y. more holes. LOWER.') addparts = splitWallCore( ldl.Chunk2D(chunk.origin, ldl.Point2D(xcutoff, upper.origin.y)), [lower]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. Y. more holes. UPPER.') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(chunk.origin.x, upper.origin.y), ldl.Point2D(xcutoff, chunk.extent.y - upper.origin.y)), [upper]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. Y. more holes. REST-OF-X.') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(chunk.origin.x + xcutoff, chunk.origin.y), ldl.Point2D(chunk.extent.x - xcutoff, chunk.extent.y)), holes[2:]) for ap in addparts: parts.append(ap) else: # Our holes overlap both x- and y-wise; for now, we're screwed. ldl.error( 'Oh dear: the segmentation algorithm can\'t cope with holes that overlap both x- and y-wise!' ) splitWallCoreLevel = splitWallCoreLevel - 1 return parts
def macro_stairs(self, bi, si): '''Make some stairs we see this as a 2D problem then add the missing dimension later (width/depth) dir tells us in which dir the steps go up length is the distance from start of lowest to end of heighest step height is the height of the highest step''' # FIXME cope with being able to make a hole through (under) the stairs origin = ldl.getPoint(bi['origin']) size = ldl.getPoint(bi['extent']) dir = si['dir'] texture = '' if bi.has_key('texture'): texture = bi['texture'] #slength = float(si['steplength']) slength = 0 sheight = float(si['stepheight']) parts = [] parts3d = [] # FIXME repeated code: n/e == s/w -- collapse into 2? # Work out which dimension is which if dir == ldl.DCP_NORTH: # use X and Y; Z rising with increasing Y length = size.y height = size.z width = size.x flip = False parts = self._macro_stairs_core(length, height, width, flip, slength, sheight, texture) for part in parts: part3d = ldl.Region3D( Point(0,part.origin.x,part.origin.y) + origin, Point(width, part.extent.x, part.extent.y) ) parts3d.append(part3d) elif dir == ldl.DCP_SOUTH: # use X and Y; Z falling with increasing Y length = size.y height = size.z width = size.x flip = True parts = self._macro_stairs_core(length, height, width, flip, slength, sheight, texture) for part in parts: part3d = ldl.Region3D( Point(0,part.origin.x,part.origin.y) + origin, Point(width, part.extent.x, part.extent.y) ) parts3d.append(part3d) elif dir == ldl.DCP_EAST: # use X and Y; Z rising with increasing X length = size.x height = size.z width = size.y flip = False parts = self._macro_stairs_core(length, height, width, flip, slength, sheight, texture) for part in parts: part3d = ldl.Region3D( Point(part.origin.x, 0, part.origin.y) + origin, Point(part.extent.x, width, part.extent.y) ) parts3d.append(part3d) elif dir == ldl.DCP_WEST: # use X and y; Z falling with increasing X length = size.x height = size.z width = size.y flip = True parts = self._macro_stairs_core(length, height, width, flip, slength, sheight, texture) for part in parts: part3d = ldl.Region3D( Point(part.origin.x, 0, part.origin.y) + origin, Point(part.extent.x, width, part.extent.y) ) parts3d.append(part3d) else: ldl.error('invalid direction specified for stairs (up and down are currently unsupported)') for part3d in parts3d: #ldl.uprint(str(part3d)) print "<solid origin='" + str(part3d.origin) + "' extent='" + str(part3d.extent) + "' texture='" + texture + "' type='step' />"
return # Utility Functions... def padded_print(self, msg): for i in range(self.padding_level): ldl.uprint(' ', sameLine=True) ldl.uprint(msg) if __name__ == "__main__": ldl.stage = '03' ldl.uprint('\n === ' + ldl.stackdescs[ldl.stage] + ' ===') styleFetcher = ldl.StyleFetcher() parser = sax.make_parser() #XMLGenerator is a special SAX handler that merely writes #SAX events back into an XML document downstream_handler = XMLGenerator() #upstream, the parser, downstream, the next handler in the chain filter_handler = LightingStyleFilter(parser, downstream_handler) #The SAX filter base is designed so that the filter takes #on much of the interface of the parser itself, including the #"parse" method try: filter_handler.parse(sys.stdin) except sax.SAXParseException, detail: ldl.error('The XML you supplied is not valid: ' + str(detail)) except: raise ldl.failParse()
def splitWallCore(chunk, holes): '''Take a given area of the face to be split and split it.''' global splitWallCoreLevel splitWallCoreLevel = splitWallCoreLevel + 1 parts = [] if len(holes) == 0: paddedPrint('sWC: 0. chunk:' + str(chunk)) parts.append(chunk) elif len(holes) == 1: hole = holes.pop() paddedPrint('sWC: 1. chunk: ' + str(chunk) + ' holes: ' + str(hole)) if hole.end.x < chunk.end.x: # The hole is not flush with one side of this chunk; split the chunk so it is. # We do this by splitting the chunk so that the hole touches its east side. # Anything left over after the east side is a single whole chunk. paddedPrint('sWC: 1. hole.end.x (' + str(hole.end.x) + ') < chunk.end.x (' + str(chunk.end.x) + ').') # Process part of chunk with hole in it... paddedPrint('sWC: 1. hole.end.x < chunk.end.x. HOLE CHUNK') addparts = splitWallCore( ldl.Chunk2D( chunk.origin, ldl.Point2D(hole.end.x-chunk.origin.x, chunk.extent.y) ), [hole]) for ap in addparts: parts.append(ap) # Process the bit left at the east side... paddedPrint('sWC: 1. hole.end.x < chunk.end.x. SOLID CHUNK') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(hole.end.x, chunk.origin.y), ldl.Point2D(chunk.end.x-hole.end.x, chunk.extent.y) ), []) for ap in addparts: parts.append(ap) else: # The end x-points of hole and chunk must be equal. # Add some parts around the hole... paddedPrint('sWC: 1. split flush.') # Under hole if (hole.origin.y - chunk.origin.y) > 0: parts.append(ldl.Chunk2D( chunk.origin, ldl.Point2D(hole.end.x-chunk.origin.x, hole.origin.y-chunk.origin.y))) # Left of hole if (hole.origin.x - chunk.origin.x) > 0: parts.append(ldl.Chunk2D( chunk.origin + ldl.Point2D(0, hole.origin.y-chunk.origin.y), ldl.Point2D(hole.origin.x-chunk.origin.x, hole.extent.y))) # Above hole if (chunk.end.y - hole.end.y) > 0: parts.append(ldl.Chunk2D( chunk.origin + ldl.Point2D(0, hole.end.y-chunk.origin.y), ldl.Point2D(hole.end.x-chunk.origin.x, chunk.end.y - hole.end.y))) paddedPrint('sWC: 1. split flush. results: ' + str([str(p) for p in parts])) else: # len(holes) > 1 paddedPrint('sWC: n. chunk: ' + str(chunk) + ' holes: ' + str([str(h) for h in holes])) '''Compare first two holes. If they do not overlap x-wise, split the chunk at the x value that represents the end of the first hole. If they do overlap x-wise, see if they overlap y-wise too. If they do, we're screwed (can't handle this yet). If they overlap y-wise See if there are any more nodes. If no, then we can just split this chunk at a given y-value to keep the holes seperate. If yes, then we need to see if we can split this chunk into two: one split vertically (at an x-value just after the 2nd hole) to seperate our two x-overlapping holes from the next one. and one split horizontally (at a y-value) to separate our overlapping holes ''' holeA = holes[0] holeB = holes[1] if holeA.end.x < holeB.origin.x: paddedPrint('sWC: n. holeA.end.x (' + str(holeA.end.x) + ') < holeB.origin.x (' + str(holeB.origin.x) + ')') # Our holes do not overlap x-wise; # split our chunk into two: # one chunk containing the first hole (flush to the edge) # another chunk containing all the other holes paddedPrint('sWC: n. holeA.end.x < holeB.origin.x. singleton') addparts = splitWallCore( ldl.Chunk2D( chunk.origin, ldl.Point2D(holeA.end.x-chunk.origin.x, chunk.extent.y) ), [holeA]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. holeA.end.x < holeB.origin.x. the rest') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(holeA.end.x, chunk.origin.y), ldl.Point2D(chunk.end.x-holeA.end.x, chunk.extent.y) ), holes[1:]) for ap in addparts: parts.append(ap) elif holeA.origin.y >= holeB.end.y or holeB.origin.y >= holeA.end.y: paddedPrint('sWC: n. Y. holeA.origin.y (' + str(holeA.origin.y) + ' >= holeB.end.y (' + str(holeB.end.y) + ')') # Our holes overlap x-wise, but they don't overlap y-wise. # Which one is on top? if holeA.origin.y >= holeB.origin.y: upper = holeA lower = holeB else: upper = holeB lower = holeA # Are there more holes? if not len(holes) > 2: paddedPrint('sWC: n. Y. no more holes') # No more holes; just split this chunk y-wise... paddedPrint('sWC: n. Y. no more holes. LOWER.') addparts = splitWallCore( ldl.Chunk2D( chunk.origin, ldl.Point2D(chunk.extent.x, upper.origin.y) ), [lower]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. Y. no more holes. UPPER.') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(chunk.origin.x, upper.origin.y), ldl.Point2D(chunk.extent.x, chunk.extent.y - upper.origin.y) ), [upper]) for ap in addparts: parts.append(ap) else: # There are more holes; split both y- and x-wise. # Use the x-value of the next hole (FIXME could break things?) xcutoff = holes[2].origin.x - chunk.origin.x paddedPrint('sWC: n. Y. more holes; xcutoff = ' + str(xcutoff)) paddedPrint('sWC: n. Y. more holes. LOWER.') addparts = splitWallCore( ldl.Chunk2D( chunk.origin, ldl.Point2D(xcutoff, upper.origin.y) ), [lower]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. Y. more holes. UPPER.') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(chunk.origin.x, upper.origin.y), ldl.Point2D(xcutoff, chunk.extent.y - upper.origin.y) ), [upper]) for ap in addparts: parts.append(ap) paddedPrint('sWC: n. Y. more holes. REST-OF-X.') addparts = splitWallCore( ldl.Chunk2D( ldl.Point2D(chunk.origin.x + xcutoff, chunk.origin.y), ldl.Point2D(chunk.extent.x - xcutoff, chunk.extent.y) ), holes[2:]) for ap in addparts: parts.append(ap) else: # Our holes overlap both x- and y-wise; for now, we're screwed. ldl.error('Oh dear: the segmentation algorithm can\'t cope with holes that overlap both x- and y-wise!') splitWallCoreLevel = splitWallCoreLevel - 1 return parts
def ignorableWhitespace(self, ws): self._accumulator.append(text) # Utility Functions... def padded_print(self, msg): for i in range(self.padding_level): ldl.uprint(' ', sameLine=True) ldl.uprint(msg) if __name__ == "__main__": ldl.stage = '04' ldl.uprint('\n === ' + ldl.stackdescs['04'] + ' ===') parser = sax.make_parser() #XMLGenerator is a special SAX handler that merely writes #SAX events back into an XML document downstream_handler = XMLGenerator() #upstream, the parser, downstream, the next handler in the chain filter_handler = BuilderFilter(parser, downstream_handler) #The SAX filter base is designed so that the filter takes #on much of the interface of the parser itself, including the #"parse" method try: filter_handler.parse(sys.stdin) except sax.SAXParseException, detail: ldl.error('The XML you supplied is not valid: ' + str(detail)) except: raise ldl.failParse()