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

gov.nasa.worldwind.formats.shapefile.ShapefileRenderable Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwind.formats.shapefile;

import gov.nasa.worldwind.WWObjectImpl;
import gov.nasa.worldwind.avlist.AVListImpl;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.*;

import java.util.*;

/**
 * @author dcollins
 * @version $Id: ShapefileRenderable.java 3232 2015-06-20 04:08:11Z dcollins $
 */
public abstract class ShapefileRenderable extends WWObjectImpl
    implements Renderable, Iterable
{
    /**
     * AttributeDelegate provides an entry point for configuring a ShapefileRenderable.Record's shape attributes and
     * key-value attributes during ShapefileRenderable construction. In particular, the dBASE attributes associated with
     * a ShapefileRecord are available only during these entry points.
     * 

* AttributeDelegate entry points may be called on a non-EDT thread. Implementations of AttributeDelegate may modify * the ShapefileRenderable.Record passed to these methods, but should not modify the ShapefileRenderable without * synchronizing access with the thread used to create the ShapefileRenderable. */ public interface AttributeDelegate { /** * Entry point for configuring a ShapefileRenderable.Record's shape attributes and key-value attributes during * ShapefileRenderable construction. The ShapefileRecord's dBASE attributes are available only during the * execution of this method. *

* This method may be called on a non-EDT thread. Implementations may modify the renderableRecord, but should * not modify the ShapefileRenderable without synchronizing access with the thread used to create the * ShapefileRenderable. * * @param shapefileRecord The shapefile record used to create the ShapefileRenderable.Record. * @param renderableRecord The ShapefileRenderable.Record to assign attributes for. */ void assignAttributes(ShapefileRecord shapefileRecord, ShapefileRenderable.Record renderableRecord); } public static class Record extends AVListImpl implements Highlightable { // Record properties. protected ShapefileRenderable shapefileRenderable; protected Sector sector; protected int ordinal; protected boolean visible = true; protected boolean highlighted; protected ShapeAttributes normalAttrs; protected ShapeAttributes highlightAttrs; // Data structures supporting record tessellation and display. protected final CompoundVecBuffer pointBuffer; protected int firstPartNumber; protected int numberOfParts; protected int numberOfPoints; public Record(ShapefileRenderable shapefileRenderable, ShapefileRecord shapefileRecord) { if (shapefileRenderable == null) { String msg = Logging.getMessage("nullValue.RenderableIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (shapefileRecord == null) { String msg = Logging.getMessage("nullValue.RecordIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.shapefileRenderable = shapefileRenderable; this.sector = shapefileRecord.getBoundingRectangle() != null ? Sector.fromDegrees( shapefileRecord.getBoundingRectangle()) : null; this.pointBuffer = shapefileRecord.getShapeFile().getPointBuffer(); this.firstPartNumber = shapefileRecord.getFirstPartNumber(); this.numberOfParts = shapefileRecord.getNumberOfParts(); this.numberOfPoints = shapefileRecord.getNumberOfPoints(); } public ShapefileRenderable getShapefileRenderable() { return this.shapefileRenderable; } public Sector getSector() { return this.sector; } public int getOrdinal() { return this.ordinal; } public boolean isVisible() { return this.visible; } public void setVisible(boolean visible) { if (this.visible != visible) { this.visible = visible; this.shapefileRenderable.recordDidChange(this); } } @Override public boolean isHighlighted() { return this.highlighted; } @Override public void setHighlighted(boolean highlighted) { if (this.highlighted != highlighted) { this.highlighted = highlighted; this.shapefileRenderable.recordDidChange(this); } } public ShapeAttributes getAttributes() { return this.normalAttrs; } public void setAttributes(ShapeAttributes normalAttrs) { if (this.normalAttrs != normalAttrs) { this.normalAttrs = normalAttrs; this.shapefileRenderable.recordDidChange(this); } } public ShapeAttributes getHighlightAttributes() { return this.highlightAttrs; } public void setHighlightAttributes(ShapeAttributes highlightAttrs) { if (this.highlightAttrs != highlightAttrs) { this.highlightAttrs = highlightAttrs; this.shapefileRenderable.recordDidChange(this); } } public int getBoundaryCount() { return this.numberOfParts; } public VecBuffer getBoundaryPoints(int index) { if (index < 0 || index >= this.numberOfParts) { String msg = Logging.getMessage("generic.indexOutOfRange", index); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } synchronized (this.pointBuffer) // synchronize access to the Shapefile's shared pointBuffer { return this.pointBuffer.subBuffer(this.firstPartNumber + index); } } public Iterable getBoundaryPositions(int index) { if (index < 0 || index >= this.numberOfParts) { String msg = Logging.getMessage("generic.indexOutOfRange", index); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } VecBuffer points = this.getBoundaryPoints(index); return points.getPositions(); } } protected Sector sector; protected ArrayList records; protected boolean visible = true; // Properties used during initialization. protected ShapeAttributes initNormalAttrs; protected ShapeAttributes initHighlightAttrs; protected ShapefileRenderable.AttributeDelegate initAttributeDelegate; protected static ShapeAttributes defaultAttributes; protected static ShapeAttributes defaultHighlightAttributes; static { defaultAttributes = new BasicShapeAttributes(); defaultAttributes.setInteriorMaterial(Material.LIGHT_GRAY); defaultAttributes.setOutlineMaterial(Material.DARK_GRAY); defaultHighlightAttributes = new BasicShapeAttributes(); defaultHighlightAttributes.setInteriorMaterial(Material.WHITE); defaultHighlightAttributes.setOutlineMaterial(Material.DARK_GRAY); } /** * Initializes this ShapefileRenderable with the specified shapefile. The normal attributes, the highlight * attributes and the attribute delegate are optional. Specifying a non-null value for normalAttrs or highlightAttrs * causes each ShapefileRenderable.Record to adopt those attributes. Specifying a non-null value for the attribute * delegate enables callbacks during creation of each ShapefileRenderable.Record. See {@link AttributeDelegate} for * more information. * * @param shapefile The shapefile to display. * @param normalAttrs The normal attributes for each ShapefileRenderable.Record. May be null to use the * default attributes. * @param highlightAttrs The highlight attributes for each ShapefileRenderable.Record. May be null to use the * default highlight attributes. * @param attributeDelegate Optional callback for configuring each ShapefileRenderable.Record's shape attributes and * key-value attributes. May be null. */ protected void init(Shapefile shapefile, ShapeAttributes normalAttrs, ShapeAttributes highlightAttrs, ShapefileRenderable.AttributeDelegate attributeDelegate) { double[] boundingRect = shapefile.getBoundingRectangle(); if (boundingRect == null) // suppress record assembly for empty shapefiles return; this.sector = Sector.fromDegrees(boundingRect); this.initNormalAttrs = normalAttrs; this.initHighlightAttrs = highlightAttrs; this.initAttributeDelegate = attributeDelegate; this.assembleRecords(shapefile); } protected void assembleRecords(Shapefile shapefile) { this.records = new ArrayList(); while (shapefile.hasNext()) { ShapefileRecord shapefileRecord = shapefile.nextRecord(); if (this.mustAssembleRecord(shapefileRecord)) { this.assembleRecord(shapefileRecord); } } this.records.trimToSize(); // Reduce memory overhead from unused ArrayList capacity. } protected boolean mustAssembleRecord(ShapefileRecord shapefileRecord) { return shapefileRecord.getNumberOfParts() > 0 && shapefileRecord.getNumberOfPoints() > 0 && !shapefileRecord.isNullRecord(); } protected void assembleRecord(ShapefileRecord shapefileRecord) { ShapefileRenderable.Record renderableRecord = new ShapefileRenderable.Record(this, shapefileRecord); this.addRecord(shapefileRecord, renderableRecord); } protected void addRecord(ShapefileRecord shapefileRecord, ShapefileRenderable.Record renderableRecord) { renderableRecord.setAttributes(this.initNormalAttrs); renderableRecord.setHighlightAttributes(this.initHighlightAttrs); renderableRecord.ordinal = this.records.size(); this.records.add(renderableRecord); if (this.initAttributeDelegate != null) { this.initAttributeDelegate.assignAttributes(shapefileRecord, renderableRecord); } } public Sector getSector() { return this.sector; } public int getRecordCount() { if (this.records == null) return 0; return this.records.size(); } public ShapefileRenderable.Record getRecord(int ordinal) { if (this.records == null || ordinal < 0 || ordinal >= this.records.size()) { String msg = Logging.getMessage("generic.indexOutOfRange", ordinal); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } return this.records.get(ordinal); } @Override public Iterator iterator() { if (this.records == null) return Collections.emptyList().iterator(); return this.records.iterator(); } public boolean isVisible() { return this.visible; } public void setVisible(boolean visible) { this.visible = visible; } protected void recordDidChange(ShapefileRenderable.Record record) { // Intentionally left empty. May be overridden by subclass. } protected ShapeAttributes determineActiveAttributes(ShapefileRenderable.Record record) { if (record.highlighted) { return record.highlightAttrs != null ? record.highlightAttrs : defaultHighlightAttributes; } else if (record.normalAttrs != null) { return record.normalAttrs; } else { return defaultAttributes; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy