class LatitudeLongitudeTranslator {

    public static final double MARGIN_RATIO = 0.04;

    private double minimumLatitude = Double.MAX_VALUE;
    private double maximumLatitude = -Double.MAX_VALUE;
    private double minimumLongitude = Double.MAX_VALUE;
    private double maximumLongitude = -Double.MAX_VALUE;
    private double latitudeLength = 0.0;
    private double longitudeLength = 0.0;

    private double innerWidth = 0.0;
    private double innerHeight = 0.0;
    private double innerWidthMargin = 0.0;
    private double innerHeightMargin = 0.0;
    private int imageWidth = -1;
    private int imageHeight = -1;

    public void addCoordinates(double latitude, double longitude) {
        if (latitude < minimumLatitude) {
            minimumLatitude = latitude;
        }
        if (latitude > maximumLatitude) {
            maximumLatitude = latitude;
        }
        if (longitude < minimumLongitude) {
            minimumLongitude = longitude;
        }
        if (longitude > maximumLongitude) {
            maximumLongitude = longitude;
        }
    }

    public void prepareFor(double width, double height) {
        latitudeLength = maximumLatitude - minimumLatitude;
        longitudeLength = maximumLongitude - minimumLongitude;
        innerWidthMargin = width * MARGIN_RATIO;
        innerHeightMargin = height * MARGIN_RATIO;
        innerWidth = width - (2.0 * innerWidthMargin);
        innerHeight = height - (2.0 * innerHeightMargin);
        // Keep ratio visually correct
        if (innerWidth > innerHeight * longitudeLength / latitudeLength) {
            innerWidth = innerHeight * longitudeLength / latitudeLength;
        } else {
            innerHeight = innerWidth * latitudeLength / longitudeLength;
        }
        imageWidth = (int) Math.floor((2.0 * innerWidthMargin) + innerWidth);
        imageHeight = (int) Math.floor((2.0 * innerHeightMargin) + innerHeight);
    }

    public int translateLongitudeToX(double longitude) {
        return (int) Math.floor(((longitude - minimumLongitude) * innerWidth / longitudeLength) + innerWidthMargin);
    }

    public int translateLatitudeToY(double latitude) {
        return (int) Math.floor(((maximumLatitude - latitude) * innerHeight / latitudeLength) + innerHeightMargin);
    }

    public double translateXToLongitude(int x) {<FILL_FUNCTION_BODY>}

    public double translateYToLatitude(double y) {
        return maximumLatitude - ((y - innerHeightMargin) * latitudeLength / innerHeight);
    }

    public int getImageWidth() {
        return imageWidth;
    }

    public int getImageHeight() {
        return imageHeight;
    }

    public void drawRoute(Graphics2D g, double lon1, double lat1, double lon2, double lat2, boolean straight, boolean dashed) {
        int x1 = translateLongitudeToX(lon1);
        int y1 = translateLatitudeToY(lat1);
        int x2 = translateLongitudeToX(lon2);
        int y2 = translateLatitudeToY(lat2);
        if (dashed) {
            g.setStroke(TangoColorFactory.FAT_DASHED_STROKE);
        }
        if (straight) {
            g.drawLine(x1, y1, x2, y2);
        } else {
            double xDistPart = (x2 - x1) / 3.0;
            double yDistPart = (y2 - y1) / 3.0;
            double ctrlx1 = x1 + xDistPart + yDistPart;
            double ctrly1 = y1 - xDistPart + yDistPart;
            double ctrlx2 = x2 - xDistPart - yDistPart;
            double ctrly2 = y2 + xDistPart - yDistPart;
            g.draw(new CubicCurve2D.Double(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
        }
        if (dashed) {
            g.setStroke(TangoColorFactory.NORMAL_STROKE);
        }
    }

}

        return minimumLongitude + ((x - innerWidthMargin) * longitudeLength / innerWidth);
    
<no_super_class>