Beispiel #1
0
    def test_polygonSplit_cutThroughHole(self):
        P = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)], [[(0.2, 0.2), (0.2, 0.8),
                                                        (0.8, 0.8),
                                                        (0.8, 0.2)]])
        e = LineString([(0.2, 0), (0.2, 1)])
        result = polygon_split(P, e)

        R1 = Polygon([(0.2, 0), (0, 0), (0, 1), (0.2, 1), (0.2, 0.8),
                      (0.2, 0.2), (0.2, 0)])
        R2 = Polygon([(0.2, 1), (1, 1), (1, 0), (0.2, 0), (0.2, 0.2),
                      (0.8, 0.2), (0.8, 0.8), (0.2, 0.8), (0.2, 1)])

        self.assertTrue(R1.equals(result[0]) and R2.equals(result[1]))
Beispiel #2
0
    def test_polygonSplit_cutThroughManyPoints(self):
        P = Polygon([(0, 0), (1, 0), (1, 1), (0.8, 1), (0.2, 0.8), (0.5, 1),
                     (0, 1)], [])
        e = LineString([(0.5, 0), (0.5, 1)])

        R1 = Polygon([(0.5, 0), (0, 0), (0, 1), (0.5, 1), (0.2, 0.8),
                      (0.5, 0.9), (0.5, 0)])
        R2 = Polygon([(0.5, 0.9), (0.8, 1), (1, 1), (1, 0), (0.5, 0),
                      (0.5, 0.9)])

        result1, result2 = polygon_split(P, e)

        self.assertTrue(result1.equals(R1) and result2.equals(R2))
Beispiel #3
0
    def test_polygonSplit_validSplit3(self):
        P = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)], [])
        e = LineString([(0.2, 0), (0, 0.2)])
        result = polygon_split(P, e)
        self.assertTrue(result)
        P1, P2 = result
        self.assertTrue(P1)
        self.assertTrue(P2)

        testPolygon1 = Polygon([(0.2, 0.0), (0.0, 0.2), (0.0, 0.0)])
        testPolygon2 = Polygon([(1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.2),
                                (0.2, 0.0)])

        self.assertTrue(P1.equals(testPolygon1) and P2.equals(testPolygon2))
Beispiel #4
0
    def test_stability(self):
        P = Polygon([(0, 0), (3, 1), (3, 0), (4, 1), (5, 0), (5, 1), (7, 1),
                     (5, 2), (7, 3), (0, 4), (0, 2.5), (1, 2), (0, 1.5),
                     (1, 1), (0, 0.5)], [[(3, 2), (3, 3), (4, 3), (4, 2)]])

        polyExterior = P.exterior

        from numpy import linspace
        from itertools import product
        searchDistances = list(linspace(0, polyExterior.length, 200))

        searchSpace = []
        for distance in searchDistances:
            solutionCandidate = polyExterior.interpolate(distance)
            searchSpace.append((solutionCandidate.x, solutionCandidate.y))

        try:
            for cutEdge in product(searchSpace, repeat=2):
                cutEdgeLS = LineString(cutEdge)
                result = polygon_split(P, cutEdgeLS)
        except Exception:
            self.fail("Stability test has failed!")
Beispiel #5
0
 def test_polygonSplit_cutOutsidePolygon1(self):
     P = Polygon([(0, 0), (0.5, 0.5), (1, 0), (1, 1), (0, 1)], [])
     e = LineString([(0, 0), (1, 0)])
     result = polygon_split(P, e)
     self.assertEqual(result, [])
Beispiel #6
0
 def test_polygonSplit_nonDecomposingCut(self):
     P = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)], [[(0.2, 0.2), (0.2, 0.8),
                                                     (0.8, 0.8),
                                                     (0.8, 0.2)]])
     e = LineString([(0.2, 0), (0.2, 0.2)])
     self.assertEqual(polygon_split(P, e), [])
Beispiel #7
0
 def test_polygonSplit_cutAlongBoundary(self):
     P = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)], [])
     e = LineString([(0, 0), (0, 1)])
     self.assertEqual(polygon_split(P, e), [])
Beispiel #8
0
 def test_polygonSplit_cutTouchesPolygon(self):
     P = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)], [])
     e = LineString([(0, 0), (0.9, 0.9)])
     self.assertEqual(polygon_split(P, e), [])
Beispiel #9
0
 def test_polygonSplit_selfintersectingPolygon(self):
     P = Polygon([(0, 0), (1, 0), (1, 1), (0.1, -0.1)], [])
     e = LineString([(0, 0), (1, 1)])
     self.assertEqual(polygon_split(P, e), [])
Beispiel #10
0
 def test_polygonSplit_inccorectEdge2(self):
     P = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)], [])
     e = LineString([(0, 0), (1, 1), (0, 1)])
     self.assertEqual(polygon_split(P, e), [])
Beispiel #11
0
 def test_polygonSplit_emptyEdge(self):
     P = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)], [])
     e = LineString([(0, 0), (1, 1)])
     self.assertEqual(polygon_split(P, []), [])
Beispiel #12
0
def compute_pairwise_optimal(polygonA=[],
							 polygonB=[],
							 robotAInitPos=[],
							 robotBInitPos=[],
							 nrOfSamples=100,
							 radius = 0.1,
							 linPenalty = 1.0,
							 angPenalty = 10*1.0/360):
	"""
	Takes two adjacent polygons and attempts to modify the shared edge such that
	the metric chi is reduced.

	TODO:
		Need to investigate assignment of cells to robots.

	Args:
		polygonA: First polygon in canonical form.
		polygonB: Second polygoni n canonical form.
		robotAInitPos: Location of robot A.
		robotBInitPos: Location of robot B.
		nrOfSamples: Samppling density to be used in the search for optimal cut.

	Returns:
		Returns the cut that minimizes the maximum chi metrix. Or [] if no such
		cut exists or original cut is the best.
	
	"""

	# The actual algorithm:
	# 1) Combine the two polygons
	# 2) Find one cut that works better
	# 3) Return that cut or no cut if nothing better was found

	if not polygonA or not polygonB:
		if DEBUG_LEVEL & 0x04:
			print("Pairwise reoptimization is requested on an empty polygon.")
		return []

	if not robotAInitPos or not robotBInitPos:
		if DEBUG_LEVEL & 0x04:
			print("Pairwise reoptimization is requested on an empty init pos.")
		return []

	if not Polygon(*polygonA).is_valid or not Polygon(*polygonB).is_valid:
		if DEBUG_LEVEL & 0x04:
			print("Pariwise reoptimization is requested on invalid polygons.")
		return []

	if not Polygon(*polygonA).is_valid or not Polygon(*polygonB).is_valid:
		if DEBUG_LEVEL & 0x04:
			print("Pariwise reoptimization is requested on invalid polygons.")
		return []

	if not Polygon(*polygonA).is_simple or not Polygon(*polygonB).is_simple:
		if DEBUG_LEVEL & 0x04:
			print("Pariwise reoptimization is requested on nonsimple polygons.")
		return []

	if not Polygon(*polygonA).touches(Polygon(*polygonB)):
		if DEBUG_LEVEL & 0x04:
			print("Pariwise reoptimization is requested on nontouching polys.")
		return []


	# Check that the polygons intersect only at the boundary and one edge
	intersection = Polygon(*polygonA).intersection(Polygon(*polygonB))


	if type(intersection) is not LineString:
		if DEBUG_LEVEL & 0x04:
			print("Pariwise reoptimization is requested but they don't touch\
				   at an edge.")
		return []


	# Combine the two polygons
	polygonUnion = Polygon(*polygonA).union(Polygon(*polygonB))
    
    # Also create a copy of polygonUnion in canonical form
	polygonUnionCanon = poly_shapely_to_canonical(polygonUnion)

	if not polygonUnion.is_valid or not polygonUnion.is_simple:
		if DEBUG_LEVEL & 0x04:
			print("Pariwise reoptimization is requested but the union resulted\
				   in bad polygon.")
		return []

	if type(polygonUnion) is not Polygon:
		if DEBUG_LEVEL & 0x04:
			print("Pariwise reoptimization is requested but union resulted in\
				   non polygon.")
		return []



	# Perform intialization stage for the optimization
	# Initializae the search space as well original cost
	polyExterior = polygonUnion.exterior
	searchDistances = list(linspace(0, polyExterior.length, nrOfSamples))

	searchSpace = []
	for distance in searchDistances:
		solutionCandidate = polyExterior.interpolate(distance)
		searchSpace.append((solutionCandidate.x, solutionCandidate.y))


	# Record the costs at this point
	chiL = compute_chi(polygon = polygonA,
						initPos = robotAInitPos,
						radius = radius,
						linPenalty = linPenalty,
						angPenalty = angPenalty)
	chiR = compute_chi(polygon = polygonB,
						initPos = robotBInitPos,
						radius = radius,
						linPenalty = linPenalty,
						angPenalty = angPenalty)

	initMaxChi = max(chiL, chiR)

	minMaxChiFinal = 10e10
	minCandidate = []

	# This search is over any two pairs of samples points on the exterior
	# It is a very costly search.
	for cutEdge in product(searchSpace, repeat=2):

		if DEBUG_LEVEL & 0x8:
			print("polygonUnionCanon: %s"%polygonUnionCanon)
			print("Cut candidate: %s"%(cutEdge, ))
		
		result = polygon_split(polygonUnionCanon, cutEdge)

		if DEBUG_LEVEL & 0x8:
			if result:
				print("%s Split Line: %s"%('GOOD', cutEdge,))
			else:
				print("%s Split Line: %s"%("BAD ", cutEdge))

		if result:
			# Resolve cell-robot assignments here.
			# This is to avoid the issue of cell assignments that
			# don't make any sense after polygon cut.
			chiA0 = compute_chi(polygon = result[0],
							   	initPos = robotAInitPos,
							   	radius = radius,
							   	linPenalty = linPenalty,
							   	angPenalty = angPenalty)
			chiA1 = compute_chi(polygon = result[1],
							   	initPos = robotAInitPos,
							   	radius = radius,
							   	linPenalty = linPenalty,
							   	angPenalty = angPenalty)
			chiB0 = compute_chi(polygon = result[0],
							   	initPos = robotBInitPos,
							   	radius = radius,
							   	linPenalty = linPenalty,
							   	angPenalty = angPenalty)							   	
			chiB1 = compute_chi(polygon = result[1],
							   	initPos = robotBInitPos,
							   	radius = radius,
							   	linPenalty = linPenalty,
							   	angPenalty = angPenalty)

			maxChiCases = [max(chiA0, chiB1),
					  	   max(chiA1, chiB0)]

			minMaxChi = min(maxChiCases)
			if minMaxChi <= minMaxChiFinal:
				minCandidate = cutEdge
				minMaxChiFinal = minMaxChi

	if DEBUG_LEVEL & 0x8:
		print("Computed min max chi as: %4.2f"%minMaxChiFinal)
		print("Cut: %s"%(minCandidate, ))

	if initMaxChi < minMaxChiFinal:
		if DEBUG_LEVEL & 0x8:
			print("No cut results in minimum altitude")
	
		return []

	newPolygons = polygon_split(polygonUnionCanon, minCandidate)
	return newPolygons
Beispiel #13
0
def compute_min_alt_cut(polygon=[], vrtx=[]):
    """Computes minimum altitude cut in a polygon from a refelx vertex.

	For a given polygon and a vertex, the function computes a cut that results
	in a pair of polygons and a minimum overall altitude.

	Several implementations of this function:
		1) Uses cones of bisection and visibility polygons to narrow down the
			search space of cuts.
		2) Uses all edges of the polygon as a search space for cuts.

	Assumptions:
		vrtx is taken from the list of verticies in the polygon chains.
			Otherwise, we may not find on the chain properly.

	Here, we will implement the second approach for improved robustness.
	Could result in excessive computation time.

	Args:
		polygon: Polygon in the form of [ [], [[],...] ] where polygon[0] is
			the exterior boundary of the polygon and polygon[1] is the list
			of boundaries of holes.
			Exterior boundary must be in ccw order. Last point != first point.
			Same for hole boundaries.
		vrtx: A vertex from which the cut is made. Can be reflex or not.

	Returns:
		minimum cut pair: List of following format:
			[TODO:] Not sure yet.
	"""

    if not polygon:
        if DEBUG_LEVEL & 0x04:
            print("Min alt cut is requested on an empty polygon.")
        return []

    if len(polygon[0]) < 3:
        if DEBUG_LEVEL & 0x04:
            print("Min alt cut is requested on a line.")
        return []

    if not vrtx:
        if DEBUG_LEVEL & 0x04:
            print("Min alt cut is requested with empty vertex.")
        return []

    if not Polygon(*polygon).is_simple:
        if DEBUG_LEVEL & 0x04:
            print("Min cut is requested on an non simple polygon.")
        return []

    if not Polygon(*polygon).is_valid:
        if DEBUG_LEVEL & 0x04:
            print("Min cut is requested on an non valid polygon.")
        return []

    # Generate a list of directions for the polygon
    directions = get_directions_set(polygon)

    # Find the minimum altitude for original polygon, a.k.a no cut
    minDirection = min(directions, key=lambda theta: get_altitude(P, theta))
    minAltitudeOriginal = get_altitude(polygon, minDirection)

    # Initialize and compute a list containing candidates for the optimal cut.
    # Due to the nature of floats, this list will contain a lot of duplicates.
    # [TODO]: Get rid of duplicates
    cutCandidates = []

    ext, holes = P

    n = len(ext)
    for i in range(n):
        edge = [ext[i], ext[(i + 1) % n]]

        cutCandidates.append(ext[i])

        # Iterate over all directions and find transition points
        for theta in directions:
            transPt = compute_transition_point(edge, theta, vrtx)
            if transPt:
                cutCandidates.append(transPt)

        if DEBUG_LEVEL & 0x8:
            print("Cut end points candidates so far: %s" % cutCandidates)

    # For any pair of directions, cut and evaluate
    minCost = 10e10
    minCandidate = []

    for dirPair in product(directions, repeat=2):
        for cutCand in cutCandidates:

            splitLine = ([vrtx, cutCand])
            result = polygon_split(P, splitLine)

            if DEBUG_LEVEL % 0x8:
                if result:
                    print("%s Split Line: %s" % (
                        'GOOD',
                        splitLine,
                    ))
                else:
                    print("%s Split Line: %s" % ("BAD ", splitLine))

            if result:
                pol1, pol2 = result

                alt1 = get_altitude(pol1, dirPair[0])
                alt2 = get_altitude(pol2, dirPair[1])

                totalAlt = alt1 + alt2

                if totalAlt <= minCost:
                    minCandidate = (cutCand, dirPair)
                    minCost = totalAlt

    if DEBUG_LEVEL & 0x8:
        print("Computed minimum altitude as: %4.2f" % minCost)
        print("Cut: %s" % [vrtx, minCandidate[0]])
        print("Direction 1: %4.2f Direction 2: %4.2f" %
              (minCandidate[1][0], minCandidate[1][1]))

    if minAltitudeOriginal < minCost:
        if DEBUG_LEVEL & 0x8:
            print("No cut results in minimum altitude")

        return []

    return minCandidate