Process the contour and returns true if a polyline could be found.
@param contour Contour. Must be a ordered in CW or CCW
@return true for success or false if one could not be fit
176909
public boolean process(List<Point2D_I32> contour ) {
		// Reset internal book keeping variables
		reset();

		if( loops ) {
			// Reject pathological case
			if (contour.size() < 3)
				return false;

			if (!findInitialTriangle(contour))
				return false;
		} else {
			// Reject pathological case
			if( contour.size() < 2 )
				return false;

			// two end points are the seeds. Plus they can't change
			addCorner(0);
			addCorner(contour.size()-1);
			initializeScore(contour,false);
		}
		savePolyline();

		sequentialSideFit(contour,loops);

		if( fatalError )
			return false;

		int MIN_SIZE = loops ? 3 : 2;

		double bestScore = Double.MAX_VALUE;
		int bestSize = -1;
		for (int i = 0; i < Math.min(maxSides-(MIN_SIZE-1),polylines.size); i++) {
			if( polylines.get(i).score < bestScore ) {
				bestPolyline = polylines.get(i);
				bestScore = bestPolyline.score;
				bestSize = i + MIN_SIZE;
			}
		}

		// There was no good match within the min/max size requirement
		if( bestSize < minSides) {
			return false;
		}

		// make sure all the sides are within error tolerance
		for (int i = 0,j=bestSize-1; i < bestSize; j=i,i++) {
			Point2D_I32 a = contour.get(bestPolyline.splits.get(i));
			Point2D_I32 b = contour.get(bestPolyline.splits.get(j));

			double length = a.distance(b);
			double thresholdSideError = this.maxSideError.compute(length);
			if( bestPolyline.sideErrors.get(i) >= thresholdSideError*thresholdSideError) {
				bestPolyline = null;
				return false;
			}
		}

		return true;
	}
1131215
public void process(List<Point2D_I32> contour , GrowQueue_I32 vertexes , Polygon2D_F64 output ) {

		int numDecreasing = 0;
		for (int i = vertexes.size-1,j=0; j < vertexes.size; i=j,j++) {
			if( vertexes.get(i) > vertexes.get(j ) )
				numDecreasing++;
		}

		boolean decreasing = numDecreasing > 1;

		output.vertexes.resize(vertexes.size);
		lines.resize(vertexes.size);

		// fit lines to each size
		for (int i = vertexes.size-1,j=0; j < vertexes.size; i=j,j++) {
			int idx0 = vertexes.get(i);
			int idx1 = vertexes.get(j);

			if( decreasing ) {
				int tmp = idx0;idx0 = idx1;idx1=tmp;
			}

			if( idx0 > idx1 ) {
				// handle special case where it wraps around
				work.clear();
				for (int k = idx0; k < contour.size(); k++) {
					work.add( contour.get(k));
				}
				for (int k = 0; k < idx1; k++) {
					work.add( contour.get(k));
				}
				FitLine_I32.polar(work,0,work.size(),polar);
			} else {
				FitLine_I32.polar(contour,idx0,idx1-idx0,polar);
			}

			UtilLine2D_F64.convert(polar,lines.get(i));
		}

		// find the corners by intersecting the side
		for (int i = vertexes.size-1,j=0; j < vertexes.size; i=j,j++) {
			LineGeneral2D_F64 lineA = lines.get(i);
			LineGeneral2D_F64 lineB = lines.get(j);

			Intersection2D_F64.intersection(lineA,lineB,output.get(j));
		}
	}
