Package com.bbn.openmap.layer.terrain

Source Code of com.bbn.openmap.layer.terrain.ProfileGenerator

// **********************************************************************
//
// <copyright>
//
//  BBN Technologies
//  10 Moulton Street
//  Cambridge, MA 02138
//  (617) 873-8000
//
//  Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/terrain/ProfileGenerator.java,v $
// $RCSfile: ProfileGenerator.java,v $
// $Revision: 1.6.2.3 $
// $Date: 2006/02/27 16:13:50 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.layer.terrain;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.image.AcmeGifFormatter;
import com.bbn.openmap.dataAccess.dted.DTEDFrameCache;
import com.bbn.openmap.layer.util.stateMachine.*;
import com.bbn.openmap.omGraphics.*;
import com.bbn.openmap.proj.*;
import com.bbn.openmap.util.Debug;

/**
* This tool lets the user draw a line on the map, and then presents
* the profile of the path in a GIF picture. The line can be drawn in
* a series if clicks, or the mouse button can be held down as the
* mouse is dragged around. The lines are drawn as great circle lines,
* which represent the straight geographical line between clicks.
*
* <P>
* The profile tool uses the ProfileStateMachine, and the Profile
* States, to keep track of the proper actions and reactions of user
* input.
*/
public class ProfileGenerator implements TerrainTool {
    /** The color of the line that is drawn on the screen. */
    Color toolColor = new Color(255, 0, 0);
    /** The state machine for user gestures. */
    protected ProfileStateMachine stateMachine;
    /** The layer that the tool is serving. */
    protected TerrainLayer layer;
    /** The list of graphics to draw. Contains the drawn line. */
    protected OMGraphicList graphics = new OMGraphicList();
    /**
     * Array of LatLonPoints. The points are the clicked points, and
     * the points in between, on a great circle. Have to figure these
     * points out, and not rely only on the poly line points, because
     * we need to get the elevations for all the points for the
     * profile.
     */
    public Vector coords;
    /**
     * These are the raw x-y points of the gestures, for the great
     * circle line points, too. These are used to construct the
     * profile image. An array of java.awt.Points.
     */
    public Vector xypoints;
    /**
     * The line drawn on the screen representing the profile line
     * path.
     */
    public OMPoly profileLine;
    /**
     * General gesture tracking, Used to track the last place of
     * interest on the screen for the creation of hte profile.
     */
    MouseEvent lastMouse;
    /**
     * A copy of the most current projection to use to update the
     * drawn line.
     */
    Projection proj;

    public ProfileGenerator(TerrainLayer tLayer) {
        layer = tLayer;
        init();
    }

    public synchronized OMGraphicList getGraphics() {
        profileLine.setLocation(setLLPoints(), OMGraphic.RADIANS);
        profileLine.generate(proj);
        return graphics;
    }

    /**
     * Create the line object, the state machine, and the vectors used
     * to keep track of the line being drawn.
     */
    public void init() {
        lastMouse = null;

        coords = new Vector();
        xypoints = new Vector();

        profileLine = new OMPoly(setLLPoints(), OMGraphic.RADIANS, OMGraphic.LINETYPE_GREATCIRCLE);
        profileLine.setLinePaint(toolColor);

        graphics.add(profileLine);
        //      System.loadLibrary("com_bbn_openmap_terrain_ProfileGenerator");

        stateMachine = new ProfileStateMachine(this);
    }

    /**
     * Clears the line from the screen, and resets the state machine.
     */
    public void reset() {
        coords.removeAllElements();
        xypoints.removeAllElements();
        profileLine.setLocation(setLLPoints(), OMGraphic.RADIANS);
        stateMachine.reset();
        layer.repaint();
        lastMouse = null;
    }

    public void setScreenParameters(Projection p) {
        proj = p;
        graphics.generate(p);
    }

    /**
     * Returns a set of lat lon points that represent the line as it
     * was drawn. The lat lon points are in an array of floats, that
     * alternate, lat, lon, etc.
     */
    public float[] setLLPoints() {
        float[] points;
        int num_points = coords.size();

        if (num_points <= 1) {

            points = new float[4];
            if (num_points == 0) {
                points[0] = 0f;
                points[1] = -6f;
            } else {
                points[0] = ((LatLonPoint) coords.elementAt(0)).radlat_;
                points[1] = ((LatLonPoint) coords.elementAt(0)).radlon_;
            }

            points[2] = points[0];
            points[3] = points[1];
        } else {
            points = new float[coords.size() * 2];
            for (int i = 0; i < coords.size(); i++) {
                points[i * 2] = ((LatLonPoint) coords.elementAt(i)).radlat_;
                points[(i * 2) + 1] = ((LatLonPoint) coords.elementAt(i)).radlon_;
            }
        }
        return points;
    }

    /**
     * Returns the current state of the state machine.
     */
    public State getState() {
        return stateMachine.getState();
    }

