All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.symbology.TacticalGraphicUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gov.nasa.worldwind.symbology;

import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.Logging;

import java.util.*;

/**
 * Utility methods for working with tactical graphics.
 *
 * @author pabercrombie
 * @version $Id: TacticalGraphicUtil.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class TacticalGraphicUtil
{
    /**
     * Convert a list of cartesian points to Positions.
     *
     * @param globe  Globe used to convert points to positions.
     * @param points Points to convert.
     *
     * @return List of positions computed from cartesian points.
     */
    public static List asPositionList(Globe globe, Vec4... points)
    {
        List positions = new ArrayList(points.length);
        for (Vec4 point : points)
        {
            positions.add(globe.computePositionFromPoint(point));
        }
        return positions;
    }

    /**
     * Get the date range from a graphic's modifiers. This method looks at the value of the AVKey.DATE_TIME
     * modifier, and returns the results as a two element array. If the value of the modifier is an
     * Iterable, then this method returns the first two values of the iteration. If the value of the
     * modifier is a single object, this method returns an array containing that object and null.
     *
     * @param graphic Graphic from which to retrieve dates.
     *
     * @return A two element array containing the altitude modifiers. One or both elements may be null.
     */
    public static Object[] getDateRange(TacticalGraphic graphic)
    {
        Object date1 = null;
        Object date2 = null;

        Object o = graphic.getModifier(SymbologyConstants.DATE_TIME_GROUP);
        if (o instanceof Iterable)
        {
            Iterator iterator = ((Iterable) o).iterator();
            if (iterator.hasNext())
            {
                date1 = iterator.next();
            }

            if (iterator.hasNext())
            {
                date2 = iterator.next();
            }
        }
        else
        {
            date1 = o;
        }

        return new Object[] {date1, date2};
    }

    /**
     * Get the altitude range from the graphic's modifiers. This method looks at the value of the
     * AVKey.ALTITUDE modifier, and returns the results as a two element array. If the value of the
     * modifier is an Iterable, then this method returns the first two values of the iteration. If the
     * value of the modifier is a single object, this method returns an array containing that object and
     * null.
     *
     * @param graphic Graphic from which to retrieve dates.
     *
     * @return A two element array containing the altitude modifiers. One or both elements may be null.
     */
    public static Object[] getAltitudeRange(TacticalGraphic graphic)
    {
        Object alt1 = null;
        Object alt2 = null;

        Object o = graphic.getModifier(SymbologyConstants.ALTITUDE_DEPTH);
        if (o instanceof Iterable)
        {
            Iterator iterator = ((Iterable) o).iterator();
            if (iterator.hasNext())
            {
                alt1 = iterator.next();
            }

            if (iterator.hasNext())
            {
                alt2 = iterator.next();
            }
        }
        else
        {
            alt1 = o;
        }

        return new Object[] {alt1, alt2};
    }

    /**
     * Position one or two labels some distance along the path. Top and bottom labels are often positioned above and
     * below the same point, so this method supports positioning a pair of labels at the same point. The label offsets
     * determine how the labels draw in relation to the line.
     *
     * @param dc        Current draw context.
     * @param positions Positions that describe the path.
     * @param label1    First label to position.
     * @param label2    Second label to position. (May be null.)
     * @param distance  Distance along the path at which to position the labels.
     */
    public static void placeLabelsOnPath(DrawContext dc, Iterable positions,
        TacticalGraphicLabel label1,
        TacticalGraphicLabel label2, double distance)
    {
        Iterator iterator = positions.iterator();
        Globe globe = dc.getGlobe();

        Position pos1 = null;
        Position pos2;
        Vec4 pt1, pt2;

        double length = 0;
        double thisDistance = 0;

        pos2 = iterator.next();
        pt2 = globe.computePointFromLocation(pos2);

        while (iterator.hasNext() && length < distance)
        {
            pos1 = pos2;
            pt1 = pt2;

            pos2 = iterator.next();
            pt2 = globe.computePointFromLocation(pos2);

            thisDistance = pt2.distanceTo2(pt1);
            length += thisDistance;
        }

        if (pos1 != null && pos2 != null && thisDistance > 0)
        {
            double delta = length - distance;
            LatLon ll = LatLon.interpolateGreatCircle(delta / thisDistance, pos1, pos2);
            pos1 = new Position(ll, 0);

            label1.setPosition(pos1);
            label1.setOrientationPosition(pos2);

            if (label2 != null)
            {
                label2.setPosition(pos1);
                label2.setOrientationPosition(pos2);
            }
        }
    }

    /**
     * Compute a point along a Bezier curve defined by a list of control points. The first and last points should mark
     * the start and end of the curve.
     * 

* This function implements the Bezier curve equation from "Mathematics for 3D Game Programming and Computer * Graphics, Second Edition" by Eric Lengyel (equation 15.16, pg. 458). *

* A typical usage looks like this: *

     * Vec4[] controlPoints = ... // Determine control points appropriate for your curve
     *
     * List curvePositions = new ArrayList();
     * int[] coefficients = new int[controlPoints.length];
     *
     * int intervals = 32;
     * double delta = 1.0 / intervals;
     * for (int i = 0; i < intervals; i++)
     * {
     *     double t = i * delta;
     *     Vec4 pt = TacticalGraphicUtil.bezierCurve(controlPoints, t, coefficients);
     *     Position pos = globe.computePositionFromPoint(p);
     *     curvePositions.add(pos);
     * }
     * 
* * @param controlPoints Control points for the curve. * @param t Interpolation parameter in the range [0..1]. * @param coefficients Array to store binomial coefficients between invocations of this function. On the first * invocation, pass an int[] with length equal to the controlPoints array. bezierCurve will * populate the array on the first invocation, and reuse the computed values on subsequent * invocations. * * @return A point along the curve. */ public static Vec4 bezierCurve(Vec4[] controlPoints, double t, int[] coefficients) { if (coefficients == null || controlPoints == null) { String message = Logging.getMessage("nullValue.ArrayIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (coefficients.length != controlPoints.length) { String message = Logging.getMessage("generic.ArrayInvalidLength", coefficients.length); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (coefficients[0] != 1) { binomial(coefficients.length - 1, coefficients); } int n = controlPoints.length - 1; Vec4 r = Vec4.ZERO; for (int k = 0; k <= n; k++) { double c = coefficients[k] * Math.pow(t, k) * Math.pow(1 - t, n - k); r = r.add3(controlPoints[k].multiply3(c)); } return r; } /** * Compute binomial coefficients for a polynomial of order n. Stated another way, computes the nth row of Pascal's * triangle. * * @param n Order of polynomial for which to calculate coefficients. * @param coefficients Array to receive coefficients. The length of this array must be n + 1. */ protected static void binomial(int n, int[] coefficients) { if (coefficients == null) { String message = Logging.getMessage("nullValue.ArrayIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (coefficients.length != n + 1) { String message = Logging.getMessage("generic.ArrayInvalidLength", coefficients.length); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // Algorithm from "Data Structures and Algorithms with Object-Oriented Design Patterns in Java" by Bruno R. // Preiss (http://www.brpreiss.com/books/opus5/html/page460.html) for (int i = 0; i <= n; i++) { coefficients[i] = 1; for (int j = i - 1; j > 0; j--) { coefficients[j] += coefficients[j - 1]; } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy