diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-07-11 14:15:27 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-07-11 14:15:27 -0500 |
commit | b85a292ce06475d560bfa1195b63a8bfe211f22d (patch) | |
tree | 463d71be55ff807513139f1de106aef6bdd7b4db /lib/tqwtplot3d/src | |
parent | ce039289815e2802fdeca8d384126c807ca9cb58 (diff) | |
download | ulab-b85a292ce06475d560bfa1195b63a8bfe211f22d.tar.gz ulab-b85a292ce06475d560bfa1195b63a8bfe211f22d.zip |
Add 0.2.7 release of qwtplot3d for future TQt3 conversion and use
Diffstat (limited to 'lib/tqwtplot3d/src')
24 files changed, 6329 insertions, 0 deletions
diff --git a/lib/tqwtplot3d/src/qwt3d_autoscaler.cpp b/lib/tqwtplot3d/src/qwt3d_autoscaler.cpp new file mode 100644 index 0000000..6e785cf --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_autoscaler.cpp @@ -0,0 +1,253 @@ +#include "qwt3d_helper.h"
+#include "qwt3d_autoscaler.h"
+
+using namespace Qwt3D;
+
+namespace
+{
+
+double floorExt( int& exponent, double x, std::vector<double>& sortedmantissi)
+{
+ if (x == 0.0)
+ {
+ exponent = 0;
+ return 0.0;
+ }
+
+ double sign = (x > 0) ? 1.0 : -1.0;
+ double lx = log10(fabs(x));
+ exponent = (int)floor(lx);
+
+ double fr = pow(10.0, lx - exponent);
+ if (fr >= 10.0)
+ {
+ fr = 1.0;
+ ++exponent;
+ }
+ else
+ {
+ for (int i=(int)sortedmantissi.size()-1; i>=0;--i)
+ {
+ if (fr>=sortedmantissi[i])
+ {
+ fr = sortedmantissi[i];
+ break;
+ }
+ }
+ }
+ return sign * fr;
+}
+
+/*
+ \brief Find the largest value out of {1,2,5}*10^n with an integer number n
+ which is smaller than or equal to x
+ \param exponent n
+ \param x Input value
+ \return Mantissa
+*/
+double floor125( int& exponent, double x)
+{
+ std::vector<double> m(2);
+ m[0] = 1;
+ m[1] = 2;
+ m[2] = 5;
+ return floorExt(exponent, x, m);
+}
+
+} // anon ns
+
+
+//! Initializes with an {1,2,5} sequence of mantissas
+LinearAutoScaler::LinearAutoScaler()
+{
+ init(0,1,1);
+ mantissi_ = std::vector<double>(3);
+ mantissi_[0] = 1;
+ mantissi_[1] = 2;
+ mantissi_[2] = 5;
+}
+//! Initialize with interval [0,1] and one requested interval
+/*!
+val mantisse A increasing ordered vector of values representing
+mantisse values between 1 and 9.
+*/
+LinearAutoScaler::LinearAutoScaler(std::vector<double>& mantisse)
+{
+ init(0,1,1);
+ if (mantisse.empty())
+ {
+ mantissi_ = std::vector<double>(3);
+ mantissi_[0] = 1;
+ mantissi_[1] = 2;
+ mantissi_[2] = 5;
+ return;
+ }
+ mantissi_ = mantisse;
+}
+
+
+//! Initialize with interval [start,stop] and number of requested intervals
+/**
+ Switchs start and stop, if stop < start and sets intervals = 1 if ivals < 1
+*/
+void LinearAutoScaler::init(double start, double stop, int ivals)
+{
+ start_ = start;
+ stop_ = stop;
+ intervals_ = ivals;
+
+ if (start_ > stop_)
+ {
+ double tmp = start_;
+ start_ = stop_;
+ stop_ = tmp;
+ }
+ if (intervals_ < 1)
+ intervals_ = 1;
+}
+
+/*!
+\return Anchor value
+
+\verbatim
+|_______|____________ _ _ _ _ _____|_____________|________________
+
+0 m*10^n start anchor := c*m*10^n
+
+c 'minimal' (anchor-start < m*10^n)
+\endverbatim
+*/
+double LinearAutoScaler::anchorvalue(double start, double m, int n)
+{
+ double stepval = m * pow(10.0, n);
+ return stepval * ceil(start / stepval);
+}
+
+/*!
+\return New number of intervals (:= l_intervals + r_intervals)
+\param l_intervals Number of intervals left from anchor
+\param r_intervals Number of intervals right from anchor
+
+\verbatim
+ -l_intervals * i -2 * i -i +r_intervals * i
+ |
+|______|_______ _ _ _ ____|____|___ _ _ _ _ _ _ _|_______|_______|_ _ _ _ _ _ _____|__|_____
+ | | | |
+0 i := m*10^n start anchor stop
+
+c 'minimal' (anchor-start < m*10^n)
+\endverbatim
+*/
+int LinearAutoScaler::segments(int& l_intervals, int& r_intervals, double start, double stop, double anchor, double m, int n)
+{
+ double val = m * pow(10.0, n);
+ double delta = (stop - anchor) / val;
+
+ r_intervals = (int)floor(delta); // right side intervals
+
+ delta = (anchor - start) / val;
+
+ l_intervals = (int)floor(delta); // left side intervals
+
+ return r_intervals + l_intervals;
+}
+
+
+/*!
+ \brief Does the actual scaling
+ \return Number of intervals after rescaling. This will in the most cases differ
+ from the requested interval number! Always >0.
+ \param a Start value after scaling (always >= start)
+ \param b Stop value after scaling (always <= stop)
+ \param start Start value
+ \param stop Stop value
+ \param ivals Requested intervals
+ \return Number of intervals after autoscaling
+
+ If the given interval has zero length the function returns the current
+ interval number and a and b remain unchanged.
+*/
+int LinearAutoScaler::execute(double& a, double& b, double start, double stop, int ivals)
+{
+ init(start,stop,ivals);
+
+ double delta = stop_ - start_;
+
+ if (isPracticallyZero(delta))
+ return intervals_;
+
+ double c;
+ int n;
+
+ c = floorExt(n, delta, mantissi_);
+
+ int l_ival, r_ival;
+
+ double anchor = anchorvalue(start_, c, n);
+ int ival = segments(l_ival, r_ival, start_, stop_, anchor, c, n);
+
+ if (ival >= intervals_)
+ {
+ a = anchor - l_ival * c * pow(10.0,n);
+ b = anchor + r_ival * c * pow(10.0,n);
+ intervals_ = ival;
+ return intervals_;
+ }
+
+ int prev_ival, prev_l_ival, prev_r_ival;
+ double prev_anchor;
+ double prev_c;
+ int prev_n;
+
+ while(1)
+ {
+ prev_c = c;
+ prev_n = n;
+ prev_anchor = anchor;
+ prev_ival = ival;
+ prev_l_ival = l_ival;
+ prev_r_ival = r_ival;
+
+
+ if (int(c) == 1)
+ {
+ c = mantissi_.back();
+ --n;
+ }
+ else
+ {
+ for (unsigned int i=mantissi_.size()-1; i>0; --i)
+ {
+ if (int(c) == mantissi_[i])
+ {
+ c = mantissi_[i-1];
+ break;
+ }
+ }
+ }
+
+ anchor = anchorvalue(start_, c, n);
+ ival = segments(l_ival, r_ival, start_, stop_, anchor, c, n);
+
+ int prev_diff = intervals_ - prev_ival;
+ int actual_diff = ival - intervals_;
+
+ if (prev_diff >= 0 && actual_diff >= 0)
+ {
+ if (prev_diff < actual_diff)
+ {
+ c = prev_c;
+ n = prev_n;
+ anchor = prev_anchor;
+ ival = prev_ival;
+ l_ival = prev_l_ival;
+ r_ival = prev_r_ival;
+ }
+ a = anchor - l_ival * c * pow(10.0,n);
+ b = anchor + r_ival * c * pow(10.0,n);
+ intervals_ = ival;
+ break;
+ }
+ }
+ return intervals_;
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_axis.cpp b/lib/tqwtplot3d/src/qwt3d_axis.cpp new file mode 100644 index 0000000..fe45f37 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_axis.cpp @@ -0,0 +1,386 @@ +#include "qwt3d_axis.h"
+
+using namespace Qwt3D;
+
+Axis::Axis()
+{
+ init();
+};
+
+Axis::~Axis()
+{
+}
+
+Axis::Axis(Triple beg, Triple end)
+{
+ init();
+ setPosition(beg,end);
+}
+
+void Axis::init()
+{
+ detachAll();
+
+ scale_ = qwt3d_ptr<Scale>(new LinearScale);
+
+ beg_ = Triple(0.0, 0.0, 0.0);
+ end_ = beg_;
+
+ majorintervals_ = 0;
+ minorintervals_ = 0;
+ setMajors(1);
+ setMinors(1);
+ setLimits(0,0);
+
+ setTicOrientation(0.0, 0.0, 0.0);
+ setTicLength(0.0, 0.0);
+ setColor(0.0, 0.0, 0.0);
+ setLineWidth(1.0);
+ symtics_ = false;
+ drawNumbers_ = false;
+ drawLabel_ = false;
+
+ drawTics_ = false;
+ autoscale_ = true;
+ markerLabel_.clear();
+ numberfont_ = QFont("Courier",12);
+ setLabelFont(QFont("Courier",14));
+
+ numbercolor_ = RGBA(0,0,0,0);
+
+ setNumberAnchor(Center);
+
+ numbergap_ = 0;
+ labelgap_ = 0;
+}
+
+void Axis::setPosition(const Triple& beg, const Triple& end)
+{
+ beg_ = beg;
+ end_ = end;
+}
+
+void Axis::setMajors(int val)
+{
+ if (val == majorintervals_)
+ return;
+
+ majorintervals_ = (val<=0) ? 1 : val; // always >= 1
+}
+
+/*!
+\see LogScale::setMinors().
+*/
+void Axis::setMinors(int val)
+{
+ if (val == minorintervals_)
+ return;
+
+ minorintervals_ = (val<=0) ? 1 : val; // always >= 1
+}
+
+void Axis::setTicLength(double majorl, double minorl)
+{
+ lmaj_ = majorl;
+ lmin_ = minorl;
+}
+
+void Axis::setTicOrientation(double tx, double ty, double tz)
+{
+ setTicOrientation(Triple(tx,ty,tz));
+}
+
+void Axis::setTicOrientation(const Triple& val)
+{
+ orientation_ = val;
+ orientation_.normalize();
+}
+
+/**
+\param val thickness for axis base line
+\param majfac relative thickness for axis major tics (majfac*val)
+\param minfac relative thickness for axis minor tics (minfac*val)
+*/
+void Axis::setLineWidth(double val, double majfac, double minfac)
+{
+ lineWidth_ = val;
+ majLineWidth_ = majfac * lineWidth_;
+ minLineWidth_ = minfac * lineWidth_;
+}
+
+void Axis::draw()
+{
+ Drawable::draw();
+
+ saveGLState();
+
+// GLStateBewarer sb(GL_LINE_SMOOTH, true);
+// glBlendFunc(GL_ONE, GL_ZERO);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4d(color.r,color.g,color.b,color.a);
+
+ drawBase();
+ drawTics();
+ drawLabel();
+
+ restoreGLState();
+}
+
+/**
+Always use AFTER drawNumbers() ! (Needs length of number string)
+*/
+void Axis::drawLabel()
+{
+ if (!drawLabel_)
+ return;
+
+ Triple diff = end() - begin();
+ Triple center = begin() + diff/2;
+
+ Triple bnumber = biggestNumberString();
+// double fac = 6*(second()-first()).length() / 100;
+
+ switch (scaleNumberAnchor_)
+ {
+ case BottomLeft:
+ case TopLeft:
+ case CenterLeft:
+ bnumber.y = 0;
+ break;
+ case BottomRight:
+ case TopRight:
+ case CenterRight:
+ bnumber.x = -bnumber.x;
+ bnumber.y = 0;
+ break;
+ case TopCenter:
+ bnumber.x = 0;
+ bnumber.y = -bnumber.y;
+ break;
+ case BottomCenter:
+ bnumber.x = 0;
+ break;
+ default:
+ break;
+ }
+
+ Triple pos = ViewPort2World(World2ViewPort(center + ticOrientation() * lmaj_) + bnumber);
+ setLabelPosition(pos, scaleNumberAnchor_);
+
+ label_.adjust(labelgap_);
+ label_.draw();
+}
+
+void Axis::drawBase()
+{
+ setDeviceLineWidth( lineWidth_ );
+ glBegin( GL_LINES );
+ glVertex3d( beg_.x, beg_.y, beg_.z);
+ glVertex3d( end_.x, end_.y, end_.z);
+ glEnd();
+}
+
+bool Axis::prepTicCalculation(Triple& startpoint)
+{
+ if (isPracticallyZero(start_, stop_))
+ return false;
+
+ autostart_ = start_;
+ autostop_ = stop_;
+
+ if (autoScale())
+ {
+ setMajors(scale_->autoscale(autostart_, autostop_, start_, stop_, majors()));
+ if (isPracticallyZero(autostart_, autostop_))
+ return false;
+ }
+
+ scale_->setLimits(start_,stop_);
+ scale_->setMajors(majors());
+ scale_->setMinors(minors());
+ scale_->setMajorLimits(autostart_,autostop_);
+ scale_->calculate();
+
+ Triple normal = (end_ - beg_);
+ //normal.normalize();
+ Triple beg = beg_ + ((autostart_ - start_) / (stop_ - start_)) * normal;
+ Triple end = end_ - ((stop_ - autostop_) / (stop_ - start_))* normal;
+
+ startpoint = end_ - beg_;
+
+ majorpos_.clear();
+ minorpos_.clear();
+
+ return true;
+}
+
+void Axis::recalculateTics()
+{
+ Triple runningpoint;
+ if (false==prepTicCalculation(runningpoint))
+ return;
+
+ unsigned int i;
+
+ for (i = 0; i != scale_->majors_p.size(); ++i)
+ {
+ double t = (scale_->majors_p[i] - start_) / (stop_-start_);
+ majorpos_.push_back(beg_ + t * runningpoint);
+ }
+ for (i = 0; i != scale_->minors_p.size(); ++i)
+ {
+ double t = (scale_->minors_p[i] - start_) / (stop_-start_);
+ minorpos_.push_back(beg_ + t * runningpoint);
+ }
+}
+
+void Axis::drawTics()
+{
+ Triple runningpoint;
+ if (!drawTics_ || false==prepTicCalculation(runningpoint))
+ return;
+
+ unsigned int i;
+ Triple nadir;
+
+ markerLabel_.resize(scale_->majors_p.size());
+ setDeviceLineWidth(majLineWidth_);
+ for (i = 0; i != scale_->majors_p.size(); ++i)
+ {
+ double t = (scale_->majors_p[i] - start_) / (stop_-start_);
+ nadir = beg_ + t * runningpoint;
+ majorpos_.push_back(drawTic(nadir, lmaj_));
+ drawTicLabel(nadir + 1.2 * lmaj_ * orientation_, i);
+ }
+ setDeviceLineWidth(minLineWidth_);
+ for (i = 0; i != scale_->minors_p.size(); ++i)
+ {
+ double t = (scale_->minors_p[i] - start_) / (stop_-start_);
+ nadir = beg_ + t * runningpoint;
+ minorpos_.push_back(drawTic(nadir, lmin_));
+ }
+}
+
+void Axis::drawTicLabel(Triple pos, int mtic)
+{
+ if (!drawNumbers_ || (mtic < 0))
+ return;
+
+ markerLabel_[mtic].setFont(numberfont_.family(), numberfont_.pointSize(), numberfont_.weight(), numberfont_.italic());
+ markerLabel_[mtic].setColor(numbercolor_);
+ markerLabel_[mtic].setString(scale_->ticLabel(mtic));
+ markerLabel_[mtic].setPosition(pos, scaleNumberAnchor_);
+ markerLabel_[mtic].adjust(numbergap_);
+ markerLabel_[mtic].draw();
+}
+
+Triple Axis::drawTic(Triple nadir, double length)
+{
+ double ilength = (symtics_) ? -length : 0.0;
+
+ glBegin( GL_LINES );
+ glVertex3d( nadir.x + ilength * orientation_.x,
+ nadir.y + ilength * orientation_.y,
+ nadir.z + ilength * orientation_.z) ;
+ glVertex3d( nadir.x + length * orientation_.x,
+ nadir.y + length * orientation_.y,
+ nadir.z + length * orientation_.z);
+ glEnd();
+ return nadir;
+}
+
+void Axis::setNumberFont(QString const& family, int pointSize, int weight, bool italic)
+{
+ numberfont_ = QFont(family, pointSize, weight, italic );
+}
+
+void Axis::setNumberFont(QFont const& font)
+{
+ numberfont_ = font;
+}
+
+void Axis::setNumberColor(RGBA col)
+{
+ numbercolor_ = col;
+}
+
+void Axis::setLabelFont(QString const& family, int pointSize, int weight, bool italic)
+{
+ labelfont_ = QFont(family, pointSize, weight, italic );
+ label_.setFont(family, pointSize, weight, italic);
+}
+
+void Axis::setLabelFont(QFont const& font)
+{
+ setLabelFont(font.family(), font.pointSize(), font.weight(), font.italic());
+}
+
+void Axis::setLabelString(QString const& name)
+{
+ label_.setString(name);
+}
+
+/*!
+ Sets label position in conjunction with an anchoring strategy
+*/
+void Axis::setLabelPosition(const Triple& pos,Qwt3D::ANCHOR an)
+{
+ label_.setPosition(pos, an);
+}
+
+//! Sets color for label
+void Axis::setLabelColor(RGBA col)
+{
+ label_.setColor(col);
+}
+
+Triple Axis::biggestNumberString()
+{
+ Triple ret;
+ unsigned size = markerLabel_.size();
+
+ double width, height;
+
+ for (unsigned i=0; i!=size; ++i)
+ {
+ width = fabs( (World2ViewPort(markerLabel_[i].second())-World2ViewPort(markerLabel_[i].first())).x );
+ height = fabs( (World2ViewPort(markerLabel_[i].second())-World2ViewPort(markerLabel_[i].first())).y );
+
+ if (width > ret.x)
+ ret.x = width + markerLabel_[i].gap();
+ if (height > ret.y)
+ ret.y = height + markerLabel_[i].gap();;
+ }
+ return ret;
+}
+
+/*!
+ This variant sets a user-defined scale object.
+ Use with a heap based initialized pointer only.
+ The axis adopts ownership.
+*/
+void Axis::setScale(Scale* val)
+{
+ scale_ = qwt3d_ptr<Scale>(val);
+}
+
+/*!
+ Sets one of the predefined scaling types.
+ \warning Too small intervals in logarithmic scales lead to
+ empty scales (or perhaps a scale only containing an isolated
+ major tic). Better switch to linear scales in such cases.
+*/
+void Axis::setScale(Qwt3D::SCALETYPE val)
+{
+ switch(val) {
+ case Qwt3D::LINEARSCALE:
+ setScale(new LinearScale);
+ break;
+ case Qwt3D::LOG10SCALE:
+ setScale(new LogScale);
+ setMinors(9);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_color.cpp b/lib/tqwtplot3d/src/qwt3d_color.cpp new file mode 100644 index 0000000..5543a8a --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_color.cpp @@ -0,0 +1,63 @@ +#include "qwt3d_color.h"
+#include "qwt3d_plot.h"
+
+using namespace Qwt3D;
+
+StandardColor::StandardColor(Plot3D* data, unsigned size)
+ : data_(data)
+{
+ Q_ASSERT(data_);
+
+ reset(size);
+}
+
+void StandardColor::reset(unsigned size)
+{
+ colors_ = ColorVector(size);
+ RGBA elem;
+
+ double dsize = size;
+
+ for (unsigned int i=0; i!=size; ++i)
+ {
+ elem.r = i / dsize;
+ elem.g = i / dsize / 4;
+ elem.b = 1 - i/dsize;
+ elem.a = 1.0;
+ colors_[i] = elem;
+ }
+}
+
+/**
+ Assigns a new ColorVector (Also overwrites the constructors size argument)
+*/
+void StandardColor::setColorVector(ColorVector const& cv)
+{
+ colors_ = cv;
+}
+
+void StandardColor::setAlpha(double a)
+{
+ if (a<0 || a>1)
+ return;
+
+ RGBA elem;
+
+ for (unsigned int i=0; i!=colors_.size(); ++i)
+ {
+ elem = colors_[i];
+ elem.a = a;
+ colors_[i] = elem;
+ }
+}
+
+RGBA StandardColor::operator()(double, double, double z) const
+{
+ Q_ASSERT(data_);
+ int index = (int)((colors_.size()-1) * (z - data_->hull().minVertex.z) / (data_->hull().maxVertex.z-data_->hull().minVertex.z));
+ if (index < 0)
+ index = 0;
+ if ((unsigned int)index > colors_.size() - 1)
+ index = (int)(colors_.size() - 1);
+ return colors_[index];
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_colorlegend.cpp b/lib/tqwtplot3d/src/qwt3d_colorlegend.cpp new file mode 100644 index 0000000..2b114aa --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_colorlegend.cpp @@ -0,0 +1,223 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#endif
+
+#include "qwt3d_colorlegend.h"
+
+using namespace Qwt3D;
+
+/**
+Contructs a legend object with an axis at the left
+side. The legend resides in the top-right area
+and has no caption. Scale numbering is shown.
+*/
+ColorLegend::ColorLegend()
+{
+ axis_.setNumbers(true);
+ axis_.setScaling(true);
+ axis_.setNumberColor(RGBA(0,0,0,1));
+ axis_.setNumberAnchor(CenterRight);
+ axis_.setNumberFont(QFont("Courier",8));
+
+ caption_.setFont("Courier", 10, QFont::Bold);
+ caption_.setColor(RGBA(0,0,0,1));
+ axisposition_ = ColorLegend::Left;
+ orientation_ = ColorLegend::BottomTop;
+ showaxis_ = true;
+ setRelPosition(Tuple(0.94, 1-0.36),Tuple(0.97, 1-0.04));
+}
+
+void ColorLegend::setTitleString(QString const& s)
+{
+ caption_.setString(s);
+}
+
+void ColorLegend::setTitleFont(QString const& family, int pointSize, int weight, bool italic)
+{
+ caption_.setFont(family, pointSize, weight, italic);
+}
+
+void ColorLegend::setLimits(double start, double stop)
+{
+ axis_.setLimits(start, stop);
+}
+
+void ColorLegend::setMajors(int majors)
+{
+ axis_.setMajors(majors);
+}
+
+void ColorLegend::setMinors(int minors)
+{
+ axis_.setMinors(minors);
+}
+
+void ColorLegend::setAutoScale(bool val)
+{
+ axis_.setAutoScale(val);
+}
+
+void ColorLegend::setScale(SCALETYPE val)
+{
+ axis_.setScale(val);
+}
+
+void ColorLegend::setScale(Scale* val)
+{
+ axis_.setScale(val);
+}
+
+
+void ColorLegend::setOrientation(ORIENTATION orientation, SCALEPOSITION pos)
+{
+ orientation_ = orientation;
+ axisposition_ = pos;
+
+ if (orientation_==BottomTop)
+ {
+ if (axisposition_ == Bottom || axisposition_ == Top)
+ axisposition_ = Left;
+ }
+ else
+ {
+ if (axisposition_ == Left || axisposition_ == Right)
+ axisposition_ = Bottom;
+ }
+}
+
+void ColorLegend::setRelPosition(Tuple relMin, Tuple relMax)
+{
+ relMin_ = relMin;
+ relMax_ = relMax;
+}
+
+void ColorLegend::setGeometryInternal()
+{
+ double ot = .99;
+
+ getMatrices(modelMatrix, projMatrix, viewport);
+ pe_.minVertex = relativePosition(Triple(relMin_.x, relMin_.y, ot));
+ pe_.maxVertex = relativePosition(Triple(relMax_.x, relMax_.y, ot));
+
+ double diff = 0;
+ Triple b;
+ Triple e;
+
+ switch (axisposition_)
+ {
+ case ColorLegend::Left:
+ b = pe_.minVertex;
+ e = pe_.maxVertex; e.x = b.x;
+ axis_.setTicOrientation(-1,0,0);
+ axis_.setNumberAnchor(CenterRight);
+ diff = pe_.maxVertex.x - pe_.minVertex.x;
+ break;
+ case ColorLegend::Right:
+ e = pe_.maxVertex;
+ b = pe_.minVertex; b.x = e.x;
+ axis_.setTicOrientation(+1,0,0);
+ axis_.setNumberAnchor(CenterLeft);
+ diff = pe_.maxVertex.x - pe_.minVertex.x;
+ break;
+ case ColorLegend::Top:
+ e = pe_.maxVertex;
+ b = pe_.minVertex; b.z = e.z;
+ axis_.setTicOrientation(0,0,+1);
+ axis_.setNumberAnchor(BottomCenter);
+ diff = pe_.maxVertex.z - pe_.minVertex.z;
+ break;
+ case ColorLegend::Bottom:
+ b = pe_.minVertex;
+ e = pe_.maxVertex; e.z = b.z;
+ axis_.setTicOrientation(0,0,-1);
+ axis_.setNumberAnchor(TopCenter);
+ diff = pe_.maxVertex.z - pe_.minVertex.z;
+ break;
+ default:
+ break;
+ }
+
+ axis_.setPosition(b,e);
+ diff /= 10;
+
+ axis_.setTicLength(diff, 0.6*diff);
+
+ Triple c;
+ c.x = pe_.minVertex.x + ((pe_.maxVertex-pe_.minVertex) / 2).x;
+ c.z = pe_.maxVertex.z;
+ c.z += (pe_.maxVertex.z-pe_.minVertex.z)/20;
+ c.y = pe_.maxVertex.y;
+
+ caption_.setPosition(c, BottomCenter);
+}
+
+void ColorLegend::draw()
+{
+ if (colors.empty())
+ return;
+
+ setGeometryInternal();
+
+ saveGLState();
+
+ Triple one = pe_.minVertex;
+ Triple two = pe_.maxVertex;
+
+ double h = (orientation_ == ColorLegend::BottomTop)
+ ? (two-one).z / colors.size()
+ : (two-one).x / colors.size();
+
+ //glEnable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ GLStateBewarer(GL_POLYGON_OFFSET_FILL,true);
+// glPolygonOffset(0.0, 0.0);
+
+ glColor4d(0, 0, 0, 1);
+ glBegin(GL_LINE_LOOP);
+ glVertex3d(one.x, one.y, one.z);
+ glVertex3d(one.x, one.y, two.z);
+ glVertex3d(two.x, one.y, two.z);
+ glVertex3d(two.x, one.y, one.z);
+ glEnd();
+
+
+ unsigned size = colors.size();
+ RGBA rgb;
+
+ if (orientation_ == ColorLegend::BottomTop)
+ {
+ for (unsigned i=1; i<=size; ++i)
+ {
+ rgb = colors[i-1];
+ glColor4d(rgb.r,rgb.g,rgb.b,rgb.a);
+ glBegin( GL_POLYGON );
+ glVertex3d( one.x, one.y, one.z+(i-1)*h );
+ glVertex3d( one.x, one.y, one.z+i*h );
+ glVertex3d( two.x, one.y, one.z+i*h );
+ glVertex3d( two.x, one.y, one.z+(i-1)*h );
+ glEnd();
+ }
+ }
+ else
+ {
+ for (unsigned i=1; i<=size; ++i)
+ {
+ rgb = colors[i-1];
+ glColor4d(rgb.r,rgb.g,rgb.b,rgb.a);
+ glBegin( GL_POLYGON );
+ glVertex3d( one.x+(i-1)*h, one.y, one.z );
+ glVertex3d( one.x+i*h, one.y, one.z );
+ glVertex3d( one.x+i*h, one.y, two.z );
+ glVertex3d( one.x+(i-1)*h, one.y, two.z );
+ glEnd();
+ }
+ }
+
+ restoreGLState();
+
+ if (showaxis_)
+ axis_.draw();
+
+ caption_.draw();
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_coordsys.cpp b/lib/tqwtplot3d/src/qwt3d_coordsys.cpp new file mode 100644 index 0000000..2aae28d --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_coordsys.cpp @@ -0,0 +1,633 @@ +#include "qwt3d_coordsys.h"
+
+using namespace std;
+using namespace Qwt3D;
+
+
+CoordinateSystem::CoordinateSystem(Triple first, Triple second, COORDSTYLE st)
+{
+ autodecoration_ = true;
+ axes = std::vector<Axis>(12);
+ setStyle(st);
+ setLineSmooth(true);
+ init(first,second);
+
+ setAxesColor(RGBA(0,0,0,1));
+ setGridLinesColor(RGBA(0.2,0.2,0.2,1));
+ setNumberFont("Courier", 12);
+ setNumberColor(RGBA(0,0,0));
+ setLabelFont("Courier", 14, QFont::Bold);
+ setGridLines(false, false);
+}
+
+CoordinateSystem::~CoordinateSystem()
+{
+ destroy();
+}
+
+void CoordinateSystem::destroy()
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setLabelString("");
+
+ detachAll();
+}
+
+void CoordinateSystem::init(Triple first, Triple second)
+{
+ destroy();
+
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setScale(LINEARSCALE);
+
+ Triple dv = second - first;
+
+ setPosition(first, second);
+
+ double majl = dv.length() / 100; // 1 %
+ setTicLength(majl, 0.6 * majl);
+
+ axes[X1].setPosition(first, first+Triple(dv.x, 0, 0)); // front bottom x
+ axes[Y1].setPosition(first, first+Triple( 0, dv.y, 0)); // bottom left y
+ axes[Z1].setPosition (first+Triple( 0, dv.y, 0), first+Triple( 0, dv.y, dv.z)); // back left z
+ axes[X1].setTicOrientation(0,-1,0);
+ axes[Y1].setTicOrientation(-1,0,0);
+ axes[Z1].setTicOrientation(-1,0,0);
+
+ axes[X1].setLimits(first.x, second.x);
+ axes[X2].setLimits(first.x, second.x);
+ axes[X3].setLimits(first.x, second.x);
+ axes[X4].setLimits(first.x, second.x);
+
+ axes[Y1].setLimits(first.y, second.y);
+ axes[Y2].setLimits(first.y, second.y);
+ axes[Y3].setLimits(first.y, second.y);
+ axes[Y4].setLimits(first.y, second.y);
+
+ axes[Z1].setLimits(first.z, second.z);
+ axes[Z2].setLimits(first.z, second.z);
+ axes[Z3].setLimits(first.z, second.z);
+ axes[Z4].setLimits(first.z, second.z);
+
+ // remaining x axes
+ axes[X2].setPosition(first+Triple( 0, 0, dv.z), first+Triple( dv.x, 0, dv.z)); // front top x
+ axes[X3].setPosition(first+Triple( 0, dv.y, dv.z), second); // back top x
+ axes[X4].setPosition(first+Triple( 0, dv.y, 0), first+Triple( dv.x, dv.y, 0)); // back bottom x
+ axes[X2].setTicOrientation(0,-1,0);
+ axes[X3].setTicOrientation(0,1,0);
+ axes[X4].setTicOrientation(0,1,0);
+
+ // remaining y axes
+ axes[Y2].setPosition(first+Triple(dv.x, 0, 0), first+Triple(dv.x, dv.y, 0)); // bottom right y
+ axes[Y3].setPosition(first+Triple(dv.x, 0, dv.z), second); // top right y
+ axes[Y4].setPosition(first+Triple(0, 0, dv.z), first+Triple(0, dv.y, dv.z)); // top left y
+ axes[Y2].setTicOrientation(1,0,0);
+ axes[Y3].setTicOrientation(1,0,0);
+ axes[Y4].setTicOrientation (-1,0,0);
+
+ // remaining z axes
+ axes[Z2].setPosition(first, first+Triple( 0, 0, dv.z)); // front left z
+ axes[Z4].setPosition(first+Triple(dv.x, dv.y, 0), second ); // back right z
+ axes[Z3].setPosition(first+Triple(dv.x, 0, 0), first+Triple(dv.x, 0, dv.z)); // front right z
+ axes[Z2].setTicOrientation(-1,0,0);
+ axes[Z4].setTicOrientation(1,0,0);
+ axes[Z3].setTicOrientation(1,0,0);
+
+ setStyle(style_);
+}
+
+void CoordinateSystem::draw()
+{
+// saveGLState();
+
+ GLStateBewarer sb(GL_LINE_SMOOTH, true);
+
+ if (!lineSmooth())
+ sb.turnOff();
+
+
+ if (autoDecoration())
+ chooseAxes();
+
+ Drawable::draw();
+
+ if( style_ == NOCOORD)
+ return;
+
+ if (majorgridlines_ || minorgridlines_)
+ recalculateAxesTics();
+ if (majorgridlines_)
+ drawMajorGridLines();
+ if (minorgridlines_)
+ drawMinorGridLines();
+
+ // restoreGLState();
+}
+
+
+//! build convex hull (6 axes: 2 x, 2 y, 2 z) and choose one of them at a time for scales, labels etc.
+void CoordinateSystem::chooseAxes()
+{
+ vector<Triple> beg(axes.size());
+ vector<Triple> end(axes.size());
+ vector<Tuple> src(2*axes.size());
+
+ unsigned i;
+ // collect axes viewport coordinates and initialize
+ for (i=0; i!=axes.size(); ++i)
+ {
+ if (style() != NOCOORD)
+ attach(&axes[i]);
+
+ beg[i] = World2ViewPort(axes[i].begin());
+ end[i] = World2ViewPort(axes[i].end());
+ src[i] = Tuple(beg[i].x, beg[i].y);
+ src[axes.size()+i] = Tuple(end[i].x, end[i].y);
+
+ axes[i].setScaling(false);
+ axes[i].setNumbers(false);
+ axes[i].setLabel(false);
+ }
+
+ vector<unsigned> idx;
+ convexhull2d(idx,src);
+
+ int rem_x = -1;
+ int rem_y = -1;
+ int rem_z = -1;
+
+
+ bool left;
+
+ int choice_x = -1;
+ int choice_y = -1;
+ int choice_z = -1;
+
+ int other_x = -1;
+ int other_y = -1;
+ int other_z = -1;
+
+ //traverse convex hull
+ for (unsigned k=0; k!=idx.size(); ++k)
+ {
+ Triple one, two;
+
+ if (idx[k] >= axes.size()) // is end point
+ one = end[idx[k]-axes.size()];
+ else // is begin point
+ one = beg[idx[k]];
+
+ unsigned int next = idx[(k+1) % idx.size()]; // next point in cv (considered as ring buffer of points)
+
+ if (next >= axes.size())
+ two = end[next-axes.size()];
+ else
+ two = beg[next];
+
+ for (i=0; i!=axes.size(); ++i)
+ {
+ if (
+ (one == beg[i] && two == end[i])
+ ||
+ (two == beg[i] && one == end[i])
+ )
+ {
+ if (i==X1 || i==X2 || i==X3 || i==X4) // x Achsen
+ {
+ if (rem_x>=0) // schon zweite Achse der konvexen Huelle ?
+ {
+ // untere der beiden x Achsen
+ double y = min(min(end[rem_x].y,end[i].y),min(beg[rem_x].y,beg[i].y));
+ choice_x = (y == beg[i].y || y == end[i].y) ? i : rem_x;
+
+ other_x = (choice_x == (int)i) ? rem_x : (int)i;
+ left = (beg[choice_x].x < beg[other_x].x || end[choice_x].x < end[other_x].x)
+ ? true
+ : false;
+
+ autoDecorateExposedAxis(axes[choice_x], left);
+
+ rem_x = -1;
+ }
+ else
+ {
+ rem_x = i;
+ }
+ }
+ else if (i==Y1 || i==Y2 || i==Y3 || i==Y4)
+ {
+ if (rem_y>=0)
+ {
+ // untere der beiden y Achsen
+ double y = min(min(end[rem_y].y,end[i].y),min(beg[rem_y].y,beg[i].y));
+ choice_y = (y == beg[i].y || y == end[i].y) ? i : rem_y;
+
+ other_y = (choice_y == (int)i) ? rem_y : (int)i;
+ left = (beg[choice_y].x < beg[other_y].x || end[choice_y].x < end[other_y].x)
+ ? true
+ : false;
+ autoDecorateExposedAxis(axes[choice_y], left);
+
+ rem_y = -1;
+ }
+ else
+ {
+ rem_y = i;
+ }
+ }
+ else if (i==Z1 || i==Z2 || i==Z3 || i==Z4)
+ {
+ if (rem_z>=0)
+ {
+ // hintere der beiden z Achsen
+ double z = max(max(end[rem_z].z,end[i].z),max(beg[rem_z].z,beg[i].z));
+ choice_z = (z == beg[i].z || z == end[i].z) ? i : rem_z;
+
+ other_z = (choice_z == (int)i) ? rem_z : (int)i;
+
+ rem_z = -1;
+
+ }
+ else
+ {
+ rem_z = i;
+ }
+ }
+ }
+ } // for axes
+ } // for idx
+
+ // fit z axis in - the onthewall axis if the decorated axes build a continous line, the opposite else
+ if (choice_x>=0 && choice_y>=0 && choice_z>=0)
+ {
+ left = (beg[choice_z].x < beg[other_z].x || end[choice_z].x < end[other_z].x)
+ ? true
+ : false;
+
+
+ if (
+ axes[choice_z].begin() == axes[choice_x].begin()
+ || axes[choice_z].begin() == axes[choice_x].end()
+ || axes[choice_z].begin() == axes[choice_y].begin()
+ || axes[choice_z].begin() == axes[choice_y].end()
+ || axes[choice_z].end() == axes[choice_x].begin()
+ || axes[choice_z].end() == axes[choice_x].end()
+ || axes[choice_z].end() == axes[choice_y].begin()
+ || axes[choice_z].end() == axes[choice_y].end()
+
+ )
+ {
+ autoDecorateExposedAxis(axes[choice_z], left);
+ }
+
+ else
+ {
+ autoDecorateExposedAxis(axes[other_z], !left);
+ choice_z = other_z; // for FRAME
+ }
+ }
+
+ if (style() == FRAME)
+ {
+ for (i=0; i!=axes.size(); ++i)
+ {
+ if ((int)i!=choice_x && (int)i!=choice_y && (int)i!=choice_z)
+ detach(&axes[i]);
+ }
+ }
+
+}
+
+
+void CoordinateSystem::autoDecorateExposedAxis(Axis& ax, bool left)
+{
+ Triple diff = World2ViewPort(ax.end()) - World2ViewPort(ax.begin());
+
+ diff = Triple(diff.x,diff.y,0); // projection
+
+ double s = diff.length();
+
+ if (!s)
+ return;
+
+ ax.setScaling(true);
+ ax.setNumbers(true);
+ ax.setLabel(true);
+
+ const double SQRT_2 = 0.7071067;
+ double sina = fabs(diff.y / s);
+
+
+ if (left) // leftmost (compared with antagonist in CV) axis -> draw decorations on the left side
+ {
+ if ( diff.x >= 0 && diff.y >= 0 && sina < SQRT_2) // 0..Pi/4
+ {
+ ax.setNumberAnchor(BottomCenter);
+ }
+ else if ( diff.x >= 0 && diff.y >= 0 && !left) // octant 2
+ {
+ ax.setNumberAnchor(CenterRight);
+ }
+ else if ( diff.x <= 0 && diff.y >= 0 && sina >= SQRT_2) // octant 3
+ {
+ ax.setNumberAnchor(CenterRight);
+ }
+ else if ( diff.x <= 0 && diff.y >= 0 ) // octant 4
+ {
+ ax.setNumberAnchor(TopCenter);
+ }
+ else if ( diff.x <= 0 && diff.y <= 0 && sina <= SQRT_2) // octant 5
+ {
+ ax.setNumberAnchor(BottomCenter);
+ }
+ else if ( diff.x <= 0 && diff.y <= 0) // octant 6
+ {
+ ax.setNumberAnchor(CenterRight);
+ }
+ else if ( diff.x >= 0 && diff.y <= 0 && sina >= SQRT_2) // octant 7
+ {
+ ax.setNumberAnchor(CenterRight);
+ }
+ else if ( diff.x >= 0 && diff.y <= 0) // octant 8
+ {
+ ax.setNumberAnchor(TopCenter);
+ }
+ }
+ else // rightmost axis
+ {
+ if ( diff.x >= 0 && diff.y >= 0 && sina <= SQRT_2)
+ {
+ ax.setNumberAnchor(TopCenter);
+ }
+ else if ( diff.x >= 0 && diff.y >= 0 && !left)
+ {
+ ax.setNumberAnchor(CenterLeft);
+ }
+ else if ( diff.x <= 0 && diff.y >= 0 && sina >= SQRT_2)
+ {
+ ax.setNumberAnchor(CenterLeft);
+ }
+ else if ( diff.x <= 0 && diff.y >= 0)
+ {
+ ax.setNumberAnchor(BottomCenter);
+ }
+ else if ( diff.x <= 0 && diff.y <= 0 && sina <= SQRT_2)
+ {
+ ax.setNumberAnchor(TopCenter);
+ }
+ else if ( diff.x <= 0 && diff.y <= 0)
+ {
+ ax.setNumberAnchor(CenterLeft);
+ }
+ else if ( diff.x >= 0 && diff.y <= 0 && sina >= SQRT_2)
+ {
+ ax.setNumberAnchor(CenterLeft);
+ }
+ else if ( diff.x >= 0 && diff.y <= 0)
+ {
+ ax.setNumberAnchor(BottomCenter);
+ }
+ }
+}
+
+
+void CoordinateSystem::setPosition(Triple first, Triple second)
+{
+ first_ = first;
+ second_ = second;
+}
+
+void CoordinateSystem::setTicLength(double major, double minor)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setTicLength(major, minor);
+}
+
+void CoordinateSystem::adjustNumbers(int val)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].adjustNumbers(val);
+}
+
+void CoordinateSystem::adjustLabels(int val)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].adjustLabel(val);
+}
+
+void CoordinateSystem::setAutoScale(bool val)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setAutoScale(val);
+}
+
+void CoordinateSystem::setAxesColor(RGBA val)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setColor(val);
+}
+
+void CoordinateSystem::recalculateAxesTics()
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].recalculateTics();
+}
+
+void CoordinateSystem::setNumberFont(QString const& family, int pointSize, int weight, bool italic)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setNumberFont(family,pointSize,weight,italic);
+}
+
+void CoordinateSystem::setNumberFont(QFont const& font)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setNumberFont(font);
+}
+
+void CoordinateSystem::setNumberColor(RGBA val)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setNumberColor( val);
+}
+
+void CoordinateSystem::setStandardScale()
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setScale(LINEARSCALE);
+}
+
+void CoordinateSystem::setLabelFont(QFont const& font)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setLabelFont(font);
+}
+
+
+void CoordinateSystem::setLabelFont(QString const& family, int pointSize, int weight, bool italic)
+{
+ setLabelFont(QFont(family,pointSize,weight,italic));
+}
+
+void CoordinateSystem::setLabelColor(RGBA val)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setLabelColor(val);
+}
+
+void CoordinateSystem::setLineWidth(double val, double majfac, double minfac)
+{
+ for (unsigned i=0; i!=axes.size(); ++i)
+ axes[i].setLineWidth(val, majfac, minfac);
+}
+
+void CoordinateSystem::setStyle(COORDSTYLE s, AXIS frame_1, AXIS frame_2, AXIS frame_3)
+{
+ style_ = s;
+
+ switch (s)
+ {
+ case NOCOORD:
+ {
+ for (unsigned i=0; i!=axes.size(); ++i)
+ detach (&axes[i]);
+ }
+ break;
+ case BOX:
+ {
+ for (unsigned i=0; i!=axes.size(); ++i)
+ attach (&axes[i]);
+ }
+ break;
+ case FRAME:
+ {
+ for (unsigned i=0; i!=axes.size(); ++i)
+ detach (&axes[i]);
+ if (!autoDecoration())
+ {
+ attach(&axes[frame_1]);
+ attach(&axes[frame_2]);
+ attach(&axes[frame_3]);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+The axis used for tic calculation is chosen randomly from the respective pair.
+For most cases an identical tic distribution is therefore recommended.
+\param majors Draw grid between major tics
+\param minors Draw grid between minor tics
+\param sides Side(s), where the grid should be drawn
+*/
+void CoordinateSystem::setGridLines(bool majors, bool minors, int sides)
+{
+ sides_ = sides;
+ majorgridlines_ = majors;
+ minorgridlines_ = minors;
+}
+
+void CoordinateSystem::drawMajorGridLines()
+{
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4d(gridlinecolor_.r,gridlinecolor_.g,gridlinecolor_.b,gridlinecolor_.a);
+ setDeviceLineWidth(axes[X1].majLineWidth());
+
+ glBegin( GL_LINES );
+ if (sides_ & Qwt3D::FLOOR)
+ {
+ drawMajorGridLines(axes[X1],axes[X4]);
+ drawMajorGridLines(axes[Y1],axes[Y2]);
+ }
+ if (sides_ & Qwt3D::CEIL)
+ {
+ drawMajorGridLines(axes[X2],axes[X3]);
+ drawMajorGridLines(axes[Y3],axes[Y4]);
+ }
+ if (sides_ & Qwt3D::LEFT)
+ {
+ drawMajorGridLines(axes[Y1],axes[Y4]);
+ drawMajorGridLines(axes[Z1],axes[Z2]);
+ }
+ if (sides_ & Qwt3D::RIGHT)
+ {
+ drawMajorGridLines(axes[Y2],axes[Y3]);
+ drawMajorGridLines(axes[Z3],axes[Z4]);
+ }
+ if (sides_ & Qwt3D::FRONT)
+ {
+ drawMajorGridLines(axes[X1],axes[X2]);
+ drawMajorGridLines(axes[Z2],axes[Z3]);
+ }
+ if (sides_ & Qwt3D::BACK)
+ {
+ drawMajorGridLines(axes[X3],axes[X4]);
+ drawMajorGridLines(axes[Z4],axes[Z1]);
+ }
+ glEnd();
+}
+
+void CoordinateSystem::drawMinorGridLines()
+{
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4d(gridlinecolor_.r,gridlinecolor_.g,gridlinecolor_.b,gridlinecolor_.a);
+ setDeviceLineWidth(axes[X1].minLineWidth());
+
+ glBegin( GL_LINES );
+ if (sides_ & Qwt3D::FLOOR)
+ {
+ drawMinorGridLines(axes[X1],axes[X4]);
+ drawMinorGridLines(axes[Y1],axes[Y2]);
+ }
+ if (sides_ & Qwt3D::CEIL)
+ {
+ drawMinorGridLines(axes[X2],axes[X3]);
+ drawMinorGridLines(axes[Y3],axes[Y4]);
+ }
+ if (sides_ & Qwt3D::LEFT)
+ {
+ drawMinorGridLines(axes[Y1],axes[Y4]);
+ drawMinorGridLines(axes[Z1],axes[Z2]);
+ }
+ if (sides_ & Qwt3D::RIGHT)
+ {
+ drawMinorGridLines(axes[Y2],axes[Y3]);
+ drawMinorGridLines(axes[Z3],axes[Z4]);
+ }
+ if (sides_ & Qwt3D::FRONT)
+ {
+ drawMinorGridLines(axes[X1],axes[X2]);
+ drawMinorGridLines(axes[Z2],axes[Z3]);
+ }
+ if (sides_ & Qwt3D::BACK)
+ {
+ drawMinorGridLines(axes[X3],axes[X4]);
+ drawMinorGridLines(axes[Z4],axes[Z1]);
+ }
+ glEnd();
+}
+
+void CoordinateSystem::drawMajorGridLines(Axis& a0, Axis& a1)
+{
+ Triple d = a1.begin()-a0.begin();
+
+ for (unsigned int i=0; i!=a0.majorPositions().size(); ++i)
+ {
+ glVertex3d( a0.majorPositions()[i].x, a0.majorPositions()[i].y, a0.majorPositions()[i].z );
+ glVertex3d( a0.majorPositions()[i].x + d.x, a0.majorPositions()[i].y + d.y, a0.majorPositions()[i].z +d.z);
+ }
+}
+
+void CoordinateSystem::drawMinorGridLines(Axis& a0, Axis& a1)
+{
+ Triple d = a1.begin()-a0.begin();
+
+ for (unsigned int i=0; i!=a0.minorPositions().size(); ++i)
+ {
+ glVertex3d( a0.minorPositions()[i].x, a0.minorPositions()[i].y, a0.minorPositions()[i].z );
+ glVertex3d( a0.minorPositions()[i].x + d.x, a0.minorPositions()[i].y + d.y, a0.minorPositions()[i].z +d.z);
+ }
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_dataviews.cpp b/lib/tqwtplot3d/src/qwt3d_dataviews.cpp new file mode 100644 index 0000000..7a022dd --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_dataviews.cpp @@ -0,0 +1,10 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#pragma warning ( disable : 4786 )
+#endif
+
+#include "qwt3d_plot.h"
+
+using namespace std;
+using namespace Qwt3D;
+
diff --git a/lib/tqwtplot3d/src/qwt3d_drawable.cpp b/lib/tqwtplot3d/src/qwt3d_drawable.cpp new file mode 100644 index 0000000..4025817 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_drawable.cpp @@ -0,0 +1,140 @@ +#include "qwt3d_drawable.h"
+
+using namespace Qwt3D;
+
+Drawable::~Drawable()
+{
+ detachAll();
+}
+
+void Drawable::saveGLState()
+{
+ glGetBooleanv(GL_LINE_SMOOTH, &ls);
+ glGetBooleanv(GL_POLYGON_SMOOTH, &pols);
+ glGetFloatv(GL_LINE_WIDTH, &lw);
+ glGetIntegerv(GL_BLEND_SRC, &blsrc);
+ glGetIntegerv(GL_BLEND_DST, &bldst);
+ glGetDoublev(GL_CURRENT_COLOR, col);
+ glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &pattern);
+ glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &factor);
+ glGetBooleanv(GL_LINE_STIPPLE, &sallowed);
+ glGetBooleanv(GL_TEXTURE_2D, &tex2d);
+ glGetIntegerv(GL_POLYGON_MODE, polmode);
+ glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
+ glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &poloffs[0]);
+ glGetFloatv(GL_POLYGON_OFFSET_UNITS, &poloffs[1]);
+ glGetBooleanv(GL_POLYGON_OFFSET_FILL, &poloffsfill);
+}
+
+void Drawable::restoreGLState()
+{
+ Enable(GL_LINE_SMOOTH, ls);
+ Enable(GL_POLYGON_SMOOTH, pols);
+
+ setDeviceLineWidth(lw);
+ glBlendFunc(blsrc, bldst);
+ glColor4dv(col);
+
+ glLineStipple(factor,pattern);
+ Enable(GL_LINE_STIPPLE,sallowed);
+ Enable(GL_TEXTURE_2D,tex2d);
+ glPolygonMode(polmode[0], polmode[1]);
+ glMatrixMode(matrixmode);
+ glPolygonOffset(poloffs[0], poloffs[1]);
+ setDevicePolygonOffset(poloffs[0], poloffs[1]);
+
+ Enable(GL_POLYGON_OFFSET_FILL, poloffsfill);
+}
+
+void Drawable::Enable(GLenum what, GLboolean val)
+{
+ if (val)
+ glEnable(what);
+ else
+ glDisable(what);
+}
+
+void Drawable::attach(Drawable* dr)
+{
+ if ( dlist.end() == std::find( dlist.begin(), dlist.end(), dr ) )
+ if (dr)
+ {
+ dlist.push_back(dr);
+ }
+}
+
+void Drawable::detach(Drawable* dr)
+{
+ std::list<Drawable*>::iterator it = std::find(dlist.begin(), dlist.end(), dr);
+
+ if ( it != dlist.end() )
+ {
+ dlist.erase(it);
+ }
+}
+void Drawable::detachAll()
+{
+ dlist.clear();
+}
+
+
+//! simplified glut routine (glUnProject): windows coordinates_p --> object coordinates_p
+/**
+ Don't rely on (use) this in display lists !
+*/
+Triple Drawable::ViewPort2World(Triple win, bool* err)
+{
+ Triple obj;
+
+ getMatrices(modelMatrix, projMatrix, viewport);
+ int res = gluUnProject(win.x, win.y, win.z, modelMatrix, projMatrix, viewport, &obj.x, &obj.y, &obj.z);
+
+ if (err)
+ *err = (res) ? false : true;
+ return obj;
+}
+
+//! simplified glut routine (glProject): object coordinates_p --> windows coordinates_p
+/**
+ Don't rely on (use) this in display lists !
+*/
+Triple Drawable::World2ViewPort(Triple obj, bool* err)
+{
+ Triple win;
+
+ getMatrices(modelMatrix, projMatrix, viewport);
+ int res = gluProject(obj.x, obj.y, obj.z, modelMatrix, projMatrix, viewport, &win.x, &win.y, &win.z);
+
+ if (err)
+ *err = (res) ? false : true;
+ return win;
+}
+
+/**
+ Don't rely on (use) this in display lists !
+*/
+Triple Drawable::relativePosition(Triple rel)
+{
+ return ViewPort2World(Triple((rel.x-viewport[0])*viewport[2],(rel.y-viewport[1])*viewport[3],rel.z));
+}
+
+void Drawable::draw()
+{
+ saveGLState();
+
+ for (std::list<Drawable*>::iterator it = dlist.begin(); it!=dlist.end(); ++it)
+ {
+ (*it)->draw();
+ }
+ restoreGLState();
+}
+
+void Drawable::setColor(double r, double g, double b, double a)
+{
+ color = RGBA(r,g,b,a);
+}
+
+void Drawable::setColor(RGBA rgba)
+{
+ color = rgba;
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_enrichment_std.cpp b/lib/tqwtplot3d/src/qwt3d_enrichment_std.cpp new file mode 100644 index 0000000..d20ffc2 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_enrichment_std.cpp @@ -0,0 +1,347 @@ +#include <math.h>
+#include "qwt3d_color.h"
+#include "qwt3d_plot.h"
+#include "qwt3d_enrichment_std.h"
+
+using namespace Qwt3D;
+
+
+/////////////////////////////////////////////////////////////////
+//
+// CrossHair
+//
+/////////////////////////////////////////////////////////////////
+
+CrossHair::CrossHair()
+{
+ configure(0, 1, false, false);
+}
+
+CrossHair::CrossHair(double rad, double linewidth, bool smooth, bool boxed)
+{
+ configure(rad, linewidth, smooth, boxed);
+}
+
+void CrossHair::configure(double rad, double linewidth, bool smooth, bool boxed)
+{
+ plot = 0;
+ radius_ = rad;
+ linewidth_ = linewidth;
+ smooth_ = smooth;
+ boxed_ = boxed;
+}
+
+void CrossHair::drawBegin()
+{
+ setDeviceLineWidth( linewidth_ );
+ oldstate_ = glIsEnabled(GL_LINE_SMOOTH);
+ if (smooth_)
+ glEnable(GL_LINE_SMOOTH);
+ else
+ glDisable(GL_LINE_SMOOTH);
+ glBegin( GL_LINES );
+}
+
+void CrossHair::drawEnd()
+{
+ glEnd();
+
+ if (oldstate_)
+ glEnable(GL_LINE_SMOOTH);
+ else
+ glDisable(GL_LINE_SMOOTH);
+}
+
+void CrossHair::draw(Qwt3D::Triple const& pos)
+{
+ RGBA rgba = (*plot->dataColor())(pos);
+ glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
+
+ double diag = (plot->hull().maxVertex-plot->hull().minVertex).length() * radius_;
+
+ glVertex3d( pos.x - diag, pos.y, pos.z);
+ glVertex3d( pos.x + diag, pos.y, pos.z);
+
+ glVertex3d( pos.x, pos.y - diag, pos.z);
+ glVertex3d( pos.x, pos.y + diag, pos.z);
+
+ glVertex3d( pos.x, pos.y, pos.z - diag);
+ glVertex3d( pos.x, pos.y, pos.z + diag);
+
+ // hull
+
+ if (!boxed_)
+ return;
+
+ glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag);
+ glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag);
+ glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag);
+ glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag);
+
+ glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag);
+ glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag);
+ glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag);
+ glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag);
+
+ glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag);
+ glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag);
+ glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag);
+ glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag);
+
+ glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag);
+ glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag);
+ glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag);
+ glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag);
+
+ glVertex3d( pos.x - diag, pos.y - diag, pos.z - diag);
+ glVertex3d( pos.x - diag, pos.y - diag, pos.z + diag);
+ glVertex3d( pos.x + diag, pos.y - diag, pos.z - diag);
+ glVertex3d( pos.x + diag, pos.y - diag, pos.z + diag);
+
+ glVertex3d( pos.x - diag, pos.y + diag, pos.z - diag);
+ glVertex3d( pos.x - diag, pos.y + diag, pos.z + diag);
+ glVertex3d( pos.x + diag, pos.y + diag, pos.z - diag);
+ glVertex3d( pos.x + diag, pos.y + diag, pos.z + diag);
+}
+
+/////////////////////////////////////////////////////////////////
+//
+// Dot
+//
+/////////////////////////////////////////////////////////////////
+
+Dot::Dot()
+{
+ configure(1, false);
+}
+
+Dot::Dot(double pointsize, bool smooth)
+{
+ configure(pointsize, smooth);
+}
+
+void Dot::configure(double pointsize, bool smooth)
+{
+ plot = 0;
+ pointsize_ = pointsize;
+ smooth_ = smooth;
+}
+
+void Dot::drawBegin()
+{
+ setDevicePointSize( pointsize_ );
+ oldstate_ = glIsEnabled(GL_POINT_SMOOTH);
+ if (smooth_)
+ glEnable(GL_POINT_SMOOTH);
+ else
+ glDisable(GL_POINT_SMOOTH);
+
+ //glPointSize(10);
+ glBegin( GL_POINTS );
+}
+
+void Dot::drawEnd()
+{
+ glEnd();
+
+ if (oldstate_)
+ glEnable(GL_POINT_SMOOTH);
+ else
+ glDisable(GL_POINT_SMOOTH);
+}
+
+void Dot::draw(Qwt3D::Triple const& pos)
+{
+ RGBA rgba = (*plot->dataColor())(pos);
+ glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
+ glVertex3d( pos.x, pos.y, pos.z);
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Cone
+//
+/////////////////////////////////////////////////////////////////
+
+Cone::Cone()
+{
+ hat = gluNewQuadric();
+ disk = gluNewQuadric();
+
+ configure(0, 3);
+}
+
+Cone::Cone(double rad, unsigned quality)
+{
+ hat = gluNewQuadric();
+ disk = gluNewQuadric();
+
+ configure(rad, quality);
+}
+
+Cone::~Cone()
+{
+ gluDeleteQuadric(hat);
+ gluDeleteQuadric(disk);
+}
+
+void Cone::configure(double rad, unsigned quality)
+{
+ plot = 0;
+ radius_ = rad;
+ quality_ = quality;
+ oldstate_ = GL_FALSE;
+
+ gluQuadricDrawStyle(hat,GLU_FILL);
+ gluQuadricNormals(hat,GLU_SMOOTH);
+ gluQuadricOrientation(hat,GLU_OUTSIDE);
+ gluQuadricDrawStyle(disk,GLU_FILL);
+ gluQuadricNormals(disk,GLU_SMOOTH);
+ gluQuadricOrientation(disk,GLU_OUTSIDE);
+}
+
+void Cone::draw(Qwt3D::Triple const& pos)
+{
+ RGBA rgba = (*plot->dataColor())(pos);
+ glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
+
+ GLint mode;
+ glGetIntegerv(GL_MATRIX_MODE, &mode);
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+
+ glTranslatef(pos.x, pos.y, pos.z);
+
+ gluCylinder(hat, 0.0, radius_, radius_*2, quality_, 1);
+ glTranslatef(0, 0, radius_*2);
+ gluDisk(disk, 0.0, radius_, quality_, 1);
+
+ glPopMatrix();
+ glMatrixMode(mode);
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Arrow
+//
+/////////////////////////////////////////////////////////////////
+
+Arrow::Arrow()
+{
+ hat = gluNewQuadric();
+ disk = gluNewQuadric();
+ base = gluNewQuadric();
+ bottom = gluNewQuadric();
+
+ gluQuadricDrawStyle(hat,GLU_FILL);
+ gluQuadricNormals(hat,GLU_SMOOTH);
+ gluQuadricOrientation(hat,GLU_OUTSIDE);
+ gluQuadricDrawStyle(disk,GLU_FILL);
+ gluQuadricNormals(disk,GLU_SMOOTH);
+ gluQuadricOrientation(disk,GLU_OUTSIDE);
+ gluQuadricDrawStyle(base,GLU_FILL);
+ gluQuadricNormals(base,GLU_SMOOTH);
+ gluQuadricOrientation(base,GLU_OUTSIDE);
+ gluQuadricDrawStyle(bottom,GLU_FILL);
+ gluQuadricNormals(bottom,GLU_SMOOTH);
+ gluQuadricOrientation(bottom,GLU_OUTSIDE);
+
+ configure(3, 0.4, 0.06, 0.02);
+}
+
+Arrow::~Arrow()
+{
+ gluDeleteQuadric(hat);
+ gluDeleteQuadric(disk);
+ gluDeleteQuadric(base);
+ gluDeleteQuadric(bottom);
+}
+
+/**
+\param segs number of faces for the fields arrows (see the gallery for examples)
+\param relconelength see picture
+\param relconerad see picture
+\param relstemrad see picture
+\image html arrowanatomy.png
+*/
+void Arrow::configure(int segs, double relconelength, double relconerad, double relstemrad)
+{
+ plot = 0;
+ segments_ = segs;
+ oldstate_ = GL_FALSE;
+ rel_cone_length = relconelength;
+ rel_cone_radius = relconerad;
+ rel_stem_radius = relstemrad;
+}
+
+void Arrow::draw(Qwt3D::Triple const& pos)
+{
+ Triple end = top_;
+ Triple beg = pos;
+ Triple vdiff = end-beg;
+ double length = vdiff.length();
+ glColor4d(rgba_.r,rgba_.g,rgba_.b,rgba_.a);
+
+ double radius[2];
+ radius[0] = rel_cone_radius * length;
+ radius[1] = rel_stem_radius * length;
+
+ GLint mode;
+ glGetIntegerv(GL_MATRIX_MODE, &mode);
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+
+
+ Triple axis;
+ double phi = calcRotation(axis, FreeVector(beg,end));
+
+ glTranslatef(beg.x, beg.y, beg.z);
+ glRotatef(phi, axis.x, axis.y, axis.z);
+
+ double baseheight = (1-rel_cone_length) * length;
+
+ glTranslatef(0, 0, baseheight);
+
+ gluCylinder(hat, radius[0], 0.0, rel_cone_length * length, segments_,1);
+ gluDisk(disk,radius[1],radius[0], segments_,1);
+
+ glTranslatef(0, 0, -baseheight);
+
+ gluCylinder(base, radius[1],radius[1], baseheight,segments_,1);
+ gluDisk(disk,0,radius[1],segments_,1);
+
+ glPopMatrix();
+ glMatrixMode(mode);
+}
+
+
+//! transform a vector on the z axis with length |beg-end|, to get them in coincidence with the vector(beg,end)
+/**
+ \return Angle in degree to rotate
+ \param axis The axis to rotate around
+ \param beg result vector base point
+ \param end result vector top point
+*/
+double Arrow::calcRotation(Triple& axis, FreeVector const& vec)
+{
+
+ Triple end = vec.top;
+ Triple beg = vec.base;
+
+ Triple firstbeg(0.0,0.0,0.0);
+ Triple firstend(0.0,0.0,(end-beg).length());
+
+ Triple first = firstend - firstbeg;
+ first.normalize();
+
+ Triple second = end-beg;
+ second.normalize();
+
+ axis = normalizedcross(first,second);
+ double cosphi = dotProduct(first,second);
+
+ return 180 * acos(cosphi) / Qwt3D::PI;
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_function.cpp b/lib/tqwtplot3d/src/qwt3d_function.cpp new file mode 100644 index 0000000..28d874e --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_function.cpp @@ -0,0 +1,101 @@ +#include "qwt3d_surfaceplot.h"
+#include "qwt3d_function.h"
+
+using namespace Qwt3D;
+
+Function::Function()
+:GridMapping()
+{
+}
+
+Function::Function(SurfacePlot& pw)
+:GridMapping()
+{
+ plotwidget_p = &pw;
+}
+
+Function::Function(SurfacePlot* pw)
+:GridMapping()
+{
+ plotwidget_p = pw;
+}
+
+void Function::assign(SurfacePlot& plotWidget)
+{
+ if (&plotWidget != plotwidget_p)
+ plotwidget_p = &plotWidget;
+}
+
+void Function::assign(SurfacePlot* plotWidget)
+{
+ if (plotWidget != plotwidget_p)
+ plotwidget_p = plotWidget;
+}
+
+void Function:: setMinZ(double val)
+{
+ range_p.minVertex.z = val;
+}
+
+void Function:: setMaxZ(double val)
+{
+ range_p.maxVertex.z = val;
+}
+
+bool Function::create()
+{
+ if ((umesh_p<=2) || (vmesh_p<=2) || !plotwidget_p)
+ return false;
+
+ /* allocate some space for the mesh */
+ double** data = new double* [umesh_p] ;
+
+ unsigned i,j;
+ for ( i = 0; i < umesh_p; i++)
+ {
+ data[i] = new double [vmesh_p];
+ }
+
+ /* get the data */
+
+ double dx = (maxu_p - minu_p) / (umesh_p - 1);
+ double dy = (maxv_p - minv_p) / (vmesh_p - 1);
+
+ for (i = 0; i < umesh_p; ++i)
+ {
+ for (j = 0; j < vmesh_p; ++j)
+ {
+ data[i][j] = operator()(minu_p + i*dx, minv_p + j*dy);
+
+ if (data[i][j] > range_p.maxVertex.z)
+ data[i][j] = range_p.maxVertex.z;
+ else if (data[i][j] < range_p.minVertex.z)
+ data[i][j] = range_p.minVertex.z;
+ }
+ }
+
+ Q_ASSERT(plotwidget_p);
+ if (!plotwidget_p)
+ {
+ fprintf(stderr,"Function: no valid Plot3D Widget assigned");
+ }
+ else
+ {
+ ((SurfacePlot*)plotwidget_p)->loadFromData(data, umesh_p, vmesh_p, minu_p, maxu_p, minv_p, maxv_p);
+ }
+
+ for ( i = 0; i < umesh_p; i++)
+ {
+ delete [] data[i];
+ }
+
+ delete [] data;
+
+ return true;
+}
+
+bool Function::create(SurfacePlot& pl)
+{
+ assign(pl);
+ return create();
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_gridmapping.cpp b/lib/tqwtplot3d/src/qwt3d_gridmapping.cpp new file mode 100644 index 0000000..4de521b --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_gridmapping.cpp @@ -0,0 +1,32 @@ +#include "qwt3d_gridmapping.h"
+#include "qwt3d_surfaceplot.h"
+
+using namespace Qwt3D;
+
+GridMapping::GridMapping()
+{
+ plotwidget_p = 0;
+ setMesh(0,0);
+ setDomain(0,0,0,0);
+ restrictRange(ParallelEpiped(Triple(-DBL_MAX,-DBL_MAX,-DBL_MAX),Triple(DBL_MAX,DBL_MAX,DBL_MAX)));
+}
+
+void GridMapping::setMesh(unsigned int columns,unsigned int rows)
+{
+ umesh_p = columns;
+ vmesh_p = rows;
+}
+
+void GridMapping::setDomain(double minu, double maxu, double minv, double maxv)
+{
+ minu_p = minu;
+ maxu_p = maxu;
+ minv_p = minv;
+ maxv_p = maxv;
+}
+
+void GridMapping::restrictRange(Qwt3D::ParallelEpiped const& p)
+{
+ range_p = p;
+}
+
diff --git a/lib/tqwtplot3d/src/qwt3d_gridplot.cpp b/lib/tqwtplot3d/src/qwt3d_gridplot.cpp new file mode 100644 index 0000000..6543785 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_gridplot.cpp @@ -0,0 +1,596 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#pragma warning ( disable : 4786 )
+#endif
+
+#include "qwt3d_surfaceplot.h"
+#include "qwt3d_enrichment_std.h"
+
+using namespace std;
+using namespace Qwt3D;
+
+
+
+void SurfacePlot::createDataG()
+{
+ createFloorData();
+
+ if (plotStyle() == NOPLOT)
+ return;
+
+ int i, j;
+ RGBA col;
+ int step = resolution();
+
+ if (plotStyle() == Qwt3D::POINTS)
+ {
+ createPoints();
+ return;
+ }
+ else if (plotStyle() == Qwt3D::USER)
+ {
+ if (userplotstyle_p)
+ createEnrichment(*userplotstyle_p);
+ return;
+ }
+
+ setDeviceLineWidth(meshLineWidth());
+
+ GLStateBewarer sb(GL_POLYGON_OFFSET_FILL,true);
+ setDevicePolygonOffset(polygonOffset(),1.0);
+
+ GLStateBewarer sb2(GL_LINE_SMOOTH, smoothDataMesh());
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+
+ int lastcol = actualDataG_->columns();
+ int lastrow = actualDataG_->rows();
+
+ if (plotStyle() != WIREFRAME)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
+
+ bool hl = (plotStyle() == HIDDENLINE);
+ if (hl)
+ {
+ col = backgroundRGBAColor();
+ glColor4d(col.r, col.g, col.b, col.a);
+ }
+
+ for (i = 0; i < lastcol - step; i += step)
+ {
+ glBegin(GL_TRIANGLE_STRIP);
+ setColorFromVertexG(i, 0, hl);
+ glNormal3dv(actualDataG_->normals[i][0]);
+ glVertex3dv(actualDataG_->vertices[i][0]);
+
+ setColorFromVertexG(i+step, 0, hl);
+ glNormal3dv(actualDataG_->normals[i+step][0]);
+ glVertex3dv(actualDataG_->vertices[i+step][0]);
+
+ for (j = 0; j < lastrow - step; j += step)
+ {
+ setColorFromVertexG(i,j+step, hl);
+ glNormal3dv(actualDataG_->normals[i][j+step]);
+ glVertex3dv(actualDataG_->vertices[i][j+step]);
+
+ setColorFromVertexG(i+step, j+step, hl);
+ glNormal3dv(actualDataG_->normals[i+step][j+step]);
+ glVertex3dv(actualDataG_->vertices[i+step][j+step]);
+ }
+ glEnd();
+ }
+ }
+
+ if (plotStyle() == FILLEDMESH || plotStyle() == WIREFRAME || plotStyle() == HIDDENLINE)
+ {
+ glColor4d(meshColor().r, meshColor().g, meshColor().b, meshColor().a);
+
+ if (step < actualDataG_->columns() && step < actualDataG_->rows())
+ {
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < actualDataG_->columns() - step; i += step)
+ glVertex3dv(actualDataG_->vertices[i][0]);
+ for (j = 0; j < actualDataG_->rows() - step; j += step)
+ glVertex3dv(actualDataG_->vertices[i][j]);
+ for (; i >= 0; i -= step)
+ glVertex3dv(actualDataG_->vertices[i][j]);
+ for (; j >= 0; j -= step)
+ glVertex3dv(actualDataG_->vertices[0][j]);
+ glEnd();
+ }
+
+ // weaving
+ for (i = step; i < actualDataG_->columns() - step; i += step)
+ {
+ glBegin(GL_LINE_STRIP);
+ for (j = 0; j < actualDataG_->rows(); j += step)
+ glVertex3dv(actualDataG_->vertices[i][j]);
+ glEnd();
+ }
+ for (j = step; j < actualDataG_->rows() - step; j += step)
+ {
+ glBegin(GL_LINE_STRIP);
+ for (i = 0; i < actualDataG_->columns(); i += step)
+ glVertex3dv(actualDataG_->vertices[i][j]);
+ glEnd();
+ }
+ }
+}
+
+void SurfacePlot::setColorFromVertexG(int ix, int iy, bool skip)
+{
+ if (skip)
+ return;
+
+ RGBA col = (*datacolor_p)(
+ actualDataG_->vertices[ix][iy][0],
+ actualDataG_->vertices[ix][iy][1],
+ actualDataG_->vertices[ix][iy][2]);
+
+ glColor4d(col.r, col.g, col.b, col.a);
+}
+
+
+void SurfacePlot::createNormalsG()
+{
+ if (!normals() || actualDataG_->empty())
+ return;
+
+ Arrow arrow;
+ arrow.setQuality(normalQuality());
+
+ Triple basev, topv, norm;
+
+ int step = resolution();
+
+ double diag = (actualDataG_->hull().maxVertex-actualDataG_->hull().minVertex).length() * normalLength();
+
+ arrow.assign(*this);
+ arrow.drawBegin();
+ for (int i = 0; i <= actualDataG_->columns() - step; i += step)
+ {
+ for (int j = 0; j <= actualDataG_->rows() - step; j += step)
+ {
+ basev = Triple(actualDataG_->vertices[i][j][0],actualDataG_->vertices[i][j][1],actualDataG_->vertices[i][j][2]);
+ topv = Triple(actualDataG_->vertices[i][j][0]+actualDataG_->normals[i][j][0],
+ actualDataG_->vertices[i][j][1]+actualDataG_->normals[i][j][1],
+ actualDataG_->vertices[i][j][2]+actualDataG_->normals[i][j][2]);
+
+ norm = topv-basev;
+ norm.normalize();
+ norm *= diag;
+
+ arrow.setTop(basev+norm);
+ arrow.setColor((*datacolor_p)(basev.x,basev.y,basev.z));
+ arrow.draw(basev);
+ }
+ }
+ arrow.drawEnd();
+}
+
+void SurfacePlot::readIn(GridData& gdata, Triple** data, unsigned int columns, unsigned int rows)
+{
+ gdata.setSize(columns,rows);
+
+ ParallelEpiped range(Triple(DBL_MAX,DBL_MAX,DBL_MAX),Triple(-DBL_MAX,-DBL_MAX,-DBL_MAX));
+
+ /* fill out the vertex array for the mesh. */
+ for (unsigned i = 0; i != columns; ++i)
+ {
+ for (unsigned j = 0; j != rows; ++j)
+ {
+ gdata.vertices[i][j][0] = data[i][j].x;
+ gdata.vertices[i][j][1] = data[i][j].y;
+ gdata.vertices[i][j][2] = data[i][j].z;
+
+ if (data[i][j].x > range.maxVertex.x)
+ range.maxVertex.x = data[i][j].x;
+ if (data[i][j].y > range.maxVertex.y)
+ range.maxVertex.y = data[i][j].y;
+ if (data[i][j].z > range.maxVertex.z)
+ range.maxVertex.z = data[i][j].z;
+ if (data[i][j].x < range.minVertex.x)
+ range.minVertex.x = data[i][j].x;
+ if (data[i][j].y < range.minVertex.y)
+ range.minVertex.y = data[i][j].y;
+ if (data[i][j].z < range.minVertex.z)
+ range.minVertex.z = data[i][j].z;
+ }
+ }
+ gdata.setHull(range);
+}
+
+
+void SurfacePlot::readIn(GridData& gdata, double** data, unsigned int columns, unsigned int rows
+ , double minx, double maxx, double miny, double maxy)
+{
+ gdata.setPeriodic(false,false);
+ gdata.setSize(columns,rows);
+
+ double dx = (maxx - minx) / (gdata.columns() - 1);
+ double dy = (maxy - miny) / (gdata.rows() - 1);
+
+ double tmin = DBL_MAX;
+ double tmax = -DBL_MAX;
+
+ /* fill out the vertex array for the mesh. */
+ for (unsigned i = 0; i != columns; ++i)
+ {
+ for (unsigned j = 0; j != rows; ++j)
+ {
+ gdata.vertices[i][j][0] = minx + i*dx;
+ gdata.vertices[i][j][1] = miny + j*dy;
+ gdata.vertices[i][j][2] = data[i][j];
+
+ if (data[i][j] > tmax)
+ tmax = data[i][j];
+ if (data[i][j] < tmin)
+ tmin = data[i][j];
+ }
+ }
+ ParallelEpiped hull =
+ ParallelEpiped(
+ Triple(
+ gdata.vertices[0][0][0],
+ gdata.vertices[0][0][1],
+ tmin
+ ),
+ Triple(
+ gdata.vertices[gdata.columns()-1][gdata.rows()-1][0],
+ gdata.vertices[gdata.columns()-1][gdata.rows()-1][1],
+ tmax
+ )
+ );
+
+ gdata.setHull(hull);
+}
+
+
+void SurfacePlot::calcNormals(GridData& gdata)
+{
+
+ unsigned int rows = gdata.rows();
+ unsigned int columns = gdata.columns();
+
+ // normals
+
+ Triple u, v, n; // for cross product
+
+ for (unsigned i = 0; i != columns; ++i)
+ {
+ for (unsigned j = 0; j != rows; ++j)
+ {
+ n = Triple(0,0,0);
+
+
+ if (i<columns-1 && j<rows-1)
+ {
+ /* get two vectors to cross */
+ u = Triple(
+ gdata.vertices[i+1][j][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i+1][j][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i+1][j][2] - gdata.vertices[i][j][2]
+ );
+
+ v = Triple(
+ gdata.vertices[i][j+1][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i][j+1][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i][j+1][2] - gdata.vertices[i][j][2]
+ );
+ /* get the normalized cross product */
+ n += normalizedcross(u,v); // right hand system here !
+ }
+
+ if (i>0 && j<rows-1)
+ {
+ u = Triple(
+ gdata.vertices[i][j+1][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i][j+1][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i][j+1][2] - gdata.vertices[i][j][2]
+ );
+ v = Triple(
+ gdata.vertices[i-1][j][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i-1][j][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i-1][j][2] - gdata.vertices[i][j][2]
+ );
+ n += normalizedcross(u,v);
+ }
+
+ if (i>0 && j>0)
+ {
+ u = Triple(
+ gdata.vertices[i-1][j][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i-1][j][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i-1][j][2] - gdata.vertices[i][j][2]
+ );
+
+ v = Triple(
+ gdata.vertices[i][j-1][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i][j-1][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i][j-1][2] - gdata.vertices[i][j][2]
+ );
+ n += normalizedcross(u,v);
+ }
+
+ if (i<columns-1 && j>0)
+ {
+ u = Triple(
+ gdata.vertices[i][j-1][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i][j-1][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i][j-1][2] - gdata.vertices[i][j][2]
+ );
+
+ v = Triple(
+ gdata.vertices[i+1][j][0] - gdata.vertices[i][j][0],
+ gdata.vertices[i+1][j][1] - gdata.vertices[i][j][1],
+ gdata.vertices[i+1][j][2] - gdata.vertices[i][j][2]
+ );
+ n += normalizedcross(u,v);
+ }
+ n.normalize();
+
+ gdata.normals[i][j][0] = n.x;
+ gdata.normals[i][j][1] = n.y;
+ gdata.normals[i][j][2] = n.z;
+ }
+ }
+}
+
+
+void SurfacePlot::sewPeriodic(GridData& gdata)
+{
+ // sewing
+
+ Triple n;
+
+ unsigned int columns = gdata.columns();
+ unsigned int rows = gdata.rows();
+
+ if (gdata.uperiodic())
+ {
+ for (unsigned i = 0; i != columns; ++i)
+ {
+ n = Triple(
+ gdata.normals[i][0][0] + gdata.normals[i][rows-1][0],
+ gdata.normals[i][0][1] + gdata.normals[i][rows-1][1],
+ gdata.normals[i][0][2] + gdata.normals[i][rows-1][2]
+ );
+
+ n.normalize();
+ gdata.normals[i][0][0] = gdata.normals[i][rows-1][0] = n.x;
+ gdata.normals[i][0][1] = gdata.normals[i][rows-1][1] = n.y;
+ gdata.normals[i][0][2] = gdata.normals[i][rows-1][2] = n.z;
+ }
+ }
+ if (gdata.vperiodic())
+ {
+ for (unsigned j = 0; j != rows; ++j)
+ {
+ n = Triple(
+ gdata.normals[0][j][0] + gdata.normals[columns-1][j][0],
+ gdata.normals[0][j][1] + gdata.normals[columns-1][j][1],
+ gdata.normals[0][j][2] + gdata.normals[columns-1][j][2]
+ );
+
+ n.normalize();
+ gdata.normals[0][j][0] = gdata.normals[columns-1][j][0] = n.x;
+ gdata.normals[0][j][1] = gdata.normals[columns-1][j][1] = n.y;
+ gdata.normals[0][j][2] = gdata.normals[columns-1][j][2] = n.z;
+ }
+ }
+}
+
+/*!
+ Convert user grid data to internal vertex structure.
+ See also NativeReader::read() and Function::create()
+*/
+bool SurfacePlot::loadFromData(Triple** data, unsigned int columns, unsigned int rows, bool uperiodic, bool vperiodic)
+{
+ actualDataC_->clear();
+ actualData_p = actualDataG_;
+
+ readIn(*actualDataG_, data, columns, rows);
+ calcNormals(*actualDataG_);
+ actualDataG_->setPeriodic(uperiodic,vperiodic);
+ sewPeriodic(*actualDataG_);
+
+ updateData();
+ updateNormals();
+ createCoordinateSystem();
+
+ return true;
+}
+
+/*!
+ Convert user grid data to internal vertex structure.
+ See also NativeReader::read() and Function::create()
+*/
+bool SurfacePlot::loadFromData(double** data, unsigned int columns, unsigned int rows
+ , double minx, double maxx, double miny, double maxy)
+{
+ actualDataC_->clear();
+ actualData_p = actualDataG_;
+
+ actualDataG_->setPeriodic(false,false);
+ actualDataG_->setSize(columns,rows);
+ readIn(*actualDataG_,data,columns,rows,minx,maxx,miny,maxy);
+ calcNormals(*actualDataG_);
+
+ updateData();
+ updateNormals();
+ createCoordinateSystem();
+
+ return true;
+}
+
+
+void SurfacePlot::createFloorDataG()
+{
+ switch (floorStyle())
+ {
+ case FLOORDATA:
+ Data2FloorG();
+ break;
+ case FLOORISO:
+ Isolines2FloorG();
+ break;
+ default:
+ break;
+ }
+}
+
+void SurfacePlot::Data2FloorG()
+{
+ if (actualData_p->empty())
+ return;
+
+ int step = resolution();
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
+
+ double zshift = actualData_p->hull().minVertex.z;
+ for (int i = 0; i < actualDataG_->columns() - step; i += step)
+ {
+ glBegin(GL_TRIANGLE_STRIP);
+ setColorFromVertexG(i, 0);
+ glVertex3d(actualDataG_->vertices[i][0][0], actualDataG_->vertices[i][0][1], zshift);
+
+ setColorFromVertexG(i+step, 0);
+ glVertex3d(actualDataG_->vertices[i+step][0][0],actualDataG_->vertices[i+step][0][1], zshift);
+ for (int j = 0; j < actualDataG_->rows() - step; j += step)
+ {
+ setColorFromVertexG(i, j+step);
+ glVertex3d(actualDataG_->vertices[i][j+step][0],actualDataG_->vertices[i][j+step][1], zshift);
+
+ setColorFromVertexG(i+step, j+step);
+ glVertex3d(actualDataG_->vertices[i+step][j+step][0],actualDataG_->vertices[i+step][j+step][1], zshift);
+ }
+ glEnd();
+ }
+}
+
+void SurfacePlot::Isolines2FloorG()
+{
+ if (isolines() <= 0 || actualData_p->empty())
+ return;
+
+ double count = (actualData_p->hull().maxVertex.z - actualData_p->hull().minVertex.z) / isolines();
+
+ RGBA col;
+
+ int step = resolution();
+
+ double zshift = actualData_p->hull().minVertex.z;
+
+ int cols = actualDataG_->columns();
+ int rows = actualDataG_->rows();
+
+ Triple t[4];
+ vector<Triple> intersection;
+
+ double lambda = 0;
+
+ GLStateBewarer sb2(GL_LINE_SMOOTH, false);
+
+ for (int k = 0; k != isolines(); ++k)
+ {
+ double val = zshift + k * count;
+
+ for (int i = 0; i < cols-step; i += step)
+ {
+ for (int j = 0; j < rows-step; j += step)
+ {
+ t[0] = Triple( actualDataG_->vertices[i][j][0],
+ actualDataG_->vertices[i][j][1],
+ actualDataG_->vertices[i][j][2]);
+
+ col = (*datacolor_p)(t[0].x,t[0].y,t[0].z);
+ glColor4d(col.r, col.g, col.b, col.a);
+// glColor4d(0,0,0,1);
+
+ t[1] = Triple( actualDataG_->vertices[i+step][j][0],
+ actualDataG_->vertices[i+step][j][1],
+ actualDataG_->vertices[i+step][j][2]);
+ t[2] = Triple( actualDataG_->vertices[i+step][j+step][0],
+ actualDataG_->vertices[i+step][j+step][1],
+ actualDataG_->vertices[i+step][j+step][2]);
+ t[3] = Triple( actualDataG_->vertices[i][j+step][0],
+ actualDataG_->vertices[i][j+step][1],
+ actualDataG_->vertices[i][j+step][2]);
+
+ double diff = 0;
+ for (int m = 0; m!=4; ++m)
+ {
+ int mm = (m+1)%4;
+ if ((val>=t[m].z && val<=t[mm].z) || (val>=t[mm].z && val<=t[m].z))
+ {
+ diff = t[mm].z - t[m].z;
+
+ if (isPracticallyZero(diff)) // degenerated
+ {
+ intersection.push_back(t[m]);
+ intersection.push_back(t[mm]);
+ continue;
+ }
+
+ lambda = (val - t[m].z) / diff;
+ intersection.push_back(Triple(t[m].x + lambda * (t[mm].x-t[m].x), t[m].y + lambda * (t[mm].y-t[m].y), val));
+ }
+ }
+
+ if (!intersection.empty())
+ {
+ if (intersection.size()>2)
+ {
+ glBegin(GL_LINE_STRIP);
+ for (unsigned dd = 0; dd!=intersection.size(); ++dd)
+ {
+ glVertex3d(intersection[dd].x, intersection[dd].y, zshift);
+ }
+ glEnd();
+ glBegin(GL_POINTS);
+ glVertex3d(intersection[0].x,intersection[0].y,zshift);
+ glEnd();
+ }
+ else if (intersection.size() == 2)
+ {
+ glBegin(GL_LINES);
+ glVertex3d(intersection[0].x,intersection[0].y,zshift);
+ glVertex3d(intersection[1].x,intersection[1].y,zshift);
+
+ // small pixel gap problem (see OpenGL spec.)
+ glVertex3d(intersection[1].x,intersection[1].y,zshift);
+ glVertex3d(intersection[0].x,intersection[0].y,zshift);
+ glEnd();
+ }
+
+ intersection.clear();
+ }
+ }
+ }
+ }
+}
+
+
+
+/*
+void SurfacePlot::calcLowResolution()
+{
+ if (!actualDataG_)
+ return;
+
+ int res = resolution();
+ if (res == 1)
+ {
+ lowresData_p = *actualDataG_;
+ return;
+ }
+
+ GridData const& src = *actualDataG_;
+ result.clear();
+
+
+}*/
+
diff --git a/lib/tqwtplot3d/src/qwt3d_io.cpp b/lib/tqwtplot3d/src/qwt3d_io.cpp new file mode 100644 index 0000000..c9ce46b --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_io.cpp @@ -0,0 +1,355 @@ +#include <time.h>
+
+#include "qwt3d_plot.h"
+#include "qwt3d_io_gl2ps.h"
+#include "qwt3d_io_reader.h"
+#if QT_VERSION < 0x040000
+#else
+ #include <QImageWriter>
+#endif
+
+using namespace Qwt3D;
+
+IO::Entry::Entry() : iofunc(0)
+{
+}
+
+IO::Entry::~Entry()
+{
+ delete iofunc;
+}
+
+IO::Entry::Entry(IO::Entry const& e)
+{
+ if (this==&e)
+ return;
+
+ fmt = e.fmt;
+ iofunc = e.iofunc->clone();
+}
+
+void IO::Entry::operator=(IO::Entry const& e)
+{
+ if (this==&e)
+ return;
+
+ delete iofunc;
+ fmt = e.fmt;
+ iofunc = e.iofunc->clone();
+}
+
+IO::Entry::Entry(QString const& s, Functor const& f)
+ : fmt(s)
+{
+ iofunc = f.clone();
+}
+
+IO::Entry::Entry(QString const& s, Function f)
+ : fmt(s)
+{
+ Wrapper w(f);
+ iofunc = w.clone();
+}
+
+
+IO::FormatCompare::FormatCompare(IO::Entry const& e)
+{
+ e_ = e;
+}
+
+bool IO::FormatCompare::operator() (IO::Entry const& e)
+{
+ return ( e.fmt == e_.fmt);
+}
+
+IO::FormatCompare2::FormatCompare2(QString s)
+{
+ s_ = s;
+}
+
+bool IO::FormatCompare2::operator() (IO::Entry const& e)
+{
+ return( e.fmt == s_);
+}
+
+
+
+
+bool IO::add_unique(Container& l, Entry const& e)
+{
+ FormatCompare comp(e);
+ l.erase(std::remove_if(l.begin(), l.end(), comp), l.end());
+ l.push_back(e);
+
+ return true;
+}
+
+IO::IT IO::find(Container& l, QString const& fmt)
+{
+ FormatCompare2 comp(fmt);
+ return std::find_if(l.begin(), l.end(), comp);
+}
+
+IO::Container& IO::rlist()
+{
+ static Container rl = Container();
+ static bool rfirst = true;
+ bool f = false;
+ f = rfirst;
+ if (rfirst)
+ {
+ rfirst = false;
+ setupHandler();
+ }
+ return rl;
+}
+
+IO::Container& IO::wlist()
+{
+ static Container wl = Container();
+ static bool wfirst = true;
+ bool f = false;
+ f = wfirst;
+ if (wfirst)
+ {
+ wfirst = false;
+ setupHandler();
+ }
+ return wl;
+}
+
+/*!
+ Registers a new IO::Function for data input.\n
+ Every call overwrites a formerly registered handler for the same format string
+ (case sensitive).
+*/
+bool IO::defineInputHandler(QString const& format, IO::Function func)
+{
+ return add_unique(rlist(), Entry(format, func));
+}
+
+/*!
+ Registers a new Functor for data input.\n
+ Every call overwrites a formerly registered handler for the same format string
+ (case sensitive).
+*/
+bool IO::defineInputHandler(QString const& format, IO::Functor const& func)
+{
+ return add_unique(rlist(), Entry(format, func));
+}
+
+/*!
+ Registers a new IO::Function for data output.
+ Every call overwrites a formerly registered handler for the same format string
+ (case sensitive).
+ */
+bool IO::defineOutputHandler(QString const& format, IO::Function func)
+{
+ return add_unique(wlist(), Entry(format, func));
+}
+
+/*!
+ Registers a new Functor for data output.\n
+ Every call overwrites a formerly registered handler for the same format string
+ (case sensitive).
+*/
+bool IO::defineOutputHandler(QString const& format, IO::Functor const& func)
+{
+ return add_unique(wlist(), Entry(format, func));
+}
+
+/*!
+ Applies a reading IO::Function or IO::Functor.
+ \param plot Plot with the content that should be loaded
+ \param fname File name
+ \param format Input format
+ \return The return value from the called Function/Functor.
+ The function returns false, if no registered handler could be found.
+*/
+bool IO::load(Plot3D* plot, QString const& fname, QString const& format)
+{
+ IT it = IO::find(rlist(), format);
+
+ if (it == rlist().end())
+ return false;
+
+ return (*it->iofunc)(plot, fname);
+}
+
+/*!
+ Applies a writing IO::Function or IO::Functor.
+ \param plot Plot with the content that should be saved
+ \param fname File name
+ \param format Output format
+ \return The return value from the called Function/Functor.
+ The function returns false, if no registered handler could be found.
+*/
+bool IO::save(Plot3D* plot, QString const& fname, QString const& format)
+{
+ IT it = IO::find(wlist(), format);
+
+ if (it == wlist().end())
+ return false;
+
+ return (*it->iofunc)(plot, fname);
+}
+
+/*!
+ Returns a list of currently registered input formats.
+*/
+QStringList IO::inputFormatList()
+{
+ QStringList list;
+ for ( IT it = rlist().begin(); it!=rlist().end(); ++it )
+ list.append(it->fmt);
+
+ return list;
+}
+
+/*!
+ Returns a list of currently registered output formats.
+*/
+QStringList IO::outputFormatList()
+{
+ QStringList list;
+ for ( IT it = wlist().begin(); it!=wlist().end(); ++it )
+ list.append(it->fmt);
+
+ return list;
+}
+
+/*!
+ Returns the input functor in charge for format and 0 if non-existent.
+*/
+IO::Functor* IO::inputHandler(QString const& format)
+{
+ IO::IT it = IO::find(rlist(), format);
+
+ if (it==rlist().end())
+ return 0;
+
+ return it->iofunc;
+}
+
+/*!
+ Returns the output functor in charge for format and 0 if non-existent.
+*/
+IO::Functor* IO::outputHandler(QString const& format)
+{
+ IO::IT it = IO::find(wlist(), format);
+
+ if (it==wlist().end())
+ return 0;
+
+ return it->iofunc;
+}
+
+bool PixmapWriter::operator()(Plot3D* plot, QString const& fname)
+{
+ QImage im = plot->grabFrameBuffer(true);
+
+#if QT_VERSION < 0x040000
+ QImageIO iio;
+ iio.setImage(im);
+#else
+ QImageWriter iio;
+#endif
+ iio.setFormat(QWT3DLOCAL8BIT(fmt_));
+ iio.setQuality(quality_);
+ iio.setFileName(fname);
+#if QT_VERSION < 0x040000
+ return iio.write();
+#else
+ return iio.write(im);
+#endif
+}
+
+//! Calls Qt's QImageIO::setQuality() function.
+void PixmapWriter::setQuality(int val)
+{
+ quality_ = val;
+}
+
+void IO::setupHandler()
+{
+#if QT_VERSION < 0x040000
+ QStringList list = QImage::outputFormatList();
+ QStringList::Iterator it = list.begin();
+#else
+ QList<QByteArray> list = QImageWriter::supportedImageFormats();
+ QList<QByteArray>::Iterator it = list.begin();
+#endif
+ PixmapWriter qtw;
+ while( it != list.end() )
+ {
+ qtw.fmt_ = *it;
+ defineOutputHandler(*it, qtw);
+ ++it;
+ }
+ VectorWriter vecfunc;
+ vecfunc.setCompressed(false);
+ vecfunc.setFormat("EPS");
+ defineOutputHandler("EPS", vecfunc);
+ vecfunc.setFormat("PS");
+ defineOutputHandler("PS", vecfunc);
+
+#ifdef GL2PS_HAVE_ZLIB
+ vecfunc.setCompressed(true);
+ vecfunc.setFormat("EPS_GZ");
+ defineOutputHandler("EPS_GZ", vecfunc);
+ vecfunc.setFormat("PS_GZ");
+ defineOutputHandler("PS_GZ", vecfunc);
+#endif
+ vecfunc.setFormat("PDF");
+ defineOutputHandler("PDF", vecfunc);
+
+ defineInputHandler("mes", NativeReader());
+ defineInputHandler("MES", NativeReader());
+}
+
+/*!
+ \deprecated Use Plot3D::save or IO::save instead.
+
+ Writes vector data supported by gl2ps. The corresponding format types are "EPS","PS"or "PDF".
+ If zlib has been configured this will be extended by "EPS_GZ" and "PS_GZ".
+ \b Beware: BSPSORT turns out to behave very slowly and memory consuming, especially in cases where
+ many polygons appear. It is still more exact than SIMPLESORT.
+*/
+bool Plot3D::saveVector(QString const& fileName, QString const& format, VectorWriter::TEXTMODE text, VectorWriter::SORTMODE sortmode)
+{
+ if (format == "EPS" || format == "EPS_GZ" || format == "PS"
+ || format == "PS_GZ" || format == "PDF")
+ {
+ VectorWriter* gl2ps = (VectorWriter*)IO::outputHandler(format);
+ if (gl2ps)
+ {
+ gl2ps->setSortMode(sortmode);
+ gl2ps->setTextMode(text);
+ }
+ return IO::save(this, fileName, format);
+ }
+ return false;
+}
+/*!
+ \deprecated Use Plot3D::save or IO::save instead.
+
+ Saves the framebuffer to the file fileName using one of the image file formats supported by Qt.
+*/
+bool Plot3D::savePixmap(QString const& fileName, QString const& format)
+{
+ if (format == "EPS" || format == "EPS_GZ" || format == "PS"
+ || format == "PS_GZ" || format == "PDF")
+ return false;
+
+ return IO::save(this, fileName, format);
+}
+
+/*!
+ Saves content in one of the registered output formats. To modify the
+ behaviour for more complex output handling use IO::outputHandler.
+*/
+bool Plot3D::save(QString const& fileName, QString const& format)
+{
+ return IO::save(this, fileName, format);
+}
+
diff --git a/lib/tqwtplot3d/src/qwt3d_io_gl2ps.cpp b/lib/tqwtplot3d/src/qwt3d_io_gl2ps.cpp new file mode 100644 index 0000000..be94e51 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_io_gl2ps.cpp @@ -0,0 +1,387 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4786 )
+#endif
+
+#include <time.h>
+#include "qwt3d_openglhelper.h"
+#include "../3rdparty/gl2ps/gl2ps.h"
+#include "qwt3d_io_gl2ps.h"
+#include "qwt3d_plot.h"
+
+using namespace Qwt3D;
+
+//! Provides a new VectorWriter object.
+IO::Functor* VectorWriter::clone() const
+{
+ return new VectorWriter(*this);
+}
+
+VectorWriter::VectorWriter()
+ : gl2ps_format_(GL2PS_EPS),
+ formaterror_(false),
+#ifdef GL2PS_HAVE_ZLIB
+ compressed_(true),
+#else
+ compressed_(false),
+#endif
+ sortmode_(SIMPLESORT),
+ landscape_(VectorWriter::AUTO),
+ textmode_(VectorWriter::PIXEL),
+ texfname_("")
+ {}
+
+
+/*!
+ Sets the mode for text output:\n
+ \param val The underlying format for the generated output:\n
+ PIXEL - poor quality but exact positioning\n
+ NATIVE - high quality but inexact positioning\n
+ TEX - high quality and exact positioning, arbitrary TeX strings as content for
+ the saved labels are possible. The disadvantage is the need for an additionally TeX run
+ to get the final output.\n
+ \param fname Optional, used only in conjunction with TeX output; file name
+ for the generated TeX file. If not set, a file called "OUTPUT.FOR.tex"
+ will be generated, where "OUTPUT.FOR" describes the file name argument for IO::save().\n\n
+ (04/05/27: On Linux platforms, pdflatex seems a file named 'dump_0.pdf.tex' mistakenly to
+ identify as PDF file.)
+*/
+void VectorWriter::setTextMode(TEXTMODE val, QString fname)
+{
+ textmode_ = val;
+ texfname_ = (fname.isEmpty()) ? QString("") : fname;
+}
+
+
+#ifdef GL2PS_HAVE_ZLIB
+//! Turns compressed output on or off (no effect if zlib support has not been set)
+void VectorWriter::setCompressed(bool val)
+{
+ compressed_ = val;
+}
+#else
+//! Turns compressed output on or off (no effect if zlib support has not been set)
+void VectorWriter::setCompressed(bool)
+{
+ compressed_ = false;
+}
+#endif
+
+
+/*!
+Set output format, must be one of "EPS_GZ", "PS_GZ", "EPS",
+"PS", "PDF" (case sensitive)
+*/
+bool VectorWriter::setFormat(QString const& format)
+{
+ if (format == QString("EPS"))
+ {
+ gl2ps_format_ = GL2PS_EPS;
+ }
+ else if (format == QString("PS"))
+ {
+ gl2ps_format_ = GL2PS_PS;
+ }
+ else if (format == QString("PDF"))
+ {
+ gl2ps_format_ = GL2PS_PDF;
+ }
+#ifdef GL2PS_HAVE_ZLIB
+ else if (format == QString("EPS_GZ"))
+ {
+ gl2ps_format_ = GL2PS_EPS;
+ }
+ else if (format == QString("PS_GZ"))
+ {
+ gl2ps_format_ = GL2PS_PS;
+ }
+#endif
+ else
+ {
+ formaterror_ = true;
+ return false;
+ }
+ formaterror_ = false;
+ return true;
+}
+
+//! Performs actual output
+bool VectorWriter::operator()(Plot3D* plot, QString const& fname)
+{
+ if (formaterror_)
+ return false;
+
+ plot->makeCurrent();
+
+
+ GLint bufsize = 0, state = GL2PS_OVERFLOW;
+ GLint viewport[4];
+
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ GLint options = GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | GL2PS_DRAW_BACKGROUND |
+ GL2PS_OCCLUSION_CULL | GL2PS_BEST_ROOT;
+
+
+ if (compressed_)
+ options |= GL2PS_COMPRESS;
+
+ switch (landscape_)
+ {
+ case VectorWriter::AUTO:
+ if (viewport[2] - viewport[0] > viewport[3] - viewport[0])
+ options |= GL2PS_LANDSCAPE;
+ break;
+ case VectorWriter::ON:
+ options |= GL2PS_LANDSCAPE;
+ break;
+ default:
+ break;
+ }
+
+ int sortmode = GL2PS_SIMPLE_SORT;
+ switch (sortmode_)
+ {
+ case VectorWriter::NOSORT:
+ sortmode = GL2PS_NO_SORT;
+ break;
+ case VectorWriter::SIMPLESORT:
+ sortmode = GL2PS_SIMPLE_SORT;
+ break;
+ case VectorWriter::BSPSORT:
+ sortmode = GL2PS_BSP_SORT;
+ break;
+ default:
+ break;
+ }
+
+ switch (textmode_)
+ {
+ case NATIVE:
+ Label::useDeviceFonts(true);
+ break;
+ case PIXEL:
+ Label::useDeviceFonts(false);
+ break;
+ case TEX:
+ options |= GL2PS_NO_PIXMAP | GL2PS_NO_TEXT;
+ break;
+ default:
+ break;
+ }
+
+ QString version = QString::number(QWT3D_MAJOR_VERSION) + "."
+ + QString::number(QWT3D_MINOR_VERSION) + "."
+ + QString::number(QWT3D_PATCH_VERSION);
+
+ QString producer = QString("QwtPlot3D ") + version +
+ " (beta) , (C) 2002";
+
+ // calculate actual year
+ time_t now;
+ struct tm *newtime;
+ time(&now);
+ newtime = gmtime(&now);
+ if (newtime && newtime->tm_year + 1900 > 2002)
+ producer += "-" + QString::number(newtime->tm_year+1900);
+
+ producer += " Micha Bieber <krischnamurti@users.sourceforge.net>";
+
+ FILE *fp = fopen(QWT3DLOCAL8BIT(fname), "wb");
+ if (!fp)
+ {
+ Label::useDeviceFonts(false);
+ return false;
+ }
+ while( state == GL2PS_OVERFLOW )
+ {
+ bufsize += 2*1024*1024;
+ gl2psBeginPage ( "---", QWT3DLOCAL8BIT(producer), viewport,
+ gl2ps_format_, sortmode,
+ options, GL_RGBA, 0, NULL, 0, 0, 0, bufsize,
+ fp, QWT3DLOCAL8BIT(fname) );
+
+ plot->updateData();
+ plot->updateGL();
+ state = gl2psEndPage();
+ }
+ fclose(fp);
+
+ // extra TeX file
+ if (textmode_ == TEX)
+ {
+ QString fn = (texfname_.isEmpty())
+ ? fname + ".tex"
+ : texfname_;
+
+ fp = fopen(QWT3DLOCAL8BIT(fn), "wb");
+ if (!fp)
+ {
+ Label::useDeviceFonts(false);
+ return false;
+ }
+ Label::useDeviceFonts(true);
+ options &= ~GL2PS_NO_PIXMAP & ~GL2PS_NO_TEXT;
+ state = GL2PS_OVERFLOW;
+ while( state == GL2PS_OVERFLOW )
+ {
+ bufsize += 2*1024*1024;
+ gl2psBeginPage ( "---", QWT3DLOCAL8BIT(producer), viewport,
+ GL2PS_TEX, sortmode,
+ options, GL_RGBA, 0, NULL, 0, 0, 0, bufsize,
+ fp, QWT3DLOCAL8BIT(fn) );
+
+ plot->updateData();
+ plot->updateGL();
+ state = gl2psEndPage();
+ }
+ fclose(fp);
+ }
+
+
+ Label::useDeviceFonts(false);
+
+ return true;
+}
+
+
+// moved
+
+GLint Qwt3D::setDeviceLineWidth(GLfloat val)
+{
+ if (val<0)
+ val=0;
+
+ GLint ret = gl2psLineWidth(val);
+
+ GLfloat lw[2];
+ glGetFloatv(GL_LINE_WIDTH_RANGE, lw);
+
+ if (val < lw[0])
+ val = lw[0];
+ else if (val > lw[1])
+ val = lw[1];
+
+ glLineWidth(val);
+ return ret;
+}
+
+GLint Qwt3D::setDevicePointSize(GLfloat val)
+{
+ if (val<0)
+ val=0;
+
+ GLint ret = gl2psPointSize(val);
+
+ GLfloat lw[2];
+ glGetFloatv(GL_POINT_SIZE_RANGE, lw);
+
+ if (val < lw[0])
+ val = lw[0];
+ else if (val > lw[1])
+ val = lw[1];
+
+ glPointSize(val);
+ return ret;
+}
+
+GLint Qwt3D::drawDevicePixels(GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const void *pixels)
+{
+ glDrawPixels(width, height, format, type, pixels);
+
+ if(format != GL_RGBA || type != GL_UNSIGNED_BYTE)
+ return GL2PS_ERROR;
+
+ GLfloat* convertedpixel = (GLfloat*)malloc(3 * width * height * sizeof(GLfloat));
+ if (!convertedpixel)
+ return GL2PS_ERROR;
+
+ GLubyte* px = (GLubyte*)pixels;
+ for (int i=0; i!=3*width*height; i+=3)
+ {
+ int pxi = (4*i)/3;
+ convertedpixel[i] = px[pxi] / float(255);
+ convertedpixel[i+1] = px[pxi+1] / float(255);
+ convertedpixel[i+2] = px[pxi+2] / float(255);
+ }
+ GLint ret = gl2psDrawPixels(width, height, 0, 0, GL_RGB, GL_FLOAT, convertedpixel);
+ free(convertedpixel);
+ return ret;
+}
+
+GLint Qwt3D::drawDeviceText(const char* str, const char* fontname, int fontsize, Triple pos, RGBA /*rgba*/, ANCHOR align, double gap)
+{
+ double vp[3];
+
+ World2ViewPort(vp[0], vp[1], vp[2], pos.x, pos.y, pos.z);
+ Triple start(vp[0],vp[1],vp[2]);
+
+ GLdouble fcol[4];
+ glGetDoublev(GL_CURRENT_COLOR, fcol);
+ GLdouble bcol[4];
+ glGetDoublev(GL_COLOR_CLEAR_VALUE, bcol);
+
+// glColor4d(color.r, color.g, color.b, color.a);
+// glClearColor(color.r, color.g, color.b, color.a);
+
+ GLint ret = GL2PS_SUCCESS;
+
+ GLint a = GL2PS_TEXT_BL;
+ switch(align)
+ {
+ case Center:
+ a = GL2PS_TEXT_C;
+ break;
+ case CenterLeft:
+ a = GL2PS_TEXT_CL;
+ start += Triple(gap,0,0);
+ break;
+ case CenterRight:
+ a = GL2PS_TEXT_CR;
+ start += Triple(-gap,0,0);
+ break;
+ case BottomCenter:
+ a = GL2PS_TEXT_B;
+ start += Triple(0,gap,0);
+ break;
+ case BottomLeft:
+ a = GL2PS_TEXT_BL;
+ start += Triple(gap,gap,0);
+ break;
+ case BottomRight:
+ a = GL2PS_TEXT_BR;
+ start += Triple(-gap,gap,0);
+ break;
+ case TopCenter:
+ a = GL2PS_TEXT_T;
+ start += Triple(0,-gap,0);
+ break;
+ case TopLeft:
+ a = GL2PS_TEXT_TL;
+ start += Triple(gap,-gap,0);
+ break;
+ case TopRight:
+ a = GL2PS_TEXT_TR;
+ start += Triple(-gap,-gap,0);
+ break;
+ default:
+ break;
+ }
+
+ ViewPort2World(vp[0], vp[1], vp[2], start.x, start.y, start.z);
+ Triple adjpos(vp[0],vp[1],vp[2]);
+
+ glRasterPos3d(adjpos.x, adjpos.y, adjpos.z);
+ ret = gl2psTextOpt(str, fontname, (int)fontsize, a, 0);
+ glColor4dv(fcol);
+ glClearColor(bcol[0], bcol[1], bcol[2], bcol[3]);
+ return ret;
+}
+
+void Qwt3D::setDevicePolygonOffset(GLfloat factor, GLfloat units)
+{
+ glPolygonOffset(factor, units);
+ gl2psEnable(GL2PS_POLYGON_OFFSET_FILL);
+}
+
diff --git a/lib/tqwtplot3d/src/qwt3d_io_reader.cpp b/lib/tqwtplot3d/src/qwt3d_io_reader.cpp new file mode 100644 index 0000000..2cc57a7 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_io_reader.cpp @@ -0,0 +1,225 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4786 )
+#endif
+
+#include <float.h>
+#include <stdio.h>
+#include <qtextstream.h>
+
+#include "qwt3d_surfaceplot.h"
+#include "qwt3d_io_reader.h"
+
+using namespace std;
+using namespace Qwt3D;
+
+const char* NativeReader::magicstring = "jk:11051895-17021986";
+
+namespace
+{
+ FILE* open(QString fname)
+ {
+ FILE* file = fopen(QWT3DLOCAL8BIT(fname), "r");
+ if (!file)
+ {
+ fprintf(stderr, "NativeReader::read: cannot open data file \"%s\"\n", QWT3DLOCAL8BIT(fname));
+ }
+ return file;
+ }
+
+ int read_char (FILE * fp, bool skipcomments = true)
+ {
+ int c;
+
+ if ((c = fgetc (fp)) == EOF)
+ return (c);
+ if (skipcomments)
+ {
+ if (c == '#')
+ {
+ do
+ {
+ if ((c = fgetc (fp)) == EOF)
+ return (c);
+ }
+ while (c != '\n' && c != '\r');
+ }
+ }
+ return (c);
+ }
+
+ char* read_field (FILE * fp, bool skipcomments = true)
+ {
+ static char buf[71];
+ int c, i;
+
+ do
+ {
+ if ((c = read_char (fp,skipcomments)) == EOF)
+ return (NULL);
+ }
+ while (isspace (c));
+ for (i = 0; i < 70 && !isspace (c); ++i)
+ {
+ buf[i] = c;
+ if ((c = read_char (fp,skipcomments)) == EOF)
+ break;
+ }
+ buf[i] = '\0';
+ return (buf);
+ }
+
+
+ //! set to data begin
+ bool extract_info(FILE* fp, unsigned int& xmesh, unsigned int& ymesh, double& xmin, double& xmax, double& ymin, double& ymax)
+ {
+ char* p;
+
+ // find out the size
+ if ((p = read_field (fp)) == 0)
+ return false;
+ xmesh = (unsigned int)atoi(p);
+
+ if ((p = read_field (fp)) == 0)
+ return false;
+ ymesh = (unsigned int)atoi (p);
+
+ if (xmesh < 1 || ymesh < 1)
+ return false;
+
+ // ... and the limits
+ if ((p = read_field (fp)) == 0)
+ return false;
+ xmin = atof (p);
+
+ if ((p = read_field (fp)) == 0)
+ return false;
+ xmax = atof (p);
+
+ if ((p = read_field (fp)) == 0)
+ return false;
+ ymin = atof (p);
+
+ if ((p = read_field (fp)) == 0)
+ return false;
+ ymax = atof (p);
+
+ if (xmin > xmax || ymin > ymax)
+ return false;
+
+ return true;
+ }
+
+ //! find out what the magic string is and compare
+ bool check_magic(FILE* fp, const char* val)
+ {
+ char* p;
+ if ((p = read_field (fp,false)) == 0)
+ return false;
+
+ if (strcmp (p, val ) != 0)
+ return false;
+ return true;
+ }
+
+ //! find out what the type is
+ bool check_type(FILE* fp, const char* val)
+ {
+ char* p;
+ if ((p = read_field (fp)) == 0)
+ return false;
+
+ if (strcmp (p, val ) != 0)
+ return false;
+ return true;
+ }
+
+ double** allocateData(int columns, int rows)
+ {
+ double** data = new double* [columns] ;
+
+ for ( int i = 0; i < columns; ++i)
+ {
+ data[i] = new double [rows];
+ }
+ return data;
+ }
+
+ void deleteData(double**data, int columns)
+ {
+ for ( int i = 0; i < columns; i++)
+ {
+ delete [] data[i];
+ }
+ delete [] data;
+ }
+}
+
+NativeReader::NativeReader()
+: minz_(-DBL_MAX), maxz_(DBL_MAX)
+{
+}
+
+bool NativeReader::collectInfo(FILE*& file, QString const& fname, unsigned& xmesh, unsigned& ymesh,
+ double& minx, double& maxx, double& miny, double& maxy)
+{
+ if (fname.isEmpty())
+ return false;
+
+ file = open(fname);
+
+ if (!file)
+ return false;
+
+
+ if (
+ (!check_magic(file, magicstring))
+ ||(!check_type(file, "MESH"))
+ ||(!extract_info(file, xmesh, ymesh, minx, maxx, miny, maxy))
+ )
+ {
+ fclose(file);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool NativeReader::operator()(Plot3D* plot, QString const& fname)
+{
+
+ FILE* file;
+ unsigned int xmesh, ymesh;
+ double minx, maxx, miny, maxy;
+
+ if ( !collectInfo(file, fname, xmesh, ymesh, minx, maxx, miny, maxy) )
+ return false;
+
+ /* allocate some space for the mesh */
+ double** data = allocateData(xmesh, ymesh);
+
+ for (unsigned int j = 0; j < ymesh; j++)
+ {
+ for (unsigned int i = 0; i < xmesh; i++)
+ {
+ if (fscanf(file, "%lf", &data[i][j]) != 1)
+ {
+ fprintf(stderr, "NativeReader::read: error in data file \"%s\"\n", QWT3DLOCAL8BIT(fname));
+ return false;
+ }
+
+ if (data[i][j] > maxz_)
+ data[i][j] = maxz_;
+ else if (data[i][j] < minz_)
+ data[i][j] = minz_;
+ }
+ }
+
+ /* close the file */
+ fclose(file);
+
+ ((SurfacePlot*)plot)->loadFromData(data, xmesh, ymesh, minx, maxx, miny, maxy);
+ deleteData(data,xmesh);
+
+ return true;
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_label.cpp b/lib/tqwtplot3d/src/qwt3d_label.cpp new file mode 100644 index 0000000..eb8b8c0 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_label.cpp @@ -0,0 +1,262 @@ +#include <qbitmap.h>
+#include "qwt3d_label.h"
+
+using namespace Qwt3D;
+
+bool Label::devicefonts_ = false;
+
+Label::Label()
+{
+ init();
+}
+
+Label::Label(const QString & family, int pointSize, int weight, bool italic)
+{
+ init(family, pointSize, weight, italic);
+}
+
+
+void Label::init(const QString & family, int pointSize, int weight, bool italic)
+{
+ init();
+ font_ = QFont(family, pointSize, weight, italic );
+}
+
+void Label::init()
+{
+ beg_ = Triple(0.0, 0.0, 0.0);
+ end_ = beg_;
+ pos_ = beg_;
+ setColor(0,0,0);
+ pm_ = QPixmap(0, 0);
+ font_ = QFont();
+ anchor_ = BottomLeft;
+ gap_ = 0;
+ flagforupdate_ = true;
+}
+
+void Label::useDeviceFonts(bool val)
+{
+ devicefonts_ = val;
+}
+
+void Label::setFont(const QString & family, int pointSize, int weight, bool italic)
+{
+ font_ = QFont(family, pointSize, weight, italic );
+ flagforupdate_ = true;
+}
+
+void Label::setString(QString const& s)
+{
+ text_ = s;
+ flagforupdate_ = true;
+}
+
+void Label::setColor(double r, double g, double b, double a)
+{
+ Drawable::setColor(r,g,b,a);
+ flagforupdate_ = true;
+}
+
+void Label::setColor(Qwt3D::RGBA rgba)
+{
+ Drawable::setColor(rgba);
+ flagforupdate_ = true;
+}
+
+/**
+example:
+
+\verbatim
+
+ Anchor TopCenter (*) resp. BottomRight(X)
+
+ +----*----+
+ | Pixmap |
+ +---------X
+
+\endverbatim
+*/
+void Label::setPosition(Triple pos, ANCHOR a)
+{
+ anchor_ = a;
+ pos_ = pos;
+}
+
+void Label::setRelPosition(Tuple rpos, ANCHOR a)
+{
+ double ot = 0.99;
+
+ getMatrices(modelMatrix, projMatrix, viewport);
+ beg_ = relativePosition(Triple(rpos.x, rpos.y, ot));
+ setPosition(beg_, a);
+}
+
+void Label::update()
+{
+ QPainter p;
+ QFontMetrics fm(font_);
+
+ QFontInfo info(font_);
+
+ QRect r = QRect(QPoint(0,0),fm.size(Qwt3D::SingleLine, text_));//fm.boundingRect(text_) misbehaviour under linux;
+
+#if QT_VERSION < 0x040000
+ r.moveBy(0, -r.top());
+#else
+ r.translate(0, -r.top());
+#endif
+
+ pm_ = QPixmap(r.width(), r.bottom());
+
+ if (pm_.isNull()) // else crash under linux
+ {
+ r = QRect(QPoint(0,0),fm.size(Qwt3D::SingleLine, QString(" "))); // draw empty space else //todo
+#if QT_VERSION < 0x040000
+ r.moveBy(0, -r.top());
+#else
+ r.translate(0, -r.top());
+#endif
+ pm_ = QPixmap(r.width(), r.bottom());
+ }
+
+ QBitmap bm(pm_.width(),pm_.height());
+ bm.fill(Qt::color0);
+ p.begin( &bm );
+ p.setPen(Qt::color1);
+ p.setFont(font_);
+ p.drawText(0,r.height() - fm.descent() -1 , text_);
+ p.end();
+
+ pm_.setMask(bm);
+
+ // avoids uninitialized areas in some cases
+#if QT_VERSION < 0x040000
+ pm_.fill();
+#endif
+ p.begin( &pm_ );
+ p.setFont( font_ );
+ p.setPen( Qt::SolidLine );
+ p.setPen( GL2Qt(color.r, color.g, color.b) );
+
+ p.drawText(0,r.height() - fm.descent() -1 , text_);
+ p.end();
+#if QT_VERSION < 0x040000
+ buf_ = pm_.convertToImage();
+#else
+ buf_ = pm_.toImage();
+#endif
+ tex_ = QGLWidget::convertToGLFormat( buf_ ); // flipped 32bit RGBA ?
+}
+
+/**
+Adds an additional shift to the anchor point. This happens in a more or less intelligent manner
+depending on the nature of the anchor:
+\verbatim
+anchor type shift
+
+left aligned -->
+right aligned <--
+top aligned top-down
+bottom aligned bottom-up
+\endverbatim
+The unit is user space dependend (one pixel on screen - play around to get satisfying results)
+*/
+void Label::adjust(int gap)
+{
+ gap_ = gap;
+}
+
+void Label::convert2screen()
+{
+ Triple start = World2ViewPort(pos_);
+
+ switch (anchor_)
+ {
+ case BottomLeft :
+ beg_ = pos_;
+ break;
+ case BottomRight:
+ beg_ = ViewPort2World(start - Triple(width() + gap_, 0, 0));
+ break;
+ case BottomCenter:
+ beg_ = ViewPort2World(start - Triple(width() / 2, -gap_, 0));
+ break;
+ case TopRight:
+ beg_ = ViewPort2World(start - Triple(width() + gap_, height(), 0));
+ break;
+ case TopLeft:
+ beg_ = ViewPort2World(start - Triple(-gap_, height(), 0));
+ break;
+ case TopCenter:
+ beg_ = ViewPort2World(start - Triple(width() / 2, height() + gap_, 0));
+ break;
+ case CenterLeft:
+ beg_ = ViewPort2World(start - Triple(-gap_, height() / 2, 0));
+ break;
+ case CenterRight:
+ beg_ = ViewPort2World(start - Triple(width() + gap_, height() / 2, 0));
+ break;
+ case Center:
+ beg_ = ViewPort2World(start - Triple(width() / 2, height() / 2, 0));
+ break;
+ default:
+ break;
+ }
+ start = World2ViewPort(beg_);
+ end_ = ViewPort2World(start + Triple(width(), height(), 0));
+}
+
+void Label::draw()
+{
+ if (flagforupdate_)
+ {
+ update();
+ flagforupdate_ = false;
+ }
+
+ if (buf_.isNull())
+ return;
+
+ GLboolean b;
+ GLint func;
+ GLdouble v;
+ glGetBooleanv(GL_ALPHA_TEST, &b);
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, &func);
+ glGetDoublev(GL_ALPHA_TEST_REF, &v);
+
+ glEnable (GL_ALPHA_TEST);
+ glAlphaFunc (GL_NOTEQUAL, 0.0);
+
+ convert2screen();
+ glRasterPos3d(beg_.x, beg_.y, beg_.z);
+
+
+ int w = tex_.width();
+ int h = tex_.height();
+
+ if (devicefonts_)
+ {
+ drawDeviceText(QWT3DLOCAL8BIT(text_), "Courier", font_.pointSize(), pos_, color, anchor_, gap_);
+ }
+ else
+ {
+ drawDevicePixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());
+// glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());
+ }
+
+
+ glAlphaFunc(func,v);
+ Enable(GL_ALPHA_TEST, b);
+}
+
+
+double Label::width() const
+{
+ return pm_.width();
+}
+
+double Label::height() const
+{
+ return pm_.height();
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_lighting.cpp b/lib/tqwtplot3d/src/qwt3d_lighting.cpp new file mode 100644 index 0000000..2f368a0 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_lighting.cpp @@ -0,0 +1,192 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#pragma warning ( disable : 4786 )
+#endif
+
+#include <float.h>
+#include "qwt3d_plot.h"
+
+using namespace Qwt3D;
+
+namespace {
+inline GLenum lightEnum(unsigned idx)
+{
+ switch(idx) {
+ case 0:
+ return GL_LIGHT0;
+ case 1:
+ return GL_LIGHT1;
+ case 2:
+ return GL_LIGHT2;
+ case 3:
+ return GL_LIGHT3;
+ case 4:
+ return GL_LIGHT4;
+ case 5:
+ return GL_LIGHT5;
+ case 6:
+ return GL_LIGHT6;
+ case 7:
+ return GL_LIGHT7;
+ default:
+ return GL_LIGHT0;
+ }
+}
+
+}
+
+void Plot3D::enableLighting(bool val)
+{
+ if (lighting_enabled_ == val)
+ return;
+
+ lighting_enabled_ = val;
+ makeCurrent();
+ if (val)
+ glEnable(GL_LIGHTING);
+ else
+ glDisable(GL_LIGHTING);
+
+ if (!initializedGL())
+ return;
+ updateGL();
+}
+
+void Plot3D::disableLighting(bool val)
+{
+ enableLighting(!val);
+}
+
+bool Plot3D::lightingEnabled() const
+{
+ return lighting_enabled_;
+}
+
+/**
+ \param light light number [0..7]
+ \see setLight
+*/
+void Plot3D::illuminate(unsigned light)
+{
+ if (light>7)
+ return;
+ lights_[light].unlit = false;
+}
+/**
+ \param light light number [0..7]
+ \see setLight
+*/
+void Plot3D::blowout(unsigned light)
+{
+ if (light>7)
+ return;
+ lights_[light].unlit = false;
+}
+
+/**
+ Sets GL material properties
+*/
+void Plot3D::setMaterialComponent(GLenum property, double r, double g, double b, double a)
+{
+ GLfloat rgba[4] = {(GLfloat)r, (GLfloat)g, (GLfloat)b, (GLfloat)a};
+ makeCurrent();
+ glMaterialfv(GL_FRONT_AND_BACK, property, rgba);
+}
+
+/**
+ This function is for convenience. It sets GL material properties with the equal r,g,b values
+ and a blending alpha with value 1.0
+*/
+void Plot3D::setMaterialComponent(GLenum property, double intensity)
+{
+ setMaterialComponent(property,intensity,intensity,intensity,1.0);
+}
+
+/**
+ Sets GL shininess
+*/
+void Plot3D::setShininess(double exponent)
+{
+ makeCurrent();
+ glMaterialf(GL_FRONT, GL_SHININESS, exponent);
+}
+
+/**
+ Sets GL light properties for light 'light'
+*/
+void Plot3D::setLightComponent(GLenum property, double r, double g, double b, double a, unsigned light)
+{
+ GLfloat rgba[4] = {(GLfloat)r, (GLfloat)g, (GLfloat)b, (GLfloat)a};
+ makeCurrent();
+ glLightfv(lightEnum(light), property, rgba);
+}
+
+/**
+ This function is for convenience. It sets GL light properties with the equal r,g,b values
+ and a blending alpha with value 1.0
+*/
+void Plot3D::setLightComponent(GLenum property, double intensity, unsigned light)
+{
+ setLightComponent(property,intensity,intensity,intensity,1.0, lightEnum(light));
+}
+
+/**
+ Set the rotation angle of the light source. If you look along the respective axis towards ascending values,
+ the rotation is performed in mathematical \e negative sense
+ \param xVal angle in \e degree to rotate around the X axis
+ \param yVal angle in \e degree to rotate around the Y axis
+ \param zVal angle in \e degree to rotate around the Z axis
+ \param light light number
+*/
+void Plot3D::setLightRotation( double xVal, double yVal, double zVal, unsigned light )
+{
+ if (light>7)
+ return;
+ lights_[light].rot.x = xVal;
+ lights_[light].rot.y = yVal;
+ lights_[light].rot.z = zVal;
+}
+
+/**
+ Set the shift in light source (world) coordinates.
+ \param xVal shift along (world) X axis
+ \param yVal shift along (world) Y axis
+ \param zVal shift along (world) Z axis
+ \param light light number
+ \see setViewportShift()
+*/
+void Plot3D::setLightShift( double xVal, double yVal, double zVal, unsigned light )
+{
+ if (light>7)
+ return;
+ lights_[light].shift.x = xVal;
+ lights_[light].shift.y = yVal;
+ lights_[light].shift.z = zVal;
+}
+
+void Plot3D::applyLight(unsigned light)
+{
+ if (lights_[light].unlit)
+ return;
+
+ glEnable(lightEnum(light));
+ glLoadIdentity();
+
+ glRotatef( lights_[light].rot.x-90, 1.0, 0.0, 0.0 );
+ glRotatef( lights_[light].rot.y , 0.0, 1.0, 0.0 );
+ glRotatef( lights_[light].rot.z , 0.0, 0.0, 1.0 );
+ GLfloat lightPos[4] = { lights_[light].shift.x, lights_[light].shift.y, lights_[light].shift.z, 1.0};
+ GLenum le = lightEnum(light);
+ glLightfv(le, GL_POSITION, lightPos);
+}
+
+void Plot3D::applyLights()
+{
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ for (unsigned i=0; i<8; ++i)
+ {
+ applyLight(i);
+ }
+ glPopMatrix();
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_meshplot.cpp b/lib/tqwtplot3d/src/qwt3d_meshplot.cpp new file mode 100644 index 0000000..0c975fe --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_meshplot.cpp @@ -0,0 +1,320 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#pragma warning ( disable : 4786 )
+#endif
+
+#include "qwt3d_surfaceplot.h"
+#include "qwt3d_enrichment_std.h"
+
+using namespace std;
+using namespace Qwt3D;
+
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// cell specific
+//
+
+
+void SurfacePlot::createDataC()
+{
+ createFloorDataC();
+
+ if (plotStyle() == NOPLOT)
+ return;
+
+ if (plotStyle() == Qwt3D::POINTS)
+ {
+ createPoints();
+ return;
+ }
+ else if (plotStyle() == Qwt3D::USER)
+ {
+ if (userplotstyle_p)
+ createEnrichment(*userplotstyle_p);
+ return;
+ }
+
+ setDeviceLineWidth(meshLineWidth());
+ GLStateBewarer sb(GL_POLYGON_OFFSET_FILL,true);
+ setDevicePolygonOffset(polygonOffset(),1.0);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ int idx = 0;
+ if (plotStyle() != WIREFRAME)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
+
+ bool hl = (plotStyle() == HIDDENLINE);
+ if (hl)
+ {
+ RGBA col = backgroundRGBAColor();
+ glColor4d(col.r, col.g, col.b, col.a);
+ }
+
+ for (unsigned i=0; i!=actualDataC_->cells.size(); ++i)
+ {
+ glBegin(GL_POLYGON);
+ for (unsigned j=0; j!=actualDataC_->cells[i].size(); ++j)
+ {
+ idx = actualDataC_->cells[i][j];
+ setColorFromVertexC(idx, hl);
+ glVertex3d( actualDataC_->nodes[idx].x, actualDataC_->nodes[idx].y, actualDataC_->nodes[idx].z );
+ glNormal3d( actualDataC_->normals[idx].x, actualDataC_->normals[idx].y, actualDataC_->normals[idx].z );
+ }
+ glEnd();
+ }
+ }
+
+ if (plotStyle() == FILLEDMESH || plotStyle() == WIREFRAME || plotStyle() == HIDDENLINE)
+ {
+ glColor4d(meshColor().r, meshColor().g, meshColor().b, meshColor().a);
+ {
+ for (unsigned i=0; i!=actualDataC_->cells.size(); ++i)
+ {
+ glBegin(GL_LINE_LOOP);
+ for (unsigned j=0; j!=actualDataC_->cells[i].size(); ++j)
+ {
+ idx = actualDataC_->cells[i][j];
+ glVertex3d( actualDataC_->nodes[idx].x, actualDataC_->nodes[idx].y, actualDataC_->nodes[idx].z );
+ }
+ glEnd();
+ }
+ }
+ }
+}
+
+// ci = cell index
+// cv = vertex index in cell ci
+void SurfacePlot::setColorFromVertexC(int node, bool skip)
+{
+ if (skip)
+ return;
+
+ RGBA col = (*datacolor_p)(
+ actualDataC_->nodes[node].x, actualDataC_->nodes[node].y, actualDataC_->nodes[node].z);
+
+ glColor4d(col.r, col.g, col.b, col.a);
+}
+
+void SurfacePlot::createFloorDataC()
+{
+ switch (floorStyle())
+ {
+ case FLOORDATA:
+ Data2FloorC();
+ break;
+ case FLOORISO:
+ Isolines2FloorC();
+ break;
+ default:
+ break;
+ }
+}
+
+void SurfacePlot::Data2FloorC()
+{
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ double zshift = actualDataC_->hull().minVertex.z;
+ int idx;
+
+ for (unsigned i = 0; i!=actualDataC_->cells.size(); ++i)
+ {
+ glBegin(GL_POLYGON);
+ for (unsigned j=0; j!=actualDataC_->cells[i].size(); ++j)
+ {
+ idx = actualDataC_->cells[i][j];
+ setColorFromVertexC(idx);
+ glVertex3d( actualDataC_->nodes[idx].x, actualDataC_->nodes[idx].y, zshift );
+ }
+ glEnd();
+ }
+}
+
+void SurfacePlot::Isolines2FloorC()
+{
+ if (isolines() <= 0 || actualData_p->empty())
+ return;
+
+ double step = (actualData_p->hull().maxVertex.z - actualData_p->hull().minVertex.z) / isolines();
+
+ RGBA col;
+
+ double zshift = actualData_p->hull().minVertex.z;
+
+ TripleField nodes;
+ TripleField intersection;
+
+ double lambda = 0;
+
+ GLStateBewarer sb2(GL_LINE_SMOOTH, false);
+
+ for (int k = 0; k != isolines(); ++k)
+ {
+ double val = zshift + k * step;
+
+ for (unsigned i=0; i!=actualDataC_->cells.size(); ++i)
+ {
+ nodes.clear();
+ unsigned cellnodes = actualDataC_->cells[i].size();
+ for (unsigned j=0; j!=cellnodes; ++j)
+ {
+ nodes.push_back(actualDataC_->nodes[actualDataC_->cells[i][j]]);
+ }
+
+ double diff = 0;
+ for (unsigned m = 0; m!=cellnodes; ++m)
+ {
+ unsigned mm = (m+1)%cellnodes;
+ if ((val>=nodes[m].z && val<=nodes[mm].z) || (val>=nodes[mm].z && val<=nodes[m].z))
+ {
+ diff = nodes[mm].z - nodes[m].z;
+
+ if (isPracticallyZero(diff)) // degenerated
+ {
+ intersection.push_back(nodes[m]);
+ intersection.push_back(nodes[mm]);
+ continue;
+ }
+
+ lambda = (val - nodes[m].z) / diff;
+ intersection.push_back(Triple(nodes[m].x + lambda * (nodes[mm].x-nodes[m].x), nodes[m].y + lambda * (nodes[mm].y-nodes[m].y), val));
+ }
+ }
+
+ if (!intersection.empty())
+ {
+ col = (*datacolor_p)(nodes[0].x,nodes[0].y,nodes[0].z);
+ glColor4d(col.r, col.g, col.b, col.a);
+ if (intersection.size()>2)
+ {
+ glBegin(GL_LINE_STRIP);
+ for (unsigned dd = 0; dd!=intersection.size(); ++dd)
+ {
+ glVertex3d(intersection[dd].x, intersection[dd].y, zshift);
+ }
+ glEnd();
+ glBegin(GL_POINTS);
+ glVertex3d(intersection[0].x,intersection[0].y,zshift);
+ glEnd();
+ }
+ else if (intersection.size() == 2)
+ {
+ glBegin(GL_LINES);
+ glVertex3d(intersection[0].x,intersection[0].y,zshift);
+ glVertex3d(intersection[1].x,intersection[1].y,zshift);
+
+ // small pixel gap problem (see OpenGL spec.)
+ glVertex3d(intersection[1].x,intersection[1].y,zshift);
+ glVertex3d(intersection[0].x,intersection[0].y,zshift);
+ glEnd();
+ }
+
+ intersection.clear();
+ }
+ }
+ }
+}
+
+void SurfacePlot::createNormalsC()
+{
+ if (!normals() || actualData_p->empty())
+ return;
+
+ if (actualDataC_->nodes.size() != actualDataC_->normals.size())
+ return;
+ Arrow arrow;
+ arrow.setQuality(normalQuality());
+
+ Triple basev, topv, norm;
+
+ double diag = (actualData_p->hull().maxVertex-actualData_p->hull().minVertex).length() * normalLength();
+
+ RGBA col;
+ arrow.assign(*this);
+ arrow.drawBegin();
+ for (unsigned i = 0; i != actualDataC_->normals.size(); ++i)
+ {
+ basev = actualDataC_->nodes[i];
+ topv = basev + actualDataC_->normals[i];
+
+ norm = topv-basev;
+ norm.normalize();
+ norm *= diag;
+
+ arrow.setTop(basev+norm);
+ arrow.setColor((*datacolor_p)(basev.x,basev.y,basev.z));
+ arrow.draw(basev);
+ }
+ arrow.drawEnd();
+}
+
+/*!
+ Convert user (non-rectangular) mesh based data to internal structure.
+ See also Qwt3D::TripleField and Qwt3D::CellField
+*/
+bool SurfacePlot::loadFromData(TripleField const& data, CellField const& poly)
+{
+ actualDataG_->clear();
+ actualData_p = actualDataC_;
+
+ actualDataC_->nodes = data;
+ actualDataC_->cells = poly;
+ actualDataC_->normals = TripleField(actualDataC_->nodes.size());
+
+ unsigned i;
+
+// normals for the moment
+ Triple n, u, v;
+ for ( i = 0; i < poly.size(); ++i)
+ {
+ if (poly[i].size() < 3)
+ n = Triple(0,0,0);
+ else
+ {
+ for (unsigned j = 0; j < poly[i].size(); ++j)
+ {
+ unsigned jj = (j+1) % poly[i].size();
+ unsigned pjj = (j) ? j-1 : poly[i].size()-1;
+ u = actualDataC_->nodes[poly[i][jj]]-actualDataC_->nodes[poly[i][j]];
+ v = actualDataC_->nodes[poly[i][pjj]]-actualDataC_->nodes[poly[i][j]];
+ n = normalizedcross(u,v);
+ actualDataC_->normals[poly[i][j]] += n;
+ }
+ }
+ }
+ for ( i = 0; i != actualDataC_->normals.size(); ++i)
+ {
+ actualDataC_->normals[i].normalize();
+ }
+
+ ParallelEpiped hull(Triple(DBL_MAX,DBL_MAX,DBL_MAX),Triple(-DBL_MAX,-DBL_MAX,-DBL_MAX));
+
+ for (i = 0; i!=data.size(); ++i)
+ {
+ if (data[i].x < hull.minVertex.x)
+ hull.minVertex.x = data[i].x;
+ if (data[i].y < hull.minVertex.y)
+ hull.minVertex.y = data[i].y;
+ if (data[i].z < hull.minVertex.z)
+ hull.minVertex.z = data[i].z;
+
+ if (data[i].x > hull.maxVertex.x)
+ hull.maxVertex.x = data[i].x;
+ if (data[i].y > hull.maxVertex.y)
+ hull.maxVertex.y = data[i].y;
+ if (data[i].z > hull.maxVertex.z)
+ hull.maxVertex.z = data[i].z;
+ }
+
+ actualDataC_->setHull(hull);
+
+ updateData();
+ updateNormals();
+ createCoordinateSystem();
+
+ return true;
+}
+
+
diff --git a/lib/tqwtplot3d/src/qwt3d_mousekeyboard.cpp b/lib/tqwtplot3d/src/qwt3d_mousekeyboard.cpp new file mode 100644 index 0000000..800bc06 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_mousekeyboard.cpp @@ -0,0 +1,387 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#pragma warning ( disable : 4786 )
+#endif
+
+#include "qwt3d_plot.h"
+
+using namespace std;
+using namespace Qwt3D;
+
+
+/**
+ Standard mouse button Function. Prepares the call to mouseMoveEvent
+ \see mouseMoveEvent()
+*/
+void Plot3D::mousePressEvent( QMouseEvent *e )
+{
+ lastMouseMovePosition_ = e->pos();
+ mpressed_ = true;
+}
+
+/**
+ Standard mouse button Function. Completes the call to mouseMoveEvent
+ \see mouseMoveEvent()
+*/
+void Plot3D::mouseReleaseEvent( QMouseEvent* )
+{
+ mpressed_ = false;
+}
+
+/**
+ Standard mouse button Function
+ \see assignMouse()
+*/
+void Plot3D::mouseMoveEvent( QMouseEvent *e )
+{
+ if (!mpressed_ || !mouseEnabled())
+ {
+ e->ignore();
+ return;
+ }
+
+#if QT_VERSION < 0x040000
+ MouseState bstate = e->state();
+#else
+ MouseState bstate(e->buttons(),e->modifiers());
+#endif
+
+ QPoint diff = e->pos() - lastMouseMovePosition_;
+
+ setRotationMouse(bstate, 3, diff);
+ setScaleMouse(bstate, 5, diff);
+ setShiftMouse(bstate, 2, diff);
+
+ lastMouseMovePosition_ = e->pos();
+}
+
+void Plot3D::setRotationMouse(MouseState bstate, double accel, QPoint diff)
+{
+ // Rotation
+ double w = max(1,width());
+ double h = max(1,height());
+
+ double relx = accel*360 * diff.x() / w;
+ double relyz = accel*360 * diff.y() / h;
+
+ double new_xrot = xRotation();
+ double new_yrot = yRotation();
+ double new_zrot = zRotation();
+
+ if ( bstate == xrot_mstate_ )
+ new_xrot = round(xRotation() + relyz) % 360;
+ if ( bstate == yrot_mstate_ )
+ new_yrot = round(yRotation() + relx) % 360;
+ if ( bstate == zrot_mstate_ )
+ new_zrot = round(zRotation() + relx) % 360;
+
+ setRotation(new_xrot, new_yrot, new_zrot);
+}
+
+void Plot3D::setScaleMouse(MouseState bstate, double accel, QPoint diff)
+{
+ // Scale
+ double w = max(1,width());
+ double h = max(1,height());
+
+ double relx = diff.x() * accel / w; relx = exp(relx) - 1;
+ double relyz = diff.y() * accel / h; relyz = exp(relyz) - 1;
+
+ double new_xscale = xScale();
+ double new_yscale = yScale();
+ double new_zscale = zScale();
+
+ if ( bstate == xscale_mstate_)
+ new_xscale = max(0.0,xScale() + relx);
+ if ( bstate == yscale_mstate_)
+ new_yscale = max(0.0,yScale() - relyz);
+ if ( bstate == zscale_mstate_)
+ new_zscale = max(0.0,zScale() - relyz);
+
+ setScale(new_xscale, new_yscale, new_zscale);
+
+ if ( bstate == zoom_mstate_)
+ setZoom(max(0.0,zoom() - relyz));
+}
+
+void Plot3D::setShiftMouse(MouseState bstate, double accel, QPoint diff)
+{
+ // Shift
+ double w = max(1,width());
+ double h = max(1,height());
+
+ double relx = diff.x() * accel / w;
+ double relyz = diff.y() * accel / h;
+
+ double new_xshift = xViewportShift();
+ double new_yshift = yViewportShift();
+
+ if ( bstate == xshift_mstate_)
+ new_xshift = xViewportShift() + relx;
+ if ( bstate == yshift_mstate_)
+ new_yshift = yViewportShift() - relyz;
+
+ setViewportShift(new_xshift, new_yshift);
+}
+
+/**
+ Standard wheel Function - zoom (wheel only) or z-scale (shift+wheel)
+*/
+void Plot3D::wheelEvent( QWheelEvent *e )
+{
+ if (!mouseEnabled())
+ return;
+
+ double accel = 0.05;
+
+ double step = accel * e->delta() / WHEEL_DELTA ;
+ step = exp(step)-1;
+
+#if QT_VERSION < 0x040000
+ if ( e->state() & Qt::ShiftButton )
+#else
+ if ( e->modifiers() & Qt::ShiftModifier )
+#endif
+ setScale(xScale(),yScale(), max(0.0,zScale() + step));
+ else
+ setZoom(max(0.0,zoom() + step ));
+}
+
+/**
+ Sets the key/mousebutton combination for data/coordinatesystem moves inside the widget\n\n
+ default behaviour:\n
+
+ \verbatim
+ rotate around x axis: Qt::LeftButton
+ rotate around y axis: Qt::LeftButton | Qt::ShiftButton
+ rotate around z axis: Qt::LeftButton
+ scale x: Qt::LeftButton | Qt::AltButton
+ scale y: Qt::LeftButton | Qt::AltButton
+ scale z: Qt::LeftButton | Qt::AltButton | Qt::ShiftButton
+ zoom: Qt::LeftButton | Qt::AltButton | Qt::ControlButton
+ shifting along x: Qt::LeftButton | Qt::ControlButton
+ shifting along y: Qt::LeftButton | Qt::ControlButton
+ \endverbatim
+
+ mouseMoveEvent() evaluates this function - if overridden, their usefulness becomes somehow limited
+*/
+void Plot3D::assignMouse(MouseState xrot, MouseState yrot, MouseState zrot,
+ MouseState xscale, MouseState yscale, MouseState zscale,
+ MouseState zoom, MouseState xshift, MouseState yshift)
+{
+ xrot_mstate_ = xrot;
+ yrot_mstate_ = yrot;
+ zrot_mstate_ = zrot;
+ xscale_mstate_ = xscale;
+ yscale_mstate_ = yscale;
+ zscale_mstate_ = zscale;
+ zoom_mstate_ = zoom;
+ xshift_mstate_ = xshift;
+ yshift_mstate_ = yshift;
+}
+
+/**
+The function has no effect if you derive from Plot3D and overrides the mouse Function too careless.
+In this case check first against mouseEnabled() in your version of mouseMoveEvent() and wheelEvent().
+A more fine grained input control can be achieved by combining assignMouse() with enableMouse().
+*/
+void Plot3D::enableMouse(bool val) {mouse_input_enabled_ = val;}
+
+/**
+\see enableMouse()
+*/
+void Plot3D::disableMouse(bool val) {mouse_input_enabled_ = !val;}
+bool Plot3D::mouseEnabled() const {return mouse_input_enabled_;}
+
+
+
+
+void Plot3D::keyPressEvent( QKeyEvent *e )
+{
+ if (!keyboardEnabled())
+ {
+ e->ignore();
+ return;
+ }
+
+#if QT_VERSION < 0x040000
+ int bstate = e->state() & Qt::KeyButtonMask; // filter kbd modifier only
+ KeyboardState keyseq = bstate + e->key();
+#else
+ KeyboardState keyseq(e->key(), e->modifiers());
+#endif
+
+ setRotationKeyboard(keyseq, kbd_rot_speed_);
+ setScaleKeyboard(keyseq, kbd_scale_speed_);
+ setShiftKeyboard(keyseq, kbd_shift_speed_);
+}
+
+void Plot3D::setRotationKeyboard(KeyboardState kseq, double speed)
+{
+ // Rotation
+ double w = max(1,width());
+ double h = max(1,height());
+
+ double relx = speed*360 / w;
+ double relyz = speed*360 / h;
+
+ double new_xrot = xRotation();
+ double new_yrot = yRotation();
+ double new_zrot = zRotation();
+
+ if ( kseq == xrot_kstate_[0] )
+ new_xrot = round(xRotation() + relyz) % 360;
+ if ( kseq == xrot_kstate_[1] )
+ new_xrot = round(xRotation() - relyz) % 360;
+ if ( kseq == yrot_kstate_[0] )
+ new_yrot = round(yRotation() + relx) % 360;
+ if ( kseq == yrot_kstate_[1] )
+ new_yrot = round(yRotation() - relx) % 360;
+ if ( kseq == zrot_kstate_[0] )
+ new_zrot = round(zRotation() + relx) % 360;
+ if ( kseq == zrot_kstate_[1] )
+ new_zrot = round(zRotation() - relx) % 360;
+
+ setRotation(new_xrot, new_yrot, new_zrot);
+}
+
+void Plot3D::setScaleKeyboard(KeyboardState kseq, double speed)
+{
+ // Scale
+ double w = max(1,width());
+ double h = max(1,height());
+
+ double relx = speed / w; relx = exp(relx) - 1;
+ double relyz = speed / h; relyz = exp(relyz) - 1;
+
+ double new_xscale = xScale();
+ double new_yscale = yScale();
+ double new_zscale = zScale();
+
+ if ( kseq == xscale_kstate_[0])
+ new_xscale = max(0.0,xScale() + relx);
+ if ( kseq == xscale_kstate_[1])
+ new_xscale = max(0.0,xScale() - relx);
+ if ( kseq == yscale_kstate_[0])
+ new_yscale = max(0.0,yScale() - relyz);
+ if ( kseq == yscale_kstate_[1])
+ new_yscale = max(0.0,yScale() + relyz);
+ if ( kseq == zscale_kstate_[0])
+ new_zscale = max(0.0,zScale() - relyz);
+ if ( kseq == zscale_kstate_[1])
+ new_zscale = max(0.0,zScale() + relyz);
+
+ setScale(new_xscale, new_yscale, new_zscale);
+
+ if ( kseq == zoom_kstate_[0])
+ setZoom(max(0.0,zoom() - relyz));
+ if ( kseq == zoom_kstate_[1])
+ setZoom(max(0.0,zoom() + relyz));
+}
+
+void Plot3D::setShiftKeyboard(KeyboardState kseq, double speed)
+{
+ // Shift
+ double w = max(1,width());
+ double h = max(1,height());
+
+ double relx = speed / w;
+ double relyz = speed / h;
+
+ double new_xshift = xViewportShift();
+ double new_yshift = yViewportShift();
+
+ if ( kseq == xshift_kstate_[0])
+ new_xshift = xViewportShift() + relx;
+ if ( kseq == xshift_kstate_[1])
+ new_xshift = xViewportShift() - relx;
+ if ( kseq == yshift_kstate_[0])
+ new_yshift = yViewportShift() - relyz;
+ if ( kseq == yshift_kstate_[1])
+ new_yshift = yViewportShift() + relyz;
+
+ setViewportShift(new_xshift, new_yshift);
+}
+
+/**
+ Sets the keybutton combination for data/coordinatesystem moves inside the widget\n\n
+ default behaviour:\n
+
+ \verbatim
+ rotate around x axis: [Key_Down, Key_Up]
+ rotate around y axis: SHIFT+[Key_Right, Key_Left]
+ rotate around z axis: [Key_Right, Key_Left]
+ scale x: ALT+[Key_Right, Key_Left]
+ scale y: ALT+[Key_Up, Key_Down]
+ scale z: ALT+SHIFT[Key_Down, Key_Up]
+ zoom: ALT+CTRL+[Key_Down, Key_Up]
+ shifting along x: CTRL+[Key_Right, Key_Left]
+ shifting along z: CTRL+[Key_Down, Key_Up]
+ \endverbatim
+*/
+void Plot3D::assignKeyboard(
+ KeyboardState xrot_n, KeyboardState xrot_p
+ ,KeyboardState yrot_n, KeyboardState yrot_p
+ ,KeyboardState zrot_n, KeyboardState zrot_p
+ ,KeyboardState xscale_n, KeyboardState xscale_p
+ ,KeyboardState yscale_n, KeyboardState yscale_p
+ ,KeyboardState zscale_n, KeyboardState zscale_p
+ ,KeyboardState zoom_n, KeyboardState zoom_p
+ ,KeyboardState xshift_n, KeyboardState xshift_p
+ ,KeyboardState yshift_n, KeyboardState yshift_p
+ )
+{
+ xrot_kstate_[0] = xrot_n;
+ yrot_kstate_[0] = yrot_n;
+ zrot_kstate_[0] = zrot_n;
+ xrot_kstate_[1] = xrot_p;
+ yrot_kstate_[1] = yrot_p;
+ zrot_kstate_[1] = zrot_p;
+
+ xscale_kstate_[0] = xscale_n;
+ yscale_kstate_[0] = yscale_n;
+ zscale_kstate_[0] = zscale_n;
+ xscale_kstate_[1] = xscale_p;
+ yscale_kstate_[1] = yscale_p;
+ zscale_kstate_[1] = zscale_p;
+
+ zoom_kstate_[0] = zoom_n;
+ xshift_kstate_[0] = xshift_n;
+ yshift_kstate_[0] = yshift_n;
+ zoom_kstate_[1] = zoom_p;
+ xshift_kstate_[1] = xshift_p;
+ yshift_kstate_[1] = yshift_p;
+}
+
+/**
+The function has no effect if you derive from Plot3D and overrides the keyboard Functions too careless.
+In this case check first against keyboardEnabled() in your version of keyPressEvent()
+A more fine grained input control can be achieved by combining assignKeyboard() with enableKeyboard().
+*/
+void Plot3D::enableKeyboard(bool val) {kbd_input_enabled_ = val;}
+
+/**
+\see enableKeyboard()
+*/
+void Plot3D::disableKeyboard(bool val) {kbd_input_enabled_ = !val;}
+bool Plot3D::keyboardEnabled() const {return kbd_input_enabled_;}
+
+/**
+Values < 0 are ignored. Default is (3,5,5)
+*/
+void Plot3D::setKeySpeed(double rot, double scale, double shift)
+{
+ if (rot > 0)
+ kbd_rot_speed_ = rot;
+ if (scale > 0)
+ kbd_scale_speed_ = scale;
+ if (shift > 0)
+ kbd_shift_speed_ = shift;
+}
+
+void Plot3D::keySpeed(double& rot, double& scale, double& shift) const
+{
+ rot = kbd_rot_speed_;
+ scale = kbd_scale_speed_;
+ shift = kbd_shift_speed_;
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_movements.cpp b/lib/tqwtplot3d/src/qwt3d_movements.cpp new file mode 100644 index 0000000..73ff9b1 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_movements.cpp @@ -0,0 +1,106 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#pragma warning ( disable : 4786 )
+#endif
+
+#include <float.h>
+#include "qwt3d_plot.h"
+
+using namespace Qwt3D;
+
+
+/**
+ Set the rotation angle of the object. If you look along the respective axis towards ascending values,
+ the rotation is performed in mathematical \e negative sense
+ \param xVal angle in \e degree to rotate around the X axis
+ \param yVal angle in \e degree to rotate around the Y axis
+ \param zVal angle in \e degree to rotate around the Z axis
+*/
+void Plot3D::setRotation( double xVal, double yVal, double zVal )
+{
+ if (xRot_ == xVal && yRot_ == yVal && zRot_ == zVal)
+ return;
+
+ xRot_ = xVal;
+ yRot_ = yVal;
+ zRot_ = zVal;
+
+ updateGL();
+ emit rotationChanged(xVal, yVal, zVal);
+}
+
+/**
+ Set the shift in object (world) coordinates.
+ \param xVal shift along (world) X axis
+ \param yVal shift along (world) Y axis
+ \param zVal shift along (world) Z axis
+ \see setViewportShift()
+*/
+void Plot3D::setShift( double xVal, double yVal, double zVal )
+{
+ if (xShift_ == xVal && yShift_ == yVal && zShift_ == zVal)
+ return;
+
+ xShift_ = xVal;
+ yShift_ = yVal;
+ zShift_ = zVal;
+ updateGL();
+ emit shiftChanged(xVal, yVal, zVal);
+}
+
+/**
+ Performs shifting along screen axes.
+ The shift moves points inside a sphere,
+ which encloses the unscaled and unzoomed data
+ by multiples of the spheres diameter
+
+ \param xVal shift along (view) X axis
+ \param yVal shift along (view) Y axis
+ \see setShift()
+*/
+void Plot3D::setViewportShift( double xVal, double yVal )
+{
+ if (xVPShift_ == xVal && yVPShift_ == yVal)
+ return;
+
+ xVPShift_ = xVal;
+ yVPShift_ = yVal;
+
+ updateGL();
+ emit vieportShiftChanged(xVPShift_, yVPShift_);
+}
+
+/**
+ Set the scale in object (world) coordinates.
+ \param xVal scaling for X values
+ \param yVal scaling for Y values
+ \param zVal scaling for Z values
+
+ A respective value of 1 represents no scaling;
+*/
+void Plot3D::setScale( double xVal, double yVal, double zVal )
+{
+ if (xScale_ == xVal && yScale_ == yVal && zScale_ == zVal)
+ return;
+
+ xScale_ = (xVal < DBL_EPSILON ) ? DBL_EPSILON : xVal;
+ yScale_ = (yVal < DBL_EPSILON ) ? DBL_EPSILON : yVal;
+ zScale_ = (zVal < DBL_EPSILON ) ? DBL_EPSILON : zVal;
+
+ updateGL();
+ emit scaleChanged(xVal, yVal, zVal);
+}
+
+/**
+ Set the (zoom in addition to scale).
+ \param val zoom value (value == 1 indicates no zooming)
+*/
+void Plot3D::setZoom( double val )
+{
+ if (zoom_ == val)
+ return;
+
+ zoom_ = (val < DBL_EPSILON ) ? DBL_EPSILON : val;
+ updateGL();
+ emit zoomChanged(val);
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_parametricsurface.cpp b/lib/tqwtplot3d/src/qwt3d_parametricsurface.cpp new file mode 100644 index 0000000..c3103c9 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_parametricsurface.cpp @@ -0,0 +1,104 @@ +#include "qwt3d_parametricsurface.h"
+#include "qwt3d_surfaceplot.h"
+
+using namespace Qwt3D;
+
+ParametricSurface::ParametricSurface()
+:GridMapping()
+{
+}
+
+ParametricSurface::ParametricSurface(SurfacePlot& pw)
+:GridMapping()
+{
+ plotwidget_p = &pw;
+ uperiodic_ = false;
+ vperiodic_ = false;
+}
+
+ParametricSurface::ParametricSurface(SurfacePlot* pw)
+:GridMapping()
+{
+ plotwidget_p = pw;
+ uperiodic_ = false;
+ vperiodic_ = false;
+}
+
+void ParametricSurface::setPeriodic(bool u, bool v)
+{
+ uperiodic_ = u;
+ vperiodic_ = v;
+}
+
+void ParametricSurface::assign(SurfacePlot& plotWidget)
+{
+ if (&plotWidget != plotwidget_p)
+ plotwidget_p = &plotWidget;
+}
+
+void ParametricSurface::assign(SurfacePlot* plotWidget)
+{
+ if (plotWidget != plotwidget_p)
+ plotwidget_p = plotWidget;
+}
+
+/**
+For plotWidget != 0 the function permanently assigns her argument (In fact, assign(plotWidget) is called)
+*/
+bool ParametricSurface::create()
+{
+ if ((umesh_p<=2) || (vmesh_p<=2) || !plotwidget_p)
+ return false;
+
+ /* allocate some space for the mesh */
+ Triple** data = new Triple* [umesh_p] ;
+
+ unsigned i,j;
+ for ( i = 0; i < umesh_p; i++)
+ {
+ data[i] = new Triple [vmesh_p];
+ }
+
+ /* get the data */
+
+ double du = (maxu_p - minu_p) / (umesh_p - 1);
+ double dv = (maxv_p - minv_p) / (vmesh_p - 1);
+
+ for (i = 0; i < umesh_p; ++i)
+ {
+ for (j = 0; j < vmesh_p; ++j)
+ {
+ data[i][j] = operator()(minu_p + i*du, minv_p + j*dv);
+
+ if (data[i][j].x > range_p.maxVertex.x)
+ data[i][j].x = range_p.maxVertex.x;
+ else if (data[i][j].y > range_p.maxVertex.y)
+ data[i][j].y = range_p.maxVertex.y;
+ else if (data[i][j].z > range_p.maxVertex.z)
+ data[i][j].z = range_p.maxVertex.z;
+ else if (data[i][j].x < range_p.minVertex.x)
+ data[i][j].x = range_p.minVertex.x;
+ else if (data[i][j].y < range_p.minVertex.y)
+ data[i][j].y = range_p.minVertex.y;
+ else if (data[i][j].z < range_p.minVertex.z)
+ data[i][j].z = range_p.minVertex.z;
+ }
+ }
+
+ ((SurfacePlot*)plotwidget_p)->loadFromData(data, umesh_p, vmesh_p, uperiodic_, vperiodic_);
+
+ for ( i = 0; i < umesh_p; i++)
+ {
+ delete [] data[i];
+ }
+
+ delete [] data;
+
+ return true;
+}
+
+bool ParametricSurface::create(SurfacePlot& pl)
+{
+ assign(pl);
+ return create();
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_plot.cpp b/lib/tqwtplot3d/src/qwt3d_plot.cpp new file mode 100644 index 0000000..e61b125 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_plot.cpp @@ -0,0 +1,498 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4305 )
+#pragma warning ( disable : 4786 )
+#endif
+
+#include "qwt3d_plot.h"
+#include "qwt3d_enrichment.h"
+
+
+using namespace Qwt3D;
+
+/*!
+ This should be the first call in your derived classes constructors.
+*/
+#if QT_VERSION < 0x040000
+Plot3D::Plot3D( QWidget* parent, const char* name )
+ : QGLWidget( parent, name )
+#else
+Plot3D::Plot3D( QWidget * parent, const QGLWidget * shareWidget)
+ : QGLWidget( parent, shareWidget)
+#endif
+{
+ initializedGL_ = false;
+ renderpixmaprequest_ = false;
+ xRot_ = yRot_ = zRot_ = 0.0; // default object rotation
+
+ xShift_ = yShift_ = zShift_ = xVPShift_ = yVPShift_ = 0.0;
+ xScale_ = yScale_ = zScale_ = 1.0;
+ zoom_ = 1;
+ ortho_ = true;
+ plotstyle_ = FILLEDMESH;
+ userplotstyle_p = 0;
+ shading_ = GOURAUD;
+ floorstyle_ = NOFLOOR;
+ isolines_ = 10;
+ displaylegend_ = false;
+ smoothdatamesh_p = false;
+ actualData_p = 0;
+
+ lastMouseMovePosition_ = QPoint(0,0);
+ mpressed_ = false;
+ mouse_input_enabled_ = true;
+
+ setPolygonOffset(0.5);
+ setMeshColor(RGBA(0.0,0.0,0.0));
+ setMeshLineWidth(1);
+ setBackgroundColor(RGBA(1.0,1.0,1.0,1.0));
+
+ displaylists_p = std::vector<GLuint>(DisplayListSize);
+ for (unsigned k=0; k!=displaylists_p.size(); ++k)
+ {
+ displaylists_p[k] = 0;
+ }
+
+ datacolor_p = new StandardColor(this, 100);
+ title_.setFont("Courier", 16, QFont::Bold);
+ title_.setString("");
+
+ setTitlePosition(0.95);
+
+ kbd_input_enabled_ = true;
+
+#if QT_VERSION < 0x040000
+ setFocusPolicy(QWidget::StrongFocus);
+ assignMouse(Qt::LeftButton,
+ Qt::LeftButton | Qt::ShiftButton,
+ Qt::LeftButton,
+ Qt::LeftButton | Qt::AltButton,
+ Qt::LeftButton | Qt::AltButton,
+ Qt::LeftButton | Qt::AltButton | Qt::ShiftButton,
+ Qt::LeftButton | Qt::AltButton | Qt::ControlButton,
+ Qt::LeftButton | Qt::ControlButton,
+ Qt::LeftButton | Qt::ControlButton);
+
+
+ assignKeyboard(Qt::Key_Down, Qt::Key_Up,
+ Qt::ShiftButton + Qt::Key_Right, Qt::ShiftButton + Qt::Key_Left,
+ Qt::Key_Right, Qt::Key_Left,
+ Qt::AltButton + Qt::Key_Right, Qt::AltButton + Qt::Key_Left,
+ Qt::AltButton + Qt::Key_Down, Qt::AltButton + Qt::Key_Up,
+ Qt::AltButton + Qt::ShiftButton + Qt::Key_Down, Qt::AltButton + Qt::ShiftButton + Qt::Key_Up,
+ Qt::AltButton + Qt::ControlButton + Qt::Key_Down, Qt::AltButton + Qt::ControlButton + Qt::Key_Up,
+ Qt::ControlButton + Qt::Key_Right, Qt::ControlButton + Qt::Key_Left,
+ Qt::ControlButton + Qt::Key_Down, Qt::ControlButton + Qt::Key_Up
+ );
+#else
+ setFocusPolicy(Qt::StrongFocus);
+ assignMouse(Qt::LeftButton,
+ MouseState(Qt::LeftButton, Qt::ShiftModifier),
+ Qt::LeftButton,
+ MouseState(Qt::LeftButton, Qt::AltModifier),
+ MouseState(Qt::LeftButton, Qt::AltModifier),
+ MouseState(Qt::LeftButton, Qt::AltModifier | Qt::ShiftModifier),
+ MouseState(Qt::LeftButton, Qt::AltModifier | Qt::ControlModifier),
+ MouseState(Qt::LeftButton, Qt::ControlModifier),
+ MouseState(Qt::LeftButton, Qt::ControlModifier)
+ );
+
+
+ assignKeyboard(Qt::Key_Down, Qt::Key_Up,
+ KeyboardState(Qt::Key_Right, Qt::ShiftModifier), KeyboardState(Qt::Key_Left, Qt::ShiftModifier),
+ Qt::Key_Right, Qt::Key_Left,
+ KeyboardState(Qt::Key_Right, Qt::AltModifier), KeyboardState(Qt::Key_Left, Qt::AltModifier),
+ KeyboardState(Qt::Key_Down, Qt::AltModifier), KeyboardState(Qt::Key_Up, Qt::AltModifier),
+ KeyboardState(Qt::Key_Down, Qt::AltModifier|Qt::ShiftModifier), KeyboardState(Qt::Key_Up, Qt::AltModifier|Qt::ShiftModifier),
+ KeyboardState(Qt::Key_Down, Qt::AltModifier|Qt::ControlModifier), KeyboardState(Qt::Key_Up, Qt::AltModifier|Qt::ControlModifier),
+ KeyboardState(Qt::Key_Right, Qt::ControlModifier), KeyboardState(Qt::Key_Left, Qt::ControlModifier),
+ KeyboardState(Qt::Key_Down, Qt::ControlModifier), KeyboardState(Qt::Key_Up, Qt::ControlModifier)
+ );
+#endif
+ setKeySpeed(3,5,5);
+
+ legend_.setLimits(0, 100);
+ legend_.setMajors(10);
+ legend_.setMinors(2);
+ legend_.setOrientation(ColorLegend::BottomTop, ColorLegend::Left);
+
+ lighting_enabled_ = false;
+ disableLighting();
+ lights_ = std::vector<Light>(8);
+}
+
+/*!
+ Release allocated resources
+*/
+
+Plot3D::~Plot3D()
+{
+ makeCurrent();
+ SaveGlDeleteLists( displaylists_p[0], displaylists_p.size() );
+ datacolor_p->destroy();
+ delete userplotstyle_p;
+ for (ELIT it = elist_p.begin(); it!=elist_p.end(); ++it)
+ delete (*it);
+
+ elist_p.clear();
+}
+
+
+/*!
+ Set up the OpenGL rendering state
+*/
+void Plot3D::initializeGL()
+{
+ glEnable( GL_BLEND );
+ glEnable(GL_DEPTH_TEST);
+ glShadeModel(GL_SMOOTH);
+
+ // Set up the lights
+
+ disableLighting();
+
+ GLfloat whiteAmb[4] = {1.0, 1.0, 1.0, 1.0};
+
+ setLightShift(0, 0, 3000);
+ glEnable(GL_COLOR_MATERIAL);
+
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, whiteAmb);
+
+ setMaterialComponent(GL_DIFFUSE, 1.0);
+ setMaterialComponent(GL_SPECULAR, 0.3);
+ setMaterialComponent(GL_SHININESS, 5.0);
+ setLightComponent(GL_DIFFUSE, 1.0);
+ setLightComponent(GL_SPECULAR, 1.0);
+
+ initializedGL_ = true;
+ if (renderpixmaprequest_)
+ {
+ updateData();
+ renderpixmaprequest_ = false;
+ }
+}
+
+/*!
+ Paint the widgets content.
+*/
+void Plot3D::paintGL()
+{
+ glClearColor(bgcolor_.r, bgcolor_.g, bgcolor_.b, bgcolor_.a);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ applyLights();
+
+ glRotatef( -90, 1.0, 0.0, 0.0 );
+ glRotatef( 0.0, 0.0, 1.0, 0.0 );
+ glRotatef( 0.0, 0.0, 0.0, 1.0 );
+
+ if (displaylegend_)
+ {
+ legend_.draw();
+ }
+ title_.setRelPosition(titlerel_, titleanchor_);
+ title_.draw();
+
+ Triple beg = coordinates_p.first();
+ Triple end = coordinates_p.second();
+
+ Triple center = beg + (end-beg) / 2;
+ double radius = (center-beg).length();
+
+ glLoadIdentity();
+
+ glRotatef( xRot_-90, 1.0, 0.0, 0.0 );
+ glRotatef( yRot_, 0.0, 1.0, 0.0 );
+ glRotatef( zRot_, 0.0, 0.0, 1.0 );
+
+ glScalef( zoom_ * xScale_, zoom_ * yScale_, zoom_ * zScale_ );
+
+ glTranslatef(xShift_-center.x, yShift_-center.y, zShift_-center.z);
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+
+ if (beg != end)
+ {
+ if (ortho_)
+ {
+ glOrtho( -radius, +radius, -radius, +radius, 0, 40 * radius);
+ }
+ else
+ {
+ glFrustum( -radius, +radius, -radius, +radius, 5 * radius, 400 * radius );
+ }
+ }
+ else
+ {
+ if (ortho_)
+ glOrtho( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
+ else
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
+ }
+
+ glTranslatef( xVPShift_ * 2 * radius , yVPShift_ * 2 * radius , -7 * radius );
+
+ if (lighting_enabled_)
+ glEnable(GL_NORMALIZE);
+
+ for (unsigned i=0; i!= displaylists_p.size(); ++i)
+ {
+ if (i!=LegendObject)
+ glCallList( displaylists_p[i] );
+ }
+ coordinates_p.draw();
+
+ if (lighting_enabled_)
+ glDisable(GL_NORMALIZE);
+
+ glMatrixMode( GL_MODELVIEW );
+ glPopMatrix();
+}
+
+
+/*!
+ Set up the OpenGL view port
+*/
+void Plot3D::resizeGL( int w, int h )
+{
+ glViewport( 0, 0, w, h );
+ paintGL();
+}
+
+/*!
+ Reimplemented from QGLWidget
+*/
+QPixmap Plot3D::renderPixmap(int w/* =0 */, int h/* =0 */, bool useContext/* =false */)
+{
+ renderpixmaprequest_ = true;
+ return QGLWidget::renderPixmap(w,h,useContext);
+}
+
+/*!
+ Create a coordinate system with generating corners beg and end
+*/
+void Plot3D::createCoordinateSystem( Triple beg, Triple end )
+{
+ if (beg != coordinates_p.first() || end != coordinates_p.second())
+ coordinates_p.init(beg, end);
+}
+
+/*!
+ Create a coordinate system from data
+*/
+void Plot3D::createCoordinateSystem()
+{
+ calculateHull();
+ Triple beg = hull().minVertex; // Irix 6.5 compiler bug
+ Triple end = hull().maxVertex;
+ createCoordinateSystem(beg, end);
+}
+
+/*!
+ Show a color legend
+*/
+void Plot3D::showColorLegend( bool show )
+{
+ displaylegend_ = show;
+ if (show)
+ datacolor_p->createVector(legend_.colors);
+ updateGL();
+}
+
+void Plot3D::setMeshColor(RGBA rgba)
+{
+ meshcolor_ = rgba;
+}
+
+void Plot3D::setBackgroundColor(RGBA rgba)
+{
+ bgcolor_ = rgba;
+}
+
+
+/*!
+ assign a new coloring object for the data.
+*/
+void Plot3D::setDataColor( Color* col )
+{
+ Q_ASSERT(datacolor_p);
+
+ datacolor_p->destroy();
+ datacolor_p = col;
+}
+
+/*!
+ Set up ortogonal or perspective mode and updates widget
+*/
+void Plot3D::setOrtho( bool val )
+{
+ if (val == ortho_)
+ return;
+ ortho_ = val;
+ updateGL();
+
+ emit projectionChanged(val);
+}
+
+/*!
+ Set style of coordinate system
+*/
+void Plot3D::setCoordinateStyle(COORDSTYLE st)
+{
+ coordinates_p.setStyle(st);
+ updateGL();
+}
+
+/*!
+ Set plotstyle for the standard plotting types. An argument of value Qwt3D::USER
+ is ignored.
+*/
+void Plot3D::setPlotStyle( PLOTSTYLE val )
+{
+ if (val == Qwt3D::USER)
+ return;
+ delete userplotstyle_p;
+ userplotstyle_p = 0;
+ plotstyle_ = val;
+}
+
+/*!
+ Set plotstyle to Qwt3D::USER and an associated enrichment object.
+*/
+Qwt3D::Enrichment* Plot3D::setPlotStyle( Qwt3D::Enrichment const& obj )
+{
+ if (&obj == userplotstyle_p)
+ return userplotstyle_p;
+
+ delete userplotstyle_p;
+ userplotstyle_p = obj.clone();
+ plotstyle_ = Qwt3D::USER;
+ return userplotstyle_p;
+}
+
+/*!
+ Set shading style
+*/
+void Plot3D::setShading( SHADINGSTYLE val )
+{
+ if (val == shading_)
+ return;
+
+ shading_ = val;
+
+ switch (shading_)
+ {
+ case FLAT:
+ glShadeModel(GL_FLAT);
+ break;
+ case GOURAUD:
+ glShadeModel(GL_SMOOTH);
+ break;
+ default:
+ break;
+ }
+ updateGL();
+}
+
+/*!
+ Set number of isolines. The lines are equidistant between minimal and maximal Z value
+*/
+void Plot3D::setIsolines(int steps)
+{
+ if (steps < 0)
+ return;
+
+ isolines_ = steps;
+}
+
+/*!
+ Set Polygon offset. The function affects the OpenGL rendering process.
+ Try different values for surfaces with polygons only and with mesh and polygons
+*/
+void Plot3D::setPolygonOffset( double val )
+{
+ polygonOffset_ = val;
+}
+
+void Plot3D::setMeshLineWidth( double val )
+{
+ Q_ASSERT(val>=0);
+
+ if (val < 0)
+ return;
+
+ meshLineWidth_ = val;
+}
+
+
+/*!
+Set relative caption position (0.5,0.5) means, the anchor point lies in the center of the screen
+*/
+void Plot3D::setTitlePosition(double rely, double relx, Qwt3D::ANCHOR anchor)
+{
+ titlerel_.y = (rely<0 || rely>1) ? 0.5 : rely;
+ titlerel_.x = (relx<0 || relx>1) ? 0.5 : relx;
+
+ titleanchor_ = anchor;
+}
+
+/*!
+Set caption font
+*/
+void Plot3D::setTitleFont(const QString& family, int pointSize, int weight, bool italic)
+{
+ title_.setFont(family, pointSize, weight, italic);
+}
+
+Enrichment* Plot3D::addEnrichment(Enrichment const& e)
+{
+ if ( elist_p.end() == std::find( elist_p.begin(), elist_p.end(), &e ) )
+ elist_p.push_back(e.clone());
+ return elist_p.back();
+}
+
+bool Plot3D::degrade(Enrichment* e)
+{
+ ELIT it = std::find(elist_p.begin(), elist_p.end(), e);
+
+ if ( it != elist_p.end() )
+ {
+ delete (*it);
+ elist_p.erase(it);
+ return true;
+ }
+ return false;
+}
+
+void Plot3D::createEnrichments()
+{
+ for (ELIT it = elist_p.begin(); it!=elist_p.end(); ++it)
+ {
+ this->createEnrichment(**it);
+ }
+}
+
+/*!
+ Update OpenGL data representation
+*/
+void Plot3D::updateData()
+{
+ makeCurrent();
+ GLStateBewarer dt(GL_DEPTH_TEST, true);
+ GLStateBewarer ls(GL_LINE_SMOOTH, true);
+
+ calculateHull();
+
+ SaveGlDeleteLists(displaylists_p[DataObject], 1); // nur Daten
+
+ displaylists_p[DataObject] = glGenLists(1);
+ glNewList(displaylists_p[DataObject], GL_COMPILE);
+
+ this->createEnrichments();
+ this->createData();
+
+ glEndList();
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_scale.cpp b/lib/tqwtplot3d/src/qwt3d_scale.cpp new file mode 100644 index 0000000..ecac454 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_scale.cpp @@ -0,0 +1,304 @@ +#include "qwt3d_scale.h"
+
+using namespace Qwt3D;
+
+Scale::Scale()
+: start_p(0.), stop_p(0.),
+ majorintervals_p(0), minorintervals_p(0),
+ mstart_p(0.), mstop_p(0.)
+{
+}
+
+/*! The function maps the double value at tic-position idx to a final
+representation. The default return value is simply the tic values QString
+representation. Overwrite this function, if you plan to transform the value
+in some way. See e.g. LogScale::ticLabel.
+\param idx the current major tic index
+\return The QString representation for the value corresponding to a valid index,
+an empty QString else.
+*/
+QString Scale::ticLabel(unsigned int idx) const
+{
+ if (idx<majors_p.size())
+ {
+ return QString::number(majors_p[idx]);
+ }
+ return QString("");
+}
+
+//! Sets start and stop value for the scale;
+void Scale::setLimits(double start, double stop)
+{
+ if (start < stop)
+ {
+ start_p = start;
+ stop_p = stop;
+ return;
+ }
+ start_p = stop;
+ stop_p = start;
+}
+
+//! Sets value of first major tic
+void Scale::setMajorLimits(double start, double stop)
+{
+ if (start < stop)
+ {
+ mstart_p = start;
+ mstop_p = stop;
+ return;
+ }
+ mstart_p = stop;
+ mstop_p = start;
+}
+
+/*!
+ \param a First major tic after applying autoscaling
+ \param b Last major tic after applying autoscaling
+ \param start Scale begin
+ \param stop Scale end
+ \param ivals Requested number of major intervals
+ \return Number of major intervals after autoscaling\n
+
+ The default implementation sets a=start, b=stop and returns ivals.
+*/
+int Scale::autoscale(double& a, double& b, double start, double stop, int ivals)
+{
+ a = start;
+ b = stop;
+ return ivals;
+}
+
+/***************************
+*
+* linear scales
+*
+***************************/
+
+
+//! Applies LinearAutoScaler::execute()
+int LinearScale::autoscale(double& a, double& b, double start, double stop, int ivals)
+{
+ return autoscaler_p.execute(a, b, start, stop, ivals);
+}
+
+//! Creates the major and minor vector for the scale
+void LinearScale::calculate()
+{
+ majors_p.clear();
+ minors_p.clear();
+
+ double interval = mstop_p-mstart_p;
+
+ double runningval;
+ int i=0;
+
+ // majors
+
+ // first tic
+// if (mstart_p<start_p || mstop_p>stop_p)
+// return;
+
+ majors_p.push_back(mstart_p);
+
+ // remaining tics
+ for (i = 1; i <= majorintervals_p; ++i)
+ {
+ double t = double(i) / majorintervals_p;
+ runningval = mstart_p + t * interval;
+ if (runningval>stop_p)
+ break;
+ if (isPracticallyZero(mstart_p, -t*interval)) // prevent rounding errors near 0
+ runningval = 0.0;
+ majors_p.push_back(runningval);
+ }
+ majorintervals_p = majors_p.size();
+ if (majorintervals_p)
+ --majorintervals_p;
+
+
+ // minors
+
+ if (!majorintervals_p || !minorintervals_p) // no valid interval
+ {
+ minorintervals_p = 0;
+ return;
+ }
+
+ // start_p mstart_p
+ // |_____________|_____ _ _ _
+
+ double step = (majors_p[1]-majors_p[0]) / minorintervals_p;
+ if (isPracticallyZero(step))
+ return;
+
+ runningval = mstart_p-step;
+ while (runningval>start_p)
+ {
+ minors_p.push_back(runningval);
+ runningval -= step;
+ }
+
+ // mstart_p mstop_p
+ // ________|_____ _ _ _ _ _ ___|__________
+
+ for (i=0; i!=majorintervals_p; ++i)
+ {
+ runningval = majors_p[i] + step;
+ for (int j=0; j!=minorintervals_p; ++j)
+ {
+ minors_p.push_back(runningval);
+ runningval += step;
+ }
+ }
+
+ // mstop_p stop_p
+ // _ _ _|_____________|
+
+ runningval = mstop_p + step;
+ while (runningval<stop_p)
+ {
+ minors_p.push_back(runningval);
+ runningval += step;
+ }
+}
+
+void LogScale::setupCounter(double& k, int& step)
+{
+ switch(minorintervals_p)
+ {
+ case 9:
+ k=9;
+ step=1;
+ break;
+ case 5:
+ k=8;
+ step=2;
+ break;
+ case 3:
+ k=5;
+ step=3;
+ break;
+ case 2:
+ k=5;
+ step=5;
+ break;
+ default:
+ k=9;
+ step=1;
+ }
+}
+
+/*! Creates major and minor vectors for the scale.
+\warning If the interval is too small, the scale becomes empty
+or will contain only a single major tic. There is no automatism
+(also not planned for now) for an 'intelligent' guess, what to do.
+Better switch manually to linear to scales in such cases.
+*/
+void LogScale::calculate()
+{
+ majors_p.clear();
+ minors_p.clear();
+
+ if (start_p < DBL_MIN_10_EXP)
+ start_p = DBL_MIN_10_EXP;
+ if (stop_p > DBL_MAX_10_EXP)
+ stop_p = DBL_MAX_10_EXP;
+
+ double interval = stop_p-start_p;
+ if (interval<=0)
+ return;
+
+ double runningval = floor(start_p);
+ while(runningval<=stop_p)
+ {
+ if (runningval>=start_p)
+ majors_p.push_back(runningval);
+ ++runningval;
+ }
+ majorintervals_p = majors_p.size();
+ if (majorintervals_p)
+ --majorintervals_p;
+
+ if (majors_p.size()<1) // not even a single major tic
+ {
+ return;
+ }
+
+
+ // minors
+
+ // start_p mstart_p
+ // |_____________|_____ _ _ _
+
+ double k;
+ int step;
+ setupCounter(k,step);
+ runningval = log10(k)+(majors_p[0]-1);
+ while (runningval>start_p && k>1)
+ {
+ minors_p.push_back(runningval);
+ k -=step;
+ runningval = log10(k)+(majors_p[0]-1);
+ }
+
+ // mstart_p mstop_p
+ // ________|_____ _ _ _ _ _ ___|__________
+
+ for (int i=0; i!=majorintervals_p; ++i)
+ {
+ setupCounter(k,step);
+ runningval = log10(k)+(majors_p[i]);
+ while (k>1)
+ {
+ minors_p.push_back(runningval);
+ k-=step;
+ runningval = log10(k)+(majors_p[i]);
+ }
+ }
+
+ // mstop_p stop_p
+ // _ _ _|_____________|
+
+ setupCounter(k,step);
+ runningval = log10(k)+(majors_p.back());
+ do
+ {
+ k-=step;
+ runningval = log10(k)+(majors_p.back());
+ }
+ while(runningval>=stop_p);
+ while (k>1)
+ {
+ minors_p.push_back(runningval);
+ k-=step;
+ runningval = log10(k)+(majors_p.back());
+ }
+}
+
+/*!
+Sets the minor intervals for the logarithmic scale. Only values of 9,5,3 or 2
+are accepted as arguments. They will produce mantissa sets of {2,3,4,5,6,7,8,9},
+{2,4,6,8}, {2,5} or {5} respectively.
+*/
+void LogScale::setMinors(int val)
+{
+ if ((val == 2) || (val == 3) || (val == 5) || (val == 9))
+ minorintervals_p = val;
+}
+
+LogScale::LogScale()
+{
+ minorintervals_p = 9;
+}
+
+//! Returns a power of 10 associated to the major value at index idx.
+QString LogScale::ticLabel(unsigned int idx) const
+{
+ if (idx<majors_p.size())
+ {
+ double val = majors_p[idx];
+ return QString::number(pow(double(10), val));
+ }
+ return QString("");
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_surfaceplot.cpp b/lib/tqwtplot3d/src/qwt3d_surfaceplot.cpp new file mode 100644 index 0000000..3caae31 --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_surfaceplot.cpp @@ -0,0 +1,183 @@ +#include "qwt3d_surfaceplot.h"
+
+using namespace std;
+using namespace Qwt3D;
+
+/**
+Initializes with dataNormals()==false, NOFLOOR, resolution() == 1
+*/
+#if QT_VERSION < 0x040000
+SurfacePlot::SurfacePlot( QWidget* parent, const char* name )
+ : Plot3D( parent, name )
+#else
+SurfacePlot::SurfacePlot( QWidget * parent, const QGLWidget * shareWidget)
+ : Plot3D( parent, shareWidget)
+#endif
+{
+ datanormals_p = false;
+ normalLength_p = 0.02;
+ normalQuality_p = 3;
+
+ resolution_p = 1;
+ actualDataG_ = new GridData();
+ actualDataC_ = new CellData();
+
+ actualData_p = actualDataG_;
+
+ floorstyle_ = NOFLOOR;
+}
+
+SurfacePlot::~SurfacePlot()
+{
+ delete actualDataG_;
+ delete actualDataC_;
+}
+
+void SurfacePlot::showNormals(bool b)
+{
+ datanormals_p = b;
+}
+
+/**
+Values < 0 or > 1 are ignored
+*/
+void SurfacePlot::setNormalLength(double val)
+{
+ if (val<0 || val>1)
+ return;
+ normalLength_p = val;
+}
+
+/**
+Values < 3 are ignored
+*/
+void SurfacePlot::setNormalQuality(int val)
+{
+ if (val<3)
+ return;
+ normalQuality_p = val;
+}
+
+/**
+ Calculates the smallest x-y-z parallelepiped enclosing the data.
+ It can be accessed by hull();
+*/
+void SurfacePlot::calculateHull()
+{
+ if (actualData_p->empty())
+ return;
+ setHull(actualData_p->hull());
+}
+
+/*!
+ Sets data resolution (res == 1 original resolution) and updates widget
+ If res < 1, the function does nothing
+*/
+void SurfacePlot::setResolution( int res )
+{
+ if (!actualData_p || actualData_p->datatype == Qwt3D::POLYGON)
+ return;
+
+ if ((resolution_p == res) || res < 1)
+ return;
+
+ resolution_p = res;
+ updateNormals();
+ updateData();
+ if (initializedGL())
+ updateGL();
+
+ emit resolutionChanged(res);
+}
+
+void SurfacePlot::updateNormals()
+{
+ SaveGlDeleteLists(displaylists_p[NormalObject], 1);
+
+ if (plotStyle() == NOPLOT && !normals() || !actualData_p)
+ return;
+
+ displaylists_p[NormalObject] = glGenLists(1);
+ glNewList(displaylists_p[NormalObject], GL_COMPILE);
+
+ if (actualData_p->datatype == Qwt3D::POLYGON)
+ createNormalsC();
+ else if (actualData_p->datatype == Qwt3D::GRID)
+ createNormalsG();
+
+ glEndList();
+}
+
+void SurfacePlot::createData()
+{
+ if (!actualData_p)
+ return;
+ if (actualData_p->datatype == Qwt3D::POLYGON)
+ createDataC();
+ else if (actualData_p->datatype == Qwt3D::GRID)
+ createDataG();
+}
+
+
+void SurfacePlot::createFloorData()
+{
+ if (!actualData_p)
+ return;
+ if (actualData_p->datatype == Qwt3D::POLYGON)
+ createFloorDataC();
+ else if (actualData_p->datatype == Qwt3D::GRID)
+ createFloorDataG();
+}
+
+/**
+ The returned value is not affected by resolution(). The pair gives (columns,rows) for grid data
+, (number of cells,1) for free formed data (datatype() == POLYGON) and (0,0) else
+*/
+pair<int,int> SurfacePlot::facets() const
+{
+ if (!hasData())
+ return pair<int,int>(0,0);
+
+ if (actualData_p->datatype == Qwt3D::POLYGON)
+ return pair<int,int>(int(actualDataC_->cells.size()), 1);
+ else if (actualData_p->datatype == Qwt3D::GRID)
+ return pair<int,int>(actualDataG_->columns(), actualDataG_->rows());
+ else
+ return pair<int,int>(0,0);
+}
+
+void SurfacePlot::createPoints()
+{
+ Dot pt;
+ createEnrichment(pt);
+}
+
+void SurfacePlot::createEnrichment(Enrichment& p)
+{
+ if (!actualData_p)
+ return;
+
+ //todo future work
+ if (p.type() != Enrichment::VERTEXENRICHMENT)
+ return;
+
+ p.assign(*this);
+ p.drawBegin();
+
+ VertexEnrichment* ve = (VertexEnrichment*)&p;
+ if (actualData_p->datatype == Qwt3D::POLYGON)
+ {
+ for (unsigned i = 0; i != actualDataC_->normals.size(); ++i)
+ ve->draw(actualDataC_->nodes[i]);
+ }
+ else if (actualData_p->datatype == Qwt3D::GRID)
+ {
+ int step = resolution();
+ for (int i = 0; i <= actualDataG_->columns() - step; i += step)
+ for (int j = 0; j <= actualDataG_->rows() - step; j += step)
+ ve->draw(Triple(actualDataG_->vertices[i][j][0],
+ actualDataG_->vertices[i][j][1],
+ actualDataG_->vertices[i][j][2]));
+ }
+ p.drawEnd();
+}
diff --git a/lib/tqwtplot3d/src/qwt3d_types.cpp b/lib/tqwtplot3d/src/qwt3d_types.cpp new file mode 100644 index 0000000..b6f3a4d --- /dev/null +++ b/lib/tqwtplot3d/src/qwt3d_types.cpp @@ -0,0 +1,222 @@ +#if defined(_MSC_VER) /* MSVC Compiler */
+#pragma warning ( disable : 4786 )
+#endif
+
+#include <stdlib.h> // qsort
+#include <algorithm>
+#include <float.h>
+#include "qwt3d_types.h"
+
+using namespace Qwt3D;
+
+#ifndef QWT3D_NOT_FOR_DOXYGEN
+
+namespace {
+ // convex hull
+
+ typedef double coordinate_type;
+
+ int ccw(coordinate_type **P, int i, int j, int k) {
+ coordinate_type a = P[i][0] - P[j][0],
+ b = P[i][1] - P[j][1],
+ c = P[k][0] - P[j][0],
+ d = P[k][1] - P[j][1];
+ return a*d - b*c <= 0; /* true if points i, j, k counterclockwise */
+ }
+
+
+#define CMPM(c,A,B) \
+ v = (*(coordinate_type**)A)[c] - (*(coordinate_type**)B)[c];\
+ if (v>0) return 1;\
+ if (v<0) return -1;
+
+ int cmpl(const void *a, const void *b) {
+ double v;
+ CMPM(0,a,b);
+ CMPM(1,b,a);
+ return 0;
+ }
+
+ int cmph(const void *a, const void *b) {return cmpl(b,a);}
+
+
+ int make_chain(coordinate_type** V, int n, int (*cmp)(const void*, const void*)) {
+ int i, j, s = 1;
+ coordinate_type* t;
+
+ qsort(V, n, sizeof(coordinate_type*), cmp);
+ for (i=2; i<n; i++) {
+ for (j=s; j>=1 && ccw(V, i, j, j-1); j--){}
+ s = j+1;
+ t = V[s]; V[s] = V[i]; V[i] = t;
+ }
+ return s;
+ }
+
+ int _ch2d(coordinate_type **P, int n) {
+ int u = make_chain(P, n, cmpl); /* make lower hull */
+ if (!n) return 0;
+ P[n] = P[0];
+ return u+make_chain(P+u, n-u+1, cmph); /* make upper hull */
+ }
+
+
+} // ns anon
+
+
+GridData::GridData()
+{
+ datatype = Qwt3D::GRID;
+ setSize(0,0);
+ setPeriodic(false,false);
+}
+
+GridData::GridData(unsigned int columns, unsigned int rows)
+{
+ datatype = Qwt3D::GRID;
+ setSize(columns,rows);
+ setPeriodic(false,false);
+}
+
+int GridData::columns() const
+{
+ return (int)vertices.size();
+}
+
+int GridData::rows() const
+{
+ return (empty()) ? 0 : (int)vertices[0].size();
+}
+
+void GridData::clear()
+{
+ setHull(ParallelEpiped());
+ {
+ for (unsigned i=0; i!=vertices.size(); ++i)
+ {
+ for (unsigned j=0; j!=vertices[i].size(); ++j)
+ {
+ delete [] vertices[i][j];
+ }
+ vertices[i].clear();
+ }
+ }
+
+ vertices.clear();
+
+ {
+ for (unsigned i=0; i!=normals.size(); ++i)
+ {
+ for (unsigned j=0; j!=normals[i].size(); ++j)
+ {
+ delete [] normals[i][j];
+ }
+ normals[i].clear();
+ }
+ }
+
+ normals.clear();
+}
+
+
+void GridData::setSize(unsigned int columns, unsigned int rows)
+{
+ this->clear();
+ vertices = std::vector<DataRow>(columns);
+ {
+ for (unsigned int i=0; i!=vertices.size(); ++i)
+ {
+ vertices[i] = DataRow(rows);
+ for (unsigned int j=0; j!=vertices[i].size(); ++j)
+ {
+ vertices[i][j] = new GLdouble[3];
+ }
+ }
+ }
+ normals = std::vector<DataRow>(columns);
+ {
+ for (unsigned int i=0; i!=normals.size(); ++i)
+ {
+ normals[i] = DataRow(rows);
+ for (unsigned int j=0; j!=normals[i].size(); ++j)
+ {
+ normals[i][j] = new GLdouble[3];
+ }
+ }
+ }
+}
+
+Triple const& CellData::operator()(unsigned cellnumber, unsigned vertexnumber)
+{
+ return nodes[cells[cellnumber][vertexnumber]];
+}
+
+void CellData::clear()
+{
+ setHull(ParallelEpiped());
+ cells.clear();
+ nodes.clear();
+ normals.clear();
+}
+
+QColor Qwt3D::GL2Qt(GLdouble r, GLdouble g, GLdouble b)
+{
+ return QColor(round(r * 255), round(g * 255), round(b * 255));
+}
+
+RGBA Qwt3D::Qt2GL(QColor col)
+{
+ QRgb qrgb = col.rgb();
+ RGBA rgba;
+ rgba.r = qRed(qrgb) / 255.0;
+ rgba.g = qGreen(qrgb) / 255.0;
+ rgba.b = qBlue(qrgb) / 255.0;
+ rgba.a = qAlpha(qrgb) / 255.0;
+ return rgba;
+}
+
+
+void Qwt3D::convexhull2d( std::vector<unsigned>& idx, const std::vector<Tuple>& src )
+{
+ idx.clear();
+ if (src.empty())
+ return;
+ if (src.size()==1)
+ {
+ idx.push_back(0);
+ return;
+ }
+ coordinate_type** points = new coordinate_type*[src.size()+1] ;
+ coordinate_type* P = new coordinate_type[src.size()*2];
+
+ int i;
+ for (i=0; i<(int)src.size(); ++i)
+ {
+ points[i] = &P[2*i];
+ points[i][0] = src[i].x;
+ points[i][1] = src[i].y;
+ }
+
+ coordinate_type* start = points[0];
+ int m = _ch2d( points, src.size() );
+ idx.resize(m);
+
+ for (i=0; i<m; ++i)
+ {
+ idx[i] = (points[i] - start)/2;
+ }
+ delete [] points;
+ delete [] P;
+}
+
+unsigned Qwt3D::tesselationSize(CellField const& t)
+{
+ unsigned ret = 0;
+
+ for (unsigned i=0; i!=t.size(); ++i)
+ ret += t[i].size();
+
+ return ret;
+}
+
+#endif // QWT3D_NOT_FOR_DOXYGEN
|