348342
static boolean polylineRelateMultiPoint_(Polyline polyline_a,
			MultiPoint multipoint_b, double tolerance, String scl,
			ProgressTracker progress_tracker) {
		RelationalOperationsMatrix relOps = new RelationalOperationsMatrix();
		relOps.resetMatrix_();
		relOps.setPredicates_(scl);
		relOps.setLinePointPredicates_();

		Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D();
		polyline_a.queryEnvelope2D(env_a);
		multipoint_b.queryEnvelope2D(env_b);

		boolean bRelationKnown = false;
		boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_(
				env_a, env_b, tolerance, progress_tracker);

		if (b_disjoint) {
			relOps.linePointDisjointPredicates_(polyline_a);
			bRelationKnown = true;
		}

		if (!bRelationKnown) {
			// Quick rasterize test to see whether the the geometries are
			// disjoint, or if one is contained in the other.
			int relation = RelationalOperations
					.tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b,
							tolerance, false);

			if (relation == RelationalOperations.Relation.disjoint) {
				relOps.linePointDisjointPredicates_(polyline_a);
				bRelationKnown = true;
			}
		}

		if (!bRelationKnown) {
			EditShape edit_shape = new EditShape();
			int geom_a = edit_shape.addGeometry(polyline_a);
			int geom_b = edit_shape.addGeometry(multipoint_b);
			relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance,
					progress_tracker);
			relOps.m_cluster_index_a = relOps.m_topo_graph
					.createUserIndexForClusters();
			markClusterEndPoints_(geom_a, relOps.m_topo_graph,
					relOps.m_cluster_index_a);
			relOps.computeMatrixTopoGraphClusters_(geom_a, geom_b);
			relOps.m_topo_graph
					.deleteUserIndexForClusters(relOps.m_cluster_index_a);
			relOps.m_topo_graph.removeShape();
		}

		boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl);
		return bRelation;
	}
31934
def removeContour(self, contour):
        
        if isinstance(contour, int):
            index = contour
        else:
            index = self._getContourIndex(contour)
        index = normalizers.normalizeIndex(index)
        if index >= len(self):
            raise ValueError("No contour located at index %d." % index)
        self._removeContour(index)
32090
public boolean contains(Coordinate coord) {
		if (coord.getX() < this.getX()) {
			return false;
		}
		if (coord.getY() < this.getY()) {
			return false;
		}
		if (coord.getX() > this.getEndPoint().getX()) {
			return false;
		}
		if (coord.getY() > this.getEndPoint().getY()) {
			return false;
		}
		return true;
	}
617254
private static boolean polylineContainsPolyline_(Polyline polyline_a,
			Polyline polyline_b, double tolerance,
			ProgressTracker progress_tracker) {
		Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D();
		polyline_a.queryEnvelope2D(env_a);
		polyline_b.queryEnvelope2D(env_b);

		// Quick envelope rejection test for false equality.
		if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance))
			return false;

		// Quick rasterize test to see whether the the geometries are disjoint.
		if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance,
				false) == Relation.disjoint)
			return false;

		return linearPathWithinLinearPath_(polyline_b, polyline_a, tolerance, false);
	}
1233394
public void findEdgesInShape(final GHIntHashSet edgeIds, final Shape shape, EdgeFilter filter) {
        GHPoint center = shape.getCenter();
        QueryResult qr = locationIndex.findClosest(center.getLat(), center.getLon(), filter);
        // TODO: if there is no street close to the center it'll fail although there are roads covered. Maybe we should check edge points or some random points in the Shape instead?
        if (!qr.isValid())
            throw new IllegalArgumentException("Shape " + shape + " does not cover graph");

        if (shape.contains(qr.getSnappedPoint().lat, qr.getSnappedPoint().lon))
            edgeIds.add(qr.getClosestEdge().getEdge());

        final boolean isPolygon = shape instanceof Polygon;

        BreadthFirstSearch bfs = new BreadthFirstSearch() {
            final NodeAccess na = graph.getNodeAccess();
            final Shape localShape = shape;

            @Override
            protected boolean goFurther(int nodeId) {
                if (isPolygon) return isInsideBBox(nodeId);

                return localShape.contains(na.getLatitude(nodeId), na.getLongitude(nodeId));
            }

            @Override
            protected boolean checkAdjacent(EdgeIteratorState edge) {
                int adjNodeId = edge.getAdjNode();

                if (localShape.contains(na.getLatitude(adjNodeId), na.getLongitude(adjNodeId))) {
                    edgeIds.add(edge.getEdge());
                    return true;
                }
                return isPolygon && isInsideBBox(adjNodeId);
            }

            private boolean isInsideBBox(int nodeId) {
                BBox bbox = localShape.getBounds();
                double lat = na.getLatitude(nodeId);
                double lon = na.getLongitude(nodeId);
                return lat <= bbox.maxLat && lat >= bbox.minLat && lon <= bbox.maxLon && lon >= bbox.minLon;
            }
        };
        bfs.start(graph.createEdgeExplorer(filter), qr.getClosestNode());
    }
