|
|
4df9cd |
|
|
|
4df9cd |
|
|
|
4da757 |
// TnzTools includes
|
|
|
4da757 |
#include <tools assistant.h=""></tools>
|
|
|
d5090c |
#include <tools assistants="" guidelineline.h=""></tools>
|
|
|
4df9cd |
|
|
|
4da757 |
// TnzCore includes
|
|
|
4da757 |
#include <tgl.h></tgl.h>
|
|
|
4df9cd |
|
|
|
249386 |
|
|
|
249386 |
//*****************************************************************************************
|
|
|
4da757 |
// TAssistantVanishingPoint implementation
|
|
|
249386 |
//*****************************************************************************************
|
|
|
249386 |
|
|
|
f36ea4 |
class TAssistantVanishingPoint final : public TAssistant {
|
|
|
4da757 |
Q_DECLARE_TR_FUNCTIONS(TAssistantVanishingPoint)
|
|
|
7900ea |
public:
|
|
|
7900ea |
const TStringId m_idPassThrough;
|
|
|
7900ea |
const TStringId m_idGrid;
|
|
|
7900ea |
const TStringId m_idPerspective;
|
|
|
7900ea |
|
|
|
c5e805 |
protected:
|
|
|
7900ea |
TAssistantPoint &m_center;
|
|
|
7900ea |
TAssistantPoint &m_a0;
|
|
|
7900ea |
TAssistantPoint &m_a1;
|
|
|
7900ea |
TAssistantPoint &m_b0;
|
|
|
7900ea |
TAssistantPoint &m_b1;
|
|
|
7900ea |
TAssistantPoint &m_grid0;
|
|
|
7900ea |
TAssistantPoint &m_grid1;
|
|
|
c5e805 |
|
|
|
4da757 |
public:
|
|
|
4da757 |
TAssistantVanishingPoint(TMetaObject &object):
|
|
|
c5e805 |
TAssistant(object),
|
|
|
7900ea |
m_idPassThrough("passThrough"),
|
|
|
7900ea |
m_idGrid("grid"),
|
|
|
7900ea |
m_idPerspective("perspective"),
|
|
|
7900ea |
m_center( addPoint("center", TAssistantPoint::CircleCross) ),
|
|
|
7c7225 |
m_a0 ( addPoint("a0", TAssistantPoint::Circle, TPointD(-50.0, 0.0)) ),
|
|
|
7c7225 |
m_a1 ( addPoint("a1", TAssistantPoint::Circle, TPointD(-75.0, 0.0)) ),
|
|
|
7c7225 |
m_b0 ( addPoint("b0", TAssistantPoint::Circle, TPointD( 50.0, 0.0)) ),
|
|
|
7c7225 |
m_b1 ( addPoint("b1", TAssistantPoint::Circle, TPointD( 75.0, 0.0)) ),
|
|
|
7c7225 |
m_grid0 ( addPoint("grid0", TAssistantPoint::CircleDoubleDots, TPointD( 0.0,-50.0)) ),
|
|
|
7c7225 |
m_grid1 ( addPoint("grid1", TAssistantPoint::CircleDots, TPointD( 25.0,-50.0)) )
|
|
|
7900ea |
{
|
|
|
7900ea |
addProperty( new TBoolProperty(m_idPassThrough.str(), getPassThrough()) );
|
|
|
7900ea |
addProperty( new TBoolProperty(m_idGrid.str(), getGrid()) );
|
|
|
7900ea |
addProperty( new TBoolProperty(m_idPerspective.str(), getPerspective()) );
|
|
|
7900ea |
}
|
|
|
4da757 |
|
|
|
4da757 |
static QString getLocalName()
|
|
|
4da757 |
{ return tr("Vanishing Point"); }
|
|
|
4da757 |
|
|
|
c7854d |
void updateTranslation() const override {
|
|
|
096df2 |
TAssistant::updateTranslation();
|
|
|
7900ea |
setTranslation(m_idPassThrough, tr("Pass Through"));
|
|
|
7900ea |
setTranslation(m_idGrid, tr("Grid"));
|
|
|
7900ea |
setTranslation(m_idPerspective, tr("Perspective"));
|
|
|
7900ea |
}
|
|
|
7900ea |
|
|
|
7900ea |
inline bool getPassThrough() const
|
|
|
7900ea |
{ return data()[m_idPassThrough].getBool(); }
|
|
|
7900ea |
inline bool getGrid() const
|
|
|
7900ea |
{ return data()[m_idGrid].getBool(); }
|
|
|
7900ea |
inline bool getPerspective() const
|
|
|
7900ea |
{ return data()[m_idPerspective].getBool(); }
|
|
|
7900ea |
|
|
|
c7854d |
void onDataChanged(const TVariant &value) override {
|
|
|
7900ea |
TAssistant::onDataChanged(value);
|
|
|
c7854d |
m_grid0.visible = m_grid1.visible = getGrid();
|
|
|
7900ea |
}
|
|
|
7900ea |
|
|
|
7900ea |
private:
|
|
|
7900ea |
void fixCenter() {
|
|
|
7900ea |
if ( !(m_a0.position == m_a1.position)
|
|
|
7900ea |
&& !(m_b0.position == m_b1.position) )
|
|
|
7900ea |
{
|
|
|
7900ea |
const TPointD &a = m_a0.position;
|
|
|
7900ea |
const TPointD &b = m_b0.position;
|
|
|
7900ea |
const TPointD da = m_a1.position - a;
|
|
|
7900ea |
const TPointD db = m_b1.position - b;
|
|
|
7900ea |
const TPointD ab = b - a;
|
|
|
7900ea |
double k = db.x*da.y - db.y*da.x;
|
|
|
7900ea |
if (fabs(k) > TConsts::epsilon) {
|
|
|
7900ea |
double lb = (da.x*ab.y - da.y*ab.x)/k;
|
|
|
7900ea |
m_center.position.x = lb*db.x + b.x;
|
|
|
7900ea |
m_center.position.y = lb*db.y + b.y;
|
|
|
7900ea |
}
|
|
|
7900ea |
}
|
|
|
7900ea |
}
|
|
|
7900ea |
|
|
|
7900ea |
void fixSidePoint(TAssistantPoint &p0, TAssistantPoint &p1, TPointD previousP0) {
|
|
|
7900ea |
if (p0.position != m_center.position && p0.position != p1.position) {
|
|
|
7900ea |
TPointD dp0 = p0.position - m_center.position;
|
|
|
7900ea |
TPointD dp1 = p1.position - previousP0;
|
|
|
7900ea |
double l0 = norm(dp0);
|
|
|
7900ea |
double l1 = norm(dp1);
|
|
|
7900ea |
if (l0 > TConsts::epsilon && l0 + l1 > TConsts::epsilon)
|
|
|
7900ea |
p1.position = m_center.position + dp0*((l0 + l1)/l0);
|
|
|
7900ea |
}
|
|
|
7900ea |
}
|
|
|
7900ea |
|
|
|
7900ea |
void fixSidePoint(TAssistantPoint &p0, TAssistantPoint &p1)
|
|
|
7900ea |
{ fixSidePoint(p0, p1, p0.position); }
|
|
|
7900ea |
|
|
|
c7854d |
void fixGrid1(const TPointD &previousCenter, const TPointD &previousGrid0) {
|
|
|
c7854d |
TPointD dx = previousCenter - previousGrid0;
|
|
|
c7854d |
double l = norm2(dx);
|
|
|
c7854d |
if (l <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
c7854d |
dx = dx*(1.0/sqrt(l));
|
|
|
c7854d |
TPointD dy(-dx.y, dx.x);
|
|
|
c7854d |
|
|
|
c7854d |
TPointD d = m_grid1.position - previousGrid0;
|
|
|
c7854d |
double x = (dx*d);
|
|
|
c7854d |
double y = (dy*d);
|
|
|
c7854d |
|
|
|
c7854d |
dx = m_center.position - m_grid0.position;
|
|
|
c7854d |
l = norm2(dx);
|
|
|
c7854d |
if (l <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
c7854d |
dx = dx*(1.0/sqrt(l));
|
|
|
c7854d |
dy = TPointD(-dx.y, dx.x);
|
|
|
c7854d |
|
|
|
c7854d |
m_grid1.position = m_grid0.position + dx*x + dy*y;
|
|
|
c7854d |
}
|
|
|
c7854d |
|
|
|
7900ea |
public:
|
|
|
7900ea |
void onFixPoints() override {
|
|
|
7900ea |
fixSidePoint(m_a0, m_a1);
|
|
|
7900ea |
fixSidePoint(m_b0, m_b1);
|
|
|
7900ea |
fixCenter();
|
|
|
7900ea |
}
|
|
|
7900ea |
|
|
|
7900ea |
void onMovePoint(TAssistantPoint &point, const TPointD &position) override {
|
|
|
c7854d |
TPointD previousCenter = m_center.position;
|
|
|
7900ea |
TPointD previous = point.position;
|
|
|
7900ea |
point.position = position;
|
|
|
3f8ca2 |
if (&point == &m_center) {
|
|
|
3f8ca2 |
fixSidePoint(m_a0, m_a1);
|
|
|
3f8ca2 |
fixSidePoint(m_b0, m_b1);
|
|
|
3f8ca2 |
} else
|
|
|
7900ea |
if (&point == &m_a0) {
|
|
|
7900ea |
fixSidePoint(m_a0, m_a1, previous);
|
|
|
7900ea |
fixSidePoint(m_b0, m_b1);
|
|
|
7900ea |
} else
|
|
|
7900ea |
if (&point == &m_b0) {
|
|
|
7900ea |
fixSidePoint(m_a0, m_a1);
|
|
|
7900ea |
fixSidePoint(m_b0, m_b1, previous);
|
|
|
7900ea |
} else
|
|
|
7900ea |
if (&point == &m_a1) {
|
|
|
7900ea |
fixCenter();
|
|
|
7900ea |
fixSidePoint(m_a0, m_a1);
|
|
|
7900ea |
fixSidePoint(m_b0, m_b1);
|
|
|
7900ea |
} else
|
|
|
7900ea |
if (&point == &m_b1) {
|
|
|
7900ea |
fixCenter();
|
|
|
7900ea |
fixSidePoint(m_b0, m_b1);
|
|
|
7900ea |
fixSidePoint(m_a0, m_a1);
|
|
|
7900ea |
}
|
|
|
c7854d |
|
|
|
c7854d |
if (&point == &m_grid0) {
|
|
|
c7854d |
fixGrid1(previousCenter, previous);
|
|
|
c7854d |
} else
|
|
|
c7854d |
if (&point != &m_grid1) {
|
|
|
c7854d |
fixGrid1(previousCenter, m_grid0.position);
|
|
|
c7854d |
}
|
|
|
7900ea |
}
|
|
|
7900ea |
|
|
|
4da757 |
void getGuidelines(
|
|
|
4da757 |
const TPointD &position,
|
|
|
4da757 |
const TAffine &toTool,
|
|
|
4da757 |
TGuidelineList &outGuidelines ) const override
|
|
|
4da757 |
{
|
|
|
7900ea |
if (getPassThrough()) {
|
|
|
7900ea |
outGuidelines.push_back(TGuidelineP(
|
|
|
7900ea |
new TGuidelineInfiniteLine(
|
|
|
7900ea |
getEnabled(),
|
|
|
7900ea |
getMagnetism(),
|
|
|
7900ea |
toTool * m_center.position,
|
|
|
7900ea |
position )));
|
|
|
7900ea |
} else {
|
|
|
7900ea |
outGuidelines.push_back(TGuidelineP(
|
|
|
7900ea |
new TGuidelineRay(
|
|
|
7900ea |
getEnabled(),
|
|
|
7900ea |
getMagnetism(),
|
|
|
7900ea |
toTool * m_center.position,
|
|
|
7900ea |
position )));
|
|
|
7900ea |
}
|
|
|
4da757 |
}
|
|
|
4da757 |
|
|
|
c7854d |
void drawSimpleGrid() const {
|
|
|
7c7225 |
double alpha = getDrawingGridAlpha();
|
|
|
7c7225 |
const TPointD &p = m_center.position;
|
|
|
9a49d4 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
9a49d4 |
double minStep = 5.0*pixelSize;
|
|
|
7c7225 |
|
|
|
7c7225 |
// calculate rays count and step
|
|
|
7c7225 |
TPointD d0 = m_grid0.position - p;
|
|
|
7c7225 |
TPointD d1 = m_grid1.position - p;
|
|
|
7c7225 |
TPointD dp = d0;
|
|
|
7c7225 |
double l = norm(d0);
|
|
|
7c7225 |
if (l <= TConsts::epsilon) return;
|
|
|
7c7225 |
if (norm2(d1) <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
7c7225 |
double a0 = atan(d0);
|
|
|
7c7225 |
double a1 = atan(d1);
|
|
|
7c7225 |
double da = fabs(a1 - a0);
|
|
|
7c7225 |
if (da > M_PI) da = M_PI - da;
|
|
|
7c7225 |
if (da < TConsts::epsilon) da = TConsts::epsilon;
|
|
|
7c7225 |
double count = M_2PI/da;
|
|
|
7c7225 |
if (count > 1e6) return;
|
|
|
7c7225 |
double radiusPart = minStep/(da*l);
|
|
|
7c7225 |
if (radiusPart > 1.0) return;
|
|
|
7c7225 |
int raysCount = (int)round(count);
|
|
|
7c7225 |
double step = M_2PI/(double)raysCount;
|
|
|
c7854d |
|
|
|
3f8ca2 |
// common data about viewport
|
|
|
3f8ca2 |
const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
|
|
|
c7854d |
TAffine4 modelview, projection;
|
|
|
c7854d |
glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
|
|
|
c7854d |
glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
|
|
|
c7854d |
TAffine matrix = (projection*modelview).get2d();
|
|
|
c7854d |
TAffine matrixInv = matrix.inv();
|
|
|
c7854d |
|
|
|
c7854d |
// calculate range
|
|
|
c7854d |
if (!(matrixInv*oneBox).contains(p)) {
|
|
|
c7854d |
TPointD corners[4] = {
|
|
|
c7854d |
TPointD(oneBox.x0, oneBox.y0),
|
|
|
c7854d |
TPointD(oneBox.x0, oneBox.y1),
|
|
|
c7854d |
TPointD(oneBox.x1, oneBox.y0),
|
|
|
c7854d |
TPointD(oneBox.x1, oneBox.y1) };
|
|
|
c7854d |
double angles[4];
|
|
|
c7854d |
double a0 = 0.0, a1 = 0.0, da = 0.0;
|
|
|
c7854d |
for(int i = 0; i < 4; ++i) {
|
|
|
c7854d |
angles[i] = atan(matrixInv*corners[i] - p) + M_2PI;
|
|
|
c7854d |
for(int j = 0; j < i; ++j) {
|
|
|
c7854d |
double d = fabs(angles[i] - angles[j]);
|
|
|
3f8ca2 |
if (d > M_PI) d = M_2PI - d;
|
|
|
c7854d |
if (d > da) da = d, a0 = angles[i], a1 = angles[j];
|
|
|
c7854d |
}
|
|
|
c7854d |
}
|
|
|
c7854d |
if (a1 < a0) std::swap(a1, a0);
|
|
|
c7854d |
if (a1 - a0 > M_PI) { std::swap(a1, a0); a1 += M_2PI; }
|
|
|
c7854d |
double a = atan(dp) + M_2PI;
|
|
|
c7854d |
a0 = ceil ((a0 - a)/step)*step + a;
|
|
|
c7854d |
a1 = floor((a1 - a)/step)*step + a;
|
|
|
c7854d |
|
|
|
c7854d |
double s = sin(a0 - a);
|
|
|
c7854d |
double c = cos(a0 - a);
|
|
|
c7854d |
dp = TPointD(c*dp.x - s*dp.y, s*dp.x + c*dp.y);
|
|
|
c7854d |
raysCount = (int)round((a1 - a0)/step);
|
|
|
c7854d |
}
|
|
|
c7854d |
|
|
|
c7854d |
// draw rays
|
|
|
c7854d |
double s = sin(step);
|
|
|
c7854d |
double c = cos(step);
|
|
|
c7854d |
for(int i = 0; i < raysCount; ++i) {
|
|
|
7c7225 |
TPointD p0 = matrix*(p + dp*radiusPart);
|
|
|
c7854d |
TPointD p1 = matrix*(p + dp);
|
|
|
7c7225 |
if (TGuidelineLineBase::truncateRay(oneBox, p0, p1))
|
|
|
c7854d |
drawSegment(matrixInv*p0, matrixInv*p1, pixelSize, alpha);
|
|
|
c7854d |
dp = TPointD(c*dp.x - s*dp.y, s*dp.x + c*dp.y);
|
|
|
c7854d |
}
|
|
|
c7854d |
}
|
|
|
c7854d |
|
|
|
c7854d |
void drawPerspectiveGrid() const {
|
|
|
3f8ca2 |
// initial calculations
|
|
|
3f8ca2 |
double alpha = getDrawingGridAlpha();
|
|
|
3f8ca2 |
const TPointD ¢er = m_center.position;
|
|
|
9a49d4 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
9a49d4 |
double minStep = 5.0*pixelSize;
|
|
|
3f8ca2 |
|
|
|
3f8ca2 |
TPointD step = m_grid1.position - m_grid0.position;
|
|
|
3f8ca2 |
double stepLen2 = norm2(step);
|
|
|
3f8ca2 |
double stepLen = sqrt(stepLen2);
|
|
|
3f8ca2 |
if (stepLen <= minStep) return;
|
|
|
3f8ca2 |
TPointD stepProj = step*(1.0/stepLen2);
|
|
|
3f8ca2 |
|
|
|
3f8ca2 |
TPointD dp = center - m_grid0.position;
|
|
|
3f8ca2 |
double startX = dp*stepProj;
|
|
|
3f8ca2 |
TPointD zeroPoint = m_grid0.position + step*startX;
|
|
|
3f8ca2 |
TPointD cz = zeroPoint - center;
|
|
|
3f8ca2 |
double czLen2 = norm2(cz);
|
|
|
3f8ca2 |
double czLen = sqrt(czLen2);
|
|
|
3f8ca2 |
if (czLen <= TConsts::epsilon) return;
|
|
|
3f8ca2 |
TPointD zeroProj = cz*(1.0/czLen2);
|
|
|
3f8ca2 |
|
|
|
3f8ca2 |
double smallK = minStep/stepLen;
|
|
|
3f8ca2 |
TPointD smallGrid0 = center - dp*smallK;
|
|
|
3f8ca2 |
TPointD smallStep = step*smallK;
|
|
|
3f8ca2 |
TPointD smallStepProj = stepProj*(1/smallK);
|
|
|
3f8ca2 |
|
|
|
3f8ca2 |
// common data about viewport
|
|
|
3f8ca2 |
const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
|
|
|
3f8ca2 |
TAffine4 modelview, projection;
|
|
|
3f8ca2 |
glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
|
|
|
3f8ca2 |
glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
|
|
|
3f8ca2 |
TAffine matrix = (projection*modelview).get2d();
|
|
|
3f8ca2 |
TAffine matrixInv = matrix.inv();
|
|
|
3f8ca2 |
|
|
|
3f8ca2 |
// calculate bounds
|
|
|
3f8ca2 |
bool found = false;
|
|
|
3f8ca2 |
double minx = 0.0, maxx = 0.0;
|
|
|
3f8ca2 |
TPointD p0 = matrix*(smallGrid0);
|
|
|
3f8ca2 |
TPointD p1 = matrix*(smallGrid0 + smallStep);
|
|
|
3f8ca2 |
if (TGuidelineLineBase::truncateInfiniteLine(oneBox, p0, p1)) {
|
|
|
3f8ca2 |
p0 = matrixInv*p0;
|
|
|
3f8ca2 |
p1 = matrixInv*p1;
|
|
|
3f8ca2 |
minx = (p0 - smallGrid0)*smallStepProj;
|
|
|
3f8ca2 |
maxx = (p1 - smallGrid0)*smallStepProj;
|
|
|
3f8ca2 |
if (maxx < minx) std::swap(maxx, minx);
|
|
|
3f8ca2 |
found = true;
|
|
|
3f8ca2 |
}
|
|
|
3f8ca2 |
if (!oneBox.contains(matrix*center)) {
|
|
|
3f8ca2 |
TPointD corners[4] = {
|
|
|
3f8ca2 |
TPointD(oneBox.x0, oneBox.y0),
|
|
|
3f8ca2 |
TPointD(oneBox.x0, oneBox.y1),
|
|
|
3f8ca2 |
TPointD(oneBox.x1, oneBox.y0),
|
|
|
3f8ca2 |
TPointD(oneBox.x1, oneBox.y1) };
|
|
|
3f8ca2 |
for(int i = 0; i < 4; ++i) {
|
|
|
3f8ca2 |
TPointD p = matrixInv*corners[i] - center;
|
|
|
3f8ca2 |
double k = p*zeroProj;
|
|
|
3f8ca2 |
if (k < TConsts::epsilon) continue;
|
|
|
3f8ca2 |
double x = startX + (p*stepProj)/k;
|
|
|
3f8ca2 |
if (!found || x < minx) minx = x;
|
|
|
3f8ca2 |
if (!found || x > maxx) maxx = x;
|
|
|
3f8ca2 |
found = true;
|
|
|
3f8ca2 |
}
|
|
|
3f8ca2 |
if (maxx <= minx) return;
|
|
|
3f8ca2 |
}
|
|
|
3f8ca2 |
|
|
|
3f8ca2 |
// draw grid
|
|
|
3f8ca2 |
if (maxx - minx > 1e6) return;
|
|
|
3f8ca2 |
for(double x = ceil(minx); x < maxx; ++x) {
|
|
|
3f8ca2 |
TPointD p = smallGrid0 + smallStep*x - center;
|
|
|
3f8ca2 |
TPointD p0 = matrix*(center + p);
|
|
|
3f8ca2 |
TPointD p1 = matrix*(center + p*2.0);
|
|
|
7c7225 |
if (TGuidelineLineBase::truncateRay(oneBox, p0, p1))
|
|
|
3f8ca2 |
drawSegment(matrixInv*p0, matrixInv*p1, pixelSize, alpha);
|
|
|
3f8ca2 |
}
|
|
|
3f8ca2 |
|
|
|
3f8ca2 |
// draw horizon
|
|
|
3f8ca2 |
p0 = matrix*(center);
|
|
|
3f8ca2 |
p1 = matrix*(center + step);
|
|
|
3f8ca2 |
if (TGuidelineLineBase::truncateInfiniteLine(oneBox, p0, p1))
|
|
|
3f8ca2 |
drawSegment(matrixInv*p0, matrixInv*p1, pixelSize, alpha);
|
|
|
c7854d |
}
|
|
|
c7854d |
|
|
|
8074a5 |
void draw(TToolViewer *viewer, bool enabled) const override {
|
|
|
4da757 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
7900ea |
const TPointD &p = m_center.position;
|
|
|
4da757 |
TPointD dx(20.0*pixelSize, 0.0);
|
|
|
4da757 |
TPointD dy(0.0, 10.0*pixelSize);
|
|
|
c7854d |
double alpha = getDrawingAlpha(enabled);
|
|
|
c7854d |
drawSegment(p-dx-dy, p+dx+dy, pixelSize, alpha);
|
|
|
c7854d |
drawSegment(p-dx+dy, p+dx-dy, pixelSize, alpha);
|
|
|
c7854d |
if (getGrid()) {
|
|
|
c7854d |
if (getPerspective())
|
|
|
c7854d |
drawPerspectiveGrid();
|
|
|
c7854d |
else
|
|
|
c7854d |
drawSimpleGrid();
|
|
|
c7854d |
}
|
|
|
4da757 |
}
|
|
|
7900ea |
|
|
|
7900ea |
void drawEdit(TToolViewer *viewer) const override {
|
|
|
7900ea |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
7900ea |
drawSegment(m_center.position, m_a1.position, pixelSize);
|
|
|
7900ea |
drawSegment(m_center.position, m_b1.position, pixelSize);
|
|
|
7900ea |
TAssistant::drawEdit(viewer);
|
|
|
7900ea |
}
|
|
|
4da757 |
};
|
|
|
249386 |
|
|
|
7900ea |
|
|
|
4df9cd |
//*****************************************************************************************
|
|
|
4da757 |
// Registration
|
|
|
4df9cd |
//*****************************************************************************************
|
|
|
4df9cd |
|
|
|
4da757 |
static TAssistantTypeT<tassistantvanishingpoint> assistantVanishingPoint("assistantVanishingPoint");</tassistantvanishingpoint>
|