/**
* Copyright 2010,2011 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* jplot2d is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.element.impl;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import org.jplot2d.data.XYGraphData;
import org.jplot2d.transform.Transform1D;
import org.jplot2d.util.GraphicsUtil;
import org.jplot2d.util.LineHatchPaint;
/**
* Down-sample the line data and construct a closed shape for filling.
*
* @author Jingjing Li
*
*/
public class XYGraphFiller {
private LayerEx layer;
private XYGraphEx graph;
private XYGraphData graphData;
private Rectangle2D clip;
private Transform1D xW2D, yW2D;
private int startx, starty;
private int endx, endy;
/**
* Returns a filler and initial it with the given arguments.
*
* @param graph
* @param clip
* @return
*/
public static XYGraphFiller getInstance(XYGraphEx graph, Rectangle2D clip) {
XYGraphFiller builder = new XYGraphFiller();
builder.setLineData(graph);
builder.setClip(clip);
return builder;
}
private XYGraphFiller() {
}
private void setLineData(XYGraphEx dp) {
this.graphData = dp.getData();
this.layer = dp.getParent();
this.graph = dp;
calcTransformXY();
}
private void setClip(Rectangle2D clip) {
this.clip = clip;
}
/**
* Calculate the transform for world value to device value
*/
private void calcTransformXY() {
xW2D = layer
.getXAxisTransform()
.getNormalTransform()
.createTransform(layer.getPaperTransform().getXPtoD(0),
layer.getPaperTransform().getXPtoD(layer.getSize().getWidth()));
yW2D = layer
.getYAxisTransform()
.getNormalTransform()
.createTransform(layer.getPaperTransform().getYPtoD(0),
layer.getPaperTransform().getYPtoD(layer.getSize().getHeight()));
}
/**
* fill paint on the given graphics.
*
* @param g
* @param p
*/
public void fill(Graphics2D g, Paint p) {
double scale = layer.getPaperTransform().getScale();
Path2D path = getFillShape();
if (p instanceof LineHatchPaint) {
LineHatchPaint lhp = (LineHatchPaint) p;
Shape[] hatch = lhp.calcHatchShapes(path, clip, scale);
g.setColor(lhp.getColor());
g.setStroke(GraphicsUtil.scaleStroke(lhp.getStroke(), scale));
for (Shape shape : hatch) {
g.draw(shape);
}
} else {
g.setPaint(p);
g.fill(path);
}
}
private Path2D getFillShape() {
Path2D.Double path = new Path2D.Double();
switch (graph.getChartType()) {
case LINECHART:
fillPolygon(path);
break;
case HISTOGRAM:
fillHistogram(path);
break;
case HISTOGRAM_EDGE:
fillEdgeHistogram(path);
break;
}
closeLine(path);
return path;
}
private void fillPolygon(Path2D path) {
boolean hasPre = false;
for (int i = 0; i < graphData.size(); i++) {
/* ignore NaN value */
if (Double.isNaN(graphData.getX(i)) || Double.isNaN(graphData.getY(i))) {
continue;
}
double x = xW2D.convert(graphData.getX(i));
double y = yW2D.convert(graphData.getY(i));
int ix = (int) (x + 0.5);
int iy = (int) (y + 0.5);
if (hasPre) {
if (endx != ix || endy != iy) {
path.lineTo(ix, iy);
}
} else {
path.moveTo(ix, iy);
startx = ix;
starty = iy;
hasPre = true;
}
endx = ix;
endy = iy;
}
}
/**
*
*/
private void fillHistogram(Path2D path) {
boolean hasPre = false;
// the x coordinate of preIdx
double preDotX = 0;
for (int i = 0; i < graphData.size(); i++) {
/* ignore NaN value */
if (Double.isNaN(graphData.getX(i)) || Double.isNaN(graphData.getY(i))) {
continue;
}
double x = xW2D.convert(graphData.getX(i));
double y = yW2D.convert(graphData.getY(i));
int iy = (int) (y + 0.5);
if (hasPre) {
// the middle x
int imx = (int) (preDotX + x + 1) / 2;
if (endx != imx || endy != iy) {
path.lineTo(imx, endy);
path.lineTo(imx, iy);
endx = imx;
endy = iy;
}
} else {
int ix = (int) (x + 0.5);
path.moveTo(ix, iy);
startx = ix;
starty = iy;
hasPre = true;
endx = ix;
endy = iy;
}
preDotX = x;
}
// the preDotX is the last x point
if (hasPre) {
path.lineTo(preDotX, endy);
}
}
private void fillEdgeHistogram(Path2D path) {
boolean hasPre = false;
for (int i = 0; i < graphData.size(); i++) {
/* ignore NaN value */
if (Double.isNaN(graphData.getX(i)) || Double.isNaN(graphData.getY(i))) {
continue;
}
double x = xW2D.convert(graphData.getX(i));
double y = yW2D.convert(graphData.getY(i));
int ix = (int) (x + 0.5);
int iy = (int) (y + 0.5);
if (hasPre) {
if (endx != ix || endy != iy) {
path.lineTo(ix, endy);
path.lineTo(ix, iy);
}
} else {
path.moveTo(ix, iy);
startx = ix;
starty = iy;
hasPre = true;
}
endx = ix;
endy = iy;
}
}
private void closeLine(Path2D path) {
switch (graph.getFillClosureType()) {
case SELF:
path.closePath();
break;
case LEFT:
path.lineTo(-Short.MAX_VALUE, endy);
path.lineTo(-Short.MAX_VALUE, starty);
path.closePath();
break;
case RIGHT:
path.lineTo(Short.MAX_VALUE, endy);
path.lineTo(Short.MAX_VALUE, starty);
path.closePath();
break;
case TOP:
path.lineTo(endx, -Short.MAX_VALUE);
path.lineTo(startx, -Short.MAX_VALUE);
path.closePath();
break;
case BOTTOM:
path.lineTo(endx, Short.MAX_VALUE);
path.lineTo(startx, Short.MAX_VALUE);
path.closePath();
break;
}
}
}
Ads help maintain this website.