Package org.openstreetmap.josm.plugins.continuosDownload

Source Code of org.openstreetmap.josm.plugins.continuosDownload.BoxStrategy$Partition

package org.openstreetmap.josm.plugins.continuosDownload;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.PriorityQueue;

import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.coor.LatLon;

public class BoxStrategy extends DownloadStrategy {

    @Override
    public Collection<Bounds> getBoxes(Bounds bbox, Collection<Bounds> present, int maxBoxes) {
        Collection<Box> existing = Box.merge(fromBounds(present));
        Collection<Box> bits = Box.merge(fromBounds(bbox).subtract_all(existing));
        Collection<Box> toFetch = optimalPart(maxBoxes, bits);
        return toBounds(Box.merge(toFetch));
    }

    /*
     * find the optimal partition - the one which requests the smallest amount
     * of extra space - given the set p of partitions
     */
    public static Collection<Box> optimalPart(int maxParts, Collection<Box> set) {
        /*
         * BUG: This code have no safeguards against timing out or running out
         * of memory. It did not happen during testing, but that is no guaranty
         * it will not happen.
         */
        ArrayList<Box> list = new ArrayList<Box>(set);
        // Sort the set from largest to smalest, there is a better chance of
        // getting good pactitions if you start with the biggest boxes because
        // the smaller boxes have little impact on the overall score.
        Collections.sort(list, new Comparator<Box>() {

            @Override
            public int compare(Box ba, Box bb) {
                return Double.compare(bb.size(), ba.size());
            }
        });

        PriorityQueue<Partition> q = new PriorityQueue<Partition>();
        q.add(new Partition());

        // Find the best partition this far and add another box to it until the
        // best partition is a partition of the complete set.
        while (!q.isEmpty()) {
            Partition a = q.remove();
            if (a.size == list.size()) {
                return a.box;
            }
           
            Box next = list.get(a.size);
           
            // Add a new box to every part in the partition and put those in the
            // queue
            for (int i = 0; i < maxParts && i <= a.box.size(); i++) {
                q.add(a.add(next, i));
            }
        }

        return null;
    }

    public static class Partition implements Comparable<Partition> {
        ArrayList<Box> box; // The merged boxes
        int size; // How many boxes have we merged this far
        double enclosingArea; // The area of the boxes we have added

        private Partition(ArrayList<Box> n, int i, double area) {
            box = n;
            size = i;
            enclosingArea = area;

        }

        public Partition() {
            this(new ArrayList<Box>(), 0, 0);
        }

        // Create a new partition with an extra box in the ith place
        public Partition add(Box next, int i) {
            ArrayList<Box> n = (ArrayList<Box>) box.clone();
            if (n.size() <= i) {
                n.add(next);
            } else {
                n.set(i, n.get(i).union(next));
            }
            return new Partition(n, size + 1, enclosingArea + next.size());
        }

        @Override
        public int compareTo(Partition other) {
            double a = area() - enclosingArea;
            double b = other.area() - other.enclosingArea;

            // Get the partition that downloads the least amount of extra area
            if (a > b)
                return 1;
            if (a < b)
                return -1;

            // Try to get to the end faster by getting the partition over the
            // most boxes
            if (size > other.size)
                return -1;
            if (size < other.size)
                return 1;

            // Prefer a partition that downloads fewest boxes
            if (box.size() > other.box.size())
                return 1;
            if (box.size() < other.box.size())
                return -1;
            return 0;
        }

        double area() {
            double r = 0;

            for (Box b : box) {
                r += b.size();
            }

            return r;
        }
    }

    /*
     * The next part is conversion between double bboxes and fpi bboxes. Sending
     * doubles to the server and back through multiple conversions and parsers
     * is less accurate. This makes it hard to detect if two areas are adjacent.
     * Converting to fpi makes computation faster and more accurate.
     */

    /*
     * Converts a double to a fixed precision integer with 7 digits
     */
    private static long toFpi(double n) {
        return (long) (n * 10000000);
    }

    /*
     * Converts a fixed precision integer to a double
     */
    private static double fromFpi(long n) {
        return (n / 10000000.0);
    }

    /*
     * Converts from bounds used in josm to boxes used here
     */
    public static Box fromBounds(Bounds bbox) {
        LatLon min = bbox.getMin(), max = bbox.getMax();
        return new Box(toFpi(min.getX()), toFpi(min.getY()), toFpi(max.getX()),
                toFpi(max.getY()));
    }

    /*
     * Converts from boxes to bounds
     */
    public static Bounds toBounds(Box bbox) {
        return new Bounds(fromFpi(bbox.y.min), fromFpi(bbox.x.min),
                fromFpi(bbox.y.max), fromFpi(bbox.x.max));
    }

    /*
     * Converts a set of boxes from bounds used in josm to boxes used here
     */
    public static Collection<Box> fromBounds(Collection<Bounds> bbox) {
        ArrayList<Box> r = new ArrayList<Box>(bbox.size());
        for (Bounds box : bbox) {
            r.add(fromBounds(box));
        }
        return r;
    }

    /*
     * Converts a set of boxes from boxes to bounds
     */
    public static Collection<Bounds> toBounds(Collection<Box> bbox) {
        ArrayList<Bounds> r = new ArrayList<Bounds>(bbox.size());
        for (Box box : bbox) {
            r.add(toBounds(box));
        }
        return r;
    }
}
TOP

Related Classes of org.openstreetmap.josm.plugins.continuosDownload.BoxStrategy$Partition

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.