diff --git a/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp b/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp index 54047bd..9eb7718 100644 --- a/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp +++ b/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp @@ -155,12 +155,13 @@ public: } void onMovePoint(TAssistantPoint &point, const TPointD &position) override { - if (&point == &getBasePoint()) - { move(position); return; } - TPointD previousCenter = m_center.position; TPointD previous = point.position; point.position = position; + if (&point == &m_center) { + fixSidePoint(m_a0, m_a1); + fixSidePoint(m_b0, m_b1); + } else if (&point == &m_a0) { fixSidePoint(m_a0, m_a1, previous); fixSidePoint(m_b0, m_b1); @@ -215,7 +216,8 @@ public: void drawSimpleGrid() const { if (m_gridRays <= 0) return; - double alpha = getDrawingGridAlpha(); + // common data about viewport + const TRectD oneBox(-1.0, -1.0, 1.0, 1.0); TAffine4 modelview, projection; glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a); glGetDoublev(GL_PROJECTION_MATRIX, projection.a); @@ -223,8 +225,9 @@ public: TAffine matrixInv = matrix.inv(); double pixelSize = sqrt(tglGetPixelSize2()); + // initial calculations + double alpha = getDrawingGridAlpha(); const TPointD &p = m_center.position; - const TRectD oneBox(-1.0, -1.0, 1.0, 1.0); TPointD dp = m_grid0.position - p; double step = M_2PI/(double)m_gridRays; @@ -242,7 +245,7 @@ public: angles[i] = atan(matrixInv*corners[i] - p) + M_2PI; for(int j = 0; j < i; ++j) { double d = fabs(angles[i] - angles[j]); - if (d > M_PI) d = M_PI - d; + if (d > M_PI) d = M_2PI - d; if (d > da) da = d, a0 = angles[i], a1 = angles[j]; } } @@ -271,7 +274,86 @@ public: } void drawPerspectiveGrid() const { - // TODO: + // initial calculations + const double minStep = 5.0; + double alpha = getDrawingGridAlpha(); + const TPointD ¢er = m_center.position; + + TPointD step = m_grid1.position - m_grid0.position; + double stepLen2 = norm2(step); + double stepLen = sqrt(stepLen2); + if (stepLen <= minStep) return; + TPointD stepProj = step*(1.0/stepLen2); + + TPointD dp = center - m_grid0.position; + double startX = dp*stepProj; + TPointD zeroPoint = m_grid0.position + 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); + + // common data about viewport + const TRectD oneBox(-1.0, -1.0, 1.0, 1.0); + TAffine4 modelview, projection; + glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a); + glGetDoublev(GL_PROJECTION_MATRIX, projection.a); + TAffine matrix = (projection*modelview).get2d(); + TAffine matrixInv = matrix.inv(); + double pixelSize = sqrt(tglGetPixelSize2()); + + // 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::truncateInfiniteRay(oneBox, p0, p1)) + drawSegment(matrixInv*p0, matrixInv*p1, pixelSize, alpha); + } + + // draw horizon + p0 = matrix*(center); + p1 = matrix*(center + step); + if (TGuidelineLineBase::truncateInfiniteLine(oneBox, p0, p1)) + drawSegment(matrixInv*p0, matrixInv*p1, pixelSize, alpha); } void draw(TToolViewer *viewer, bool enabled) const override { diff --git a/toonz/sources/tnztools/assistants/guidelineline.cpp b/toonz/sources/tnztools/assistants/guidelineline.cpp index faa5e16..5d47771 100644 --- a/toonz/sources/tnztools/assistants/guidelineline.cpp +++ b/toonz/sources/tnztools/assistants/guidelineline.cpp @@ -22,7 +22,7 @@ TGuidelineLineBase::calcDirection(const TPointD &p0, const TPointD &p1) { static bool -truncateX(double &x0, double &y0, double &x1, double &y1, double minx, double maxx) { +fitX(double &x0, double &y0, double &x1, double &y1, double minx, double maxx) { double dx = x1 - x0; if (fabs(dx) < TConsts::epsilon) return false; double k = (y1 - y0)/dx; @@ -36,21 +36,36 @@ truncateX(double &x0, double &y0, double &x1, double &y1, double minx, double ma return true; } +static bool +truncateX(double &x0, double &y0, double &x1, double &y1, double minx, double maxx) { + if (x0 <= minx && x1 <= minx) return false; + if (x0 >= maxx && x1 >= maxx) return false; + double dx = x1 - x0; + if (fabs(dx) < TConsts::epsilon) return true; + double k = (y1 - y0)/dx; + if (dx > 0.0) { + if (x0 < minx) { y0 += k*(minx - x0); x0 = minx; } + if (x1 > maxx) { y1 += k*(maxx - x1); x1 = maxx; } + } else { + if (x0 > maxx) { y0 += k*(maxx - x0); x0 = maxx; } + if (x1 < minx) { y1 += k*(minx - x1); x1 = minx; } + } + return true; +} + bool TGuidelineLineBase::truncateInfiniteLine(const TRectD &bounds, TPointD &p0, TPointD &p1) { if (bounds.isEmpty()) return false; TPointD d = p0 - p1; TDimensionD size = bounds.getSize(); - if (fabs(d.x)*bounds.y0 > bounds.x0*fabs(d.y)) { + if (fabs(d.x)*(bounds.y1 - bounds.y0) > fabs(d.y)*(bounds.x1 - bounds.x0)) { // horizontal - if (!truncateX(p0.x, p0.y, p1.x, p1.y, bounds.x0, bounds.x1)) return false; - if (p0.y <= bounds.y0 && p1.y <= bounds.y0) return false; - if (p0.y >= bounds.y1 && p1.y >= bounds.y1) return false; + if (!fitX (p0.x, p0.y, p1.x, p1.y, bounds.x0, bounds.x1)) return false; + if (!truncateX(p0.y, p0.x, p1.y, p1.x, bounds.y0, bounds.y1)) return false; } else { // vertical - if (!truncateX(p0.y, p0.x, p1.y, p1.x, bounds.y0, bounds.y1)) return false; - if (p0.x <= bounds.x0 && p1.x <= bounds.x0) return false; - if (p0.x >= bounds.x1 && p1.x >= bounds.x1) return false; + if (!fitX (p0.y, p0.x, p1.y, p1.x, bounds.y0, bounds.y1)) return false; + if (!truncateX(p0.x, p0.y, p1.x, p1.y, bounds.x0, bounds.x1)) return false; } return true; } @@ -59,10 +74,11 @@ bool TGuidelineLineBase::truncateInfiniteRay(const TRectD &bounds, TPointD &p0, TPointD &p1) { if (bounds.isEmpty()) return false; TRectD b(bounds); - if (b.contains(p0)) { - (p0.x < p1.x ? b.x0 : b.x1) = p0.x; - (p0.y < p1.y ? b.y0 : b.y1) = p0.y; - } + if (p0.x <= p1.x && b.x0 <= p0.x) b.x0 = p0.x; + if (p0.x > p1.x && b.x1 > p0.x) b.x1 = p0.x; + if (p0.y <= p1.y && b.y0 <= p0.y) b.y0 = p0.y; + if (p0.y > p1.y && b.y1 > p0.y) b.y1 = p0.y; + if (b.isEmpty()) return false; return truncateInfiniteLine(b, p0, p1); }