From 13f20b94a2eb2a73f09fb3b2af52746ff32b1d0f Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Sep 17 2023 13:15:59 +0000 Subject: #assistants: fix perspective grids --- diff --git a/toonz/sources/include/tools/assistant.h b/toonz/sources/include/tools/assistant.h index 53b3ac2..a8e8ea3 100644 --- a/toonz/sources/include/tools/assistant.h +++ b/toonz/sources/include/tools/assistant.h @@ -318,12 +318,14 @@ protected: double getDrawingAlpha(bool enabled = true) const; double getDrawingGridAlpha() const; - static void drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize, double alpha); + static void drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize, double alpha0, double alpha1); static void drawMark(const TPointD &p, const TPointD &normal, double pixelSize, double alpha); static void drawDot(const TPointD &p, double alpha); static void drawPoint(const TAssistantPoint &point, double pixelSize); static void drawIndex(const TPointD &p, int index, bool selected, double pixelSize); + static inline void drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize, double alpha) + { drawSegment(p0, p1, pixelSize, alpha, alpha); } inline void drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize) const { drawSegment(p0, p1, pixelSize, getDrawingAlpha()); } inline void drawDot(const TPointD &p) const @@ -369,6 +371,7 @@ public: void updateTranslation() const override; virtual void getGuidelines(const TPointD &position, const TAffine &toTool, TGuidelineList &outGuidelines) const; + // calc W-coefficient and i-bounds for formula: x0 + 1/(i*W + 1) static bool calcPerspectiveStep( double minStep, double minX, @@ -376,9 +379,9 @@ public: double x0, double x1, double x2, - double &outK, - double &outMin, - double &outMax ); + double &outW, + double &outMinI, + double &outMaxI ); static bool scanAssistants( TTool *tool, diff --git a/toonz/sources/tnztools/assistant.cpp b/toonz/sources/tnztools/assistant.cpp index e037f9b..40061e4 100644 --- a/toonz/sources/tnztools/assistant.cpp +++ b/toonz/sources/tnztools/assistant.cpp @@ -435,11 +435,16 @@ TAssistantBase::getDrawingGridAlpha() const //--------------------------------------------------------------------------------------------------- void -TAssistantBase::drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize, double alpha) { - double colorBlack[4] = { 0.0, 0.0, 0.0, alpha }; - double colorWhite[4] = { 1.0, 1.0, 1.0, alpha }; +TAssistantBase::drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize, double alpha0, double alpha1) { + double colors[][4] = { + { 1, 1, 1, alpha0 }, + { 1, 1, 1, alpha1 }, + { 0, 0, 0, alpha0 }, + { 0, 0, 0, alpha1 }, + }; - if (drawFlags & DRAW_ERROR) colorBlack[0] = 1; + if (drawFlags & DRAW_ERROR) + colors[2][0] = colors[3][0] = 1; glPushAttrib(GL_ALL_ATTRIB_BITS); tglEnableBlending(); @@ -449,10 +454,12 @@ TAssistantBase::drawSegment(const TPointD &p0, const TPointD &p1, double pixelSi if (k > TConsts::epsilon*TConsts::epsilon) { k = 0.5*pixelSize*lineWidthScale/sqrt(k); d = TPointD(-k*d.y, k*d.x); - glColor4dv(colorWhite); - tglDrawSegment(p0 - d, p1 - d); - glColor4dv(colorBlack); - tglDrawSegment(p0 + d, p1 + d); + glBegin(GL_LINES); + glColor4dv(colors[0]); tglVertex(p0 - d); + glColor4dv(colors[1]); tglVertex(p1 - d); + glColor4dv(colors[2]); tglVertex(p0 + d); + glColor4dv(colors[3]); tglVertex(p1 + d); + glEnd(); } glPopAttrib(); } @@ -727,28 +734,67 @@ TAssistant::calcPerspectiveStep( double x0, double x1, double x2, - double &outK, - double &outMin, - double &outMax ) + double &outW, + double &outMinI, + double &outMaxI ) { - outK = outMin = outMax = 0.0; - - double dx1 = x1 - x0; - double dx2 = x2 - x0; - if (fabs(dx1) <= TConsts::epsilon) return false; - if (fabs(dx2) <= TConsts::epsilon) return false; - if ((dx1 < 0.0) != (dx2 < 0.0)) dx2 = -dx2; - if (fabs(dx2 - dx1) <= minStep) return false; - if (fabs(dx2) < fabs(dx1)) std::swap(dx1, dx2); - - if (x0 <= minX + TConsts::epsilon && dx1 < 0.0) return false; - if (x0 >= maxX - TConsts::epsilon && dx1 > 0.0) return false; - - outK = dx2/dx1; - double minI = log(minStep/fabs(dx1*(1.0 - 1.0/outK)))/log(outK); - outMin = dx1*pow(outK, floor(minI - TConsts::epsilon)); - if (fabs(outMin) < TConsts::epsilon) return false; - outMax = (dx1 > 0.0 ? maxX : minX) - x0; + outW = outMinI = outMaxI = 0; + if (!(minStep > TConsts::epsilon)) return false; + if (!(minX + TConsts::epsilon < maxX)) return false; + + minX -= x0; + maxX -= x0; + x1 -= x0; + x2 -= x0; + + // check and fix input + if (!(fabs(x1) > TConsts::epsilon)) return false; + if (!(fabs(x2) > TConsts::epsilon)) return false; + if (!(fabs(x1 - x2) > TConsts::epsilon)) return false; + if ((x1 < 0) != (x2 < 0)) x2 = -x2; + if (fabs(x2) < fabs(x1)) std::swap(x1, x2); + + // check if bounds is behind the horizon + if (x1 < 0 && !(minX < -TConsts::epsilon)) return false; + if (x1 > 0 && !(maxX > TConsts::epsilon)) return false; + + // calc W and initial bounds + double w = 1/x2 - 1/x1; + double d = sqrt(fabs(w/minStep)); + if (x1 < 0) d = -d; + double i0 = (d - 1)/w; + double i1 = -1/w; + + // min/max bounds + if (x1 < 0) { + if (maxX < -TConsts::epsilon) + i0 = std::max( i0, (1 - maxX)/(maxX*w) ); + i1 = std::min( i1, (1 - minX)/(minX*w) ); + } else { + if (minX > TConsts::epsilon) + i0 = std::max( i0, (1 - minX)/(minX*w) ); + i1 = std::min( i1, (1 - maxX)/(maxX*w) ); + } + + // i must be iterable (i < i + 1) + const double bound = 1e10; + i0 = i0 > -bound ? (i0 < bound ? i0 : bound) : -bound; + i1 = i1 > -bound ? (i1 < bound ? i1 : bound) : -bound; + + // tune beginning of grid to place it axact to grid points + // must be: i0 + integer == ig + double ig = (1 - x1)/(x1*w); + double frac = ig - floor(ig); + i0 = ceil(i0 - frac + TConsts::epsilon) + frac; + i1 -= TConsts::epsilon; + + // restrict count + if (i1 - i0 > 10000) return false; + if (!(i0 < i1)) return false; + + outW = w; + outMinI = i0; + outMaxI = i1; return true; } diff --git a/toonz/sources/tnztools/assistants/assistantellipse.cpp b/toonz/sources/tnztools/assistants/assistantellipse.cpp index 19a2857..4b24ac7 100644 --- a/toonz/sources/tnztools/assistants/assistantellipse.cpp +++ b/toonz/sources/tnztools/assistants/assistantellipse.cpp @@ -245,7 +245,7 @@ void TAssistantEllipse::drawRuler( double alpha ) { double pixelSize = sqrt(tglGetPixelSize2()); - double minStep = 10.0*pixelSize; + double minStep = (perspective ? 5 : 10)*pixelSize; TAffine em = ellipseMatrix; TAffine ellipseMatrixInv = ellipseMatrix.inv(); @@ -275,10 +275,13 @@ void TAssistantEllipse::drawRuler( // draw perspective if (ga0 < 0.0) { if (ga1 > 0.0) ga1 -= M_2PI; } else { if (ga1 < 0.0) ga1 += M_2PI; } - double k = 0.0, begin = 0.0, end = 0.0; - if (!calcPerspectiveStep(actualMinStep, 0.0, M_2PI, 0.0, fabs(ga0), ga1, k, begin, end)) return; - for(double a = begin; fabs(a) < fabs(end); a *= k) { - TPointD p( cos(a), (ga0 < 0.0 ? -1.0 : 1.0)*sin(a) ); + double w, i0, i1; + double bound0 = ga0 < 0 ? -M_2PI : 0; + double bound1 = ga0 < 0 ? 0 : M_2PI; + if (!calcPerspectiveStep(actualMinStep, bound0, bound1, 0, ga0, ga1, w, i0, i1)) return; + for(double i = i0; i < i1; i += 1) { + double a = 1/(i*w + 1); + TPointD p( cos(a), sin(a) ); TPointD n( p.x*r.y, p.y*r.x ); // perp to allipse double nl2 = norm2(n); if (nl2 > TConsts::epsilon*TConsts::epsilon) { @@ -323,7 +326,7 @@ void TAssistantEllipse::drawConcentricGrid( TAffine screenMatrixInv = screenMatrix.inv(); double pixelSize = sqrt(tglGetPixelSize2()); - double minStep = 10.0*pixelSize; + double minStep = (perspective ? 2.5 : 10.0)*pixelSize; TAffine ellipseMatrixInv = ellipseMatrix.inv(); // calculate bounds @@ -364,7 +367,7 @@ void TAssistantEllipse::drawConcentricGrid( // draw const TAffine &em = ellipseMatrix; - double r = sqrt(0.5*(norm2(TPointD(em.a11, em.a21)) + norm2(TPointD(em.a12, em.a22)))); + double r = sqrt(std::min( norm2(TPointD(em.a11, em.a21)), norm2(TPointD(em.a12, em.a22)) )); double actualMinStep = minStep/r; double gs0 = norm(ellipseMatrixInv*grid0); double gs1 = norm(ellipseMatrixInv*grid1); @@ -373,10 +376,19 @@ void TAssistantEllipse::drawConcentricGrid( if (perspective) { // draw perspective - double k = 0.0, begin = 0.0, end = 0.0; - if (!calcPerspectiveStep(actualMinStep, min, max, 0.0, gs0, gs1, k, begin, end)) return; - for(double x = begin; fabs(x) < fabs(end); x *= k) - drawEllipse(ellipseMatrix * TAffine::scale(x), screenMatrixInv, pixelSize, alpha); + double w, i0, i1; + actualMinStep /= 2; + if (!calcPerspectiveStep(actualMinStep, min, max, 0, gs0, gs1, w, i0, i1)) return; + for(double i = i0; i < i1; i += 1) { + double x = 1/(i*w + 1); + + double curStep = fabs(w*x*x); + double curAlpha = (curStep - actualMinStep)/actualMinStep; + if (curAlpha < 0) continue; + if (curAlpha > 1) curAlpha = 1; + + drawEllipse(ellipseMatrix * TAffine::scale(x), screenMatrixInv, pixelSize, alpha*curAlpha); + } } else { // draw linear double dx = fabs(gs1 - gs0); diff --git a/toonz/sources/tnztools/assistants/assistantline.cpp b/toonz/sources/tnztools/assistants/assistantline.cpp index f078e45..6563d01 100644 --- a/toonz/sources/tnztools/assistants/assistantline.cpp +++ b/toonz/sources/tnztools/assistants/assistantline.cpp @@ -52,32 +52,36 @@ void TAssistantLine::onDataChanged(const TVariant &value) { } -void TAssistantLine::fixGrid1(const TPointD &previousA, const TPointD &previousB) { - TPointD dx = previousB - previousA; - double l = norm2(dx); - if (l <= TConsts::epsilon*TConsts::epsilon) return; - dx = dx*(1.0/sqrt(l)); - TPointD dy(-dx.y, dx.x); - - TPointD g1 = m_grid1.position - m_grid0.position; - g1 = TPointD(dx*g1, dy*g1); - - dx = m_b.position - m_a.position; - l = norm2(dx); - if (l <= TConsts::epsilon*TConsts::epsilon) return; - dx = dx*(1.0/sqrt(l)); - dy = TPointD(-dx.y, dx.x); - - m_grid1.position = m_grid0.position + dx*g1.x + dy*g1.y; +void TAssistantLine::fixGrid(const TPointD &prevA, const TPointD &prevB) { + TPointD dx0 = prevB - prevA; + TPointD dx1 = m_b.position - m_a.position; + double l0 = norm2(dx0); + double l1 = norm2(dx1); + if (!( l0 > TConsts::epsilon*TConsts::epsilon + && l1 > TConsts::epsilon*TConsts::epsilon )) return; + dx0 *= 1/sqrt(l0); + dx1 *= 1/sqrt(l1); + TPointD dy0(-dx0.y, dx0.x); + TPointD dy1(-dx1.y, dx1.x); + + if (getParallel()) { + TPointD g1 = m_grid1.position - m_grid0.position; + m_grid1.position = m_grid0.position + g1*dx0*dx1 + g1*dy0*dy1; + } else { + TPointD g0 = m_grid0.position - prevA; + TPointD g1 = m_grid1.position - prevA; + m_grid0.position = m_a.position + g0*dx0*dx1 + g0*dy0*dy1; + m_grid1.position = m_a.position + g1*dx0*dx1 + g1*dy0*dy1; + } } void TAssistantLine::onMovePoint(TAssistantPoint &point, const TPointD &position) { - TPointD previousA = m_a.position; - TPointD previousB = m_b.position; + TPointD prevA = m_a.position; + TPointD prevB = m_b.position; point.position = position; if (&point != &m_grid1) - fixGrid1(previousA, previousB); + fixGrid(prevA, prevB); } @@ -141,7 +145,7 @@ void TAssistantLine::drawRuler( double alpha ) { double pixelSize = sqrt(tglGetPixelSize2()); - double minStep = 10.0*pixelSize; + double minStep = (perspectiveBase ? 5 : 10)*pixelSize; TPointD direction = b - a; double l2 = norm2(direction); @@ -156,10 +160,12 @@ void TAssistantLine::drawRuler( if (perspectiveBase) { // draw perspective double xa0 = dirProj*(*perspectiveBase - a); - double k = 0.0, begin = 0.0, end = 0.0; - if (!calcPerspectiveStep(minStep/dirLen, 0.0, 1.0, xa0, xg0, xg1, k, begin, end)) return; - for(double x = begin; fabs(x) < fabs(end); x *= k) - drawMark(a + direction*(xa0 + x), normal, pixelSize, alpha); + double w, i0, i1; + if (!calcPerspectiveStep(minStep/dirLen, 0, 1, xa0, xg0, xg1, w, i0, i1)) return; + for(double i = i0; i < i1; i += 1) { + double x = xa0 + 1/(i*w + 1); + drawMark(a + direction*x, normal, pixelSize, alpha); + } } else { // draw linear double dx = fabs(xg1 - xg0); @@ -207,7 +213,7 @@ void TAssistantLine::drawGrid( TAffine matrix = (projection*modelview).get2d(); TAffine matrixInv = matrix.inv(); double pixelSize = sqrt(tglGetPixelSize2()); - double minStep = (perspective ? 2.5 : 10.0)*pixelSize; + double minStep = (perspective ? 2.5 : 10)*pixelSize; TPointD ab = b - a; double abLen2 = norm2(ab); @@ -229,6 +235,9 @@ void TAssistantLine::drawGrid( if (perspective) { if (restrictA) drawLine(matrix, matrixInv, pixelSize, a, a + ag, false, false, alpha); if (restrictB) drawLine(matrix, matrixInv, pixelSize, a, a + ag + ab, false, false, alpha); + // horizon + if (!restrictA) drawLine(matrix, matrixInv, pixelSize, a - ab, a, restrictA, restrictB, alpha); else + if (!restrictB) drawLine(matrix, matrixInv, pixelSize, a, a + ab, restrictA, restrictB, alpha); } else { if (restrictA) drawLine(matrix, matrixInv, pixelSize, a, a + ag, false, false, alpha); if (restrictB) drawLine(matrix, matrixInv, pixelSize, b, b + ag, false, false, alpha); @@ -256,13 +265,22 @@ void TAssistantLine::drawGrid( double x1 = abpAgProj*(grid1 - a); if (perspective) { - double k = 0.0, begin = 0.0, end = 0.0; - if (!calcPerspectiveStep(minStepX, minX, maxX, 0.0, x0, x1, k, begin, end)) return; + double w, i0, i1; + minStepX /= 2; + + if (!calcPerspectiveStep(minStepX, minX, maxX, 0, x0, x1, w, i0, i1)) return; double abk = 1.0/fabs(x0); - for(double x = begin; fabs(x) < fabs(end); x *= k) { + for(double i = i0; i < i1; i += 1) { + double x = 1/(i*w + 1); + + double curStep = fabs(w*x*x); + double curAlpha = (curStep - minStepX)/minStepX; + if (curAlpha < 0) continue; + if (curAlpha > 1) curAlpha = 1; + TPointD ca = a + ag*x; TPointD cb = ca + ab*(abk*x); - drawLine(matrix, matrixInv, pixelSize, ca, cb, restrictA, restrictB, alpha); + drawLine(matrix, matrixInv, pixelSize, ca, cb, restrictA, restrictB, alpha*curAlpha); } } else { double dx = fabs(x1 - x0); diff --git a/toonz/sources/tnztools/assistants/assistantline.h b/toonz/sources/tnztools/assistants/assistantline.h index 5069906..135ac5f 100644 --- a/toonz/sources/tnztools/assistants/assistantline.h +++ b/toonz/sources/tnztools/assistants/assistantline.h @@ -53,7 +53,7 @@ public: void onDataChanged(const TVariant &value) override; private: - void fixGrid1(const TPointD &previousA, const TPointD &previousB); + void fixGrid(const TPointD &prevA, const TPointD &prevB); public: void onMovePoint(TAssistantPoint &point, const TPointD &position) override; diff --git a/toonz/sources/tnztools/assistants/assistantperspective.cpp b/toonz/sources/tnztools/assistants/assistantperspective.cpp index 6030dc6..3913eed 100644 --- a/toonz/sources/tnztools/assistants/assistantperspective.cpp +++ b/toonz/sources/tnztools/assistants/assistantperspective.cpp @@ -46,16 +46,16 @@ public: m_idGridXY("gridXY"), m_idGridYZ("gridYZ"), m_idGridZX("gridZX"), - m_o ( addPoint("o", TAssistantPoint::CircleCross) ), - m_x ( addPoint("x", TAssistantPoint::CircleFill, TPointD( 50, 0 )) ), - m_y ( addPoint("y", TAssistantPoint::CircleFill, TPointD( 0, 50 )) ), - m_z ( addPoint("z", TAssistantPoint::CircleFill, TPointD( 25, -25 )) ), - m_xy ( addPoint("xy", TAssistantPoint::Circle, TPointD( 50, 50 )) ), - m_yz ( addPoint("yz", TAssistantPoint::Circle, TPointD( 25, 25 )) ), - m_zx ( addPoint("zx", TAssistantPoint::Circle, TPointD( 75, -25 )) ), - m_vx ( addPoint("vx", TAssistantPoint::Circle) ), - m_vy ( addPoint("vy", TAssistantPoint::Circle) ), - m_vz ( addPoint("vz", TAssistantPoint::Circle) ) + m_o ( addPoint("o", TAssistantPoint::CircleCross) ), + m_x ( addPoint("x", TAssistantPoint::CircleFill, TPointD( 50, 0 )) ), + m_y ( addPoint("y", TAssistantPoint::CircleFill, TPointD( 0, 50 )) ), + m_z ( addPoint("z", TAssistantPoint::CircleFill, TPointD( 25, 25 )) ), + m_xy ( addPoint("xy", TAssistantPoint::Circle, TPointD( 50, 50 )) ), + m_yz ( addPoint("yz", TAssistantPoint::Circle, TPointD( 25, 25 )) ), + m_zx ( addPoint("zx", TAssistantPoint::Circle, TPointD( 75, 25 )) ), + m_vx ( addPoint("vx", TAssistantPoint::Circle) ), + m_vy ( addPoint("vy", TAssistantPoint::Circle) ), + m_vz ( addPoint("vz", TAssistantPoint::Circle) ) { addProperty( new TBoolProperty(m_idParallelX.str(), getParallelX()) ); addProperty( new TBoolProperty(m_idParallelY.str(), getParallelY()) ); diff --git a/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp b/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp index ac027d4..23e8aa3 100644 --- a/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp +++ b/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp @@ -256,81 +256,75 @@ void TAssistantVanishingPoint::drawPerspectiveGrid( // initial calculations double pixelSize = sqrt(tglGetPixelSize2()); double minStep = 5.0*pixelSize; - - TPointD step = grid1 - grid0; - double stepLen2 = norm2(step); - double stepLen = sqrt(stepLen2); - if (stepLen <= minStep) return; - TPointD stepProj = step*(1.0/stepLen2); - - TPointD dp = center - grid0; - double startX = dp*stepProj; - TPointD zeroPoint = grid0 + step*startX; - TPointD cz = zeroPoint - center; - double czLen2 = norm2(cz); - double czLen = sqrt(czLen2); - if (czLen <= TConsts::epsilon) return; - TPointD zeroProj = cz*(1.0/czLen2); - - double smallK = minStep/stepLen; - TPointD smallGrid0 = center - dp*smallK; - TPointD smallStep = step*smallK; - TPointD smallStepProj = stepProj*(1/smallK); + + TPointD ox = grid1 - grid0; + double lx = norm2(ox); + if (!(lx > TConsts::epsilon*TConsts::epsilon)) return; // common data about viewport - const TRectD oneBox(-1.0, -1.0, 1.0, 1.0); + const TRectD oneBox(-1, -1, 1, 1); TAffine4 modelview, projection; glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a); glGetDoublev(GL_PROJECTION_MATRIX, projection.a); TAffine matrix = (projection*modelview).get2d(); TAffine matrixInv = matrix.inv(); - - // calculate bounds - bool found = false; - double minx = 0.0, maxx = 0.0; - TPointD p0 = matrix*(smallGrid0); - TPointD p1 = matrix*(smallGrid0 + smallStep); - if (TGuidelineLineBase::truncateInfiniteLine(oneBox, p0, p1)) { - p0 = matrixInv*p0; - p1 = matrixInv*p1; - minx = (p0 - smallGrid0)*smallStepProj; - maxx = (p1 - smallGrid0)*smallStepProj; - if (maxx < minx) std::swap(maxx, minx); - found = true; - } - if (!oneBox.contains(matrix*center)) { - TPointD corners[4] = { - TPointD(oneBox.x0, oneBox.y0), - TPointD(oneBox.x0, oneBox.y1), - TPointD(oneBox.x1, oneBox.y0), - TPointD(oneBox.x1, oneBox.y1) }; - for(int i = 0; i < 4; ++i) { - TPointD p = matrixInv*corners[i] - center; - double k = p*zeroProj; - if (k < TConsts::epsilon) continue; - double x = startX + (p*stepProj)/k; - if (!found || x < minx) minx = x; - if (!found || x > maxx) maxx = x; - found = true; - } - if (maxx <= minx) return; - } - - // draw grid - if (maxx - minx > 1e6) return; - for(double x = ceil(minx); x < maxx; ++x) { - TPointD p = smallGrid0 + smallStep*x - center; - TPointD p0 = matrix*(center + p); - TPointD p1 = matrix*(center + p*2.0); - if (TGuidelineLineBase::truncateRay(oneBox, p0, p1)) - drawSegment(matrixInv*p0, matrixInv*p1, pixelSize, alpha); - } - + // draw horizon - p0 = matrix*(center); - p1 = matrix*(center + step); + TPointD p0 = matrix*center; + TPointD p1 = matrix*(center + ox); if (TGuidelineLineBase::truncateInfiniteLine(oneBox, p0, p1)) drawSegment(matrixInv*p0, matrixInv*p1, pixelSize, alpha); + + // build grid matrix + TPointD dg = grid0 - center; + lx = sqrt(lx); + ox *= 1/lx; + TPointD oy(-ox.y, ox.x); + double baseY = dg*oy; + if (!(fabs(baseY) > TConsts::epsilon)) return; + if (baseY < 0) { oy = -oy; baseY = -baseY; } + double baseX = dg*ox/baseY; + double stepX = lx/baseY; + double k = stepX*4/minStep; + double dk = 1/k; + TAffine gridMatrix( ox.x, oy.x, center.x, + ox.y, oy.y, center.y ); + matrix = matrix*gridMatrix; + matrixInv = matrix.inv(); + + const TRectD bounds = matrixInv*oneBox; + + // top bound + double x1 = bounds.y1*k - 1; + if (x1 < TConsts::epsilon) return; + double x0 = -x1; + + // angle bounds + double y; + y = bounds.x0 < 0 ? bounds.y0 : bounds.y1; + if (y > TConsts::epsilon) x0 = std::max(x0, bounds.x0/y); + y = bounds.x1 < 0 ? bounds.y1 : bounds.y0; + if (y > TConsts::epsilon) x1 = std::min(x1, bounds.x1/y); + + // delta bounds + if (bounds.x0 < 0) + x0 = std::max( x0, (1 - sqrt(1 - 4*bounds.x0*dk))*k/2 ); + if (bounds.x1 > 0) + x1 = std::min( x1, (sqrt(1 + 4*bounds.x1*dk) - 1)*k/2 ); + + // draw grid + double i0 = ceil((x0 - baseX)/stepX); + x0 = baseX + stepX*i0; + for(double x = x0; x < x1; x += stepX) { + double l = dk*(fabs(x) + 1); + TPointD p0 = gridMatrix*TPointD(x*l, l); + TPointD p1 = gridMatrix*TPointD(x*l*2, l*2); + drawSegment(p0, p1, pixelSize, 0, alpha); + if (bounds.y1 > l*2 + TConsts::epsilon) { + TPointD p2 = gridMatrix*TPointD(x*bounds.y1, bounds.y1); + drawSegment(p1, p2, pixelSize, alpha); + } + } }