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

src.gov.nasa.worldwind.render.MultiResolutionPath Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show 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.render;

import com.jogamp.common.nio.Buffers;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.util.Logging;

import java.awt.*;
import java.nio.IntBuffer;
import java.util.Iterator;

/**
 * A Version of {@link Path} that provides level-of-detail. Positions in a {@code Path} are filtered based on a "skip
 * count", the number of positions to skip between positions that are drawn. The skip-count algorithm can be replaced by
 * the application. The default algorithm skips up to four positions, depending on the eye distance from the positions.
 * Also, if the segment between any two positions is too small to be distinguished, it is not drawn. See {@link
 * #makePositions(DrawContext, gov.nasa.worldwind.render.Path.PathData)}.
 *
 * @author tag
 * @version $Id: MultiResolutionPath.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class MultiResolutionPath extends Path
{
    /**
     * This interface provides the means for the application to specify the algorithm used to determine the number of
     * specified positions skipped during path tessellation.
     * 

* This class overrides the method {@link Path#makePositions(DrawContext, PathData)}. */ public interface SkipCountComputer { /** * Determines the number of positions to skip for the current viewing state. Determines the number of positions * to skip for the current viewing state. * * @param dc the current draw context. * @param pathData this shape's current path data. * * @return the number of positions to skip when computing the tessellated or non-tessellated path. */ public int computeSkipCount(DrawContext dc, PathData pathData); } /** Subclass of PathData that adds the capability to map which ordinal number corresponds to each rendered position. */ protected static class MultiResolutionPathData extends PathData { /** Maps indices of rendered positions to their corresponding ordinal numbers. */ protected IntBuffer positionOrdinals; /** * Creates a new MultiResolutionPathData with the specified draw context and path. * * @param dc the draw context associated with this path data. * @param shape the shape associated with this path data. */ public MultiResolutionPathData(DrawContext dc, Path shape) { super(dc, shape); } /** * Returns a buffer mapping indices of rendered positions to their corresponding ordinal numbers. * * @return a buffer mapping positions to ordinal numbers. */ public IntBuffer getPositionOrdinals() { return this.positionOrdinals; } /** * Specifies a buffer that maps indices of rendered positions to their corresponding ordinal numbers. * * @param posOrdinals a buffer that maps positions to ordinal numbers. */ public void setPositionOrdinals(IntBuffer posOrdinals) { this.positionOrdinals = posOrdinals; } } /** * The default implementation of SkipCountComputer. This implementation returns a value of 4 when the * eye distance to the path is greater than 10e3, a value of 2 when the eye distance is greater than 1e3 meters but * less then 10e3, and a value of 1 when the eye distance is less than 1e3. */ protected SkipCountComputer skipCountComputer = new SkipCountComputer() { public int computeSkipCount(DrawContext dc, PathData pathData) { double d = getDistanceMetric(dc, pathData); return d > 10e3 ? 4 : d > 1e3 ? 2 : 1; } }; /** * Creates a path with specified positions. When the path is rendered, only path positions that are visually * distinct for the current viewing state are considered. The path adjusts the positions it uses as the view state * changes, using more of the specified positions as the eye point comes closer to the shape. *

* Note: If fewer than two positions are specified, no path is drawn. * * @param positions the path positions. This reference is retained by this shape; the positions are not copied. If * any positions in the set change, {@link #setPositions(Iterable)} must be called to inform this * shape of the change. * * @throws IllegalArgumentException if positions is null. */ public MultiResolutionPath(Iterable positions) { super(positions); } /** * Creates a path with specified positions specified via a generic list. When the path is rendered, only path * positions that are visually distinct for the current viewing state are considered. The path adjusts the positions * it uses as the view state changes, using more of the specified positions as the eye point comes closer to the * shape. *

* Note: If fewer than two positions are specified, no path is drawn. * * @param positions the path positions. This reference is retained by this shape; the positions are not copied. If * any positions in the set change, {@link #setPositions(Iterable)} must be called to inform this * shape of the change. * * @throws IllegalArgumentException if positions is null. */ public MultiResolutionPath(Position.PositionList positions) { super(positions); } /** * Indicates the SkipCountComputer that is used to determine the number of specified positions skipped during path * tessellation. * * @return the SkipCountComputer used during path tessellation. */ public SkipCountComputer getSkipCountComputer() { return this.skipCountComputer; } /** * Specifies the SkipCountComputer that determines the number of specified positions skipped during path * tessellation. * * @param computer the SkipCountComputer to use during path tessellation. * * @throws IllegalArgumentException if the computer is null. */ public void setSkipCountComputer(SkipCountComputer computer) { if (computer == null) { String message = Logging.getMessage("nullValue.CallbackIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.skipCountComputer = computer; } /** * {@inheritDoc} *

* Overridden to return a new instance of MultiResolutionPathData. */ @Override protected AbstractShapeData createCacheEntry(DrawContext dc) { return new MultiResolutionPathData(dc, this); } /** * {@inheritDoc} *

* Overridden to initialize and build the PathData's positionOrdinals buffer. */ @Override protected void makeTessellatedPositions(DrawContext dc, PathData pathData) { if (this.numPositions < 2) return; MultiResolutionPathData mrpd = (MultiResolutionPathData) pathData; if (mrpd.positionOrdinals == null || mrpd.positionOrdinals.capacity() < this.numPositions) mrpd.positionOrdinals = Buffers.newDirectIntBuffer(this.numPositions); else mrpd.positionOrdinals.clear(); super.makeTessellatedPositions(dc, pathData); mrpd.positionOrdinals.flip(); } /** * {@inheritDoc} *

* Overridden to skip positions from this Path's original positions list. Positions are skipped first according to * this Path's skipCountComputer. The skipCountComputer determines how many positions this path skips between * tessellated positions. Any positions remaining after this step are skipped if the segment they are part of is * either very small or not visible. */ @Override protected void makePositions(DrawContext dc, PathData pathData) { Iterator iter = this.positions.iterator(); Position posA = iter.next(); int ordinalA = 0; Color colorA = this.getColor(posA, ordinalA); this.addTessellatedPosition(posA, colorA, ordinalA, pathData); // add the first position of the path int skipCount = this.skipCountComputer.computeSkipCount(dc, pathData); // Tessellate each segment of the path. Vec4 ptA = this.computePoint(dc.getTerrain(), posA); for (int i = 1; iter.hasNext(); i++) { Position posB = iter.next(); if (i % skipCount != 0 && iter.hasNext()) { continue; } Vec4 ptB = this.computePoint(dc.getTerrain(), posB); if (iter.hasNext()) // if this is not the final position { // If the segment is very small or not visible, don't use it. if (this.isSmall(dc, ptA, ptB, 8) || !this.isSegmentVisible(dc, posA, posB, ptA, ptB)) continue; } Color colorB = this.getColor(posB, i); this.makeSegment(dc, posA, posB, ptA, ptB, colorA, colorB, ordinalA, i, pathData); posA = posB; ptA = ptB; colorA = colorB; ordinalA = i; } } /** * {@inheritDoc} *

* Overridden to create a mapping between the current tessellated position and the specified ordinal, if the ordinal * is not null. */ @Override protected void addTessellatedPosition(Position pos, Color color, Integer ordinal, PathData pathData) { if (ordinal != null) { // NOTE: Assign these indices before adding the new position to the tessellatedPositions list. MultiResolutionPathData mrpd = (MultiResolutionPathData) pathData; mrpd.positionOrdinals.put(ordinal); } super.addTessellatedPosition(pos, color, ordinal, pathData); } /** * {@inheritDoc} *

* Overridden to use the MultiResolutionPathData's positionOrdinals buffer to map the specified position index to * its corresponding ordinal number. */ @Override protected Integer getOrdinal(int positionIndex) { MultiResolutionPathData mrpd = (MultiResolutionPathData) this.getCurrentPathData(); return mrpd.positionOrdinals.get(positionIndex); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy