/*
* This file is part of LaTeXDraw.
* Copyright (c) 2005-2017 Arnaud BLOUIN
* LaTeXDraw is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
* LaTeXDraw is distributed without any warranty; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package net.sf.latexdraw.models.impl;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.stream.IntStream;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import net.sf.latexdraw.models.MathUtils;
import net.sf.latexdraw.models.ShapeFactory;
import net.sf.latexdraw.models.interfaces.prop.IDotProp;
import net.sf.latexdraw.models.interfaces.prop.IPlotProp;
import net.sf.latexdraw.models.interfaces.shape.Color;
import net.sf.latexdraw.models.interfaces.shape.DotStyle;
import net.sf.latexdraw.models.interfaces.shape.IPlot;
import net.sf.latexdraw.models.interfaces.shape.IPoint;
import net.sf.latexdraw.models.interfaces.shape.IShape;
import net.sf.latexdraw.models.interfaces.shape.PlotStyle;
import net.sf.latexdraw.models.interfaces.shape.Position;
import net.sf.latexdraw.parsers.ps.PSFunctionParser;
import net.sf.latexdraw.view.pst.PSTricksConstants;
/**
* Implementation of the plotted function.
* @author Arnaud Blouin
*/
class LPlot extends LPositionShape implements IPlot {
private final IntegerProperty nbPoints;
private final ObjectProperty<PlotStyle> style;
private final ObjectProperty<DotStyle> dotStyle;
private final DoubleProperty dotDiametre;
private final BooleanProperty polar;
private final DoubleProperty minX;
private final DoubleProperty maxX;
private final StringProperty equation;
private final DoubleProperty xscale;
private final DoubleProperty yscale;
private PSFunctionParser parser;
LPlot(final IPoint pt, final double xMin, final double xMax, final String equationPlot, final boolean polarCoord) {
super(pt);
if(!(MathUtils.INST.isValidPt(pt) && xMin < xMax && MathUtils.INST.isValidCoord(xMin) && MathUtils.INST.isValidCoord(xMax)))
throw new IllegalArgumentException("Parameter not valid: " + xMin + " " + xMax + " " + MathUtils.INST.isValidPt(pt));
nbPoints = new SimpleIntegerProperty(50);
style = new SimpleObjectProperty<>(PlotStyle.CURVE);
equation = new SimpleStringProperty(equationPlot);
parser = new PSFunctionParser(equationPlot);
dotStyle = new SimpleObjectProperty<>(DotStyle.DOT);
dotDiametre = new SimpleDoubleProperty(PSTricksConstants.DEFAULT_ARROW_DOTSIZE_DIM * IShape.PPC + PSTricksConstants.DEFAULT_ARROW_DOTSIZE_NUM);
polar = new SimpleBooleanProperty(polarCoord);
minX = new SimpleDoubleProperty(xMin);
maxX = new SimpleDoubleProperty(xMax);
xscale = new SimpleDoubleProperty(1d);
yscale = new SimpleDoubleProperty(1d);
}
@Override
public void copy(final IShape sh) {
super.copy(sh);
if(sh instanceof IPlotProp) {
final IPlotProp plot = (IPlotProp) sh;
style.set(plot.getPlotStyle());
nbPoints.set(plot.getNbPlottedPoints());
polar.set(plot.isPolar());
dotStyle.set(plot.getDotStyle());
dotDiametre.set(plot.getDiametre());
minX.set(plot.getPlotMinX());
maxX.set(plot.getPlotMaxX());
xscale.set(plot.getXScale());
yscale.set(plot.getYScale());
setPlotEquation(plot.getPlotEquation());
}else if(sh instanceof IDotProp) {
final IDotProp dot = (IDotProp) sh;
dotStyle.set(dot.getDotStyle());
dotDiametre.set(dot.getDiametre());
}
parser = new PSFunctionParser(equation.get());
}
@Override
public void mirrorVertical(final IPoint origin) {
final IPoint gc = getGravityCentre();
if(MathUtils.INST.isValidPt(origin) && !origin.equals(gc, 0.0001)) {
translate(0d, gc.verticalSymmetry(origin).getY() - gc.getY());
}
}
@Override
public void mirrorHorizontal(final IPoint origin) {
final IPoint gc = getGravityCentre();
if(MathUtils.INST.isValidPt(origin) && !origin.equals(gc, 0.0001)) {
translate(gc.horizontalSymmetry(origin).getX() - gc.getX(), 0d);
}
}
@Override
public PlotStyle getPlotStyle() {
return style.get();
}
@Override
public void setPlotStyle(final PlotStyle plotStyle) {
if(plotStyle != null) {
style.setValue(plotStyle);
}
}
@Override
public boolean isShowPtsable() {
return false;
}
@Override
public boolean isThicknessable() {
return getPlotStyle() != PlotStyle.DOTS;
}
@Override
public boolean isShadowable() {
return getPlotStyle() != PlotStyle.DOTS;
}
@Override
public boolean isLineStylable() {
return getPlotStyle() != PlotStyle.DOTS;
}
@Override
public boolean isInteriorStylable() {
return getPlotStyle() != PlotStyle.DOTS;
}
@Override
public boolean isFillable() {
return getPlotStyle() != PlotStyle.DOTS || dotStyle.get().isFillable();
}
@Override
public boolean isDbleBorderable() {
return getPlotStyle() != PlotStyle.DOTS;
}
@Override
public double getPlottingStep() {
return (getPlotMaxX() - getPlotMinX()) / (getNbPlottedPoints() - 1);
}
@Override
public IPoint getTopLeftPoint() {
final double step = getPlottingStep();
final IPoint pos = getPosition();
final double plotMinX = getPlotMinX();
final double yMax = IntStream.range(0, getNbPlottedPoints()).mapToDouble(x -> getY(plotMinX + x * step)).max().orElse(0.0);
return ShapeFactory.INST.createPoint(pos.getX() + plotMinX * IShape.PPC * getXScale(), pos.getY() - yMax * IShape.PPC * getYScale());
}
@Override
public IPoint getBottomRightPoint() {
final double step = getPlottingStep();
final IPoint pos = getPosition();
final double plotMinX = getPlotMinX();
final double yMin = IntStream.range(0, getNbPlottedPoints()).mapToDouble(x -> getY(plotMinX + x * step)).min().orElse(0.0);
return ShapeFactory.INST.createPoint(pos.getX() + getPlotMaxX() * IShape.PPC * getXScale(), pos.getY() - yMin * IShape.PPC * getYScale());
}
@Override
public IPoint getTopRightPoint() {
final double step = getPlottingStep();
final IPoint pos = getPosition();
final double plotMinX = getPlotMinX();
final double maxY = IntStream.range(0, getNbPlottedPoints()).mapToDouble(x -> getY(plotMinX + x * step)).max().orElse(0.0);
return ShapeFactory.INST.createPoint(pos.getX() + getPlotMaxX() * IShape.PPC * getXScale(), pos.getY() - maxY * IShape.PPC * getYScale());
}
@Override
public IPoint getBottomLeftPoint() {
final double step = getPlottingStep();
final IPoint pos = getPosition();
final double plotMinX = getPlotMinX();
final double yMin = IntStream.range(0, getNbPlottedPoints()).mapToDouble(x -> getY(plotMinX + x * step)).min().orElse(0.0);
return ShapeFactory.INST.createPoint(pos.getX() + plotMinX * IShape.PPC * getXScale(), pos.getY() - yMin * IShape.PPC * getYScale());
}
@Override
protected void scaleSetPointsWithRatio(final List<IPoint> pts, final double prevWidth, final double prevHeight, final Position pos, final Rectangle2D bound) {
scaleSetPoints(pts, prevWidth, prevHeight, pos, bound);
}
@Override
protected void scaleSetPoints(final List<IPoint> pts, final double prevWidth, final double prevHeight, final Position pos, final Rectangle2D bound) {
switch(pos) {
case EAST:
getPtAt(0).translate(bound.getWidth() - prevWidth, 0d);
break;
case WEST:
getPtAt(0).translate(prevWidth - bound.getWidth(), 0d);
break;
case SOUTH:
getPtAt(0).translate(0d, bound.getHeight() - prevHeight);
break;
case NORTH:
getPtAt(0).translate(0d, prevHeight - bound.getHeight());
break;
case NE:
getPtAt(0).translate(bound.getWidth() - prevWidth, prevHeight - bound.getHeight());
break;
case NW:
getPtAt(0).translate(prevWidth - bound.getWidth(), prevHeight - bound.getHeight());
break;
case SE:
getPtAt(0).translate(bound.getWidth() - prevWidth, bound.getHeight() - prevHeight);
break;
case SW:
getPtAt(0).translate(prevWidth - bound.getWidth(), bound.getHeight() - prevHeight);
break;
}
}
@Override
public IPoint getPosition() {
return getPtAt(0);
}
@Override
public int getNbPlottedPoints() {
return nbPoints.get();
}
@Override
public void setNbPlottedPoints(final int nbPts) {
if(nbPts > 1) {
nbPoints.setValue(nbPts);
}
}
@Override
public double getY(final double x) {
return parser.getY(x);
}
@Override
public String getPlotEquation() {
return equation.get();
}
@Override
public void setPlotEquation(final String eq) {
if(eq != null && !eq.isEmpty()) {
parser = new PSFunctionParser(eq);
equation.setValue(eq);
}
}
@Override
public double getPlotMinX() {
return minX.get();
}
@Override
public void setPlotMinX(final double x) {
if(MathUtils.INST.isValidCoord(x) && x < getPlotMaxX()) {
minX.setValue(x);
}
}
@Override
public double getPlotMaxX() {
return maxX.get();
}
@Override
public void setPlotMaxX(final double x) {
if(MathUtils.INST.isValidCoord(x) && x > getPlotMinX()) {
maxX.setValue(x);
}
}
@Override
public boolean isPolar() {
return polar.get();
}
@Override
public void setPolar(final boolean pol) {
polar.setValue(pol);
}
@Override
public double getDiametre() {
return dotDiametre.get();
}
@Override
public void setDiametre(final double diam) {
if(diam > 0d && MathUtils.INST.isValidCoord(diam)) {
dotDiametre.setValue(diam);
}
}
@Override
public Color getDotFillingCol() {
return super.getFillingCol();
}
@Override
public void setDotFillingCol(final Color col) {
setFillingCol(col);
}
@Override
public DotStyle getDotStyle() {
return dotStyle.get();
}
@Override
public void setDotStyle(final DotStyle dotst) {
if(dotst != null) {
dotStyle.setValue(dotst);
}
}
@Override
public void setScale(final double scale) {
setXScale(scale);
setYScale(scale);
}
@Override
public double getXScale() {
return xscale.get();
}
@Override
public void setXScale(final double xscalePlot) {
if(xscalePlot > 0d && MathUtils.INST.isValidCoord(xscalePlot)) {
xscale.setValue(xscalePlot);
}
}
@Override
public double getYScale() {
return yscale.get();
}
@Override
public void setYScale(final double yScalePlot) {
if(yScalePlot > 0d && MathUtils.INST.isValidCoord(yScalePlot)) {
yscale.setValue(yScalePlot);
}
}
@Override
public BooleanProperty polarProperty() {
return polar;
}
@Override
public StringProperty plotEquationProperty() {
return equation;
}
@Override
public DoubleProperty plotMinXProperty() {
return minX;
}
@Override
public DoubleProperty plotMaxXProperty() {
return maxX;
}
@Override
public IntegerProperty nbPlottedPointsProperty() {
return nbPoints;
}
@Override
public ObjectProperty<PlotStyle> plotStyleProperty() {
return style;
}
@Override
public ObjectProperty<DotStyle> dotStyleProperty() {
return dotStyle;
}
@Override
public DoubleProperty dotDiametreProperty() {
return dotDiametre;
}
@Override
public DoubleProperty xScaleProperty() {
return xscale;
}
@Override
public DoubleProperty yScaleProperty() {
return yscale;
}
}