コード例 #1
0
    private bool TickBucketFloodfillV3(
        FloodfillPointBucket bucket,
        HashSet <Vector2Int> visited,
        HashSet <FloodfillPointBucket> buckets,
        BucketGraph graph,
        List <FloodfillDebugInfo> debugInfos)
    {
        if (bucket.nextQueue.Count == 0)
        {
            UnityEngine.Debug.Log("break");
            return(false);
        }


        Vector2Int        pixel           = bucket.nextQueue.Dequeue();
        List <Vector2Int> mergeCandidates = new List <Vector2Int>();

        FloodfillStepNotBlack(
            pixel.x,
            pixel.y,
            bucket.ogPos.x,
            bucket.ogPos.y,
            l0,
            l1,
            visited,
            bucket.visitedPoints,
            bucket.nextQueue,
            ref mergeCandidates);

        foreach (Vector2Int mergeCandidate in mergeCandidates)
        {
            foreach (FloodfillPointBucket retrieveBucket in buckets)
            {
                if (retrieveBucket.visitedPoints.Contains(mergeCandidate))
                {
                    graph.AddEdge(bucket, retrieveBucket);
                    graph.AddEdge(retrieveBucket, bucket);
                }
            }
        }
        return(true);
    }
コード例 #2
0
    /*   Routine to find top left point
     *
     * Pipeline:
     *  - Floodfill image from top left with black to find borders
     *  - Find candidate points
     *  - Floodfill from candidate points
     *  - Select point where floodfill lasts the longest.
     *
     * -> For now shelved because not performant enough
     * -> Should be optimizable with bucket based approach
     * */
    internal void FindTopLeftPointByFloodfill()
    {
        HashSet <Vector2Int> candidates = new HashSet <Vector2Int>();

        //Step 1
        CVFloodfill(7);

        /*  Step 2
         *  Get all candidate pixels where layout is:
         *  b = black pixel
         *  C = candidate
         *  x = non-black pixel
         *
         *  b b b b
         *  b b c x
         *  b b x x
         *
         * */
        for (int y = 0; y < l1; y++)
        {
            for (int x = 0; x < l0; x++)
            {
                //if (x > 1000 || y > 1000)
                //    continue;
                int intensity = GetIntensity(x, y);
                //if pixel is exactly black (was set by first floodfill)
                if (intensity == INTENSITY_BLACK)
                {
                    TryAddCandidateForTopLeftPoint(candidates, x, y);
                }
            }
        }
        UnityEngine.Debug.Log("Found " + candidates.Count + " candidates");
        //Dictionary<Vector2Int, FloodfillPointBucket>pointToBucket = new Dictionary<Vector2Int, FloodfillPointBucket>();
        //foreach (Vector2Int candidate in candidates)
        //{
        //    pointToBucket.Add(candidate, new FloodfillPointBucket(candidate));
        //}

        //Step 3 - Find top left pixel of map from candidates

        /* Idea:    Start floodfill from each candidate for non black pixels (only in bottom right direction)
         *          Origin pixel which had the largest number of pixels floodfilled must be top left
         *
         * Problem: Still ~9000 candidates in test map (because of jagged outlines).
         *          Finishing 9000 floodfills many of which are traversing a big part of the map takes too long         *
         * Idea:    When two floodfills meet -> merge buckets to guarantee each pixel only gets processed once (except for merge pixels)
         *
         * Problem: Merging needs to iterate all pixels anyway.         *
         * Idea:    Make buckets outer loop!! This way all buckets must be closed by the point of a merge
         *
         *
         * */
        int safety = 0;

        //old version -> buckets are inner loop
        //while (candidates.Count > 1)
        //{
        //    HashSet<Vector2Int> toRemove = new HashSet<Vector2Int>();
        //    foreach (Vector2Int candidate in candidates)
        //    {
        //        safety++;
        //        if (pointToBucket.ContainsKey(candidate))
        //        {
        //            if (!TickBucketFloodfill(toRemove, pointToBucket[candidate], pointToBucket))
        //                ;
        //        }
        //        //problem pointToBucket got removed but candidate didn't get removed yet.

        //    }
        //    UnityEngine.Debug.Log(candidates.Count);

        //    foreach (Vector2Int remove in toRemove)
        //        candidates.Remove(remove);
        //    //weird! still 3000 buckets after 15m pixels have been iterated... should have converged since picture is only ~15m pixels in total!
        //    //-> because pixels are associated with original bucket even after merge happened
        //    if (safety > 15000000)
        //    {
        //        UnityEngine.Debug.Log(candidates.Count);
        //        break;
        //    }
        //}
        //HashSet<Vector2Int> visited = new HashSet<Vector2Int>();
        ////new version -> buckets are outer loop
        //foreach (Vector2Int vec in candidates)
        //{
        //    //each candidate gets traversed but if a pixel is already occupied for this candidate the nextQueue of that bucket will be 0
        //    /*
        //     * The only case where buckets need to be merged is when one bucket is farther left or to the top than another bucket since
        //     * otherwise the origin pixel of the bucket would be inside the area traversed by the first bucket.
        //     *
        //     * Problem with v2 -> migrating queue to bucket is costly. Migrating closed list even more so.
        //     *
        //     * */
        //    while (TickBucketFloodfillV2(vec, pointToBucket, visited))
        //    {
        //        safety++;
        //        if (safety > 20000000)
        //            break;
        //    }
        //    if (safety > 20000000)
        //        break;
        //}


        //new solution: only create bucket if we have to. And create graph of buckets.
        //In the end traverse graph to find top left pixel
        //still too slow! Nvm this stuff. let the user do it.
        HashSet <Vector2Int>           visited    = new HashSet <Vector2Int>();
        BucketGraph                    graph      = new BucketGraph();
        HashSet <FloodfillPointBucket> buckets    = new HashSet <FloodfillPointBucket>();
        List <FloodfillDebugInfo>      debugInfos = new List <FloodfillDebugInfo>();
        int smax = 10000000;

        foreach (Vector2Int v2i in candidates)
        {
            if (visited.Contains(v2i))
            {
                continue;
            }

            FloodfillPointBucket currentBucket = new FloodfillPointBucket(v2i);
            buckets.Add(currentBucket);
            while (TickBucketFloodfillV3(currentBucket, visited, buckets, graph, debugInfos))
            {
                safety++;
                if (safety > smax)
                {
                    break;
                }
            }

            if (safety >= smax)
            {
                UnityEngine.Debug.Log("too many steps!");
                break;
            }
        }
        UnityEngine.Debug.Log("number of edges: " + graph.edges.Count);
        UnityEngine.Debug.Log("number of visited pixels: " + visited.Count);
        foreach (FloodfillDebugInfo debugInfo in debugInfos)
        {
            UnityEngine.Debug.Log(debugInfo.ToString());
        }
    }