759911
static int findCornerSeed(List<Point2D_I32> contour ) {
		Point2D_I32 a = contour.get(0);

		int best = -1;
		double bestDistance = -Double.MAX_VALUE;

		for (int i = 1; i < contour.size(); i++) {
			Point2D_I32 b = contour.get(i);

			double d = distanceSq(a,b);
			if( d > bestDistance ) {
				bestDistance = d;
				best = i;
			}
		}

		return best;
	}
1374321
private static boolean polylineRelateMultiPoint_(Polyline polyline_a,
			MultiPoint multipoint_b, double tolerance, int relation,
			ProgressTracker progress_tracker) {
		switch (relation) {
		case Relation.disjoint:
			return polylineDisjointMultiPoint_(polyline_a, multipoint_b,
					tolerance, progress_tracker);

		case Relation.contains:
			return polylineContainsMultiPoint_(polyline_a, multipoint_b,
					tolerance, progress_tracker);

		case Relation.touches:
			return polylineTouchesMultiPoint_(polyline_a, multipoint_b,
					tolerance, progress_tracker);

		case Relation.crosses:
			return polylineCrossesMultiPoint_(polyline_a, multipoint_b,
					tolerance, progress_tracker);

		default:
			break; // warning fix
		}

		return false;
	}
1374963
private static boolean polylineOverlapsPolyline_(Polyline polyline_a,
			Polyline polyline_b, double tolerance,
			ProgressTracker progress_tracker) {
		// Quick rasterize test to see whether the the geometries are disjoint.
		if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance,
				false) == Relation.disjoint)
			return false;

		return linearPathOverlapsLinearPath_(polyline_a, polyline_b, tolerance);
	}
371755
public boolean process( T image ) {
		configureContourDetector(image);
		binary.reshape(image.width,image.height);

		inputToBinary.process(image,binary);
		detectorSquare.process(image, binary);
		detectorSquare.refineAll();

		detectorSquare.getPolygons(found,null);

		clusters = s2c.process(found);
		c2g.process(clusters);
		List<SquareGrid> grids = c2g.getGrids();

		SquareGrid match = null;
		double matchSize = 0;
		for( SquareGrid g : grids ) {
			if (g.columns != numCols || g.rows != numRows) {
				if( g.columns == numRows && g.rows == numCols ) {
					tools.transpose(g);
				} else {
					continue;
				}
			}

			double size = tools.computeSize(g);
			if( size > matchSize ) {
				matchSize = size;
				match = g;
			}
		}

		if( match != null ) {
			if( tools.checkFlip(match) ) {
				tools.flipRows(match);
			}
			tools.putIntoCanonical(match);
			if( !tools.orderSquareCorners(match) )
				return false;

			extractCalibrationPoints(match);
			return true;
		}
		return false;
	}
960829
private void squaresToPositionList() {
		this.positionPatterns.reset();
		List<DetectPolygonFromContour.Info> infoList = squareDetector.getPolygonInfo();
		for (int i = 0; i < infoList.size(); i++) {
			DetectPolygonFromContour.Info info = infoList.get(i);

			// The test below has been commented out because the new external only contour
			// detector discards all information related to internal contours
			// squares with no internal contour cannot possibly be a finder pattern
//			if( !info.hasInternal() )
//				continue;

			// See if the appearance matches a finder pattern
			double grayThreshold = (info.edgeInside+info.edgeOutside)/2;
			if( !checkPositionPatternAppearance(info.polygon,(float)grayThreshold))
				continue;

			// refine the edge estimate
			squareDetector.refine(info);

			PositionPatternNode pp = this.positionPatterns.grow();
			pp.reset();
			pp.square = info.polygon;
			pp.grayThreshold = grayThreshold;

			graph.computeNodeInfo(pp);
		}
	}
1150741
private static int[] findLeftMostVertex(Contour contour) {
        int minx = contour.verts[0];
        int minz = contour.verts[2];
        int leftmost = 0;
        for (int i = 1; i < contour.nverts; i++) {
            int x = contour.verts[i * 4 + 0];
            int z = contour.verts[i * 4 + 2];
            if (x < minx || (x == minx && z < minz)) {
                minx = x;
                minz = z;
                leftmost = i;
            }
        }
        return new int[] { minx, minz, leftmost };
    }
