|
|
373f71 |
|
|
|
373f71 |
|
|
|
373f71 |
// TnzTools includes
|
|
|
373f71 |
#include <tools assistant.h=""></tools>
|
|
|
373f71 |
#include <tools assistants="" guidelineline.h=""></tools>
|
|
|
373f71 |
#include <tools assistants="" guidelineellipse.h=""></tools>
|
|
|
373f71 |
|
|
|
373f71 |
#include "assistantellipse.h"
|
|
|
373f71 |
|
|
|
373f71 |
// TnzCore includes
|
|
|
373f71 |
#include <tgl.h></tgl.h>
|
|
|
373f71 |
|
|
|
373f71 |
// std includes
|
|
|
373f71 |
#include <limits></limits>
|
|
|
373f71 |
|
|
|
373f71 |
|
|
|
373f71 |
//*****************************************************************************************
|
|
|
373f71 |
// TAssistantFisheye implementation
|
|
|
373f71 |
//*****************************************************************************************
|
|
|
373f71 |
|
|
|
373f71 |
class TAssistantFisheye final : public TAssistant {
|
|
|
373f71 |
Q_DECLARE_TR_FUNCTIONS(TAssistantEllipse)
|
|
|
373f71 |
public:
|
|
|
373f71 |
const TStringId m_idCircle;
|
|
|
373f71 |
const TStringId m_idGrid;
|
|
|
b48b31 |
const TStringId m_idGridDepth;
|
|
|
c011a5 |
const TStringId m_idFlipGrids;
|
|
|
373f71 |
|
|
|
373f71 |
protected:
|
|
|
373f71 |
TAssistantPoint &m_center;
|
|
|
373f71 |
TAssistantPoint &m_a;
|
|
|
373f71 |
TAssistantPoint &m_b;
|
|
|
373f71 |
TAssistantPoint &m_grid0;
|
|
|
373f71 |
TAssistantPoint &m_grid1;
|
|
|
b48b31 |
TAssistantPoint &m_gridD0;
|
|
|
b48b31 |
TAssistantPoint &m_gridD1;
|
|
|
373f71 |
|
|
|
373f71 |
public:
|
|
|
373f71 |
TAssistantFisheye(TMetaObject &object):
|
|
|
373f71 |
TAssistant(object),
|
|
|
373f71 |
m_idCircle("circle"),
|
|
|
373f71 |
m_idGrid("grid"),
|
|
|
b48b31 |
m_idGridDepth("gridDepth"),
|
|
|
c011a5 |
m_idFlipGrids("flipGrids"),
|
|
|
373f71 |
m_center( addPoint("center", TAssistantPoint::CircleCross) ),
|
|
|
373f71 |
m_a( addPoint("a", TAssistantPoint::CircleFill, TPointD(200, 0)) ),
|
|
|
373f71 |
m_b( addPoint("b", TAssistantPoint::Circle, TPointD( 0, 200)) ),
|
|
|
b48b31 |
m_grid0( addPoint("grid0", TAssistantPoint::CircleDoubleDots, TPointD( -25, 25)) ),
|
|
|
b48b31 |
m_grid1( addPoint("grid1", TAssistantPoint::CircleDots, TPointD( 25, -25)) ),
|
|
|
b48b31 |
m_gridD0( addPoint("gridD0", TAssistantPoint::CircleDoubleDots, TPointD( -70, -70)) ),
|
|
|
b48b31 |
m_gridD1( addPoint("gridD1", TAssistantPoint::CircleDots, TPointD( -90, -90)) )
|
|
|
373f71 |
{
|
|
|
373f71 |
addProperty( new TBoolProperty(m_idCircle.str(), getCircle()) );
|
|
|
373f71 |
addProperty( new TBoolProperty(m_idGrid.str(), getGrid()) );
|
|
|
b48b31 |
addProperty( new TBoolProperty(m_idGridDepth.str(), getGridDepth()) );
|
|
|
c011a5 |
addProperty( new TBoolProperty(m_idFlipGrids.str(), getFlipGrids()) );
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
static QString getLocalName()
|
|
|
373f71 |
{ return tr("Fish Eye"); }
|
|
|
373f71 |
|
|
|
373f71 |
void updateTranslation() const override {
|
|
|
373f71 |
TAssistant::updateTranslation();
|
|
|
373f71 |
setTranslation(m_idCircle, tr("Circle"));
|
|
|
373f71 |
setTranslation(m_idGrid, tr("Grid"));
|
|
|
b48b31 |
setTranslation(m_idGridDepth, tr("Depth Grid"));
|
|
|
c011a5 |
setTranslation(m_idFlipGrids, tr("Flip Grids"));
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
inline bool getCircle() const
|
|
|
373f71 |
{ return data()[m_idCircle].getBool(); }
|
|
|
373f71 |
inline bool getGrid() const
|
|
|
373f71 |
{ return data()[m_idGrid].getBool(); }
|
|
|
b48b31 |
inline bool getGridDepth() const
|
|
|
b48b31 |
{ return data()[m_idGridDepth].getBool(); }
|
|
|
c011a5 |
inline bool getFlipGrids() const
|
|
|
c011a5 |
{ return data()[m_idFlipGrids].getBool(); }
|
|
|
373f71 |
|
|
|
373f71 |
void onDataChanged(const TVariant &value) override {
|
|
|
373f71 |
TAssistant::onDataChanged(value);
|
|
|
b48b31 |
m_grid0.visible = m_grid1.visible = getGrid();
|
|
|
b48b31 |
m_gridD0.visible = m_gridD1.visible = getGridDepth();
|
|
|
b48b31 |
bool prevB = m_b.visible;
|
|
|
b48b31 |
m_b.visible = !getCircle();
|
|
|
b48b31 |
if (prevB && !m_b.visible)
|
|
|
b48b31 |
fixBAndGrid(m_center.position, m_a.position, m_b.position);
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
private:
|
|
|
373f71 |
void fixBAndGrid(
|
|
|
373f71 |
TPointD prevCenter,
|
|
|
373f71 |
TPointD prevA,
|
|
|
373f71 |
TPointD prevB )
|
|
|
373f71 |
{
|
|
|
373f71 |
const TPointD ¢er = m_center.position;
|
|
|
373f71 |
TPointD da0 = prevA - prevCenter;
|
|
|
373f71 |
TPointD da1 = m_a.position - center;
|
|
|
373f71 |
double la0 = norm2(da0);
|
|
|
373f71 |
double la1 = norm2(da1);
|
|
|
373f71 |
if (!(la0 > TConsts::epsilon) || !(la1 > TConsts::epsilon))
|
|
|
373f71 |
return;
|
|
|
373f71 |
|
|
|
373f71 |
TPointD db = m_b.position - center;
|
|
|
373f71 |
TPointD dp0 = TPointD(-da0.y, da0.x);
|
|
|
373f71 |
TPointD dp1 = TPointD(-da1.y, da1.x);
|
|
|
373f71 |
if (getCircle()) {
|
|
|
373f71 |
m_b.position = center + (db*dp0 < 0 ? -dp1 : dp1);
|
|
|
373f71 |
} else {
|
|
|
373f71 |
m_b.position = db*dp0/la0*dp1 + center;
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
TPointD db0 = prevB - prevCenter;
|
|
|
373f71 |
TPointD db1 = m_b.position - center;
|
|
|
373f71 |
double lb0 = norm2(db0);
|
|
|
373f71 |
double lb1 = norm2(db1);
|
|
|
373f71 |
if (!(lb0 > TConsts::epsilon) || !(lb1 > TConsts::epsilon))
|
|
|
373f71 |
return;
|
|
|
373f71 |
|
|
|
b48b31 |
TPointD dg0 = m_grid0.position - center;
|
|
|
b48b31 |
TPointD dg1 = m_grid1.position - center;
|
|
|
b48b31 |
TPointD dgD0 = m_gridD0.position - center;
|
|
|
b48b31 |
TPointD dgD1 = m_gridD1.position - center;
|
|
|
b48b31 |
m_grid0.position = dg0*da0/la0*da1 + dg0*db0/lb0*db1 + center;
|
|
|
b48b31 |
m_grid1.position = dg1*da0/la0*da1 + dg1*db0/lb0*db1 + center;
|
|
|
b48b31 |
m_gridD0.position = dgD0*da0/la0*da1 + dgD0*db0/lb0*db1 + center;
|
|
|
b48b31 |
m_gridD1.position = dgD1*da0/la0*da1 + dgD1*db0/lb0*db1 + center;
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
c011a5 |
void fixGridD1() {
|
|
|
c011a5 |
TAffine em = calcEllipseMatrix();
|
|
|
c011a5 |
TAffine emi = em.inv();
|
|
|
c011a5 |
TPointD d0 = emi*m_gridD0.position;
|
|
|
c011a5 |
TPointD d1 = emi*m_gridD1.position;
|
|
|
c011a5 |
double l0 = norm2(d0);
|
|
|
c011a5 |
double l1 = norm2(d1);
|
|
|
c011a5 |
if ( l0 > TConsts::epsilon*TConsts::epsilon
|
|
|
c011a5 |
&& l1 > TConsts::epsilon*TConsts::epsilon )
|
|
|
c011a5 |
m_gridD1.position = em*( d0*sqrt(l1/l0) );
|
|
|
c011a5 |
}
|
|
|
373f71 |
|
|
|
373f71 |
public:
|
|
|
373f71 |
void onMovePoint(TAssistantPoint &point, const TPointD &position) override {
|
|
|
373f71 |
TPointD prevCenter = m_center.position;
|
|
|
373f71 |
TPointD prevA = m_a.position;
|
|
|
373f71 |
TPointD prevB = m_b.position;
|
|
|
373f71 |
point.position = position;
|
|
|
373f71 |
if (&point == &m_center) {
|
|
|
373f71 |
TPointD d = m_center.position - prevCenter;
|
|
|
373f71 |
m_a.position += d;
|
|
|
373f71 |
m_b.position += d;
|
|
|
373f71 |
m_grid0.position += d;
|
|
|
373f71 |
m_grid1.position += d;
|
|
|
b48b31 |
m_gridD0.position += d;
|
|
|
b48b31 |
m_gridD1.position += d;
|
|
|
373f71 |
} else
|
|
|
373f71 |
if (&point == &m_a || &point == &m_b) {
|
|
|
373f71 |
fixBAndGrid(prevCenter, prevA, prevB);
|
|
|
c011a5 |
} else
|
|
|
c011a5 |
if (&point == &m_gridD0 || &point == &m_gridD1) {
|
|
|
c011a5 |
fixGridD1();
|
|
|
373f71 |
}
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
TAffine calcEllipseMatrix() const {
|
|
|
373f71 |
TPointD da = m_a.position - m_center.position;
|
|
|
373f71 |
TPointD db = m_b.position - m_center.position;
|
|
|
373f71 |
double r1 = norm(da);
|
|
|
373f71 |
if (r1 <= TConsts::epsilon) return TAffine::zero();
|
|
|
373f71 |
double r2 = fabs( (rotate90(da)*db)*(1.0/r1) );
|
|
|
373f71 |
if (r2 <= TConsts::epsilon) return TAffine::zero();
|
|
|
373f71 |
return TAffine::translation(m_center.position)
|
|
|
373f71 |
* TAffine::rotation(atan(da))
|
|
|
373f71 |
* TAffine::scale(r1, r2);
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
void getGuidelines(
|
|
|
373f71 |
const TPointD &position,
|
|
|
373f71 |
const TAffine &toTool,
|
|
|
373f71 |
TGuidelineList &outGuidelines ) const override
|
|
|
373f71 |
{
|
|
|
373f71 |
TAffine matrix = calcEllipseMatrix();
|
|
|
373f71 |
if (matrix.isZero()) return;
|
|
|
373f71 |
|
|
|
373f71 |
matrix = toTool*matrix;
|
|
|
373f71 |
TAffine matrixInv = matrix.inv();
|
|
|
373f71 |
|
|
|
373f71 |
TPointD p = matrixInv*position;
|
|
|
373f71 |
double l = norm(p);
|
|
|
373f71 |
|
|
|
373f71 |
if (l > TConsts::epsilon) {
|
|
|
373f71 |
// radius
|
|
|
373f71 |
outGuidelines.push_back(TGuidelineP(
|
|
|
373f71 |
new TGuidelineLine(
|
|
|
373f71 |
getEnabled(),
|
|
|
373f71 |
getMagnetism(),
|
|
|
373f71 |
matrix*TPointD(0, 0),
|
|
|
373f71 |
matrix*(p/l) )));
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
if (!(l < 1.0 - TConsts::epsilon)) {
|
|
|
373f71 |
// bound ellipse
|
|
|
373f71 |
outGuidelines.push_back(TGuidelineP(
|
|
|
373f71 |
new TGuidelineEllipse(
|
|
|
373f71 |
getEnabled(),
|
|
|
373f71 |
getMagnetism(),
|
|
|
373f71 |
matrix )));
|
|
|
373f71 |
} else {
|
|
|
373f71 |
// ellipse scaled by X
|
|
|
373f71 |
double kx = fabs(p.x/sqrt(1.0 - p.y*p.y));
|
|
|
373f71 |
outGuidelines.push_back(TGuidelineP(
|
|
|
373f71 |
new TGuidelineEllipse(
|
|
|
373f71 |
getEnabled(),
|
|
|
373f71 |
getMagnetism(),
|
|
|
373f71 |
matrix * TAffine::scale(kx, 1.0) )));
|
|
|
373f71 |
|
|
|
373f71 |
// ellipse scaled by Y
|
|
|
373f71 |
double ky = fabs(p.y/sqrt(1.0 - p.x*p.x));
|
|
|
373f71 |
outGuidelines.push_back(TGuidelineP(
|
|
|
373f71 |
new TGuidelineEllipse(
|
|
|
373f71 |
getEnabled(),
|
|
|
373f71 |
getMagnetism(),
|
|
|
373f71 |
matrix * TAffine::scale(1.0, ky) )));
|
|
|
373f71 |
}
|
|
|
373f71 |
}
|
|
|
373f71 |
|
|
|
373f71 |
public:
|
|
|
c011a5 |
void draw(TToolViewer*, bool enabled) const override {
|
|
|
373f71 |
TAffine ellipseMatrix = calcEllipseMatrix();
|
|
|
373f71 |
if (ellipseMatrix.isZero()) return;
|
|
|
c011a5 |
|
|
|
c011a5 |
TAffine ellipseMatrix2 = ellipseMatrix;
|
|
|
c011a5 |
std::swap(ellipseMatrix.a11, ellipseMatrix.a12);
|
|
|
c011a5 |
std::swap(ellipseMatrix.a21, ellipseMatrix.a22);
|
|
|
373f71 |
|
|
|
373f71 |
// common data about viewport
|
|
|
373f71 |
const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
|
|
|
373f71 |
TAffine4 modelview, projection;
|
|
|
373f71 |
glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
|
|
|
373f71 |
glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
|
|
|
373f71 |
TAffine matrix = (projection*modelview).get2d();
|
|
|
373f71 |
TAffine matrixInv = matrix.inv();
|
|
|
373f71 |
|
|
|
373f71 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
373f71 |
const double crossSize = 0.1;
|
|
|
373f71 |
double alpha = getDrawingAlpha(enabled);
|
|
|
c011a5 |
double gridAlpha = getDrawingGridAlpha();
|
|
|
373f71 |
|
|
|
373f71 |
drawSegment( ellipseMatrix*TPointD(-crossSize, 0.0),
|
|
|
373f71 |
ellipseMatrix*TPointD( crossSize, 0.0), pixelSize, alpha);
|
|
|
373f71 |
drawSegment( ellipseMatrix*TPointD(0.0, -crossSize),
|
|
|
373f71 |
ellipseMatrix*TPointD(0.0, crossSize), pixelSize, alpha);
|
|
|
373f71 |
TAssistantEllipse::drawEllipse(ellipseMatrix, matrixInv, pixelSize, alpha);
|
|
|
373f71 |
|
|
|
c011a5 |
const TPointD *bound = getGrid() && getGridDepth() ? &m_gridD0.position : nullptr;
|
|
|
c011a5 |
const TPointD *boundA = nullptr;
|
|
|
c011a5 |
const TPointD *boundB = bound;
|
|
|
c011a5 |
if (getFlipGrids()) std::swap(boundA, boundB);
|
|
|
c011a5 |
|
|
|
373f71 |
if (getGrid()) {
|
|
|
373f71 |
TAssistantEllipse::drawParallelGrid(
|
|
|
c011a5 |
ellipseMatrix, m_grid0.position, m_grid1.position,
|
|
|
c011a5 |
boundA, boundB, true, false, false, gridAlpha );
|
|
|
373f71 |
TAssistantEllipse::drawParallelGrid(
|
|
|
c011a5 |
ellipseMatrix2, m_grid0.position, m_grid1.position,
|
|
|
c011a5 |
boundA, boundB, true, false, false, gridAlpha );
|
|
|
b48b31 |
}
|
|
|
b48b31 |
|
|
|
b48b31 |
if (getGridDepth()) {
|
|
|
b48b31 |
TAssistantEllipse::drawParallelGrid(
|
|
|
c011a5 |
ellipseMatrix, m_gridD0.position, m_gridD1.position,
|
|
|
c011a5 |
boundB, boundA, false, true, false, gridAlpha );
|
|
|
b48b31 |
TAssistantEllipse::drawParallelGrid(
|
|
|
c011a5 |
ellipseMatrix2, m_gridD0.position, m_gridD1.position,
|
|
|
c011a5 |
boundB, boundA, false, true, false, gridAlpha );
|
|
|
c011a5 |
}
|
|
|
c011a5 |
|
|
|
c011a5 |
if (bound) {
|
|
|
c011a5 |
TPointD b = ellipseMatrix.inv()*(*bound);
|
|
|
c011a5 |
double r = norm2(b);
|
|
|
c011a5 |
if (r < 1 - TConsts::epsilon) {
|
|
|
c011a5 |
double bx = b.x/sqrt(1 - b.y*b.y);
|
|
|
c011a5 |
double by = b.y/sqrt(1 - b.x*b.x);
|
|
|
c011a5 |
|
|
|
c011a5 |
TAngleRangeSet ranges;
|
|
|
c011a5 |
ranges.add( TAngleRangeSet::fromDouble(-M_PI/2), TAngleRangeSet::fromDouble(M_PI/2) );
|
|
|
c011a5 |
TAssistantEllipse::drawEllipseRanges(
|
|
|
c011a5 |
ranges,
|
|
|
c011a5 |
ellipseMatrix*TAffine::scale(bx, 1),
|
|
|
c011a5 |
matrixInv,
|
|
|
c011a5 |
pixelSize,
|
|
|
c011a5 |
alpha );
|
|
|
c011a5 |
|
|
|
c011a5 |
ranges.clear();
|
|
|
c011a5 |
ranges.add( TAngleRangeSet::fromDouble(0.0), TAngleRangeSet::fromDouble(M_PI) );
|
|
|
c011a5 |
TAssistantEllipse::drawEllipseRanges(
|
|
|
c011a5 |
ranges,
|
|
|
c011a5 |
ellipseMatrix*TAffine::scale(1, by),
|
|
|
c011a5 |
matrixInv,
|
|
|
c011a5 |
pixelSize,
|
|
|
c011a5 |
alpha );
|
|
|
c011a5 |
|
|
|
c011a5 |
TPointD bb = bound == boundA ? TPointD(0, 0) : b/sqrt(r);
|
|
|
c011a5 |
drawSegment( ellipseMatrix*b, ellipseMatrix*bb, pixelSize, alpha );
|
|
|
c011a5 |
}
|
|
|
373f71 |
}
|
|
|
373f71 |
}
|
|
|
373f71 |
};
|
|
|
373f71 |
|
|
|
373f71 |
|
|
|
373f71 |
//*****************************************************************************************
|
|
|
373f71 |
// Registration
|
|
|
373f71 |
//*****************************************************************************************
|
|
|
373f71 |
|
|
|
373f71 |
static TAssistantTypeT<tassistantfisheye> assistantFisheye("assistantFisheye");</tassistantfisheye>
|
|
|
373f71 |
|