    /**
     * Creates the line points for the path drawn on the screen, and
     * collects the elevation values for those points. Makes the call
     * to write the new gif file to disk.
     */
    public void createProfileImage() {

        Debug.message("terrain",
                "ProfileGenerator:createProfileImage(): Creating image");

        if (layer == null || layer.frameCache == null) {
            Debug.error("ProfileGenerator:  can't access the DTED data through the terrain layer.");
            return;
        }

        // Set the final line, as it was drawn.
        profileLine.setLocation(setLLPoints(), OMGraphic.RADIANS);

        int total_distance = 0;
        int[] distances = new int[xypoints.size()];
        Point tmpPoint1, tmpPoint2;
        distances[0] = 0;
        for (int j = 1; j < xypoints.size(); j++) {
            tmpPoint1 = (Point) xypoints.elementAt(j);
            tmpPoint2 = (Point) xypoints.elementAt(j - 1);
            // Needed for the GIF, the number of pixels (distance)
            // between points of the line. The distances array is the
            // distance between this point and the next in the xy
            // point array.
            distances[j] = TerrainLayer.numPixelsBetween(tmpPoint1.x,
                    tmpPoint1.y,
                    tmpPoint2.x,
                    tmpPoint2.y);
            total_distance += distances[j];
        }

        int tmp = 0;
        int max = 0;
        int[] heights = new int[xypoints.size()];
        // Go through the points and get the heights
        for (int i = 0; i < heights.length; i++) {
            LatLonPoint llp = ((LatLonPoint) coords.elementAt(i));
            // Ask the cache for the elevation
            tmp = layer.frameCache.getElevation(llp.getLatitude(),
                    llp.getLongitude());

            if (tmp == DTEDFrameCache.NO_DATA)
                tmp = -1;
            if (tmp > max)
                max = tmp;
            heights[i] = tmp;
        }
        // get the picture drawn and written
        createGIFFile(total_distance, max, distances, heights);
    }

    /**
     * Create the image and write it the location.
     *
     * @param distance total length of line, in pixels
     * @param max highest point, in meters of all the heights in the
     *        line.
     * @param post_dist array of pixel distances between the points
     * @param post_height the array of heights
     */
    protected void createGIFFile(int distance, int max, int[] post_dist,
                                 int[] post_height) {

        int box_height_buffer = 20;
        int gif_height_buffer = 20;
        int gif_width_buffer = 20;
        int text_width = 100;

        int box_height = max + (box_height_buffer * 2);
        int box_width = distance;
        int gif_height = box_height + (gif_height_buffer * 2);
        int gif_width = box_width + (gif_width_buffer * 2) + text_width;

        AcmeGifFormatter formatter = new AcmeGifFormatter();
        java.awt.Graphics graphics = formatter.getGraphics(gif_width,
                gif_height);

//        Color gray10 = new Color(25, 25, 25);
        Color gray50 = new Color(128, 128, 128);
//        Color gray75 = new Color(191, 191, 191);
        Color gray90 = new Color(230, 230, 230);

        Debug.message("terrain",
                "ProfileGenerator gif creation: drawing boundaries");
        /* Fill in the generic colors */
        graphics.setColor(gray90);
        graphics.fillRect(0, 0, gif_width, gif_height);

        graphics.setColor(gray50);
        graphics.fillRect(gif_width_buffer,
                gif_height_buffer,
                box_width,
                box_height);

        Debug.message("terrain", "ProfileGenerator gif creation: drawing edges");
        // outside edge
        graphics.setColor(Color.black);
        graphics.drawRect(0, 0, gif_width - 1, gif_height - 1);
        // inside edge
        graphics.drawRect(gif_width_buffer,
                gif_height_buffer,
                box_width,
                box_height);

        graphics.setColor(Color.yellow);
        // 0 height line
        graphics.drawLine(gif_width_buffer + 1,
                gif_height_buffer + box_height - box_height_buffer,
                gif_width_buffer + box_width - 1,
                gif_height_buffer + box_height - box_height_buffer);

        // These are the horizontal reference lines in the image.
        graphics.setColor(Color.black);
        FontMetrics f = graphics.getFontMetrics();

        Debug.message("terrain",
                "ProfileGenerator gif creation: drawing level lines");
        for (int i = 1; i < 9; i++) {

            graphics.drawLine(gif_width_buffer, gif_height_buffer + box_height
                    - box_height_buffer - (max * i / 8), gif_width_buffer
                    + box_width + 5, gif_height_buffer + box_height
                    - box_height_buffer - (max * i / 8));

            int meters = max * i / 8;
            int feet = (int) (meters * 3.2);
            String lineLabel = meters + "m / " + feet + "ft";
//            byte[] lineLabelBytes = lineLabel.getBytes();

            graphics.drawString(lineLabel,
                    gif_width_buffer + box_width + 10,
                    gif_height_buffer + box_height - box_height_buffer
                            - (max * i / 8) + (f.getAscent() / 2));
        }

//        int last_x = gif_width_buffer + 1;
//        int last_height = gif_height_buffer + box_height - box_height_buffer
//                - post_height[0];

        int total_distance = 0;
        Debug.message("terrain",
                "ProfileGenerator gif creation: drawing profile");

        graphics.setColor(Color.red);
        for (int i = 1; i < post_height.length; i++) {
            graphics.drawLine(gif_width_buffer + total_distance,
                    gif_height_buffer + box_height - box_height_buffer
                            - post_height[i - 1],
                    gif_width_buffer + post_dist[i] + total_distance,
                    gif_height_buffer + box_height - box_height_buffer
                            - post_height[i]);

            total_distance += post_dist[i];
        }

        javax.swing.ImageIcon ii = new javax.swing.ImageIcon(formatter.getBufferedImage());
        javax.swing.JFrame jf = com.bbn.openmap.util.PaletteHelper.getPaletteWindow(new javax.swing.JLabel(ii),
                "Path Profile",
                (ComponentListener) null);

        jf.setVisible(true);

        //      byte[] imageBytes = formatter.getImageBytes();
        //      String tmppath = null;
        //      try {
        //          String tmpDir = Environment.get(Environment.TmpDir);
        //          if (tmpDir != null) {
        //              tmppath = tmpDir + File.separator + "openmap-" +
        //                  Environment.timestamp() + ".gif";
        //              FileOutputStream fs = new FileOutputStream(tmppath);
        //              fs.write(imageBytes);
        //              fs.close(); // close the streams

        //              String url = "file://" + tmppath;
        //              layer.fireRequestURL(url);
        //          } else {
        //              Debug.error("ProfileGenerator: can't create image file,
        // because the openmap.TempDirectory was not set.");
        //          }
        //      } catch (IOException e) {
        //          Debug.error("ProfileGenerator: Cannot write to temp file:"
        // +
        //                      Environment.get("line.separator") +
        //                      "\"" + tmppath + "\"");
        //      }
        //      String imageString = new String(imageBytes);
        //      layer.fireRequestBrowserContent(imageString);
    }

