|
|
9a49d4 |
|
|
|
9a49d4 |
|
|
|
9a49d4 |
// TnzTools includes
|
|
|
da4ce3 |
#include "assistantellipse.h"
|
|
|
9a49d4 |
|
|
|
9a49d4 |
|
|
|
9a49d4 |
//*****************************************************************************************
|
|
|
9a49d4 |
// TAssistantEllipse implementation
|
|
|
9a49d4 |
//*****************************************************************************************
|
|
|
9a49d4 |
|
|
|
da4ce3 |
TAssistantEllipse::TAssistantEllipse(TMetaObject &object):
|
|
|
da4ce3 |
TAssistant(object),
|
|
|
da4ce3 |
m_idCircle("circle"),
|
|
|
da4ce3 |
m_idRestrictA("restrictA"),
|
|
|
da4ce3 |
m_idRestrictB("restrictB"),
|
|
|
da4ce3 |
m_idRepeat("repeat"),
|
|
|
da4ce3 |
m_idGrid("grid"),
|
|
|
da4ce3 |
m_idPerspective("perspective"),
|
|
|
da4ce3 |
m_center( addPoint("center", TAssistantPoint::CircleCross) ),
|
|
|
da4ce3 |
m_a( addPoint("a", TAssistantPoint::CircleFill, TPointD(150, 0)) ),
|
|
|
da4ce3 |
m_b( addPoint("b", TAssistantPoint::Circle, TPointD( 0, 100)) ),
|
|
|
da4ce3 |
m_grid0( addPoint("grid0", TAssistantPoint::CircleDoubleDots, TPointD( 10, -30)) ),
|
|
|
da4ce3 |
m_grid1( addPoint("grid1", TAssistantPoint::CircleDots, TPointD( 60, -60)) )
|
|
|
da4ce3 |
{
|
|
|
da4ce3 |
addProperty( new TBoolProperty(m_idCircle.str(), getCircle()) );
|
|
|
da4ce3 |
addProperty( new TBoolProperty(m_idRestrictA.str(), getRestrictA()) );
|
|
|
da4ce3 |
addProperty( new TBoolProperty(m_idRestrictB.str(), getRestrictB()) );
|
|
|
da4ce3 |
addProperty( new TBoolProperty(m_idRepeat.str(), getRepeat()) );
|
|
|
da4ce3 |
addProperty( new TBoolProperty(m_idGrid.str(), getGrid()) );
|
|
|
da4ce3 |
addProperty( new TBoolProperty(m_idPerspective.str(), getPerspective()) );
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
QString TAssistantEllipse::getLocalName()
|
|
|
da4ce3 |
{ return tr("Ellipse"); }
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::updateTranslation() const {
|
|
|
da4ce3 |
TAssistant::updateTranslation();
|
|
|
da4ce3 |
setTranslation(m_idCircle, tr("Circle"));
|
|
|
da4ce3 |
setTranslation(m_idRestrictA, tr("Restrict A"));
|
|
|
da4ce3 |
setTranslation(m_idRestrictB, tr("Restrict B"));
|
|
|
da4ce3 |
setTranslation(m_idRepeat, tr("Repeat"));
|
|
|
da4ce3 |
setTranslation(m_idGrid, tr("Grid"));
|
|
|
da4ce3 |
setTranslation(m_idPerspective, tr("Perspective"));
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::onDataChanged(const TVariant &value) {
|
|
|
da4ce3 |
TAssistant::onDataChanged(value);
|
|
|
da4ce3 |
m_grid0.visible = m_grid1.visible = getGrid();
|
|
|
da4ce3 |
if (getCircle() == m_b.visible) {
|
|
|
da4ce3 |
m_b.visible = !getCircle();
|
|
|
da4ce3 |
if (!m_b.visible)
|
|
|
da4ce3 |
fixBAndGrid(m_center.position, m_a.position, m_b.position);
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::fixBAndGrid(
|
|
|
da4ce3 |
TPointD prevCenter,
|
|
|
da4ce3 |
TPointD prevA,
|
|
|
da4ce3 |
TPointD prevB )
|
|
|
da4ce3 |
{
|
|
|
da4ce3 |
const TPointD ¢er = m_center.position;
|
|
|
da4ce3 |
TPointD da0 = prevA - prevCenter;
|
|
|
da4ce3 |
TPointD da1 = m_a.position - center;
|
|
|
da4ce3 |
double la0 = norm2(da0);
|
|
|
da4ce3 |
double la1 = norm2(da1);
|
|
|
da4ce3 |
if (!(la0 > TConsts::epsilon) || !(la1 > TConsts::epsilon))
|
|
|
da4ce3 |
return;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
TPointD db = m_b.position - center;
|
|
|
da4ce3 |
TPointD dp0 = TPointD(-da0.y, da0.x);
|
|
|
da4ce3 |
TPointD dp1 = TPointD(-da1.y, da1.x);
|
|
|
da4ce3 |
if (getCircle()) {
|
|
|
da4ce3 |
m_b.position = center + (db*dp0 < 0 ? -dp1 : dp1);
|
|
|
da4ce3 |
} else {
|
|
|
da4ce3 |
m_b.position = db*dp0/la0*dp1 + center;
|
|
|
9a49d4 |
}
|
|
|
9a49d4 |
|
|
|
da4ce3 |
TPointD db0 = prevB - prevCenter;
|
|
|
da4ce3 |
TPointD db1 = m_b.position - center;
|
|
|
da4ce3 |
double lb0 = norm2(db0);
|
|
|
da4ce3 |
double lb1 = norm2(db1);
|
|
|
da4ce3 |
if (!(lb0 > TConsts::epsilon) || !(lb1 > TConsts::epsilon))
|
|
|
da4ce3 |
return;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
TPointD dg0 = m_grid0.position - center;
|
|
|
da4ce3 |
TPointD dg1 = m_grid1.position - center;
|
|
|
da4ce3 |
m_grid0.position = dg0*da0/la0*da1 + dg0*db0/lb0*db1 + center;
|
|
|
da4ce3 |
m_grid1.position = dg1*da0/la0*da1 + dg1*db0/lb0*db1 + center;
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::onMovePoint(TAssistantPoint &point, const TPointD &position) {
|
|
|
da4ce3 |
TPointD prevCenter = m_center.position;
|
|
|
da4ce3 |
TPointD prevA = m_a.position;
|
|
|
da4ce3 |
TPointD prevB = m_b.position;
|
|
|
da4ce3 |
point.position = position;
|
|
|
da4ce3 |
if (&point == &m_center) {
|
|
|
da4ce3 |
TPointD d = m_center.position - prevCenter;
|
|
|
da4ce3 |
m_a.position += d;
|
|
|
da4ce3 |
m_b.position += d;
|
|
|
da4ce3 |
m_grid0.position += d;
|
|
|
da4ce3 |
m_grid1.position += d;
|
|
|
da4ce3 |
} else
|
|
|
da4ce3 |
if (&point == &m_a || &point == &m_b) {
|
|
|
da4ce3 |
fixBAndGrid(prevCenter, prevA, prevB);
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
TAffine TAssistantEllipse::calcEllipseMatrix() const {
|
|
|
da4ce3 |
TPointD da = m_a.position - m_center.position;
|
|
|
da4ce3 |
TPointD db = m_b.position - m_center.position;
|
|
|
da4ce3 |
double r1 = norm(da);
|
|
|
da4ce3 |
if (r1 <= TConsts::epsilon) return TAffine::zero();
|
|
|
da4ce3 |
double r2 = fabs( (rotate90(da)*db)*(1.0/r1) );
|
|
|
da4ce3 |
if (r2 <= TConsts::epsilon) return TAffine::zero();
|
|
|
da4ce3 |
return TAffine::translation(m_center.position)
|
|
|
da4ce3 |
* TAffine::rotation(atan(da))
|
|
|
da4ce3 |
* TAffine::scale(r1, r2);
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::getGuidelines(
|
|
|
da4ce3 |
const TPointD &position,
|
|
|
da4ce3 |
const TAffine &toTool,
|
|
|
da4ce3 |
TGuidelineList &outGuidelines ) const
|
|
|
da4ce3 |
{
|
|
|
da4ce3 |
bool restrictA = getRestrictA();
|
|
|
da4ce3 |
bool restrictB = getRestrictB();
|
|
|
da4ce3 |
bool repeat = getRepeat();
|
|
|
da4ce3 |
|
|
|
da4ce3 |
TAffine matrix = calcEllipseMatrix();
|
|
|
da4ce3 |
if (matrix.isZero()) return;
|
|
|
da4ce3 |
if (!restrictA && restrictB) {
|
|
|
da4ce3 |
std::swap(matrix.a11, matrix.a12);
|
|
|
da4ce3 |
std::swap(matrix.a21, matrix.a22);
|
|
|
da4ce3 |
std::swap(restrictA, restrictB);
|
|
|
9a49d4 |
}
|
|
|
9a49d4 |
|
|
|
da4ce3 |
matrix = toTool*matrix;
|
|
|
da4ce3 |
TAffine matrixInv = matrix.inv();
|
|
|
da4ce3 |
|
|
|
da4ce3 |
if (restrictA && restrictB) {
|
|
|
da4ce3 |
// ellipse
|
|
|
da4ce3 |
outGuidelines.push_back(TGuidelineP(
|
|
|
da4ce3 |
new TGuidelineEllipse(
|
|
|
da4ce3 |
getEnabled(),
|
|
|
da4ce3 |
getMagnetism(),
|
|
|
da4ce3 |
matrix,
|
|
|
da4ce3 |
matrixInv )));
|
|
|
da4ce3 |
} else
|
|
|
da4ce3 |
if (!restrictA && !restrictB) {
|
|
|
da4ce3 |
// scaled ellipse
|
|
|
da4ce3 |
TPointD p = matrixInv*position;
|
|
|
da4ce3 |
double l = norm(p);
|
|
|
da4ce3 |
outGuidelines.push_back(TGuidelineP(
|
|
|
da4ce3 |
new TGuidelineEllipse(
|
|
|
da4ce3 |
getEnabled(),
|
|
|
da4ce3 |
getMagnetism(),
|
|
|
da4ce3 |
matrix * TAffine::scale(l) )));
|
|
|
da4ce3 |
} else { // restrictA
|
|
|
da4ce3 |
TPointD p = matrixInv*position;
|
|
|
da4ce3 |
if (repeat) {
|
|
|
da4ce3 |
double ox = round(0.5*p.x)*2.0;
|
|
|
da4ce3 |
p.x -= ox;
|
|
|
da4ce3 |
matrix *= TAffine::translation(ox, 0.0);
|
|
|
9a49d4 |
}
|
|
|
9a49d4 |
|
|
|
da4ce3 |
// scale by Y
|
|
|
da4ce3 |
if (p.x <= TConsts::epsilon - 1.0) {
|
|
|
da4ce3 |
// line x = -1
|
|
|
9a49d4 |
outGuidelines.push_back(TGuidelineP(
|
|
|
da4ce3 |
new TGuidelineInfiniteLine(
|
|
|
9a49d4 |
getEnabled(),
|
|
|
9a49d4 |
getMagnetism(),
|
|
|
da4ce3 |
matrix*TPointD(-1.0, 0.0),
|
|
|
da4ce3 |
matrix*TPointD(-1.0, 1.0) )));
|
|
|
9a49d4 |
} else
|
|
|
da4ce3 |
if (p.x >= 1.0 - TConsts::epsilon) {
|
|
|
da4ce3 |
// line x = 1
|
|
|
da4ce3 |
outGuidelines.push_back(TGuidelineP(
|
|
|
da4ce3 |
new TGuidelineInfiniteLine(
|
|
|
da4ce3 |
getEnabled(),
|
|
|
da4ce3 |
getMagnetism(),
|
|
|
da4ce3 |
matrix*TPointD(1.0, 0.0),
|
|
|
da4ce3 |
matrix*TPointD(1.0, 1.0) )));
|
|
|
da4ce3 |
} else {
|
|
|
da4ce3 |
// ellipse scaled by Y
|
|
|
da4ce3 |
double k = fabs(p.y/sqrt(1.0 - p.x*p.x));
|
|
|
9a49d4 |
outGuidelines.push_back(TGuidelineP(
|
|
|
9a49d4 |
new TGuidelineEllipse(
|
|
|
9a49d4 |
getEnabled(),
|
|
|
9a49d4 |
getMagnetism(),
|
|
|
da4ce3 |
matrix * TAffine::scale(1.0, k) )));
|
|
|
9a49d4 |
}
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::drawEllipseRanges(
|
|
|
da4ce3 |
const TAngleRangeSet &ranges,
|
|
|
da4ce3 |
const TAffine &ellipseMatrix,
|
|
|
da4ce3 |
const TAffine &screenMatrixInv,
|
|
|
da4ce3 |
double pixelSize,
|
|
|
da4ce3 |
double alpha )
|
|
|
da4ce3 |
{
|
|
|
da4ce3 |
assert(ranges.check());
|
|
|
da4ce3 |
TAngleRangeSet actualRanges(ranges);
|
|
|
da4ce3 |
const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
|
|
|
da4ce3 |
if (!TGuidelineEllipse::truncateEllipse(actualRanges, ellipseMatrix.inv()*screenMatrixInv, oneBox))
|
|
|
da4ce3 |
return;
|
|
|
da4ce3 |
assert(actualRanges.check());
|
|
|
da4ce3 |
|
|
|
da4ce3 |
int segments = TGuidelineEllipse::calcSegmentsCount(ellipseMatrix, pixelSize);
|
|
|
da4ce3 |
double da = M_2PI/segments;
|
|
|
da4ce3 |
double s = sin(da);
|
|
|
da4ce3 |
double c = cos(da);
|
|
|
da4ce3 |
|
|
|
da4ce3 |
for(TAngleRangeSet::Iterator i(actualRanges); i; ++i) {
|
|
|
da4ce3 |
double a0 = i.d0();
|
|
|
da4ce3 |
double a1 = i.d1greater();
|
|
|
da4ce3 |
int cnt = (int)floor((a1 - a0)/da);
|
|
|
da4ce3 |
TPointD r(cos(a0), sin(a0));
|
|
|
da4ce3 |
TPointD p0 = ellipseMatrix*r;
|
|
|
da4ce3 |
for(int j = 0; j < cnt; ++j) {
|
|
|
da4ce3 |
r = TPointD(r.x*c - r.y*s, r.y*c + r.x*s);
|
|
|
da4ce3 |
TPointD p1 = ellipseMatrix*r;
|
|
|
da4ce3 |
drawSegment(p0, p1, pixelSize, alpha);
|
|
|
da4ce3 |
p0 = p1;
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
drawSegment(p0, ellipseMatrix*TPointD(cos(a1), sin(a1)), pixelSize, alpha);
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::drawRuler(
|
|
|
da4ce3 |
const TAffine &ellipseMatrix,
|
|
|
da4ce3 |
const TPointD &grid0,
|
|
|
da4ce3 |
const TPointD &grid1,
|
|
|
da4ce3 |
bool perspective,
|
|
|
da4ce3 |
double alpha
|
|
|
da4ce3 |
) {
|
|
|
da4ce3 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
da4ce3 |
double minStep = 10.0*pixelSize;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
TAffine em = ellipseMatrix;
|
|
|
da4ce3 |
TAffine ellipseMatrixInv = ellipseMatrix.inv();
|
|
|
da4ce3 |
TPointD g0 = ellipseMatrixInv * grid0;
|
|
|
da4ce3 |
TPointD g1 = ellipseMatrixInv * grid1;
|
|
|
da4ce3 |
if (norm2(g0) <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
da4ce3 |
if (norm2(g1) <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
da4ce3 |
double ga0 = atan(g0);
|
|
|
da4ce3 |
double ga1 = atan(g1);
|
|
|
da4ce3 |
|
|
|
da4ce3 |
// x and y radiuses
|
|
|
da4ce3 |
TPointD r( norm2(TPointD(em.a11, em.a21)), norm2(TPointD(em.a12, em.a22)) );
|
|
|
da4ce3 |
double avgR = 0.5*(r.x + r.y);
|
|
|
da4ce3 |
if (avgR <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
da4ce3 |
avgR = sqrt(avgR);
|
|
|
da4ce3 |
double actualMinStep = minStep/avgR;
|
|
|
da4ce3 |
r.x = sqrt(r.x);
|
|
|
da4ce3 |
r.y = sqrt(r.y);
|
|
|
da4ce3 |
|
|
|
da4ce3 |
// remove radiuses from ellipse matrix
|
|
|
da4ce3 |
double rkx = r.x > TConsts::epsilon ? 1.0/r.x : 0.0;
|
|
|
da4ce3 |
double rky = r.y > TConsts::epsilon ? 1.0/r.y : 0.0;
|
|
|
da4ce3 |
em.a11 *= rkx; em.a21 *= rkx;
|
|
|
da4ce3 |
em.a12 *= rky; em.a22 *= rky;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
if (perspective) {
|
|
|
da4ce3 |
// draw perspective
|
|
|
da4ce3 |
if (ga0 < 0.0) { if (ga1 > 0.0) ga1 -= M_2PI; }
|
|
|
da4ce3 |
else { if (ga1 < 0.0) ga1 += M_2PI; }
|
|
|
da4ce3 |
double k = 0.0, begin = 0.0, end = 0.0;
|
|
|
da4ce3 |
if (!calcPerspectiveStep(actualMinStep, 0.0, M_2PI, 0.0, fabs(ga0), ga1, k, begin, end)) return;
|
|
|
da4ce3 |
for(double a = begin; fabs(a) < fabs(end); a *= k) {
|
|
|
da4ce3 |
TPointD p( cos(a), (ga0 < 0.0 ? -1.0 : 1.0)*sin(a) );
|
|
|
da4ce3 |
TPointD n( p.x*r.y, p.y*r.x ); // perp to allipse
|
|
|
da4ce3 |
double nl2 = norm2(n);
|
|
|
da4ce3 |
if (nl2 > TConsts::epsilon*TConsts::epsilon) {
|
|
|
da4ce3 |
p.x *= r.x;
|
|
|
da4ce3 |
p.y *= r.y;
|
|
|
da4ce3 |
n = n*(1.0/sqrt(nl2));
|
|
|
da4ce3 |
drawMark(em*p, em.transformDirection(n), pixelSize, alpha);
|
|
|
f278a5 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
} else {
|
|
|
da4ce3 |
// draw linear
|
|
|
da4ce3 |
double da = ga1 - ga0;
|
|
|
da4ce3 |
if (da < 0.0) { da = -da; std::swap(ga0, ga1); }
|
|
|
da4ce3 |
if (ga1 - ga0 > M_PI) { da = M_2PI - da; std::swap(ga0, ga1); }
|
|
|
da4ce3 |
if (da < actualMinStep) return;
|
|
|
da4ce3 |
for(double a = ga0 - floor(M_PI/da)*da; a < ga0 + M_PI; a += da) {
|
|
|
da4ce3 |
TPointD p( cos(a), sin(a) );
|
|
|
da4ce3 |
TPointD n( p.x*r.y, p.y*r.x ); // perp to allipse
|
|
|
da4ce3 |
double nl2 = norm2(n);
|
|
|
da4ce3 |
if (nl2 > TConsts::epsilon*TConsts::epsilon) {
|
|
|
da4ce3 |
p.x *= r.x;
|
|
|
da4ce3 |
p.y *= r.y;
|
|
|
da4ce3 |
n = n*(1.0/sqrt(nl2));
|
|
|
da4ce3 |
drawMark(em*p, em.transformDirection(n), pixelSize, alpha);
|
|
|
f278a5 |
}
|
|
|
9a49d4 |
}
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::drawConcentricGrid(
|
|
|
da4ce3 |
const TAffine &ellipseMatrix,
|
|
|
da4ce3 |
const TPointD &grid0,
|
|
|
da4ce3 |
const TPointD &grid1,
|
|
|
da4ce3 |
bool perspective,
|
|
|
da4ce3 |
double alpha )
|
|
|
da4ce3 |
{
|
|
|
da4ce3 |
TAffine4 modelview, projection;
|
|
|
da4ce3 |
glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
|
|
|
da4ce3 |
glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
|
|
|
da4ce3 |
TAffine screenMatrix = (projection*modelview).get2d();
|
|
|
da4ce3 |
TAffine screenMatrixInv = screenMatrix.inv();
|
|
|
da4ce3 |
|
|
|
da4ce3 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
373f71 |
double minStep = 10.0*pixelSize;
|
|
|
da4ce3 |
TAffine ellipseMatrixInv = ellipseMatrix.inv();
|
|
|
da4ce3 |
|
|
|
da4ce3 |
// calculate bounds
|
|
|
da4ce3 |
TAffine matrixInv = ellipseMatrixInv * screenMatrixInv;
|
|
|
da4ce3 |
TPointD o = matrixInv * TPointD(-1.0, -1.0);
|
|
|
da4ce3 |
TPointD dx = matrixInv.transformDirection( TPointD(2.0, 0.0) );
|
|
|
da4ce3 |
TPointD dy = matrixInv.transformDirection( TPointD(0.0, 2.0) );
|
|
|
da4ce3 |
double max = 0.0;
|
|
|
da4ce3 |
double min = std::numeric_limits<double>::infinity();</double>
|
|
|
da4ce3 |
|
|
|
da4ce3 |
// distance to points
|
|
|
da4ce3 |
TPointD corners[] = { o, o+dx, o+dx+dy, o+dy };
|
|
|
da4ce3 |
for(int i = 0; i < 4; ++i) {
|
|
|
da4ce3 |
double k = norm(corners[i]);
|
|
|
da4ce3 |
if (k < min) min = k;
|
|
|
da4ce3 |
if (k > max) max = k;
|
|
|
9a49d4 |
}
|
|
|
9a49d4 |
|
|
|
da4ce3 |
// distance to sides
|
|
|
da4ce3 |
TPointD lines[] = { dx, dy, -1.0*dx, -1.0*dy };
|
|
|
da4ce3 |
int positive = 0, negative = 0;
|
|
|
da4ce3 |
for(int i = 0; i < 4; ++i) {
|
|
|
da4ce3 |
double len2 = norm2(lines[i]);
|
|
|
da4ce3 |
if (len2 <= TConsts::epsilon*TConsts::epsilon) continue;
|
|
|
da4ce3 |
double k = (corners[i]*rotate90(lines[i]))/sqrt(len2);
|
|
|
da4ce3 |
if (k > TConsts::epsilon) ++positive;
|
|
|
da4ce3 |
if (k < TConsts::epsilon) ++negative;
|
|
|
da4ce3 |
double l = -(corners[i]*lines[i]);
|
|
|
da4ce3 |
if (l <= TConsts::epsilon || l >= len2 - TConsts::epsilon) continue;
|
|
|
da4ce3 |
k = fabs(k);
|
|
|
da4ce3 |
if (k < min) min = k;
|
|
|
da4ce3 |
if (k > max) max = k;
|
|
|
9a49d4 |
}
|
|
|
9a49d4 |
|
|
|
da4ce3 |
// if center is inside bounds
|
|
|
da4ce3 |
if (min < 0.0 || positive == 0 || negative == 0) min = 0.0;
|
|
|
da4ce3 |
if (max <= min) return;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
// draw
|
|
|
da4ce3 |
const TAffine &em = ellipseMatrix;
|
|
|
da4ce3 |
double r = sqrt(0.5*(norm2(TPointD(em.a11, em.a21)) + norm2(TPointD(em.a12, em.a22))));
|
|
|
da4ce3 |
double actualMinStep = minStep/r;
|
|
|
da4ce3 |
double gs0 = norm(ellipseMatrixInv*grid0);
|
|
|
da4ce3 |
double gs1 = norm(ellipseMatrixInv*grid1);
|
|
|
da4ce3 |
if (gs0 <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
da4ce3 |
if (gs1 <= TConsts::epsilon*TConsts::epsilon) return;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
if (perspective) {
|
|
|
da4ce3 |
// draw perspective
|
|
|
da4ce3 |
double k = 0.0, begin = 0.0, end = 0.0;
|
|
|
da4ce3 |
if (!calcPerspectiveStep(actualMinStep, min, max, 0.0, gs0, gs1, k, begin, end)) return;
|
|
|
da4ce3 |
for(double x = begin; fabs(x) < fabs(end); x *= k)
|
|
|
da4ce3 |
drawEllipse(ellipseMatrix * TAffine::scale(x), screenMatrixInv, pixelSize, alpha);
|
|
|
da4ce3 |
} else {
|
|
|
da4ce3 |
// draw linear
|
|
|
da4ce3 |
double dx = fabs(gs1 - gs0);
|
|
|
da4ce3 |
if (dx*r < minStep) return;
|
|
|
da4ce3 |
for(double x = gs0 + ceil((min - gs0)/dx)*dx; x < max; x += dx)
|
|
|
da4ce3 |
drawEllipse(ellipseMatrix * TAffine::scale(x), screenMatrixInv, pixelSize, alpha);
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::drawParallelGrid(
|
|
|
da4ce3 |
const TAffine &ellipseMatrix,
|
|
|
da4ce3 |
const TPointD &grid0,
|
|
|
da4ce3 |
const TPointD &grid1,
|
|
|
da4ce3 |
bool perspective,
|
|
|
da4ce3 |
bool repeat,
|
|
|
da4ce3 |
double alpha )
|
|
|
da4ce3 |
{
|
|
|
da4ce3 |
TAffine4 modelview, projection;
|
|
|
da4ce3 |
glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
|
|
|
da4ce3 |
glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
|
|
|
da4ce3 |
TAffine screenMatrix = (projection*modelview).get2d();
|
|
|
da4ce3 |
TAffine screenMatrixInv = screenMatrix.inv();
|
|
|
da4ce3 |
|
|
|
da4ce3 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
da4ce3 |
double minStep = 10.0*pixelSize;
|
|
|
da4ce3 |
TAffine ellipseMatrixInv = ellipseMatrix.inv();
|
|
|
da4ce3 |
|
|
|
da4ce3 |
const TAffine &em = ellipseMatrix;
|
|
|
da4ce3 |
double r = sqrt(0.5*(norm2(TPointD(em.a11, em.a21)) + norm2(TPointD(em.a12, em.a22))));
|
|
|
da4ce3 |
double actualMinStep = minStep/r;
|
|
|
da4ce3 |
TPointD g0 = ellipseMatrixInv*grid0;
|
|
|
da4ce3 |
TPointD g1 = ellipseMatrixInv*grid1;
|
|
|
da4ce3 |
if (repeat)
|
|
|
da4ce3 |
{ g0.x -= round(0.5*g0.x)*2.0; g1.x -= round(0.5*g1.x)*2.0; }
|
|
|
da4ce3 |
if (fabs(g0.x) >= 1.0 - TConsts::epsilon) return;
|
|
|
da4ce3 |
if (fabs(g1.x) >= 1.0 - TConsts::epsilon) return;
|
|
|
da4ce3 |
double gs0 = g0.y/sqrt(1.0 - g0.x*g0.x);
|
|
|
da4ce3 |
double gs1 = g1.y/sqrt(1.0 - g1.x*g1.x);
|
|
|
da4ce3 |
if (fabs(gs0) >= 1.0 - TConsts::epsilon) return;
|
|
|
da4ce3 |
if (fabs(gs1) >= 1.0 - TConsts::epsilon) return;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
TAngleRangeSet ranges;
|
|
|
da4ce3 |
ranges.add( TAngleRangeSet::fromDouble(0.0), TAngleRangeSet::fromDouble(M_PI) );
|
|
|
da4ce3 |
|
|
|
da4ce3 |
if (perspective) {
|
|
|
da4ce3 |
// draw perspective (actually angular)
|
|
|
da4ce3 |
double a0 = asin(gs0);
|
|
|
da4ce3 |
double a1 = asin(gs1);
|
|
|
da4ce3 |
double da = fabs(a1 - a0);
|
|
|
da4ce3 |
if (fabs(sin(da)) < 2.0*actualMinStep) return;
|
|
|
da4ce3 |
for(double a = a0 + ceil((-M_PI_2 - a0)/da)*da; a < M_PI_2; a += da)
|
|
|
da4ce3 |
drawEllipseRanges(
|
|
|
da4ce3 |
ranges,
|
|
|
da4ce3 |
ellipseMatrix*TAffine::scale(a < 0.0 ? -1.0 : 1.0, sin(a)),
|
|
|
da4ce3 |
screenMatrixInv,
|
|
|
da4ce3 |
pixelSize,
|
|
|
da4ce3 |
alpha );
|
|
|
da4ce3 |
} else {
|
|
|
da4ce3 |
// draw linear
|
|
|
da4ce3 |
double dx = fabs(gs1 - gs0);
|
|
|
da4ce3 |
if (dx < actualMinStep) return;
|
|
|
da4ce3 |
for(double x = gs0 + ceil((-1.0 - gs0)/dx)*dx; x < 1.0; x += dx)
|
|
|
da4ce3 |
drawEllipseRanges(
|
|
|
da4ce3 |
ranges,
|
|
|
da4ce3 |
ellipseMatrix*TAffine::scale(x < 0.0 ? -1.0 : 1.0, x),
|
|
|
da4ce3 |
screenMatrixInv,
|
|
|
da4ce3 |
pixelSize,
|
|
|
da4ce3 |
alpha );
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
|
|
|
da4ce3 |
|
|
|
da4ce3 |
void TAssistantEllipse::draw(
|
|
|
da4ce3 |
const TAffine &ellipseMatrix,
|
|
|
da4ce3 |
const TAffine &screenMatrixInv,
|
|
|
da4ce3 |
double ox,
|
|
|
da4ce3 |
double pixelSize,
|
|
|
da4ce3 |
bool enabled ) const
|
|
|
da4ce3 |
{
|
|
|
da4ce3 |
const double crossSize = 0.1;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
double alpha = getDrawingAlpha(enabled);
|
|
|
da4ce3 |
double gridAlpha = getDrawingGridAlpha();
|
|
|
da4ce3 |
bool grid = getGrid();
|
|
|
da4ce3 |
bool ruler = getRestrictA() && getRestrictB();
|
|
|
da4ce3 |
bool concentric = !getRestrictA() && !getRestrictB();
|
|
|
da4ce3 |
|
|
|
da4ce3 |
drawSegment( ellipseMatrix*TPointD(-crossSize, 0.0),
|
|
|
da4ce3 |
ellipseMatrix*TPointD( crossSize, 0.0), pixelSize, alpha);
|
|
|
da4ce3 |
drawSegment( ellipseMatrix*TPointD(0.0, -crossSize),
|
|
|
da4ce3 |
ellipseMatrix*TPointD(0.0, crossSize), pixelSize, alpha);
|
|
|
da4ce3 |
drawEllipse(ellipseMatrix, screenMatrixInv, pixelSize, alpha);
|
|
|
da4ce3 |
if (ox > 1.0)
|
|
|
da4ce3 |
drawSegment( ellipseMatrix*TPointD(-1.0, -1.0),
|
|
|
da4ce3 |
ellipseMatrix*TPointD(-1.0, 1.0), pixelSize, alpha);
|
|
|
da4ce3 |
else if (ox < -1.0)
|
|
|
da4ce3 |
drawSegment( ellipseMatrix*TPointD( 1.0, -1.0),
|
|
|
da4ce3 |
ellipseMatrix*TPointD( 1.0, 1.0), pixelSize, alpha);
|
|
|
da4ce3 |
|
|
|
da4ce3 |
if (!grid) return;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
if (ruler) {
|
|
|
da4ce3 |
drawRuler(
|
|
|
da4ce3 |
ellipseMatrix,
|
|
|
da4ce3 |
m_grid0.position,
|
|
|
da4ce3 |
m_grid1.position,
|
|
|
da4ce3 |
getPerspective(),
|
|
|
da4ce3 |
alpha );
|
|
|
da4ce3 |
} else
|
|
|
da4ce3 |
if (concentric) {
|
|
|
da4ce3 |
drawConcentricGrid(
|
|
|
da4ce3 |
ellipseMatrix,
|
|
|
da4ce3 |
m_grid0.position,
|
|
|
da4ce3 |
m_grid1.position,
|
|
|
da4ce3 |
getPerspective(),
|
|
|
da4ce3 |
gridAlpha );
|
|
|
da4ce3 |
} else {
|
|
|
da4ce3 |
drawParallelGrid(
|
|
|
da4ce3 |
ellipseMatrix,
|
|
|
da4ce3 |
m_grid0.position,
|
|
|
da4ce3 |
m_grid1.position,
|
|
|
da4ce3 |
getPerspective(),
|
|
|
da4ce3 |
getRepeat(),
|
|
|
da4ce3 |
gridAlpha );
|
|
|
da4ce3 |
}
|
|
|
da4ce3 |
}
|
|
|
9a49d4 |
|
|
|
9a49d4 |
|
|
|
da4ce3 |
void TAssistantEllipse::draw(TToolViewer*, bool enabled) const {
|
|
|
da4ce3 |
bool restrictA = getRestrictA();
|
|
|
da4ce3 |
bool restrictB = getRestrictB();
|
|
|
da4ce3 |
bool repeat = getRepeat();
|
|
|
da4ce3 |
double minStep = 30.0;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
TAffine ellipseMatrix = calcEllipseMatrix();
|
|
|
da4ce3 |
if (ellipseMatrix.isZero()) return;
|
|
|
da4ce3 |
if (!restrictA && restrictB) {
|
|
|
da4ce3 |
std::swap(ellipseMatrix.a11, ellipseMatrix.a12);
|
|
|
da4ce3 |
std::swap(ellipseMatrix.a21, ellipseMatrix.a22);
|
|
|
da4ce3 |
}
|
|
|
9a49d4 |
|
|
|
da4ce3 |
// common data about viewport
|
|
|
da4ce3 |
const TRectD oneBox(-1.0, -1.0, 1.0, 1.0);
|
|
|
da4ce3 |
TAffine4 modelview, projection;
|
|
|
da4ce3 |
glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a);
|
|
|
da4ce3 |
glGetDoublev(GL_PROJECTION_MATRIX, projection.a);
|
|
|
da4ce3 |
TAffine matrix = (projection*modelview).get2d();
|
|
|
da4ce3 |
TAffine matrixInv = matrix.inv();
|
|
|
da4ce3 |
double pixelSize = sqrt(tglGetPixelSize2());
|
|
|
da4ce3 |
|
|
|
da4ce3 |
if (!repeat || restrictA == restrictB || norm(TPointD(ellipseMatrix.a11, ellipseMatrix.a21)) < minStep*pixelSize) {
|
|
|
da4ce3 |
draw(ellipseMatrix, matrixInv, 0.0, pixelSize, enabled);
|
|
|
da4ce3 |
} else {
|
|
|
da4ce3 |
// calculate bounds
|
|
|
da4ce3 |
TPointD o(ellipseMatrix.a13, ellipseMatrix.a23);
|
|
|
da4ce3 |
TPointD proj(ellipseMatrix.a11, ellipseMatrix.a21);
|
|
|
da4ce3 |
proj = proj * (1.0/norm2(proj));
|
|
|
da4ce3 |
TPointD corners[4] = {
|
|
|
da4ce3 |
TPointD(oneBox.x0, oneBox.y0),
|
|
|
da4ce3 |
TPointD(oneBox.x0, oneBox.y1),
|
|
|
da4ce3 |
TPointD(oneBox.x1, oneBox.y0),
|
|
|
da4ce3 |
TPointD(oneBox.x1, oneBox.y1) };
|
|
|
da4ce3 |
double minX = 0.0, maxX = 0.0;
|
|
|
da4ce3 |
for(int i = 0; i < 4; ++i) {
|
|
|
da4ce3 |
double x = proj * (matrixInv*corners[i] - o);
|
|
|
da4ce3 |
if (i == 0 || x < minX) minX = x;
|
|
|
da4ce3 |
if (i == 0 || x > maxX) maxX = x;
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
if (maxX <= minX) return;
|
|
|
da4ce3 |
|
|
|
da4ce3 |
// draw
|
|
|
da4ce3 |
for(double ox = round(0.5*minX)*2.0; ox - 1.0 < maxX; ox += 2.0)
|
|
|
da4ce3 |
draw(ellipseMatrix*TAffine::translation(ox, 0.0), matrixInv, ox, pixelSize, enabled);
|
|
|
9a49d4 |
}
|
|
|
da4ce3 |
}
|
|
|
9a49d4 |
|
|
|
9a49d4 |
|
|
|
9a49d4 |
//*****************************************************************************************
|
|
|
9a49d4 |
// Registration
|
|
|
9a49d4 |
//*****************************************************************************************
|
|
|
9a49d4 |
|
|
|
9a49d4 |
static TAssistantTypeT<tassistantellipse> assistantEllipse("assistantEllipse");</tassistantellipse>
|
|
|
9a49d4 |
|