def pruneRelativeHeading(scenario, verbosity): """Prune based on requirements bounding the relative heading of an Object. Specifically, if an object O is: * positioned uniformly within a polygonal region B; * aligned to a polygonal vector field F (up to a bounded offset); and another object O' is: * aligned to a polygonal vector field F' (up to a bounded offset); * at most some finite maximum distance from O; * required to have relative heading within a bounded offset of that of O; then we can instead position O uniformly in the subset of B intersecting the cells of F which satisfy the relative heading requirements w.r.t. some cell of F' which is within the distance bound. """ # Check which objects are (approximately) aligned to polygonal vector fields fields = {} for obj in scenario.objects: field, offsetL, offsetR = matchPolygonalField(obj.heading, obj.position) if field is not None: fields[obj] = (field, offsetL, offsetR) # Check for relative heading relations among such objects for obj, (field, offsetL, offsetR) in fields.items(): position = currentPropValue(obj, 'position') base = matchInRegion(position) if base is None: # obj must be positioned uniformly in a Region continue basePoly = regions.toPolygon(base) if basePoly is None: # the Region must be polygonal continue newBasePoly = basePoly for rel in obj._relations: if isinstance(rel, RelativeHeadingRelation) and rel.target in fields: tField, tOffsetL, tOffsetR = fields[rel.target] maxDist = maxDistanceBetween(scenario, obj, rel.target) if maxDist == float( 'inf' ): # the distance between the objects must be bounded continue feasible = feasibleRHPolygon(field, offsetL, offsetR, tField, tOffsetL, tOffsetR, rel.lower, rel.upper, maxDist) if feasible is None: # the RH bounds may be too weak to restrict the space continue try: pruned = newBasePoly & feasible except shapely.geos.TopologicalError: # TODO how can we prevent these?? pruned = newBasePoly & feasible.buffer(0.1, cap_style=2) if verbosity >= 1: percent = 100 * (1.0 - (pruned.area / newBasePoly.area)) print( f' Relative heading constraint pruned {percent:.1f}% of space.' ) newBasePoly = pruned if newBasePoly is not basePoly: newBase = regions.PolygonalRegion(polygon=newBasePoly, orientation=base.orientation) newPos = regions.Region.uniformPointIn(newBase) obj.position.conditionTo(newPos)
def pruneContainment(scenario, verbosity): """Prune based on the requirement that individual Objects fit within their container. Specifically, if O is positioned uniformly in region B and has container C, then we can instead pick a position uniformly in their intersection. If we can also lower bound the radius of O, then we can first erode C by that distance. """ for obj in scenario.objects: base = matchInRegion(obj.position) if base is None: # match objects positioned uniformly in a Region continue basePoly = regions.toPolygon(base) if basePoly is None: # to prune, the Region must be polygonal continue container = scenario.containerOfObject(obj) containerPoly = regions.toPolygon(container) if containerPoly is None: # the object's container must also be polygonal return None minRadius, _ = supportInterval(obj.inradius) if minRadius is not None: # if we can lower bound the radius, erode the container containerPoly = containerPoly.buffer(-minRadius) elif base is container: continue newBasePoly = basePoly & containerPoly # restrict the base Region to the container if verbosity >= 1: percent = 100 * (1.0 - (newBasePoly.area / basePoly.area)) print( f' Region containment constraint pruned {percent:.1f}% of space.' ) newBase = regions.PolygonalRegion(polygon=newBasePoly, orientation=base.orientation) newPos = regions.Region.uniformPointIn(newBase) obj.position.conditionTo(newPos)
def pruneRelativeHeading(scenario, verbosity): # Check which objects are (approximately) aligned to polygonal vector fields fields = {} for obj in scenario.objects: field, offsetL, offsetR = matchPolygonalField(obj.heading, obj.position) if field is not None: fields[obj] = (field, offsetL, offsetR) # Check for relative heading relations for obj, (field, offsetL, offsetR) in fields.items(): position = currentPropValue(obj, 'position') base = matchInRegion(position) if base is None: continue basePoly = regions.toPolygon(base) if basePoly is None: continue newBasePoly = basePoly for rel in obj._relations: if isinstance(rel, RelativeHeadingRelation) and rel.target in fields: tField, tOffsetL, tOffsetR = fields[rel.target] maxDist = maxDistanceBetween(scenario, obj, rel.target) if maxDist is None: continue feasible = feasibleRHPolygon(field, offsetL, offsetR, tField, tOffsetL, tOffsetR, rel.lower, rel.upper, maxDist) if feasible is None: continue try: pruned = newBasePoly & feasible except shapely.geos.TopologicalError: # TODO how can we prevent these?? pruned = newBasePoly & feasible.buffer(0.1, cap_style=2) if verbosity >= 1: percent = 100 * (1.0 - (pruned.area / newBasePoly.area)) print( f' Relative heading constraint pruned {percent:.1f}% of space.' ) newBasePoly = pruned if newBasePoly is not basePoly: newBase = regions.PolygonalRegion(polygon=newBasePoly, orientation=base.orientation) newPos = regions.Region.uniformPointIn(newBase) obj.position.conditionTo(newPos)