    /**
     * Used to keep track of another point for the line, as determined
     * by the state machine.
     *
     * @param event Mouse event that supplies the location
     */
    protected void addProfileEvent(MouseEvent event) {
        LatLonPoint llp = proj.inverse(event.getX(), event.getY());
        if (lastMouse != null) {
            // Check for proximity of the click, since a double
            // click means the end of the line.
            if ((Math.abs(lastMouse.getX() - event.getX()) > MAX_SPACE_BETWEEN_PIXELS)
                    || (Math.abs(lastMouse.getY() - event.getY()) > MAX_SPACE_BETWEEN_PIXELS)) {
                // The line may need to be broken up into smaller
                // segments in order for it to be a true straight
                // line, to figure out the segments. The interior
                // points are added to the vector.
                addGreatCirclePoints(lastMouse, event);
                // Now add the end point to the vector
                coords.addElement(llp);
                // The xy points don't need the interior points, the
                // line gets these points and figures them out for
                // itself. This may be redundant is some way.
                xypoints.addElement(event.getPoint());
            }
        } else {
            coords.addElement(llp);
            xypoints.addElement(event.getPoint());
        }
        lastMouse = event;
        // Reset the line to have all the new points
        profileLine.setLocation(setLLPoints(), OMGraphic.RADIANS);
        profileLine.generate(proj);
    }

    /**
     * Figure out the internal points to create a great circle line
     * between two points on the screen. The interior points are added
     * to the coords array, but not to the xy points array.
     *
     * @param beginning the starting mouse event
     * @param ending the ending mouse event
     */
    protected void addGreatCirclePoints(MouseEvent beginning, MouseEvent ending) {
        LatLonPoint beg = proj.inverse(beginning.getX(), beginning.getY());
        LatLonPoint end = proj.inverse(ending.getX(), ending.getY());

        int num_points = (TerrainLayer.numPixelsBetween(beginning.getX(),
                beginning.getY(),
                ending.getX(),
                ending.getY()) - 2)
                / MAX_SPACE_BETWEEN_PIXELS;

        float[] radPoints = GreatCircle.great_circle(beg.radlat_,
                beg.radlon_,
                end.radlat_,
                end.radlon_,
                num_points,
                true);
        for (int i = 0; i < radPoints.length; i++) {
            coords.addElement(new LatLonPoint(radPoints[i], radPoints[i + 1], true));
            Point pt = new Point();
            proj.forward(radPoints[i], radPoints[i + 1], pt, true);
            xypoints.addElement(pt);

            //        System.out.println("addCGPoints: point " + i + " lat="
            // +
            //                           RadianPoint.radToDeg(radPoints[i].lat) + ", lon=" +
            //                           RadianPoint.radToDeg(radPoints[i].lon) + ", x=" +
            //                           (short)pt.x + ", y=" + (short)pt.y);
            i++;
        }
    }

}
TOP

Related Classes of com.bbn.openmap.layer.terrain.ProfileGenerator

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.