1274805
private static boolean polylineWithinEnvelope_(Polyline polyline_a,
			Envelope envelope_b, double tolerance,
			ProgressTracker progress_tracker) {
		Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D();
		polyline_a.queryEnvelope2D(env_a);
		envelope_b.queryEnvelope2D(env_b);

		if (!envelopeInfContainsEnvelope_(env_b, env_a, tolerance))
			return false;

		if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance)
			return false;

		if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance)
			return envelopeInfContainsEnvelope_(env_b, env_a, tolerance);

		SegmentIterator seg_iter_a = polyline_a.querySegmentIterator();
		Envelope2D env_b_deflated = new Envelope2D();
		env_b_deflated.setCoords(env_b);
		env_b_deflated.inflate(-tolerance, -tolerance);

		boolean b_interior = false;
		Envelope2D env_segment_a = new Envelope2D();
		Envelope2D env_inter = new Envelope2D();

		while (seg_iter_a.nextPath()) {
			while (seg_iter_a.hasNextSegment()) {
				Segment segment_a = seg_iter_a.nextSegment();
				segment_a.queryEnvelope2D(env_segment_a);

				if (env_b_deflated.containsExclusive(env_segment_a)) {
					b_interior = true;
					continue;
				}

				env_inter.setCoords(env_b_deflated);
				env_inter.intersect(env_segment_a);

				if (!env_inter.isEmpty()
						&& (env_inter.getHeight() > tolerance || env_inter
								.getWidth() > tolerance))
					b_interior = true;
			}
		}

		return b_interior;
	}
243145
private static boolean polygonCrossesPolyline_(Polygon polygon_a,
			Polyline polyline_b, double tolerance,
			ProgressTracker progress_tracker) {
		// Quick rasterize test to see whether the the geometries are disjoint,
		// or if one is contained in the other.
		int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b,
				tolerance, false);

		if (relation == Relation.disjoint || relation == Relation.contains)
			return false;

		return polygonCrossesPolylineImpl_(polygon_a, polyline_b, tolerance,
				null);
	}
1289874
private static boolean polylineOverlapsEnvelope_(Polyline polyline_a,
			Envelope envelope_b, double tolerance,
			ProgressTracker progress_tracker) {
		Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D();
		polyline_a.queryEnvelope2D(env_a);
		envelope_b.queryEnvelope2D(env_b);

		if (envelopeInfContainsEnvelope_(env_a, env_b, tolerance)
				|| envelopeInfContainsEnvelope_(env_b, env_a, tolerance))
			return false;

		if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance))
			return false;

		if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance)
			return false; // lines cannot overlap areas

		if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance)
			return false; // lines cannot overlap points

		// Treat as polyline
		Polyline polyline_b = new Polyline();
		Point p = new Point();
		envelope_b.queryCornerByVal(0, p);
		polyline_b.startPath(p);
		envelope_b.queryCornerByVal(2, p);
		polyline_b.lineTo(p);
		return linearPathOverlapsLinearPath_(polyline_a, polyline_b, tolerance);
	}
730996
public static void fitCannyBinary( GrayF32 input ) {

		BufferedImage displayImage = new BufferedImage(input.width,input.height,BufferedImage.TYPE_INT_RGB);
		GrayU8 binary = new GrayU8(input.width,input.height);

		// Finds edges inside the image
		CannyEdge<GrayF32,GrayF32> canny =
				FactoryEdgeDetectors.canny(2, false, true, GrayF32.class, GrayF32.class);

		canny.process(input,0.1f,0.3f,binary);

		// Only external contours are relevant
		List<Contour> contours = BinaryImageOps.contourExternal(binary, ConnectRule.EIGHT);

		Graphics2D g2 = displayImage.createGraphics();
		g2.setStroke(new BasicStroke(2));

		// used to select colors for each line
		Random rand = new Random(234);

		for( Contour c : contours ) {
			List<PointIndex_I32> vertexes = ShapeFittingOps.fitPolygon(c.external,true, minSide,cornerPenalty);

			g2.setColor(new Color(rand.nextInt()));
			VisualizeShapes.drawPolygon(vertexes,true,g2);
		}

		gui.addImage(displayImage, "Canny Contour");
	}