/* Copyright (c) 2008-2019 Jan W. Krieger () This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) any later version. This program 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 (LGPL) for more details. You should have received a copy of the GNU Lesser General Public License (LGPL) along with this program. If not, see . */ #include "jkqtplotter/graphs/jkqtpgeometric.h" #include "jkqtplotter/jkqtpbaseplotter.h" #include "jkqtplotter/jkqtplotter.h" #include #include #include #define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgzgetPlotter()) { } JKQTPGeoBaseLine::JKQTPGeoBaseLine(JKQTBasePlotter *parent): JKQTPPlotObject(parent) { } JKQTPGeoBaseLine::JKQTPGeoBaseLine(JKQTPlotter *parent): JKQTPGeoBaseLine(parent->getPlotter()) { } void JKQTPGeoBaseLine::setAlpha(float alpha) { auto color=getLineColor(); color.setAlphaF(alpha); setLineColor(color); } void JKQTPGeoBaseLine::setColor(QColor c) { setLineColor(c); } void JKQTPGeoBaseLine::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(getLinePen(painter, parent)); double y=rect.top()+rect.height()/2.0; if (rect.width()>0) painter.drawLine(QLineF(rect.left(), y, rect.right(), y)); } QColor JKQTPGeoBaseLine::getKeyLabelColor() const { return getLineColor(); } JKQTPGeoBaseFilled::JKQTPGeoBaseFilled(QColor color, QColor fillColor, double lineWidth, Qt::PenStyle style, Qt::BrushStyle fillStyle, JKQTBasePlotter* parent): JKQTPGeoBaseLine(color, lineWidth, style, parent) { setFillColor(fillColor); setFillStyle(fillStyle); } JKQTPGeoBaseFilled::JKQTPGeoBaseFilled(QColor color, QColor fillColor, double lineWidth, Qt::PenStyle style, Qt::BrushStyle fillStyle, JKQTPlotter* parent): JKQTPGeoBaseLine(color, lineWidth, style, parent) { setFillColor(fillColor); setFillStyle(fillStyle); } JKQTPGeoBaseFilled::JKQTPGeoBaseFilled(QColor color, QColor fillColor, double lineWidth, Qt::PenStyle style, JKQTPlotter* parent): JKQTPGeoBaseLine(color, lineWidth, style, parent) { setFillColor(fillColor); setFillStyle(Qt::SolidPattern); } JKQTPGeoBaseFilled::JKQTPGeoBaseFilled(QColor color, QColor fillColor, double lineWidth, JKQTPlotter* parent): JKQTPGeoBaseLine(color, lineWidth, Qt::SolidLine, parent) { setFillColor(fillColor); setFillStyle(Qt::SolidPattern); } JKQTPGeoBaseFilled::JKQTPGeoBaseFilled(QColor color, QColor fillColor, JKQTPlotter* parent): JKQTPGeoBaseLine(color, 2.0, Qt::SolidLine, parent) { setFillColor(fillColor); setFillStyle(Qt::SolidPattern); } void JKQTPGeoBaseFilled::setAlpha(float alpha) { JKQTPGeoBaseLine::setAlpha(alpha); auto fillColor=getFillColor(); fillColor.setAlphaF(alpha); setFillColor(fillColor); } void JKQTPGeoBaseFilled::setAlpha(float alphaLine, float alphaFill) { JKQTPGeoBaseLine::setAlpha(alphaLine); auto fillColor=getFillColor(); fillColor.setAlphaF(alphaFill); setFillColor(fillColor); } void JKQTPGeoBaseFilled::setColor(QColor c) { JKQTPGeoBaseLine::setColor(c); setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c)); } void JKQTPGeoBaseFilled::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(getLinePen(painter, parent)); painter.setBrush(getFillBrush(painter, parent)); painter.drawRect(rect); } JKQTPGeoText::JKQTPGeoText(JKQTBasePlotter* parent, double x, double y, const QString& text, double fontSize, QColor color): JKQTPPlotObject(parent), JKQTPGraphTextStyleMixin(parent) { this->x=x; this->y=y; this->text=text; setTextFontSize(fontSize); setTextColor(color); } JKQTPGeoText::JKQTPGeoText(JKQTPlotter* parent, double x, double y, const QString& text, double fontSize, QColor color): JKQTPGeoText(parent->getPlotter(),x,y,text,fontSize,color) { } JKQTPGeoText::JKQTPGeoText(JKQTBasePlotter *parent, double x, double y, const QString &text): JKQTPPlotObject(parent), JKQTPGraphTextStyleMixin(parent) { this->x=x; this->y=y; this->text=text; } JKQTPGeoText::JKQTPGeoText(JKQTPlotter *parent, double x, double y, const QString &text): JKQTPGeoText(parent->getPlotter(),x,y,text) { } void JKQTPGeoText::setText(const QString &__value) { this->text = __value; } QString JKQTPGeoText::getText() const { return this->text; } void JKQTPGeoText::setX(double __value) { this->x = __value; } double JKQTPGeoText::getX() const { return this->x; } void JKQTPGeoText::setY(double __value) { this->y = __value; } double JKQTPGeoText::getY() const { return this->y; } void JKQTPGeoText::setColor(QColor c) { setTextColor(c); } bool JKQTPGeoText::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) { minx=maxx=x; smallestGreaterZero=0; if (x>10.0*DBL_MIN) smallestGreaterZero=x; return true; } bool JKQTPGeoText::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) { miny=maxy=y; smallestGreaterZero=0; if (y>10.0*DBL_MIN) smallestGreaterZero=y; return true; } void JKQTPGeoText::draw(JKQTPEnhancedPainter& painter) { clearHitTestData(); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); parent->getMathText()->setFontRomanOrSpecial(getTextFontName()); parent->getMathText()->setFontSize(getTextFontSize()*parent->getFontSizeMultiplier()); parent->getMathText()->setFontColor(getTextColor()); parent->getMathText()->parse(text); parent->getMathText()->draw(painter, transformX(x), transformY(y)); } void JKQTPGeoText::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(QPen(getTextColor())); double y=rect.top()+rect.height()/2.0; if (rect.width()>0) painter.drawLine(QLineF(rect.left(), y, rect.right(), y)); } QColor JKQTPGeoText::getKeyLabelColor() const { return getTextColor(); } JKQTPGeoLine::JKQTPGeoLine(JKQTBasePlotter* parent, double x1, double y1, double x2, double y2, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoBaseLine(color, lineWidth, style, parent) { this->x1=x1; this->y1=y1; this->x2=x2; this->y2=y2; } JKQTPGeoLine::JKQTPGeoLine(JKQTPlotter* parent, double x1, double y1, double x2, double y2, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoLine(parent->getPlotter(), x1,y1,x2,y2,color, lineWidth, style) { } JKQTPGeoLine::JKQTPGeoLine(JKQTBasePlotter *parent, double x1, double y1, double x2, double y2): JKQTPGeoBaseLine(parent) { this->x1=x1; this->y1=y1; this->x2=x2; this->y2=y2; } JKQTPGeoLine::JKQTPGeoLine(JKQTPlotter *parent, double x1, double y1, double x2, double y2): JKQTPGeoLine(parent->getPlotter(), x1,y1,x2,y2) { } bool JKQTPGeoLine::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) { minx=qMin(x1, x2); maxx=qMax(x1, x2); smallestGreaterZero=0; double xvsgz; xvsgz=x1; SmallestGreaterZeroCompare_xvsgz(); xvsgz=x2; SmallestGreaterZeroCompare_xvsgz(); return true; } bool JKQTPGeoLine::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) { miny=qMin(y1, y2); maxy=qMax(y1, y2); smallestGreaterZero=0; double xvsgz; xvsgz=y1; SmallestGreaterZeroCompare_xvsgz(); xvsgz=y2; SmallestGreaterZeroCompare_xvsgz(); return true; } void JKQTPGeoLine::draw(JKQTPEnhancedPainter& painter) { clearHitTestData(); reserveHitTestData(2); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(getLinePen(painter, parent)); QLineF l(QPointF(transformX(x1), transformY(y1)), QPointF(transformX(x2), transformY(y2))); if (l.length()>0) { painter.drawLine(l); addHitTestData(x1, y1); addHitTestData(x2, y2); } } void JKQTPGeoLine::setX1(double __value) { this->x1 = __value; } double JKQTPGeoLine::getX1() const { return this->x1; } void JKQTPGeoLine::setY1(double __value) { this->y1 = __value; } double JKQTPGeoLine::getY1() const { return this->y1; } void JKQTPGeoLine::setX2(double __value) { this->x2 = __value; } double JKQTPGeoLine::getX2() const { return this->x2; } void JKQTPGeoLine::setY2(double __value) { this->y2 = __value; } double JKQTPGeoLine::getY2() const { return this->y2; } JKQTPGeoArrow::JKQTPGeoArrow(JKQTBasePlotter* parent, double x1, double y1, double x2, double y2, QColor color, JKQTPLineDecoratorStyle headStyle, JKQTPLineDecoratorStyle tailStyle, double lineWidth, Qt::PenStyle style): JKQTPGeoBaseDecoratedLine(color, lineWidth, headStyle, tailStyle, style, parent) { this->x1=x1; this->y1=y1; this->x2=x2; this->y2=y2; } JKQTPGeoArrow::JKQTPGeoArrow(JKQTPlotter* parent, double x1, double y1, double x2, double y2, QColor color, JKQTPLineDecoratorStyle headStyle, JKQTPLineDecoratorStyle tailStyle, double lineWidth, Qt::PenStyle style): JKQTPGeoArrow(parent->getPlotter(), x1,y1,x2,y2,color, headStyle, tailStyle, lineWidth, style) { } bool JKQTPGeoArrow::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) { minx=qMin(x1, x2); maxx=qMax(x1, x2); smallestGreaterZero=0; double xvsgz; xvsgz=x1; SmallestGreaterZeroCompare_xvsgz(); xvsgz=x2; SmallestGreaterZeroCompare_xvsgz(); return true; } bool JKQTPGeoArrow::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) { miny=qMin(y1, y2); maxy=qMax(y1, y2); smallestGreaterZero=0; double xvsgz; xvsgz=y1; SmallestGreaterZeroCompare_xvsgz(); xvsgz=y2; SmallestGreaterZeroCompare_xvsgz(); return true; } void JKQTPGeoArrow::draw(JKQTPEnhancedPainter& painter) { clearHitTestData(); reserveHitTestData(2); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(getLinePen(painter, parent)); painter.setBrush(getLineColor()); QPointF xx1(transformX(x1),transformY(y1)); QPointF xx2(transformX(x2), transformY(y2)); const double angle1=atan2(xx2.y()-xx1.y(), xx2.x()-xx1.x()); const double angle2=atan2(xx1.y()-xx2.y(), xx1.x()-xx2.x()); if ( QLineF(xx1, xx2).length()>0) { QPointF lx1=xx1, lx2=xx2; JKQTPPlotLineDecorator(painter, xx1.x(), xx1.y(), angle1, getTailDecoratorStyle(), getTailDecoratorSizeFactor()*getLinePen(painter, getParent()).widthF(), &lx1); JKQTPPlotLineDecorator(painter, xx2.x(), xx2.y(), angle2, getHeadDecoratorStyle(), getHeadDecoratorSizeFactor()*getLinePen(painter, getParent()).widthF(), &lx2); // draw corrected line painter.drawLine(QLineF(lx1, lx2)); addHitTestData(x1, y1); addHitTestData(x2, y2); } } void JKQTPGeoArrow::setX1(double __value) { this->x1 = __value; } double JKQTPGeoArrow::getX1() const { return this->x1; } void JKQTPGeoArrow::setY1(double __value) { this->y1 = __value; } double JKQTPGeoArrow::getY1() const { return this->y1; } void JKQTPGeoArrow::setX2(double __value) { this->x2 = __value; } double JKQTPGeoArrow::getX2() const { return this->x2; } void JKQTPGeoArrow::setY2(double __value) { this->y2 = __value; } double JKQTPGeoArrow::getY2() const { return this->y2; } JKQTPGeoInfiniteLine::JKQTPGeoInfiniteLine(JKQTBasePlotter* parent, double x, double y, double dx, double dy, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoBaseLine(color, lineWidth, style, parent) { this->x=x; this->y=y; this->dx=dx; this->dy=dy; this->two_sided=false; } JKQTPGeoInfiniteLine::JKQTPGeoInfiniteLine(JKQTPlotter* parent, double x, double y, double dx, double dy, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoInfiniteLine(parent->getPlotter(), x, y, dx, dy, color, lineWidth, style) { } bool JKQTPGeoInfiniteLine::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) { minx=x; maxx=x; smallestGreaterZero=0; if (x>10.0*DBL_MIN) smallestGreaterZero=x; return true; } bool JKQTPGeoInfiniteLine::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) { miny=y; maxy=y; smallestGreaterZero=0; if (y>10.0*DBL_MIN) smallestGreaterZero=y; return true; } void JKQTPGeoInfiniteLine::draw(JKQTPEnhancedPainter& painter) { clearHitTestData(); reserveHitTestData(2); double xmin=parent->getXAxis()->getMin(); double xmax=parent->getXAxis()->getMax(); double ymin=parent->getYAxis()->getMin(); double ymax=parent->getYAxis()->getMax(); QRectF bbox(QPointF(xmin, ymin), QPointF(xmax, ymax)); bool doDraw=false; double x2=x, y2=y; double x1=x, y1=y; // normalize lengh of direction double dl=sqrt(dx*dx+dy*dy); dx=dx/dl; dy=dy/dl; // first catch cases where we are parallel to one coordinate axis if (dy==0) { doDraw=((y>=ymin)&&(y<=ymax)); x1=xmin; x2=xmax; if (!two_sided) { if ((dx>0)&&(x>xmin)) { x1=x; } else if ((dx<0)&&(x=xmin)&&(x<=xmax)); y1=ymin; y2=ymax; if (!two_sided) { if ((dy>0)&&(y>ymin)) { y1=y; } else if ((dy<0)&&(yxmin)&&(xymin use it t1=tymin; if (two_sided) { doDraw=true; } else if (t1>0) { doDraw=true; } else { t1=0; } } else if (xymin0) { doDraw=true; } else { t1=0; } } else if (xymin>xmax) { //(xymin,ymin) is on the right, next to the rectangle, so we have to intersect with x=xmax t1=(xmax-x)/dx; if (two_sided) { doDraw=true; } else if (t1>0) { doDraw=true; } else { t1=0; } } if ((xymax>xmin)&&(xymax use it t2=tymax; if (two_sided) { doDraw=true; } else if (t2>0) { doDraw=true; } else { t2=0; } } else if (xymax0) { doDraw=true; } else { t2=0; } } else if (xymax>xmax) { //(xymax,ymax) is on the right, next to the rectangle, so we have to intersect with x=xmax t2=(xmax-x)/dx; if (two_sided) { doDraw=true; } else if (t2>0) { doDraw=true; } else { t2=0; } } x1=x+t1*dx; y1=y+t1*dy; x2=x+t2*dx; y2=y+t2*dy; } if (doDraw) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(getLinePen(painter, parent)); QLineF l(QPointF(transformX(x1), transformY(y1)), QPointF(transformX(x2), transformY(y2))); if (l.length()>0) { painter.drawLine(l); addHitTestData(x, y, formatHitTestDefaultLabel(x,y)+ QString(", \\ensuremath{\\mathrm{\\mathbf{d}}y/\\mathrm{\\mathbf{d}}x\\;=\\;%1/%2\\;=\\;%3\\;=\\;%4\\degree}").arg(jkqtp_floattolatexqstr(dy, 3)).arg(jkqtp_floattolatexqstr(dx, 3)).arg(jkqtp_floattolatexqstr(dy/dx, 3)).arg(jkqtp_floattolatexqstr(atan2(dy,dx), 1))); addHitTestData(x1, y1); addHitTestData(x2, y2); } } } void JKQTPGeoInfiniteLine::setX(double __value) { this->x = __value; } double JKQTPGeoInfiniteLine::getX() const { return this->x; } void JKQTPGeoInfiniteLine::setY(double __value) { this->y = __value; } double JKQTPGeoInfiniteLine::getY() const { return this->y; } void JKQTPGeoInfiniteLine::setDx(double __value) { this->dx = __value; } double JKQTPGeoInfiniteLine::getDx() const { return this->dx; } void JKQTPGeoInfiniteLine::setDy(double __value) { this->dy = __value; } double JKQTPGeoInfiniteLine::getDy() const { return this->dy; } void JKQTPGeoInfiniteLine::setTwoSided(bool __value) { this->two_sided = __value; } bool JKQTPGeoInfiniteLine::getTwoSided() const { return this->two_sided; } JKQTPGeoPolyLines::JKQTPGeoPolyLines(JKQTBasePlotter* parent, const QVector& points, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoBaseLine(color, lineWidth, style, parent) { this->points=points; } JKQTPGeoPolyLines::JKQTPGeoPolyLines(JKQTPlotter* parent, const QVector& points, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoBaseLine(color, lineWidth, style, parent) { this->points=points; } JKQTPGeoPolyLines::JKQTPGeoPolyLines(JKQTBasePlotter *parent, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoBaseLine(color, lineWidth, style, parent) { } JKQTPGeoPolyLines::JKQTPGeoPolyLines(JKQTPlotter *parent, QColor color, double lineWidth, Qt::PenStyle style): JKQTPGeoBaseLine(color, lineWidth, style, parent) { } bool JKQTPGeoPolyLines::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) { minx=0; maxx=0; smallestGreaterZero=0; if (points.size()>0) { minx=points[0].x(); maxx=points[0].x(); for (int i=1; imaxx) maxx=x; if (x0) { miny=points[0].y(); maxy=points[0].y(); for (int i=1; imaxy) maxy=y; if (y &__value) { this->points = __value; } QVector JKQTPGeoPolyLines::getPoints() const { return this->points; } void JKQTPGeoPolyLines::appendPoint(const QPointF &p) { points.append(p); } void JKQTPGeoPolyLines::appendPoint(const double x, const double y) { points.append(QPointF(x, y)); } JKQTPGeoRectangle::JKQTPGeoRectangle(JKQTBasePlotter* parent, double x, double y, double width, double height, QColor color, double lineWidth, Qt::PenStyle style, QColor fillColor, Qt::BrushStyle fillStyle): JKQTPGeoBaseFilled(color, fillColor, lineWidth, style, fillStyle, parent) { this->x=x; this->y=y; angle=0; this->width=width; this->height=height; } JKQTPGeoRectangle::JKQTPGeoRectangle(JKQTPlotter* parent, double x, double y, double width, double height, QColor color, double lineWidth, Qt::PenStyle style, QColor fillColor, Qt::BrushStyle fillStyle): JKQTPGeoBaseFilled(color, fillColor, lineWidth, style, fillStyle, parent) { this->x=x; this->y=y; angle=0; this->width=width; this->height=height; } JKQTPGeoRectangle::JKQTPGeoRectangle(JKQTBasePlotter *parent, double x, double y, double width, double height, double angle, QColor color, double lineWidth, Qt::PenStyle style, QColor fillColor, Qt::BrushStyle fillStyle): JKQTPGeoBaseFilled(color, fillColor, lineWidth, style, fillStyle, parent) { this->x=x; this->y=y; this->angle=angle; this->width=width; this->height=height; } JKQTPGeoRectangle::JKQTPGeoRectangle(JKQTPlotter *parent, double x, double y, double width, double height, double angle, QColor color, double lineWidth, Qt::PenStyle style, QColor fillColor, Qt::BrushStyle fillStyle): JKQTPGeoBaseFilled(color, fillColor, lineWidth, style, fillStyle, parent) { this->x=x; this->y=y; this->angle=angle; this->width=width; this->height=height; } JKQTPGeoRectangle::JKQTPGeoRectangle(JKQTBasePlotter *parent, QPointF bottomleft, QPointF topright, QColor color, double lineWidth, Qt::PenStyle style, QColor fillColor, Qt::BrushStyle fillStyle): JKQTPGeoBaseFilled(color, fillColor, lineWidth, style, fillStyle, parent) { this->angle=0; this->width=fabs(topright.x()-bottomleft.x()); this->height=fabs(topright.y()-bottomleft.y()); this->x=bottomleft.x()+this->width/2.0; this->y=bottomleft.y()+this->height/2.0; } JKQTPGeoRectangle::JKQTPGeoRectangle(JKQTPlotter *parent, QPointF bottomleft, QPointF topright, QColor color, double lineWidth, Qt::PenStyle style, QColor fillColor, Qt::BrushStyle fillStyle): JKQTPGeoBaseFilled(color, fillColor, lineWidth, style, fillStyle, parent) { this->angle=0; this->width=fabs(topright.x()-bottomleft.x()); this->height=fabs(topright.y()-bottomleft.y()); this->x=bottomleft.x()+this->width/2.0; this->y=bottomleft.y()+this->height/2.0; } QTransform JKQTPGeoRectangle::getTransform() { QTransform trans; trans.rotate(angle); return trans; } bool JKQTPGeoRectangle::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) { QRectF bound=getPolygon().boundingRect(); //std::cout<<"JKQTPGeoRectangle::getXMinMax: b.left="<