![JAR search and dependency download from the Maven repository](/logo.png)
org.meteoinfo.chart.plot.Plot2D Maven / Gradle / Ivy
/* Copyright 2016 - Yaqiang Wang,
* [email protected]
*
* This library 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 2.1 of the License, or (at
* your option) any later version.
*
* This library 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 Lesser
* General Public License for more details.
*/
package org.meteoinfo.chart.plot;
import org.meteoinfo.chart.ChartLegend;
import org.meteoinfo.chart.ChartText;
import org.meteoinfo.chart.axis.LogAxis;
import org.meteoinfo.chart.axis.TimeAxis;
import org.meteoinfo.common.Extent;
import org.meteoinfo.common.MIMath;
import org.meteoinfo.common.PointD;
import org.meteoinfo.common.PointF;
import org.meteoinfo.data.Dataset;
import org.meteoinfo.geo.drawing.Draw;
import org.meteoinfo.geometry.graphic.Graphic;
import org.meteoinfo.geometry.graphic.GraphicCollection;
import org.meteoinfo.geometry.graphic.ImageGraphic;
import org.meteoinfo.geometry.legend.*;
import org.meteoinfo.geometry.shape.Polygon;
import org.meteoinfo.geometry.shape.Shape;
import org.meteoinfo.geometry.shape.*;
import org.meteoinfo.geometry.geoprocess.GeometryUtil;
import org.meteoinfo.chart.shape.PolylineErrorShape;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import static org.meteoinfo.geo.drawing.Draw.getHatchImage;
/**
*
* @author Yaqiang Wang
*/
public class Plot2D extends AbstractPlot2D {
//
private GraphicCollection graphics;
private float barsWidth = 0.8f;
//
//
public Plot2D() {
super();
this.graphics = new GraphicCollection();
}
//
//
/**
* Get graphics
*
* @return Graphics
*/
public GraphicCollection getGraphics() {
return this.graphics;
}
/**
* Get the number of graphics
* @return The number of graphics
*/
public int getGraphicNumber() {
return this.graphics.size();
}
/**
* Set graphics
*
* @param value Graphics
*/
public void setGraphics(GraphicCollection value) {
this.graphics = value;
}
/**
* Get bars width (0 - 1), only used for automatic bar width.
* @return Bars width
*/
public float getBarsWidth(){
return this.barsWidth;
}
/**
* Set bars width (0 - 1), only used for automatic bar width.
* @param value Bars width
*/
public void setBarsWidth(float value){
this.barsWidth = value;
}
//
//
/**
* Add a graphic
*
* @param g Grahic
*/
public void addGraphic(Graphic g) {
this.graphics.add(g);
}
/**
* Add a graphic by index
*
* @param idx Index
* @param g Graphic
*/
public void addGraphic(int idx, Graphic g) {
this.graphics.add(idx, g);
}
/**
* Remove a graphic
*
* @param g Graphic
*/
public void removeGraphic(Graphic g) {
this.graphics.remove(g);
}
/**
* Remove a graphic by index
*
* @param idx Index
*/
public void removeGraphic(int idx) {
this.graphics.remove(idx);
}
/**
* Remove last graphic
*/
public void removeLastGraphic() {
this.graphics.remove(this.graphics.size() - 1);
}
/**
* Add graphic list
*
* @param gs Graphic list
*/
public void addGraphics(List gs) {
this.graphics.addAll(gs);
}
@Override
void drawGraph(Graphics2D g, Rectangle2D area) {
if (isPiePlot()){
plotPie(g, area);
} else
plotGraphics(g, area);
}
private boolean isPiePlot(){
boolean isPie = false;
int n = 0;
for (int m = 0; m < this.graphics.getNumGraphics(); m++) {
Graphic graphic = this.graphics.get(m).getGraphicN(0);
ShapeTypes st = graphic.getShape().getShapeType();
switch (st){
case ARC:
isPie = true;
n += 1;
break;
}
}
//return isPie && n == 1;
return isPie;
}
void plotPie(Graphics2D g, Rectangle2D area){
AffineTransform oldMatrix = g.getTransform();
g.translate(area.getX(), area.getY());
//Draw background
if (this.background != null) {
g.setColor(this.getBackground());
g.fill(new Rectangle2D.Double(0, 0, area.getWidth(), area.getHeight()));
}
for (int m = 0; m < this.graphics.getNumGraphics(); m++) {
Graphic graphic = this.graphics.get(m);
ColorBreak cb = graphic.getLegend();
for (int i = 0; i < graphic.getNumGraphics(); i++) {
Graphic gg = graphic.getGraphicN(i);
if (!graphic.isSingleLegend()) {
cb = gg.getLegend();
}
Shape shape = gg.getShape();
switch (shape.getShapeType()) {
case POINT:
case POINT_M:
case POINT_Z:
this.drawPoint(g, (PointShape) shape, (PointBreak) cb, area);
break;
case TEXT:
this.drawText((ChartText)shape, g, area);
break;
case POLYLINE:
case POLYLINE_Z:
if (cb instanceof PointBreak) {
this.drawPolyline(g, (PolylineShape) shape, (PointBreak) cb, area);
} else {
this.drawPolyline(g, (PolylineShape) shape, (PolylineBreak) cb, area);
}
break;
case POLYGON:
case POLYGON_Z:
for (Polygon poly : ((PolygonShape) shape).getPolygons()) {
drawPolygon(g, poly, (PolygonBreak) cb, false, area);
}
break;
case RECTANGLE:
this.drawRectangle(g, (RectangleShape) shape, (PolygonBreak) cb, false, area);
break;
case ARC:
this.drawArc(g, (ArcShape) shape, (PolygonBreak) cb, area);
break;
case WIND_BARB:
this.drawWindBarb(g, (WindBarb) shape, (PointBreak) cb, area);
break;
case WIND_ARROW:
this.drawWindArrow(g, (WindArrow) shape, (ArrowBreak) cb, area);
break;
case IMAGE:
this.drawImage(g, gg, area);
break;
}
}
if (graphic instanceof GraphicCollection) {
GraphicCollection gc = (GraphicCollection) graphic;
if (gc.getLabelSet().isDrawLabels()) {
this.drawLabels(g, gc, area);
}
}
}
g.setTransform(oldMatrix);
}
void plotGraphics(Graphics2D g, Rectangle2D area) {
AffineTransform oldMatrix = g.getTransform();
java.awt.Shape oldRegion = g.getClip();
if (this.clip) {
g.setClip(area);
}
g.translate(area.getX(), area.getY());
int barIdx = 0;
for (int m = 0; m < this.graphics.getNumGraphics(); m++) {
Graphic graphic = this.graphics.get(m);
ColorBreak cb = graphic.getLegend();
ShapeTypes shapeType = graphic.getGraphicN(0).getShape().getShapeType();
switch(shapeType){
case BAR:
this.drawBars(g, (GraphicCollection) graphic, barIdx, area);
barIdx += 1;
break;
}
for (int i = 0; i < graphic.getNumGraphics(); i++) {
Graphic gg = graphic.getGraphicN(i);
if (!graphic.isSingleLegend()) {
cb = gg.getLegend();
}
Shape shape = gg.getShape();
switch (shape.getShapeType()) {
case POINT:
case POINT_M:
case POINT_Z:
this.drawPoint(g, (PointShape) shape, (PointBreak) cb, area);
break;
case TEXT:
this.drawText((ChartText)shape, g, area);
break;
case POLYLINE:
case POLYLINE_Z:
if (shape instanceof CapPolylineShape){
this.drawCapPolyline(g, (CapPolylineShape) shape, (PolylineBreak) cb, area);
} else {
switch (cb.getBreakType()){
case POINT_BREAK:
this.drawPolyline(g, (PolylineShape) shape, (PointBreak) cb, area);
break;
case POLYLINE_BREAK:
this.drawPolyline(g, (PolylineShape) shape, (PolylineBreak) cb, area);
break;
case COLOR_BREAK_COLLECTION:
this.drawPolyline(g, (PolylineShape) shape, (ColorBreakCollection) cb, area);
break;
}
}
break;
case CURVE_LINE:
this.drawCurveline(g, (CurveLineShape) shape, (PolylineBreak) cb, area);
break;
case POLYLINE_ERROR:
if (cb instanceof PointBreak) {
this.drawPolylineError(g, (PolylineErrorShape) shape, (PointBreak) cb, area);
} else {
this.drawPolylineError(g, (PolylineErrorShape) shape, (PolylineBreak) cb, area);
}
break;
case POLYGON:
case POLYGON_Z:
for (Polygon poly : ((PolygonShape) shape).getPolygons()) {
drawPolygon(g, poly, (PolygonBreak) cb, false, area);
}
break;
case RECTANGLE:
this.drawRectangle(g, (RectangleShape) shape, (PolygonBreak) cb, false, area);
break;
case CIRCLE:
this.drawCircle(g, (CircleShape) shape, (PolygonBreak) cb, false, area);
break;
case ELLIPSE:
this.drawEllipse(g, (EllipseShape) shape, (PolygonBreak) cb, false, area);
break;
case ARC:
this.drawArc(g, (ArcShape) shape, (PolygonBreak) cb, area);
break;
case WIND_BARB:
this.drawWindBarb(g, (WindBarb) shape, (PointBreak) cb, area);
break;
case WIND_ARROW:
this.drawWindArrow(g, (WindArrow) shape, (ArrowBreak) cb, area);
break;
case IMAGE:
this.drawImage(g, gg, area);
break;
}
}
if (graphic instanceof GraphicCollection) {
GraphicCollection gc = (GraphicCollection) graphic;
if (gc.getLabelSet().isDrawLabels()) {
this.drawLabels(g, gc, area);
}
}
}
g.setTransform(oldMatrix);
if (this.clip) {
g.setClip(oldRegion);
}
}
private void drawPoint(Graphics2D g, PointShape aPS, PointBreak aPB, Rectangle2D area) {
PointD p = aPS.getPoint();
double[] sXY = projToScreen(p.X, p.Y, area);
PointF pf = new PointF((float) sXY[0], (float) sXY[1]);
RenderingHints rend = g.getRenderingHints();
boolean rc = false;
if (this.symbolAntialias && rend.get(RenderingHints.KEY_ANTIALIASING) != RenderingHints.VALUE_ANTIALIAS_ON) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
rc = true;
}
Draw.drawPoint(pf, aPB, g);
if (rc){
g.setRenderingHints(rend);
}
}
void drawText(ChartText text, Graphics2D g, Rectangle2D area) {
float x, y;
switch (text.getCoordinates()) {
case AXES:
x = (float) (area.getWidth() * text.getX());
y = (float) (area.getHeight() * (1 - text.getY()));
this.drawText(g, text, x, y);
break;
case FIGURE:
x = (float) (area.getWidth() * text.getX());
y = (float) (area.getHeight() * (1 - text.getY()));
this.drawText(g, text, x, y);
break;
case DATA:
double[] xy = this.projToScreen(text.getX(), text.getY(), area);
x = (float) xy[0];
y = (float) xy[1];
this.drawText(g, text, x, y);
break;
}
}
private void drawText(Graphics2D g, ChartText text, float x, float y) {
g.setFont(text.getFont());
g.setColor(text.getColor());
switch (text.getYAlign()) {
case TOP:
y += g.getFontMetrics(g.getFont()).getAscent();
break;
case CENTER:
y += g.getFontMetrics(g.getFont()).getAscent() / 2;
break;
}
String s = text.getText();
switch (text.getXAlign()) {
case RIGHT:
x = x - g.getFontMetrics(g.getFont()).stringWidth(s);
break;
case CENTER:
x = x - g.getFontMetrics(g.getFont()).stringWidth(s) * 0.5f;
break;
}
Draw.drawString(g, s, x, y, text.isUseExternalFont());
}
private void drawWindBarb(Graphics2D g, WindBarb aPS, PointBreak aPB, Rectangle2D area) {
PointD p = aPS.getPoint();
double[] sXY = projToScreen(p.X, p.Y, area);
PointF pf = new PointF((float) sXY[0], (float) sXY[1]);
Draw.drawWindBarb(pf, aPS, aPB, g);
}
private void drawWindArrow(Graphics2D g, WindArrow aPS, ArrowBreak aPB, Rectangle2D area) {
PointD p = aPS.getPoint();
double[] sXY = projToScreen(p.X, p.Y, area);
PointF pf = new PointF((float) sXY[0], (float) sXY[1]);
float zoom = aPB.getSize() / 10;
Draw.drawArrow(pf, aPS, aPB, g, zoom);
}
private void drawPolyline(Graphics2D g, PolylineShape aPLS, PointBreak aPB, Rectangle2D area) {
for (Polyline aline : aPLS.getPolylines()) {
double[] sXY;
PointF p;
for (int i = 0; i < aline.getPointList().size(); i++) {
PointD wPoint = aline.getPointList().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
p = new PointF((float) sXY[0], (float) sXY[1]);
Draw.drawPoint(p, aPB, g);
}
}
}
private void drawPolyline(Graphics2D g, PolylineShape aPLS, PolylineBreak aPLB, Rectangle2D area) {
for (Polyline aline : aPLS.getPolylines()) {
double[] sXY;
PointF[] points = new PointF[aline.getPointList().size()];
for (int i = 0; i < aline.getPointList().size(); i++) {
PointD wPoint = aline.getPointList().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
points[i] = new PointF((float) sXY[0], (float) sXY[1]);
}
Draw.drawPolyline(points, aPLB, g);
}
}
private void drawPolyline(Graphics2D g, PolylineShape aPLS, ColorBreakCollection cpc, Rectangle2D area) {
for (Polyline aline : aPLS.getPolylines()) {
double[] sXY;
PointF[] points = new PointF[aline.getPointList().size()];
for (int i = 0; i < aline.getPointList().size(); i++) {
PointD wPoint = aline.getPointList().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
points[i] = new PointF((float) sXY[0], (float) sXY[1]);
}
Draw.drawPolyline(points, cpc, g);
}
}
private void drawCapPolyline(Graphics2D g, CapPolylineShape aPLS, PolylineBreak aPLB, Rectangle2D area) {
for (Polyline aline : aPLS.getPolylines()) {
double[] sXY;
PointF[] points = new PointF[aline.getPointList().size()];
for (int i = 0; i < aline.getPointList().size(); i++) {
PointD wPoint = aline.getPointList().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
points[i] = new PointF((float) sXY[0], (float) sXY[1]);
}
Draw.drawPolyline(points, aPLB, g);
float capLen = aPLS.getCapLen();
int idx = points.length - 1;
if (aPLS.getCapAngle() == 0){
PointF[] ps = new PointF[2];
ps[0] = new PointF(points[0].X - capLen / 2, points[0].Y);
ps[1] = new PointF(points[0].X + capLen / 2, points[0].Y);
Draw.drawPolyline(ps, aPLB, g);
ps = new PointF[2];
ps[0] = new PointF(points[idx].X - capLen / 2, points[idx].Y);
ps[1] = new PointF(points[idx].X + capLen / 2, points[idx].Y);
Draw.drawPolyline(ps, aPLB, g);
} else {
PointF[] ps = new PointF[2];
ps[0] = new PointF(points[0].X, points[0].Y - capLen / 2);
ps[1] = new PointF(points[0].X, points[0].Y + capLen / 2);
Draw.drawPolyline(ps, aPLB, g);
ps = new PointF[2];
ps[0] = new PointF(points[idx].X, points[idx].Y - capLen / 2);
ps[1] = new PointF(points[idx].X, points[idx].Y + capLen / 2);
Draw.drawPolyline(ps, aPLB, g);
}
}
}
private void drawCurveline(Graphics2D g, CurveLineShape aPLS, PolylineBreak aPLB, Rectangle2D area) {
for (Polyline aline : aPLS.getPolylines()) {
double[] sXY;
PointF[] points = new PointF[aline.getPointList().size()];
for (int i = 0; i < aline.getPointList().size(); i++) {
PointD wPoint = aline.getPointList().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
points[i] = new PointF((float) sXY[0], (float) sXY[1]);
}
Draw.drawCurveLine(points, aPLB, g);
}
}
private void drawPolylineError(Graphics2D g, PolylineErrorShape aPLS, PointBreak aPB, Rectangle2D area) {
for (Polyline aline : aPLS.getPolylines()) {
double[] sXY;
PointF p;
double error;
double elen = 6;
g.setColor(aPB.getColor());
for (int i = 0; i < aline.getPointList().size(); i++) {
PointD wPoint = aline.getPointList().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
p = new PointF((float) sXY[0], (float) sXY[1]);
if (aPLS.getYerror() != null) {
error = aPLS.getYerror(i);
error = this.projYLength(error, area);
g.draw(new Line2D.Double(p.X, p.Y - error, p.X, p.Y + error));
g.draw(new Line2D.Double(p.X - (elen * 0.5), p.Y - error, p.X + (elen * 0.5), p.Y - error));
g.draw(new Line2D.Double(p.X - (elen * 0.5), p.Y + error, p.X + (elen * 0.5), p.Y + error));
}
if (aPLS.getXerror() != null) {
error = aPLS.getXerror(i);
error = this.projXLength(error, area);
g.draw(new Line2D.Double(p.X - error, p.Y, p.X + error, p.Y));
g.draw(new Line2D.Double(p.X - error, p.Y - (elen * 0.5), p.X - error, p.Y + (elen * 0.5)));
g.draw(new Line2D.Double(p.X + error, p.Y - (elen * 0.5), p.X + error, p.Y + (elen * 0.5)));
}
Draw.drawPoint(p, aPB, g);
}
}
}
private void drawPolylineError(Graphics2D g, PolylineErrorShape aPLS, PolylineBreak aPLB, Rectangle2D area) {
for (Polyline aline : aPLS.getPolylines()) {
double[] sXY;
PointF[] points = new PointF[aline.getPointList().size()];
PointF p;
double error;
double elen = 6;
g.setColor(aPLB.getColor());
for (int i = 0; i < aline.getPointList().size(); i++) {
PointD wPoint = aline.getPointList().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
p = new PointF((float) sXY[0], (float) sXY[1]);
points[i] = p;
if (aPLS.getYerror() != null) {
error = aPLS.getYerror(i);
error = this.projYLength(error, area);
g.draw(new Line2D.Double(p.X, p.Y - error, p.X, p.Y + error));
g.draw(new Line2D.Double(p.X - (elen * 0.5), p.Y - error, p.X + (elen * 0.5), p.Y - error));
g.draw(new Line2D.Double(p.X - (elen * 0.5), p.Y + error, p.X + (elen * 0.5), p.Y + error));
}
if (aPLS.getXerror() != null) {
error = aPLS.getXerror(i);
error = this.projXLength(error, area);
g.draw(new Line2D.Double(p.X - error, p.Y, p.X + error, p.Y));
g.draw(new Line2D.Double(p.X - error, p.Y - (elen * 0.5), p.X - error, p.Y + (elen * 0.5)));
g.draw(new Line2D.Double(p.X + error, p.Y - (elen * 0.5), p.X + error, p.Y + (elen * 0.5)));
}
}
Draw.drawPolyline(points, aPLB, g);
}
}
private void drawLabels(Graphics2D g, GraphicCollection graphics, Rectangle2D area) {
Extent lExtent = graphics.getExtent();
Extent drawExtent = this.getDrawExtent();
if (!MIMath.isExtentCross(lExtent, drawExtent)) {
return;
}
Font drawFont;
List extentList = new ArrayList<>();
Extent maxExtent = new Extent();
Extent aExtent;
int i, j;
List LabelPoints = graphics.getLabelPoints();
String LabelStr;
PointF aPoint = new PointF();
for (i = 0; i < LabelPoints.size(); i++) {
Graphic aLP = LabelPoints.get(i);
PointShape aPS = (PointShape) aLP.getShape();
LabelBreak aLB = (LabelBreak) aLP.getLegend();
aPS.setVisible(true);
LabelStr = aLB.getText();
aPoint.X = (float) aPS.getPoint().X;
aPoint.Y = (float) aPS.getPoint().Y;
drawFont = aLB.getFont();
if (aPoint.X < drawExtent.minX || aPoint.X > drawExtent.maxX
|| aPoint.Y < drawExtent.minY || aPoint.Y > drawExtent.maxY) {
continue;
}
double[] xy = projToScreen(aPoint.X, aPoint.Y, area);
aPoint.X = (float) xy[0];
aPoint.Y = (float) xy[1];
FontMetrics metrics = g.getFontMetrics(drawFont);
Dimension labSize = new Dimension(metrics.stringWidth(LabelStr), metrics.getHeight());
switch (aLB.getAlignType()) {
case CENTER:
aPoint.X = (float) xy[0] - labSize.width / 2;
break;
case LEFT:
aPoint.X = (float) xy[0] - labSize.width;
break;
}
aPoint.Y += labSize.height / 2;
aPoint.Y -= aLB.getYShift();
aPoint.X += aLB.getXShift();
AffineTransform tempTrans = g.getTransform();
if (aLB.getAngle() != 0) {
//AffineTransform myTrans = new AffineTransform();
AffineTransform myTrans = (AffineTransform)tempTrans.clone();
myTrans.translate(aPoint.X, aPoint.Y);
myTrans.rotate(aLB.getAngle() * Math.PI / 180);
g.setTransform(myTrans);
aPoint.X = 0;
aPoint.Y = 0;
}
boolean ifDraw = true;
Rectangle rect = this.getGraphicRectangle(g, aLP, area);
aExtent = new Extent();
aExtent.minX = rect.x;
aExtent.maxX = rect.x + rect.width;
aExtent.minY = rect.y;
aExtent.maxY = rect.y + rect.height;
if (graphics.getLabelSet().isAvoidCollision()) {
//Judge extent
if (extentList.isEmpty()) {
maxExtent = (Extent) aExtent.clone();
extentList.add(aExtent);
} else if (!MIMath.isExtentCross(aExtent, maxExtent)) {
extentList.add(aExtent);
maxExtent = MIMath.getLagerExtent(maxExtent, aExtent);
} else {
for (j = 0; j < extentList.size(); j++) {
if (MIMath.isExtentCross(aExtent, extentList.get(j))) {
ifDraw = false;
break;
}
}
if (ifDraw) {
extentList.add(aExtent);
maxExtent = MIMath.getLagerExtent(maxExtent, aExtent);
} else {
aPS.setVisible(false);
}
}
}
if (ifDraw) {
if (graphics.getLabelSet().isDrawShadow()) {
g.setColor(graphics.getLabelSet().getShadowColor());
g.fill(new Rectangle.Float((float) aExtent.minX, (float) aExtent.minY, labSize.width, labSize.height));
}
g.setFont(drawFont);
//g.setColor(aLayer.getLabelSet().getLabelColor());
g.setColor(aLP.getLegend().getColor());
g.drawString(LabelStr, aPoint.X, aPoint.Y);
//Draw selected rectangle
if (aPS.isSelected()) {
float[] dashPattern = new float[]{2.0F, 1.0F};
g.setColor(Color.cyan);
g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER, 10.0f, dashPattern, 0.0f));
g.draw(new Rectangle.Float((float) aExtent.minX, (float) aExtent.minY, labSize.width, labSize.height));
}
}
if (aLB.getAngle() != 0) {
g.setTransform(tempTrans);
}
}
}
/**
* Get graphic rectangle
*
* @param g The graphics
* @param aGraphic The graphic
* @param area Area
* @return Rectangle
*/
public Rectangle getGraphicRectangle(Graphics2D g, Graphic aGraphic, Rectangle2D area) {
Rectangle rect = new Rectangle();
double[] sXY;
float aX, aY;
switch (aGraphic.getShape().getShapeType()) {
case POINT:
case POINT_M:
PointShape aPS = (PointShape) aGraphic.getShape();
sXY = projToScreen(aPS.getPoint().X, aPS.getPoint().Y, area);
aX = (float) sXY[0];
aY = (float) sXY[1];
switch (aGraphic.getLegend().getBreakType()) {
case POINT_BREAK:
PointBreak aPB = (PointBreak) aGraphic.getLegend();
int buffer = (int) aPB.getSize() + 2;
rect.x = (int) aX - buffer / 2;
rect.y = (int) aY - buffer / 2;
rect.width = buffer;
rect.height = buffer;
break;
case LABEL_BREAK:
LabelBreak aLB = (LabelBreak) aGraphic.getLegend();
g.setFont(aLB.getFont());
//FontMetrics metrics = g.getFontMetrics(aLB.getFont());
//Dimension labSize = new Dimension(metrics.stringWidth(aLB.getText()), metrics.getHeight());
Dimension labSize = Draw.getStringDimension(aLB.getText(), g);
switch (aLB.getAlignType()) {
case CENTER:
aX = aX - labSize.width / 2;
break;
case LEFT:
aX = aX - labSize.width;
break;
}
aY -= aLB.getYShift();
aY -= labSize.height / 3;
rect.x = (int) aX;
rect.y = (int) aY;
rect.width = (int) labSize.width;
rect.height = (int) labSize.height;
break;
}
break;
case POLYLINE:
case POLYGON:
case RECTANGLE:
case CURVE_LINE:
case ELLIPSE:
case CIRCLE:
case CURVE_POLYGON:
List newPList = (List) aGraphic.getShape().getPoints();
List points = new ArrayList<>();
for (PointD wPoint : newPList) {
sXY = projToScreen(wPoint.X, wPoint.Y, area);
aX = (float) sXY[0];
aY = (float) sXY[1];
points.add(new PointD(aX, aY));
}
Extent aExtent = GeometryUtil.getPointsExtent(points);
rect.x = (int) aExtent.minX;
rect.y = (int) aExtent.minY;
rect.width = (int) (aExtent.maxX - aExtent.minX);
rect.height = (int) (aExtent.maxY - aExtent.minY);
break;
}
return rect;
}
private List drawPolygon(Graphics2D g, Polygon aPG, PolygonBreak aPGB,
boolean isSelected, Rectangle2D area) {
int len = aPG.getOutLine().size();
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, len);
PointD wPoint;
double[] sXY;
List rPoints = new ArrayList<>();
for (int i = 0; i < aPG.getOutLine().size(); i++) {
wPoint = aPG.getOutLine().get(i);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
if (i == 0) {
path.moveTo(sXY[0], sXY[1]);
} else {
path.lineTo(sXY[0], sXY[1]);
}
rPoints.add(new PointF((float) sXY[0], (float) sXY[1]));
}
List newPList;
if (aPG.hasHole()) {
for (int h = 0; h < aPG.getHoleLines().size(); h++) {
newPList = (List)aPG.getHoleLines().get(h);
for (int j = 0; j < newPList.size(); j++) {
wPoint = newPList.get(j);
sXY = projToScreen(wPoint.X, wPoint.Y, area);
if (j == 0) {
path.moveTo(sXY[0], sXY[1]);
} else {
path.lineTo(sXY[0], sXY[1]);
}
}
}
}
path.closePath();
if (aPGB.isDrawFill()) {
//int alpha = (int)((1 - (double)transparencyPerc / 100.0) * 255);
//Color aColor = Color.FromArgb(alpha, aPGB.Color);
Color aColor = aPGB.getColor();
if (isSelected) {
aColor = this.getSelectedColor();
}
if (aPGB.isUsingHatchStyle()) {
int size = aPGB.getStyleSize();
BufferedImage bi = getHatchImage(aPGB.getStyle(), size, aPGB.getColor(), aPGB.getBackColor());
Rectangle2D rect = new Rectangle2D.Double(0, 0, size, size);
g.setPaint(new TexturePaint(bi, rect));
g.fill(path);
} else {
g.setColor(aColor);
g.fill(path);
}
} else if (isSelected) {
g.setColor(this.getSelectedColor());
g.fill(path);
}
if (aPGB.isDrawOutline()) {
BasicStroke pen = new BasicStroke(aPGB.getOutlineSize());
g.setStroke(pen);
g.setColor(aPGB.getOutlineColor());
g.draw(path);
}
return rPoints;
}
private void drawRectangle(Graphics2D g, RectangleShape rs, PolygonBreak aPGB,
boolean isSelected, Rectangle2D area) {
Extent extent = rs.getExtent();
double[] sXY;
sXY = projToScreen(extent.minX, extent.minY + extent.getHeight(), area);
double x = sXY[0];
double y = sXY[1];
double width = this.projXLength(extent.getWidth(), area);
double height = this.projYLength(extent.getHeight(), area);
RectangularShape rshape;
if (rs.isRound())
rshape = new RoundRectangle2D.Double(x, y, width, height, width * rs.getRoundX(), height * rs.getRoundY());
else
rshape = new Rectangle2D.Double(x, y, width, height);
if (aPGB.isDrawFill()) {
Color aColor = aPGB.getColor();
if (isSelected) {
aColor = this.getSelectedColor();
}
if (aPGB.isUsingHatchStyle()) {
int size = aPGB.getStyleSize();
BufferedImage bi = getHatchImage(aPGB.getStyle(), size, aPGB.getColor(), aPGB.getBackColor());
Rectangle2D rect = new Rectangle2D.Double(0, 0, size, size);
g.setPaint(new TexturePaint(bi, rect));
g.fill(rshape);
} else {
g.setColor(aColor);
g.fill(rshape);
}
} else if (isSelected) {
g.setColor(this.getSelectedColor());
g.fill(rshape);
}
if (aPGB.isDrawOutline()) {
BasicStroke pen = new BasicStroke(aPGB.getOutlineSize());
g.setStroke(pen);
g.setColor(aPGB.getOutlineColor());
g.draw(rshape);
}
}
private void drawCircle(Graphics2D g, CircleShape rs, PolygonBreak aPGB,
boolean isSelected, Rectangle2D area) {
Extent extent = rs.getExtent();
double[] sXY;
sXY = projToScreen(extent.minX, extent.minY + extent.getHeight(), area);
double x = sXY[0];
double y = sXY[1];
double width = this.projXLength(extent.getWidth(), area);
java.awt.Shape shape = new Ellipse2D.Double(x, y, width, width);
if (aPGB.isDrawFill()) {
Color aColor = aPGB.getColor();
if (isSelected) {
aColor = this.getSelectedColor();
}
if (aPGB.isUsingHatchStyle()) {
int size = aPGB.getStyleSize();
BufferedImage bi = getHatchImage(aPGB.getStyle(), size, aPGB.getColor(), aPGB.getBackColor());
Rectangle2D rect = new Rectangle2D.Double(0, 0, size, size);
g.setPaint(new TexturePaint(bi, rect));
g.fill(shape);
} else {
g.setColor(aColor);
g.fill(shape);
}
} else if (isSelected) {
g.setColor(this.getSelectedColor());
g.fill(shape);
}
if (aPGB.isDrawOutline()) {
BasicStroke pen = new BasicStroke(aPGB.getOutlineSize());
g.setStroke(pen);
g.setColor(aPGB.getOutlineColor());
g.draw(shape);
}
}
private void drawEllipse(Graphics2D g, EllipseShape rs, PolygonBreak aPGB,
boolean isSelected, Rectangle2D area) {
Extent extent = rs.getExtent();
double[] sXY;
sXY = projToScreen(extent.minX, extent.minY + extent.getHeight(), area);
double x = sXY[0];
double y = sXY[1];
double width = this.projXLength(extent.getWidth(), area);
double height = this.projYLength(extent.getHeight(), area);
java.awt.Shape shape = new Ellipse2D.Double(x, y, width, height);
AffineTransform atf = g.getTransform();
if (rs.getAngle() != 0) {
AffineTransform newATF = (AffineTransform) atf.clone();
newATF.translate(x + width / 2, y + height / 2);
newATF.rotate(Math.toRadians(rs.getAngle()));
g.setTransform(newATF);
shape = new Ellipse2D.Double(-width * 0.5, -height * 0.5, width, height);
}
if (aPGB.isDrawFill()) {
Color aColor = aPGB.getColor();
if (isSelected) {
aColor = this.getSelectedColor();
}
if (aPGB.isUsingHatchStyle()) {
int size = aPGB.getStyleSize();
BufferedImage bi = getHatchImage(aPGB.getStyle(), size, aPGB.getColor(), aPGB.getBackColor());
Rectangle2D rect = new Rectangle2D.Double(0, 0, size, size);
g.setPaint(new TexturePaint(bi, rect));
g.fill(shape);
} else {
g.setColor(aColor);
g.fill(shape);
}
} else if (isSelected) {
g.setColor(this.getSelectedColor());
g.fill(shape);
}
if (aPGB.isDrawOutline()) {
BasicStroke pen = new BasicStroke(aPGB.getOutlineSize());
g.setStroke(pen);
g.setColor(aPGB.getOutlineColor());
g.draw(shape);
}
if (rs.getAngle() != 0) {
g.setTransform(atf);
}
}
private void drawArc(Graphics2D g, ArcShape aShape, PolygonBreak aPGB,
Rectangle2D area, float dist, float ex, Font labelFont, Color labelColor) {
float startAngle = aShape.getStartAngle();
float sweepAngle = aShape.getSweepAngle();
float angle = startAngle + sweepAngle / 2;
float space = 20;
Rectangle2D rect = new Rectangle2D.Double(area.getX() + ex + space, area.getY() + ex + space, area.getWidth() - ex - space,
area.getHeight() - ex - space);
double dx = 0, dy = 0;
if (aShape.getExplode() > 0) {
dx = ex * Math.cos((360 - angle) * Math.PI / 180);
dy = ex * Math.sin((360 - angle) * Math.PI / 180);
rect.setRect(rect.getX() + dx, rect.getY() + dy, rect.getWidth(), rect.getHeight());
}
float sx = (float) (rect.getX() - area.getX());
float sy = (float) (rect.getY() - area.getY());
Draw.drawPie(new PointF(sx, sy), (float) rect.getWidth(), (float) rect.getHeight(),
startAngle, sweepAngle, aPGB, g);
float x, y, w, h;
PointF sPoint = new PointF((float) (rect.getWidth() * 0.5 + sx), (float) (rect.getHeight() * 0.5 + sy));
String label = aPGB.getCaption();
if (angle > 360) {
angle = angle - 360;
}
float r = (float) (rect.getWidth() * 0.5) + dist;
PointF lPoint = Draw.getPieLabelPoint(sPoint, r, angle);
x = lPoint.X;
y = lPoint.Y;
Dimension dim = Draw.getStringDimension(label, g);
h = dim.height;
w = dim.width;
if ((angle >= 0 && angle < 45)) {
//x = x + dis;
y = y - h;
} else if (angle >= 45 && angle < 90) {
//y = y - dis;
} else if (angle >= 90 && angle < 135) {
x = x - w;
//y = y - dis;
} else if (angle >= 135 && angle < 225) {
x = x - w - 3;
y = y + h / 2;
} else if (angle >= 225 && angle < 270) {
x = x - w / 2;
y = y + h;
} else if (angle >= 270 && angle < 315) {
//x = x + dis;
y = y + h;
} else {
//x = x + dis;
y = y + h / 2;
}
g.setFont(labelFont);
g.setColor(labelColor);
//g.drawOval((int)(x - 3), (int)(y - 3), 6, 6);
g.drawString(label, x, y);
}
private void drawArc(Graphics2D g, ArcShape aShape, PolygonBreak aPGB,
Rectangle2D area) {
float startAngle = aShape.getStartAngle();
float sweepAngle = aShape.getSweepAngle();
Extent extent = aShape.getExtent();
double[] sXY;
sXY = projToScreen(extent.minX, extent.minY + extent.getHeight(), area);
double x = sXY[0];
double y = sXY[1];
double width = this.projXLength(extent.getWidth(), area);
double height = this.projYLength(extent.getHeight(), area);
Float wedgeWidth = aShape.getWedgeWidth();
if (wedgeWidth == null) {
Draw.drawPie(new PointF((float)x, (float)y),
(float) width, (float) height, startAngle, sweepAngle, aPGB, g);
} else {
wedgeWidth = (float)this.projXLength(wedgeWidth, area);
Draw.drawPie(new PointF((float)x, (float)y),
(float) width, (float) height, startAngle, sweepAngle, aPGB, wedgeWidth, g);
}
}
private void drawBar(Graphics2D g, BarShape bar, BarBreak bb, float width, Rectangle2D area) {
double[] xy;
xy = this.projToScreen(0, 0, area);
float y0 = (float) xy[1];
width = (float) this.projXLength(width, area);
xy = projToScreen(bar.getPoint().X, bar.getPoint().Y, area);
double x = xy[0];
double y = xy[1];
float height;
height = Math.abs((float) (y - y0));
float yb = y0;
if (y >= y0) {
yb += height;
}
Draw.drawBar(new PointF((float) x, yb), width, height, bb, g, false, 5);
}
private int getBarSeriesNum() {
int n = 0;
for (Graphic g : this.graphics.getGraphics()) {
if (g.getGraphicN(0).getShape().getShapeType() == ShapeTypes.BAR) {
n += 1;
}
}
return n;
}
private void drawBars(Graphics2D g, GraphicCollection bars, int barIdx, Rectangle2D area) {
double[] xy;
xy = this.projToScreen(0, 0, area);
float y0 = (float) xy[1];
int len = bars.getNumGraphics();
PointF[] points = new PointF[len];
for (int i = 0; i < len; i++) {
BarShape bs = (BarShape) bars.getGraphicN(i).getShape();
xy = this.projToScreen(bs.getPoint().X, bs.getPoint().Y, area);
points[i] = new PointF((float) xy[0], (float) xy[1]);
}
float width;
int barSeriesN = this.getBarSeriesNum();
BarShape bs1 = (BarShape) bars.getGraphicN(0).getShape();
if (bs1.isAutoWidth()) {
if (len > 1) {
width = (float) ((points[1].X - points[0].X) * this.barsWidth) / barSeriesN;
} else {
width = (float) (area.getWidth() / 10) / barSeriesN;
}
float height;
BarBreak bb;
for (int i = 0; i < len; i++) {
BarShape bs = (BarShape) bars.getGraphicN(i).getShape();
bb = (BarBreak) bars.getGraphicN(i).getLegend();
height = Math.abs((float) (points[i].Y - y0));
float yBottom = y0;
if (bs.isDrawBottom()) {
xy = this.projToScreen(bs.getPoint().X, bs.getBottom(), area);
yBottom = (float) xy[1];
}
float yb = yBottom;
if (points[i].Y >= y0) {
yb += height;
}
Draw.drawBar(new PointF(points[i].X - width * barSeriesN / 2
+ barIdx * width, yb), width, height, bb, g, false, 5);
if (bs.isDrawError()) {
PointF p = (PointF) points[i].clone();
p.Y -= y0 - yBottom;
double elen = 6;
double error = bs.getError();
error = this.projYLength(error, area);
double x = p.X - width * barSeriesN / 2
+ barIdx * width + width / 2;
g.setColor(bb.getErrorColor());
g.draw(new Line2D.Double(x, p.Y - error, x, p.Y + error));
g.draw(new Line2D.Double(x - (elen * 0.5), p.Y - error, x + (elen * 0.5), p.Y - error));
g.draw(new Line2D.Double(x - (elen * 0.5), p.Y + error, x + (elen * 0.5), p.Y + error));
}
}
} else {
width = (float) this.projXLength(bs1.getWidth(), area);
float height;
BarBreak bb;
for (int i = 0; i < len; i++) {
BarShape bs = (BarShape) bars.getGraphicN(i).getShape();
bb = (BarBreak) bars.getGraphicN(i).getLegend();
height = Math.abs((float) (points[i].Y - y0));
float yBottom = y0;
if (bs.isDrawBottom()) {
xy = this.projToScreen(bs.getPoint().X, bs.getBottom(), area);
yBottom = (float) xy[1];
}
float yb = yBottom;
if (points[i].Y >= y0) {
yb += height;
}
Draw.drawBar(new PointF(points[i].X, yb), width, height, bb, g, false, 5);
if (bs.isDrawError()) {
PointF p = (PointF) points[i].clone();
p.Y -= y0 - yBottom;
double elen = 6;
double error = bs.getError();
error = this.projYLength(error, area);
double x = p.X + width / 2;
g.setColor(bb.getErrorColor());
g.draw(new Line2D.Double(x, p.Y - error, x, p.Y + error));
g.draw(new Line2D.Double(x - (elen * 0.5), p.Y - error, x + (elen * 0.5), p.Y - error));
g.draw(new Line2D.Double(x - (elen * 0.5), p.Y + error, x + (elen * 0.5), p.Y + error));
}
}
}
//Draw baseline
boolean drawBaseline = true;
if (drawBaseline) {
g.setColor(Color.black);
g.draw(new Line2D.Double(0, y0, area.getWidth(), y0));
}
}
private double getBarXInterval(int idx) {
Graphic gg = this.graphics.get(idx);
if (gg.getNumGraphics() == 1) {
if (gg.getGraphicN(0).getShape().getPoints().get(0).X == 0) {
return 1;
} else {
return gg.getGraphicN(0).getShape().getPoints().get(0).X / 10;
}
} else {
return gg.getGraphicN(1).getShape().getPoints().get(0).X
- gg.getGraphicN(0).getShape().getPoints().get(0).X;
}
}
private int getBarIndex() {
int idx = -1;
for (int i = 0; i < this.graphics.size(); i++) {
if (this.graphics.get(i).getGraphicN(0).getShape().getShapeType() == ShapeTypes.BAR) {
idx = i;
break;
}
}
return idx;
}
private int getImageIndex() {
int idx = -1;
for (int i = 0; i < this.graphics.size(); i++) {
if (this.graphics.get(i).getGraphicN(0).getShape().getShapeType() == ShapeTypes.IMAGE) {
idx = i;
break;
}
}
return idx;
}
private void drawImage(Graphics2D g, Graphic igraphic, Rectangle2D area) {
ImageShape ishape = (ImageShape) igraphic.getShape();
BufferedImage image = ishape.getImage();
//double sx = ishape.getPoint().X, sy = ishape.getPoint().Y + image.getHeight();
Extent extent = ishape.getExtent();
double sx = extent.minX, sy = extent.maxY;
double[] xy1 = this.projToScreen(sx, sy, area);
double ex = extent.maxX, ey = extent.minY;
//double[] xy2 = this.projToScreen(sx + image.getWidth(), ishape.getPoint().Y, area);
double[] xy2 = this.projToScreen(ex, ey, area);
int x = (int) xy1[0];
int y = (int) xy1[1];
int width = (int) (xy2[0] - xy1[0]);
int height = (int) (xy2[1] - xy1[1]);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, ishape.getInterpolation());
g.drawImage(image, x, y, width, height, null);
}
@Override
Extent getAutoExtent() {
Extent extent = (Extent)this.graphics.getExtent().clone();
if (extent.minX == extent.maxX) {
extent.minX = extent.minX - Math.abs(extent.minX);
extent.maxX = extent.maxX + Math.abs(extent.minX);
}
if (extent.minY == extent.maxY) {
extent.minY = extent.minY - Math.abs(extent.minY);
extent.maxY = extent.maxY + Math.abs(extent.maxY);
}
int imageIdx = this.getImageIndex();
if (imageIdx >= 0){
return extent;
}
int barIdx = this.getBarIndex();
if (barIdx >= 0) {
double dx = getBarXInterval(barIdx);
extent.minX -= dx;
extent.maxX += dx;
}
double[] xValues;
if (this.getXAxis() instanceof TimeAxis) {
xValues = (double[]) MIMath.getIntervalValues(extent.minX, extent.maxX, false).get(0);
xValues[0] = extent.minX;
xValues[xValues.length - 1] = extent.maxX;
} else if (this.getXAxis() instanceof LogAxis) {
xValues = (double[]) MIMath.getIntervalValues_Log(extent.minX, extent.maxX);
} else {
xValues = (double[]) MIMath.getIntervalValues(extent.minX, extent.maxX, true).get(0);
}
double[] yValues;
if (this.getYAxis() instanceof LogAxis) {
yValues = (double[]) MIMath.getIntervalValues_Log(extent.minY, extent.maxY);
} else {
yValues = (double[]) MIMath.getIntervalValues(extent.minY, extent.maxY, true).get(0);
}
if (this.getPlotOrientation() == PlotOrientation.VERTICAL) {
return new Extent(xValues[0], xValues[xValues.length - 1], yValues[0], yValues[yValues.length - 1]);
} else {
return new Extent(yValues[0], yValues[yValues.length - 1], xValues[0], xValues[xValues.length - 1]);
}
}
/**
* Set auto extent
*/
@Override
public void setAutoExtent() {
Extent extent = this.getAutoExtent();
this.setDrawExtent(extent);
this.setExtent((Extent) extent.clone());
}
@Override
public void updateLegendScheme() {
if (this.getLegend() == null) {
this.setLegend(new ChartLegend(this.getLegendScheme()));
} else {
this.getLegend().setLegendScheme(this.getLegendScheme());
}
}
@Override
public Dataset getDataset() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void setDataset(Dataset dataset) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Get legend scheme
*
* @return Legend scheme
*/
public LegendScheme getLegendScheme() {
LegendScheme ls = null;
int n = this.graphics.getNumGraphics();
for (int i = n - 1; i >= 0; i--) {
Graphic g = this.graphics.getGraphicN(i);
if (g instanceof ImageGraphic) {
ls = ((ImageGraphic)g).getLegendScheme();
} else if (g instanceof GraphicCollection) {
ls = ((GraphicCollection)g).getLegendScheme();
}
}
if (ls == null) {
ShapeTypes stype = ShapeTypes.POLYLINE;
ls = new LegendScheme(stype);
for (Graphic g : this.graphics.getGraphics()) {
ls.getLegendBreaks().add(g.getLegend());
}
}
return ls;
}
//
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy