package org.das2.graph; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.geom.Arc2D; import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.util.LinkedHashMap; import java.util.Map; import org.das2.datum.UnitsUtil; import org.das2.qds.QDataSet; import org.das2.qds.examples.Schemes; import org.das2.qds.ops.Ops; import static java.lang.Math.cos; import static java.lang.Math.sin; import javax.swing.Icon; import javax.swing.ImageIcon; import org.das2.qds.DataSetUtil; import org.das2.qds.SemanticOps; /** * Draw the region bounded by the dataset. If the dataset is a bounding box, the box is drawn. If the * data is a rank 2 time series with bins (N by 2), then it is drawn. This supports the following * types: * @author jbf * @see org.das2.qds.examples.Schemes#isBoundingBox(org.das2.qds.QDataSet) */ public class BoundsRenderer extends Renderer { private void expectDs() { getParent().postException( this, new IllegalArgumentException("Expect rank 2 bins or rank 3 array of bins dataset") ); } @Override public boolean acceptsDataSet(QDataSet ds) { if ( ds.rank()==1 || Schemes.isBoundingBox(ds) || Schemes.isArrayOfBoundingBox(ds) ) { return true; } else { return false; } } @Override public boolean acceptContext(int x, int y) { return context==null ? false : context.contains(x, y); } public Area selectionArea() { if ( context==null ) { return null; } else { return new Area(context); } } @Override public Icon getListIcon() { Image i = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D) i.getGraphics(); g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); Shape pbox= new Rectangle2D.Double(0,0,15,15); GeneralPath p= new GeneralPath(); p.append( pbox.getPathIterator(null), true ); p.closePath(); GraphUtil.fillWithTexture(g, p, fillColor, fillTexture ); g.draw(p); return new ImageIcon(i); } @Override public String getListLabel() { return "" + ( getLegendLabel().length()> 0 ? getLegendLabel() +" " : "bounds" ); } private GeneralPath context=null; public static QDataSet doAutorange( QDataSet ds ) { if ( ds.length()==0 ) { return null; } if ( Schemes.isBoundingBox(ds) ) { QDataSet xxx= Ops.slice0( ds,0 ); QDataSet yyy= Ops.slice0( ds,1 ); xxx= Ops.rescaleRangeLogLin( xxx, -0.1, 1.1 ); yyy= Ops.rescaleRangeLogLin( yyy, -0.1, 1.1 ); return Ops.join( xxx, yyy ); } else if ( Schemes.isArrayOfBoundingBox(ds) ) { QDataSet xx=null; QDataSet yy=null; for ( int i=0; i controls= new LinkedHashMap(); controls.put( "fillColor", encodeColorControl(fillColor) ); controls.put( "color", encodeColorControl(color) ); if ( !fillTexture.isEmpty() ) controls.put( "fillTexture", fillTexture ); if ( polar ) controls.put( "polar", encodeBooleanControl( polar ) ); return Renderer.formatControl(controls); } @Override public void setControl(String s) { String oldControl= getControl(); super.setControl(s); this.color= getColorControl( "color", color ); this.fillColor= getColorControl( "fillColor", fillColor ); this.fillTexture= getControl( "fillTexture", fillTexture ); this.polar= getBooleanControl( "polar", false ); if ( !oldControl.equals(s) ) { updateCacheImage(); } } public Color getColor() { return color; } public void setColor(Color color) { Color old = this.color; this.color = color; if ( !color.equals(old) ) { updateCacheImage(); } propertyChangeSupport.firePropertyChange(PROP_COLOR, old, color); } public Color getFillColor() { return fillColor; } public void setFillColor( Color color ) { Color old = this.fillColor; this.fillColor = color; if ( !color.equals(old) ) { updateCacheImage(); } propertyChangeSupport.firePropertyChange(PROP_COLOR, old, color ); } private String fillTexture = "solid"; // solid, hash, none public static final String PROP_FILLTEXTURE = "fillTexture"; public String getFillTexture() { return fillTexture; } public void setFillTexture(String fillTexture) { String old = this.fillTexture; this.fillTexture = fillTexture; if ( !old.equals(fillTexture) ) { updateCacheImage(); } propertyChangeSupport.firePropertyChange(PROP_FILLTEXTURE, old, fillTexture); } private boolean polar = false; public static final String PROP_POLAR = "polar"; public boolean isPolar() { return polar; } /** * if true then transform render the data in polar coordinates * @param polar */ public void setPolar(boolean polar) { boolean old = this.polar; this.polar = polar; if ( old!=polar ) { updateCacheImage(); } propertyChangeSupport.firePropertyChange(PROP_POLAR, old, polar); } @Override public void render(Graphics2D g1, DasAxis xAxis, DasAxis yAxis ) { Graphics2D g= (Graphics2D)g1; QDataSet d= this.getDataSet(); if ( d==null ) { if ( getLastException()!=null ) { renderException(g, xAxis, yAxis, lastException); } else { getParent().postMessage(this, "no data set", DasPlot.INFO, null, null); } return; } if ( d.length()==0 ) return; if ( !( d.rank()==1 || d.rank()==2 || d.rank()==3 ) ) { expectDs(); return; } QDataSet mins; QDataSet maxs; if ( Schemes.isBoundingBox(d) || Schemes.isBoundingBox(d.slice(0) )) { if ( d.rank()==2 ) { // make it a single-element rank 3 d= Ops.join( null, d ); } GeneralPath pbox= new GeneralPath(); for ( int i=0; i