From 28366ac7528530d2dad3049aa6b80642ba90e486 Mon Sep 17 00:00:00 2001 From: Jeremy Bullock Date: Sat, 19 Sep 2020 22:06:44 -0600 Subject: [PATCH] Add perspective grids to vanishing points (#185) * Add perspective grids to vanishing points * Limit tools --- toonz/sources/tnztools/fullcolorbrushtool.cpp | 74 +++-- .../sources/tnztools/toonzrasterbrushtool.cpp | 68 ++-- .../sources/tnztools/toonzvectorbrushtool.cpp | 293 +++++++++--------- toonz/sources/toonz/sceneviewer.cpp | 73 +++-- toonz/sources/toonz/sceneviewer.h | 5 + .../sources/toonz/sceneviewercontextmenu.cpp | 52 ++-- toonz/sources/toonz/sceneviewerevents.cpp | 9 + toonz/sources/toonz/viewerdraw.cpp | 94 ++++++ toonz/sources/toonz/viewerdraw.h | 2 + 9 files changed, 407 insertions(+), 263 deletions(-) diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp index 4e695c96..8a91439e 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.cpp +++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp @@ -335,6 +335,7 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, if (!deletedPoint) m_assistantPoints.push_back(pos); simLevel->getProperties()->setVanishingPoints(m_assistantPoints); level->setDirtyFlag(true); + invalidate(); return; } if (e.isAltPressed() && e.isShiftPressed() && !e.isCtrlPressed()) { @@ -503,53 +504,48 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos, invalidateRect += (brushRect); double denominator = m_lastPoint.x - m_firstPoint.x; if (denominator == 0) denominator == 0.001; - double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator); + double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator); double radAngle = std::atan(abs(slope)); - double angle = radAngle * (180 / 3.14159); + double angle = radAngle * (180 / 3.14159); if (abs(angle) >= 82.5) m_lastPoint.x = m_firstPoint.x; else if (abs(angle) < 7.5) m_lastPoint.y = m_firstPoint.y; else { - double xDistance = m_lastPoint.x - m_firstPoint.x; - double yDistance = m_lastPoint.y - m_firstPoint.y; + double xDistance = m_lastPoint.x - m_firstPoint.x; + double yDistance = m_lastPoint.y - m_firstPoint.y; - double totalDistance = std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2)); - double xLength = 0.0; - double yLength = 0.0; - if (angle >= 7.5 && angle < 22.5) { - yLength = std::sin(15 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(15 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 22.5 && angle < 37.5) { - yLength = std::sin(30 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(30 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 37.5 && angle < 52.5) { - yLength = std::sin(45 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(45 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 52.5 && angle < 67.5) { - yLength = std::sin(60 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(60 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 67.5 && angle < 82.5) { - yLength = std::sin(75 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(75 * (3.14159 / 180)) * totalDistance; - } + double totalDistance = + std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2)); + double xLength = 0.0; + double yLength = 0.0; + if (angle >= 7.5 && angle < 22.5) { + yLength = std::sin(15 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(15 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 22.5 && angle < 37.5) { + yLength = std::sin(30 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(30 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 37.5 && angle < 52.5) { + yLength = std::sin(45 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(45 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 52.5 && angle < 67.5) { + yLength = std::sin(60 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(60 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 67.5 && angle < 82.5) { + yLength = std::sin(75 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(75 * (3.14159 / 180)) * totalDistance; + } - if (yDistance == abs(yDistance)) { - m_lastPoint.y = m_firstPoint.y + yLength; - } - else { - m_lastPoint.y = m_firstPoint.y - yLength; - } - if (xDistance == abs(xDistance)) { - m_lastPoint.x = m_firstPoint.x + xLength; - } - else { - m_lastPoint.x = m_firstPoint.x - xLength; - } + if (yDistance == abs(yDistance)) { + m_lastPoint.y = m_firstPoint.y + yLength; + } else { + m_lastPoint.y = m_firstPoint.y - yLength; + } + if (xDistance == abs(xDistance)) { + m_lastPoint.x = m_firstPoint.x + xLength; + } else { + m_lastPoint.x = m_firstPoint.x - xLength; + } } } diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.cpp b/toonz/sources/tnztools/toonzrasterbrushtool.cpp index 56554db1..cb74c7f1 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.cpp +++ b/toonz/sources/tnztools/toonzrasterbrushtool.cpp @@ -1270,6 +1270,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, if (!deletedPoint) m_assistantPoints.push_back(pos); simLevel->getProperties()->setVanishingPoints(m_assistantPoints); level->setDirtyFlag(true); + invalidate(); return; } if (e.isAltPressed() && e.isShiftPressed() && !e.isCtrlPressed()) { @@ -1537,56 +1538,49 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos, double denominator = m_lastPoint.x - m_firstPoint.x; if (denominator == 0) denominator == 0.001; - double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator); + double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator); double radAngle = std::atan(abs(slope)); - double angle = radAngle * (180 / 3.14159); + double angle = radAngle * (180 / 3.14159); if (abs(angle) >= 82.5) { - // make it vertical - m_lastPoint.x = m_firstPoint.x; - } - else if (abs(angle) < 7.5) { - // make it horizontal - m_lastPoint.y = m_firstPoint.y; - } - else { + // make it vertical + m_lastPoint.x = m_firstPoint.x; + } else if (abs(angle) < 7.5) { + // make it horizontal + m_lastPoint.y = m_firstPoint.y; + } else { double xDistance = m_lastPoint.x - m_firstPoint.x; double yDistance = m_lastPoint.y - m_firstPoint.y; - double totalDistance = std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2)); + double totalDistance = + std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2)); double xLength = 0.0; double yLength = 0.0; if (angle >= 7.5 && angle < 22.5) { - yLength = std::sin(15 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(15 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 22.5 && angle < 37.5) { - yLength = std::sin(30 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(30 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 37.5 && angle < 52.5) { - yLength = std::sin(45 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(45 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 52.5 && angle < 67.5) { - yLength = std::sin(60 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(60 * (3.14159 / 180)) * totalDistance; - } - else if (angle >= 67.5 && angle < 82.5) { - yLength = std::sin(75 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(75 * (3.14159 / 180)) * totalDistance; + yLength = std::sin(15 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(15 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 22.5 && angle < 37.5) { + yLength = std::sin(30 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(30 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 37.5 && angle < 52.5) { + yLength = std::sin(45 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(45 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 52.5 && angle < 67.5) { + yLength = std::sin(60 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(60 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 67.5 && angle < 82.5) { + yLength = std::sin(75 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(75 * (3.14159 / 180)) * totalDistance; } if (yDistance == abs(yDistance)) { - m_lastPoint.y = m_firstPoint.y + yLength; - } - else { - m_lastPoint.y = m_firstPoint.y - yLength; + m_lastPoint.y = m_firstPoint.y + yLength; + } else { + m_lastPoint.y = m_firstPoint.y - yLength; } if (xDistance == abs(xDistance)) { - m_lastPoint.x = m_firstPoint.x + xLength; - } - else { - m_lastPoint.x = m_firstPoint.x - xLength; + m_lastPoint.x = m_firstPoint.x + xLength; + } else { + m_lastPoint.x = m_firstPoint.x - xLength; } } } diff --git a/toonz/sources/tnztools/toonzvectorbrushtool.cpp b/toonz/sources/tnztools/toonzvectorbrushtool.cpp index 5431d89b..f16852fe 100644 --- a/toonz/sources/tnztools/toonzvectorbrushtool.cpp +++ b/toonz/sources/tnztools/toonzvectorbrushtool.cpp @@ -750,6 +750,7 @@ void ToonzVectorBrushTool::leftButtonDown(const TPointD &pos, if (!deletedPoint) m_assistantPoints.push_back(pos); simLevel->getProperties()->setVanishingPoints(m_assistantPoints); level->setDirtyFlag(true); + invalidate(); return; } @@ -789,150 +790,150 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos, return; } - if ((e.isCtrlPressed() && e.isAltPressed() && !e.isShiftPressed()) || m_addingAssistant) { + if ((e.isCtrlPressed() && e.isAltPressed() && !e.isShiftPressed()) || + m_addingAssistant) { return; } TRectD invalidateRect; - m_lastPoint = pos; + m_lastPoint = pos; bool nonShiftStraight = false; - if (e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) { - invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); - nonShiftStraight = true; - double distance = (m_brushPos.x) * 0.5; - TRectD brushRect = - TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance), - TPointD(m_brushPos.x + distance, m_brushPos.y + distance)); - invalidateRect += (brushRect); + if (e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) { + invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); + nonShiftStraight = true; + double distance = (m_brushPos.x) * 0.5; + TRectD brushRect = + TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance), + TPointD(m_brushPos.x + distance, m_brushPos.y + distance)); + invalidateRect += (brushRect); - // let's get info about our current location - double denominator = m_lastPoint.x - m_firstPoint.x; - double numerator = m_lastPoint.y - m_firstPoint.y; - if (areAlmostEqual(denominator, 0.0, 0.0001)) { - denominator = denominator < 0 ? -0.0001 : 0.0001; + // let's get info about our current location + double denominator = m_lastPoint.x - m_firstPoint.x; + double numerator = m_lastPoint.y - m_firstPoint.y; + if (areAlmostEqual(denominator, 0.0, 0.0001)) { + denominator = denominator < 0 ? -0.0001 : 0.0001; + } + if (areAlmostEqual(numerator, 0.0, 0.0001)) { + numerator = numerator < 0 ? -0.0001 : 0.0001; + } + double slope = (numerator / denominator); + double angle = std::atan(slope) * (180 / 3.14159); + + // now let's get the angle of each of the assistant points + std::vector anglesToAssistants; + for (auto point : m_assistantPoints) { + double newDenominator = point.x - m_firstPoint.x; + double newNumerator = point.y - m_firstPoint.y; + if (areAlmostEqual(newDenominator, 0.0, 0.0001)) { + newDenominator = newDenominator < 0 ? -0.0001 : 0.0001; } - if (areAlmostEqual(numerator, 0.0, 0.0001)) { - numerator = numerator < 0 ? -0.0001 : 0.0001; - } - double slope = (numerator / denominator); - double angle = std::atan(slope) * (180 / 3.14159); - - // now let's get the angle of each of the assistant points - std::vector anglesToAssistants; - for (auto point : m_assistantPoints) { - double newDenominator = point.x - m_firstPoint.x; - double newNumerator = point.y - m_firstPoint.y; - if (areAlmostEqual(newDenominator, 0.0, 0.0001)) { - newDenominator = newDenominator < 0 ? -0.0001 : 0.0001; - } - if (areAlmostEqual(newNumerator, 0.0, 0.0001)) { - newNumerator = newNumerator < 0 ? -0.0001 : 0.0001; - } - - double newSlope = (newNumerator / newDenominator); - double newAngle = std::atan(newSlope) * (180 / 3.14159); - anglesToAssistants.push_back(newAngle); + if (areAlmostEqual(newNumerator, 0.0, 0.0001)) { + newNumerator = newNumerator < 0 ? -0.0001 : 0.0001; } - // figure out which angle is closer - TPointD pointToUse = TPointD(0.0, 0.0); - double difference = 360; + double newSlope = (newNumerator / newDenominator); + double newAngle = std::atan(newSlope) * (180 / 3.14159); + anglesToAssistants.push_back(newAngle); + } - for (int i = 0; i < anglesToAssistants.size(); i++) { - double newDifference = abs(angle - anglesToAssistants.at(i)); - if (newDifference < difference || (180 - newDifference) < difference) { - difference = std::min(newDifference, (180 - newDifference)); - pointToUse = m_assistantPoints.at(i); - } - } + // figure out which angle is closer + TPointD pointToUse = TPointD(0.0, 0.0); + double difference = 360; - double distanceFirstToLast = - std::sqrt(std::pow((m_lastPoint.x - m_firstPoint.x), 2) + - std::pow((m_lastPoint.y - m_firstPoint.y), 2)); - double distanceLastToAssistant = - std::sqrt(std::pow((pointToUse.x - m_lastPoint.x), 2) + - std::pow((pointToUse.y - m_lastPoint.y), 2)); - double distanceFirstToAssistant = - std::sqrt(std::pow((pointToUse.x - m_firstPoint.x), 2) + - std::pow((pointToUse.y - m_firstPoint.y), 2)); - - if (distanceFirstToAssistant == 0.0) distanceFirstToAssistant = 0.001; - - double ratio = distanceFirstToLast / distanceFirstToAssistant; - - double newX; - double newY; - - // flip the direction if the last point is farther than the first point - if (distanceFirstToAssistant < distanceLastToAssistant && - distanceFirstToLast < distanceLastToAssistant) { - newX = ((1 + ratio) * m_firstPoint.x) - (ratio * pointToUse.x); - newY = ((1 + ratio) * m_firstPoint.y) - (ratio * pointToUse.y); - } else { - newX = ((1 - ratio) * m_firstPoint.x) + (ratio * pointToUse.x); - newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y); - } - - m_lastPoint = TPointD(newX, newY); - invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2); - } else if (e.isCtrlPressed() && !e.isAltPressed() && !e.isShiftPressed()) { - invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); - nonShiftStraight = true; - double distance = (m_brushPos.x) * 0.5; - TRectD brushRect = - TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance), - TPointD(m_brushPos.x + distance, m_brushPos.y + distance)); - invalidateRect += (brushRect); - - double denominator = m_lastPoint.x - m_firstPoint.x; - if (denominator == 0) denominator == 0.001; - double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator); - double radAngle = std::atan(abs(slope)); - double angle = radAngle * (180 / 3.14159); - if (abs(angle) >= 82.5) { - // make it vertical - m_lastPoint.x = m_firstPoint.x; - } else if (abs(angle) < 7.5) { - // make it horizontal - m_lastPoint.y = m_firstPoint.y; - } else { - double xDistance = m_lastPoint.x - m_firstPoint.x; - double yDistance = m_lastPoint.y - m_firstPoint.y; - - double totalDistance = - std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2)); - double xLength = 0.0; - double yLength = 0.0; - if (angle >= 7.5 && angle < 22.5) { - yLength = std::sin(15 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(15 * (3.14159 / 180)) * totalDistance; - } else if (angle >= 22.5 && angle < 37.5) { - yLength = std::sin(30 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(30 * (3.14159 / 180)) * totalDistance; - } else if (angle >= 37.5 && angle < 52.5) { - yLength = std::sin(45 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(45 * (3.14159 / 180)) * totalDistance; - } else if (angle >= 52.5 && angle < 67.5) { - yLength = std::sin(60 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(60 * (3.14159 / 180)) * totalDistance; - } else if (angle >= 67.5 && angle < 82.5) { - yLength = std::sin(75 * (3.14159 / 180)) * totalDistance; - xLength = std::cos(75 * (3.14159 / 180)) * totalDistance; - } - - if (yDistance == abs(yDistance)) { - m_lastPoint.y = m_firstPoint.y + yLength; - } else { - m_lastPoint.y = m_firstPoint.y - yLength; - } - if (xDistance == abs(xDistance)) { - m_lastPoint.x = m_firstPoint.x + xLength; - } else { - m_lastPoint.x = m_firstPoint.x - xLength; - } + for (int i = 0; i < anglesToAssistants.size(); i++) { + double newDifference = abs(angle - anglesToAssistants.at(i)); + if (newDifference < difference || (180 - newDifference) < difference) { + difference = std::min(newDifference, (180 - newDifference)); + pointToUse = m_assistantPoints.at(i); } } - + + double distanceFirstToLast = + std::sqrt(std::pow((m_lastPoint.x - m_firstPoint.x), 2) + + std::pow((m_lastPoint.y - m_firstPoint.y), 2)); + double distanceLastToAssistant = + std::sqrt(std::pow((pointToUse.x - m_lastPoint.x), 2) + + std::pow((pointToUse.y - m_lastPoint.y), 2)); + double distanceFirstToAssistant = + std::sqrt(std::pow((pointToUse.x - m_firstPoint.x), 2) + + std::pow((pointToUse.y - m_firstPoint.y), 2)); + + if (distanceFirstToAssistant == 0.0) distanceFirstToAssistant = 0.001; + + double ratio = distanceFirstToLast / distanceFirstToAssistant; + + double newX; + double newY; + + // flip the direction if the last point is farther than the first point + if (distanceFirstToAssistant < distanceLastToAssistant && + distanceFirstToLast < distanceLastToAssistant) { + newX = ((1 + ratio) * m_firstPoint.x) - (ratio * pointToUse.x); + newY = ((1 + ratio) * m_firstPoint.y) - (ratio * pointToUse.y); + } else { + newX = ((1 - ratio) * m_firstPoint.x) + (ratio * pointToUse.x); + newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y); + } + + m_lastPoint = TPointD(newX, newY); + invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2); + } else if (e.isCtrlPressed() && !e.isAltPressed() && !e.isShiftPressed()) { + invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); + nonShiftStraight = true; + double distance = (m_brushPos.x) * 0.5; + TRectD brushRect = + TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance), + TPointD(m_brushPos.x + distance, m_brushPos.y + distance)); + invalidateRect += (brushRect); + + double denominator = m_lastPoint.x - m_firstPoint.x; + if (denominator == 0) denominator == 0.001; + double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator); + double radAngle = std::atan(abs(slope)); + double angle = radAngle * (180 / 3.14159); + if (abs(angle) >= 82.5) { + // make it vertical + m_lastPoint.x = m_firstPoint.x; + } else if (abs(angle) < 7.5) { + // make it horizontal + m_lastPoint.y = m_firstPoint.y; + } else { + double xDistance = m_lastPoint.x - m_firstPoint.x; + double yDistance = m_lastPoint.y - m_firstPoint.y; + + double totalDistance = + std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2)); + double xLength = 0.0; + double yLength = 0.0; + if (angle >= 7.5 && angle < 22.5) { + yLength = std::sin(15 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(15 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 22.5 && angle < 37.5) { + yLength = std::sin(30 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(30 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 37.5 && angle < 52.5) { + yLength = std::sin(45 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(45 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 52.5 && angle < 67.5) { + yLength = std::sin(60 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(60 * (3.14159 / 180)) * totalDistance; + } else if (angle >= 67.5 && angle < 82.5) { + yLength = std::sin(75 * (3.14159 / 180)) * totalDistance; + xLength = std::cos(75 * (3.14159 / 180)) * totalDistance; + } + + if (yDistance == abs(yDistance)) { + m_lastPoint.y = m_firstPoint.y + yLength; + } else { + m_lastPoint.y = m_firstPoint.y - yLength; + } + if (xDistance == abs(xDistance)) { + m_lastPoint.x = m_firstPoint.x + xLength; + } else { + m_lastPoint.x = m_firstPoint.x - xLength; + } + } + } m_lastDragPos = pos; m_lastDragEvent = e; @@ -962,19 +963,19 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos, m_toggleSnap = !e.isAltPressed() && e.isCtrlPressed() && e.isShiftPressed(); if (!nonShiftStraight) { - checkStrokeSnapping(false, m_toggleSnap); - checkGuideSnapping(false, m_toggleSnap); - m_brushPos = m_lastSnapPoint; - } - else { - m_brushPos = m_lastPoint; + checkStrokeSnapping(false, m_toggleSnap); + checkGuideSnapping(false, m_toggleSnap); + m_brushPos = m_lastSnapPoint; + } else { + m_brushPos = m_lastPoint; } if (m_foundLastSnap) invalidateRect += TRectD(m_lastSnapPoint - snapThick, m_lastSnapPoint + snapThick); - if ((e.isShiftPressed() && !e.isCtrlPressed() && !e.isAltPressed()) || nonShiftStraight) { + if ((e.isShiftPressed() && !e.isCtrlPressed() && !e.isAltPressed()) || + nonShiftStraight) { m_smoothStroke.clearPoints(); m_track.add(TThickPoint(m_brushPos, thickness), getPixelSize() * getPixelSize()); @@ -1014,21 +1015,24 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos, return; } - if ((e.isAltPressed() && e.isCtrlPressed() && !e.isShiftPressed()) || m_addingAssistant) { + if ((e.isAltPressed() && e.isCtrlPressed() && !e.isShiftPressed()) || + m_addingAssistant) { m_addingAssistant = false; return; } bool nonShiftStraight = false; - if ((e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) || (!e.isAltPressed() && e.isCtrlPressed() && !e.isShiftPressed())) { - nonShiftStraight = true; + if ((e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) || + (!e.isAltPressed() && e.isCtrlPressed() && !e.isShiftPressed())) { + nonShiftStraight = true; } if (m_isPath) { double error = 20.0 * getPixelSize(); TStroke *stroke; - if ((e.isShiftPressed() && !e.isCtrlPressed() && !e.isAltPressed()) || nonShiftStraight) { + if ((e.isShiftPressed() && !e.isCtrlPressed() && !e.isAltPressed()) || + nonShiftStraight) { m_track.removeMiddlePoints(); stroke = m_track.makeStroke(0); } else { @@ -1096,7 +1100,8 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos, error *= getPixelSize(); TStroke *stroke; - if ((e.isShiftPressed() && !e.isCtrlPressed() && !e.isAltPressed()) || nonShiftStraight) { + if ((e.isShiftPressed() && !e.isCtrlPressed() && !e.isAltPressed()) || + nonShiftStraight) { m_track.removeMiddlePoints(); stroke = m_track.makeStroke(0); } else { @@ -1215,7 +1220,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos, } assert(stroke); m_track.clear(); - m_toggleSnap = false; + m_toggleSnap = false; m_addingAssistant = false; } diff --git a/toonz/sources/toonz/sceneviewer.cpp b/toonz/sources/toonz/sceneviewer.cpp index 65b54df5..c88317f4 100644 --- a/toonz/sources/toonz/sceneviewer.cpp +++ b/toonz/sources/toonz/sceneviewer.cpp @@ -72,6 +72,7 @@ #include "trasterimage.h" #include "tstroke.h" #include "ttoonzimage.h" +#include "tenv.h" // Qt includes #include @@ -88,6 +89,8 @@ #include "sceneviewer.h" +TEnv::IntVar ShowPerspectiveGrids("ShowPerspectiveGrids", 1); + void drawSpline(const TAffine &viewMatrix, const TRect &clipRect, bool camera3d, double pixelSize); @@ -777,6 +780,7 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent) , m_toolDisableReason("") , m_editPreviewSubCamera(false) , m_locator(NULL) + , m_showPerspectiveGrids(ShowPerspectiveGrids) , m_isLocator(false) , m_isBusyOnTabletMove(false) { m_visualSettings.m_sceneProperties = @@ -1709,6 +1713,23 @@ void SceneViewer::drawOverlay() { // draw tool gadgets TTool *tool = app->getCurrentTool()->getTool(); TXshSimpleLevel *sl = app->getCurrentLevel()->getSimpleLevel(); + if (sl && m_showPerspectiveGrids) { + std::vector assistantPoints = + sl->getProperties()->getVanishingPoints(); + if (assistantPoints.size() > 0) { + if (tool->getToolType() & TTool::LevelTool && + !app->getCurrentObject()->isSpline() && + (tool->getName() == "T_Brush" || tool->getName() == "T_Geometric")) { + glPushMatrix(); + tglMultMatrix(getViewMatrix() * tool->getMatrix()); + glScaled(m_dpiScale.x, m_dpiScale.y, 1); + ViewerDraw::drawPerspectiveGuides( + this, (m_draw3DMode) ? m_zoomScale3D : m_viewAff[m_viewMode].det(), + assistantPoints); + glPopMatrix(); + } + } + } // Call tool->draw() even if the level is read only (i.e. to show hooks) if (tool && (tool->isEnabled() || (sl && sl->isReadOnly()))) { // tool->setViewer(this); // Moved at @@ -2156,7 +2177,7 @@ double SceneViewer::projectToZ(const TPointD &delta) { GLint viewport[4]; double modelview[16], projection[16]; glGetIntegerv(GL_VIEWPORT, viewport); - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) projection[i] = (double)m_projectionMatrix.constData()[i]; glGetDoublev(GL_MODELVIEW_MATRIX, modelview); @@ -2318,9 +2339,8 @@ void SceneViewer::zoomQt(bool forward, bool reset) { if (reset || ((m_zoomScale3D < 500 || !forward) && (m_zoomScale3D > 0.01 || forward))) { double oldZoomScale = m_zoomScale3D; - m_zoomScale3D = - reset ? 1 - : ImageUtils::getQuantizedZoomFactor(m_zoomScale3D, forward); + m_zoomScale3D = reset ? 1 : ImageUtils::getQuantizedZoomFactor( + m_zoomScale3D, forward); m_pan3D = -(m_zoomScale3D / oldZoomScale) * -m_pan3D; } @@ -2341,18 +2361,17 @@ void SceneViewer::zoomQt(bool forward, bool reset) { int i; for (i = 0; i < 2; i++) { - TAffine &viewAff = m_viewAff[i]; + TAffine &viewAff = m_viewAff[i]; if (m_isFlippedX) viewAff = viewAff * TScale(-1, 1); if (m_isFlippedX) viewAff = viewAff * TScale(1, -1); - double scale2 = std::abs(viewAff.det()); + double scale2 = std::abs(viewAff.det()); if (m_isFlippedX) viewAff = viewAff * TScale(-1, 1); if (m_isFlippedX) viewAff = viewAff * TScale(1, -1); if (reset || ((scale2 < 100000 || !forward) && (scale2 > 0.001 * 0.05 || forward))) { double oldZoomScale = sqrt(scale2) * dpiFactor; - double zoomScale = - reset ? 1 - : ImageUtils::getQuantizedZoomFactor(oldZoomScale, forward); + double zoomScale = reset ? 1 : ImageUtils::getQuantizedZoomFactor( + oldZoomScale, forward); // threshold value -0.001 is intended to absorb the error of calculation if ((oldZoomScale - zoomScaleFittingWithScreen) * @@ -2655,9 +2674,9 @@ void SceneViewer::fitToCamera() { TPointD P11 = cameraAff * cameraRect.getP11(); TPointD p0 = TPointD(std::min({P00.x, P01.x, P10.x, P11.x}), std::min({P00.y, P01.y, P10.y, P11.y})); - TPointD p1 = TPointD(std::max({P00.x, P01.x, P10.x, P11.x}), + TPointD p1 = TPointD(std::max({P00.x, P01.x, P10.x, P11.x}), std::max({P00.y, P01.y, P10.y, P11.y})); - cameraRect = TRectD(p0.x, p0.y, p1.x, p1.y); + cameraRect = TRectD(p0.x, p0.y, p1.x, p1.y); // Pan if (!is3DView()) { @@ -2700,9 +2719,9 @@ void SceneViewer::fitToCameraOutline() { TPointD P11 = cameraAff * cameraRect.getP11(); TPointD p0 = TPointD(std::min({P00.x, P01.x, P10.x, P11.x}), std::min({P00.y, P01.y, P10.y, P11.y})); - TPointD p1 = TPointD(std::max({P00.x, P01.x, P10.x, P11.x}), + TPointD p1 = TPointD(std::max({P00.x, P01.x, P10.x, P11.x}), std::max({P00.y, P01.y, P10.y, P11.y})); - cameraRect = TRectD(p0.x, p0.y, p1.x, p1.y); + cameraRect = TRectD(p0.x, p0.y, p1.x, p1.y); // Pan if (!is3DView()) { @@ -2752,8 +2771,8 @@ void SceneViewer::resetZoom() { TPointD realCenter(m_viewAff[m_viewMode].a13, m_viewAff[m_viewMode].a23); TAffine aff = getNormalZoomScale() * TRotation(realCenter, m_rotationAngle[m_viewMode]); - aff.a13 = realCenter.x; - aff.a23 = realCenter.y; + aff.a13 = realCenter.x; + aff.a23 = realCenter.y; if (m_isFlippedX) aff = aff * TScale(-1, 1); if (m_isFlippedY) aff = aff * TScale(1, -1); setViewMatrix(aff, m_viewMode); @@ -2810,17 +2829,16 @@ void SceneViewer::setActualPixelSize() { } else dpi = sl->getDpi(fid); - const double inch = Stage::inch; - TAffine tempAff = getNormalZoomScale(); - if (m_isFlippedX) tempAff = tempAff * TScale(-1, 1); - if (m_isFlippedY) tempAff = tempAff * TScale(1, -1); - TPointD tempScale = dpi; + const double inch = Stage::inch; + TAffine tempAff = getNormalZoomScale(); + if (m_isFlippedX) tempAff = tempAff * TScale(-1, 1); + if (m_isFlippedY) tempAff = tempAff * TScale(1, -1); + TPointD tempScale = dpi; if (m_isFlippedX) tempScale.x = -tempScale.x; if (m_isFlippedY) tempScale.y = -tempScale.y; for (int i = 0; i < m_viewAff.size(); ++i) - setViewMatrix(dpi == TPointD(0, 0) - ? tempAff - : TScale(tempScale.x / inch, tempScale.y / inch), + setViewMatrix(dpi == TPointD(0, 0) ? tempAff : TScale(tempScale.x / inch, + tempScale.y / inch), i); m_pos = QPoint(0, 0); @@ -3103,7 +3121,7 @@ void drawSpline(const TAffine &viewMatrix, const TRect &clipRect, bool camera3d, TStageObject *pegbar = objId != TStageObjectId::NoneId ? xsh->getStageObject(objId) : 0; - const TStroke *stroke = 0; + const TStroke *stroke = 0; if (pegbar && pegbar->getSpline()) stroke = pegbar->getSpline()->getStroke(); if (!stroke) return; @@ -3332,3 +3350,10 @@ void SceneViewer::registerContext() { TGLDisplayListsManager::instance()->attachContext(displayListId, tglContext); l_contexts.insert(tglContext); } + +//----------------------------------------------------------------------------- + +void SceneViewer::setShowPerspectiveGrids(bool show) { + m_showPerspectiveGrids = show; + ShowPerspectiveGrids = show ? 1 : 0; +} \ No newline at end of file diff --git a/toonz/sources/toonz/sceneviewer.h b/toonz/sources/toonz/sceneviewer.h index 3c8fe8f1..8fe727a1 100644 --- a/toonz/sources/toonz/sceneviewer.h +++ b/toonz/sources/toonz/sceneviewer.h @@ -167,6 +167,8 @@ class SceneViewer final : public GLWidgetForHighDpi, TRectD m_clipRect; bool m_isPicking; + bool m_showPerspectiveGrids = true; + bool m_canShowPerspectiveGrids = false; TRaster32P m_3DSideL; TRaster32P m_3DSideR; @@ -264,6 +266,9 @@ public: m_vRuler = v; m_hRuler = h; } + bool getShowPerspectiveGrids() { return m_showPerspectiveGrids; } + void setShowPerspectiveGrids(bool show); + bool getCanShowPerspectiveGrids() { return m_canShowPerspectiveGrids; } bool is3DView() const override; TDimension getViewportSize() const { return TDimension(width(), height()); } diff --git a/toonz/sources/toonz/sceneviewercontextmenu.cpp b/toonz/sources/toonz/sceneviewercontextmenu.cpp index 038d53b4..292f2acb 100644 --- a/toonz/sources/toonz/sceneviewercontextmenu.cpp +++ b/toonz/sources/toonz/sceneviewercontextmenu.cpp @@ -50,8 +50,9 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) /*- サブカメラの消去 -*/ if (parent->isEditPreviewSubcamera()) { action = addAction(tr("Reset Subcamera")); - ret = ret && parent->connect(action, SIGNAL(triggered()), - SLOT(doDeleteSubCamera())); + ret = + ret && + parent->connect(action, SIGNAL(triggered()), SLOT(doDeleteSubCamera())); addSeparator(); } @@ -68,8 +69,9 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) action = commandManager->createAction(V_ShowHideFullScreen, this, !isFullScreen); addAction(action); - ret = ret && parent->connect(action, SIGNAL(triggered()), fsWidget, - SLOT(toggleFullScreen())); + ret = ret && + parent->connect(action, SIGNAL(triggered()), fsWidget, + SLOT(toggleFullScreen())); } // swap compared @@ -127,13 +129,21 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) // actual pixel size action = commandManager->createAction(V_ActualPixelSize, this); addAction(action); - ret = ret && parent->connect(action, SIGNAL(triggered()), - SLOT(setActualPixelSize())); + ret = + ret && + parent->connect(action, SIGNAL(triggered()), SLOT(setActualPixelSize())); // onion skin if (Preferences::instance()->isOnionSkinEnabled() && !parent->isPreviewEnabled()) OnioniSkinMaskGUI::addOnionSkinCommand(this); + if (parent->getCanShowPerspectiveGrids()) { + action = new QAction(tr("Toggle Perspective Grid"), this); + connect(action, &QAction::triggered, [=]() { + parent->setShowPerspectiveGrids(!parent->getShowPerspectiveGrids()); + }); + addAction(action); + } if (tool->getTargetType() & TTool::VectorImage) { auto addOptionAction = [](const QString &label, const int data, @@ -157,9 +167,9 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) guidedDrawingMenu, guidedDrawingGroup); addOptionAction(tr("All Drawings"), 3, guidedDrawingStatus, guidedDrawingMenu, guidedDrawingGroup); - ret = - ret && parent->connect(guidedDrawingGroup, SIGNAL(triggered(QAction *)), - this, SLOT(setGuidedDrawingType(QAction *))); + ret = ret && + parent->connect(guidedDrawingGroup, SIGNAL(triggered(QAction *)), + this, SLOT(setGuidedDrawingType(QAction *))); guidedDrawingMenu->addSeparator(); bool enableOption = guidedDrawingStatus == 1 || guidedDrawingStatus == 2; @@ -167,8 +177,9 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) action->setCheckable(true); action->setChecked(Preferences::instance()->getGuidedAutoInbetween()); action->setEnabled(enableOption); - ret = ret && parent->connect(action, SIGNAL(triggered()), this, - SLOT(setGuidedAutoInbetween())); + ret = ret && + parent->connect(action, SIGNAL(triggered()), this, + SLOT(setGuidedAutoInbetween())); guidedDrawingMenu->addSeparator(); int guidedInterpolation = Preferences::instance()->getGuidedInterpolation(); QActionGroup *interpolationGroup = new QActionGroup(this); @@ -230,22 +241,25 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) action = addAction(tr("Save Previewed Frames")); action->setShortcut(QKeySequence( CommandManager::instance()->getKeyFromId(MI_SavePreviewedFrames))); - ret = ret && parent->connect(action, SIGNAL(triggered()), this, - SLOT(savePreviewedFrames())); + ret = ret && + parent->connect(action, SIGNAL(triggered()), this, + SLOT(savePreviewedFrames())); // regenerate preview action = addAction(tr("Regenerate Preview")); action->setShortcut(QKeySequence( CommandManager::instance()->getKeyFromId(MI_RegeneratePreview))); - ret = ret && parent->connect(action, SIGNAL(triggered()), - SLOT(regeneratePreview())); + ret = + ret && + parent->connect(action, SIGNAL(triggered()), SLOT(regeneratePreview())); // regenerate frame preview action = addAction(tr("Regenerate Frame Preview")); action->setShortcut(QKeySequence( CommandManager::instance()->getKeyFromId(MI_RegenerateFramePr))); - ret = ret && parent->connect(action, SIGNAL(triggered()), - SLOT(regeneratePreviewFrame())); + ret = ret && + parent->connect(action, SIGNAL(triggered()), + SLOT(regeneratePreviewFrame())); } assert(ret); @@ -299,9 +313,9 @@ void SceneViewerContextMenu::addSelectCommand(QMenu *menu, TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); TStageObject *stageObject = xsh->getStageObject(id); if (!stageObject) return; - QString text = (id.isTable()) ? tr("Table") : getName(stageObject); + QString text = (id.isTable()) ? tr("Table") : getName(stageObject); if (menu == this) text = tr("Select %1").arg(text); - QAction *action = new QAction(text, this); + QAction *action = new QAction(text, this); action->setData(id.getCode()); connect(action, SIGNAL(triggered()), this, SLOT(onSetCurrent())); menu->addAction(action); diff --git a/toonz/sources/toonz/sceneviewerevents.cpp b/toonz/sources/toonz/sceneviewerevents.cpp index c3f42612..97d0164c 100644 --- a/toonz/sources/toonz/sceneviewerevents.cpp +++ b/toonz/sources/toonz/sceneviewerevents.cpp @@ -1811,6 +1811,15 @@ void SceneViewer::onContextMenu(const QPoint &pos, const QPoint &globalPos) { i++) columnIndices.push_back(i); + TXshLevelHandle *level = TApp::instance()->getCurrentLevel(); + if (level) { + TXshSimpleLevel *sl = level->getSimpleLevel(); + if (sl) { + int vp = sl->getProperties()->getVanishingPoints().size(); + if (vp > 0) m_canShowPerspectiveGrids = true; + } + } + SceneViewerContextMenu *menu = new SceneViewerContextMenu(this); TTool *tool = TApp::instance()->getCurrentTool()->getTool(); diff --git a/toonz/sources/toonz/viewerdraw.cpp b/toonz/sources/toonz/viewerdraw.cpp index 053b8806..9d93dd3c 100644 --- a/toonz/sources/toonz/viewerdraw.cpp +++ b/toonz/sources/toonz/viewerdraw.cpp @@ -378,6 +378,100 @@ void ViewerDraw::drawGridAndGuides(SceneViewer *viewer, double sc, Ruler *vr, //----------------------------------------------------------------------------- +void ViewerDraw::drawPerspectiveGuides(SceneViewer *viewer, double sc, + std::vector assistantPoints) { + int x1, x2, y1, y2; + viewer->rect().getCoords(&x1, &y1, &x2, &y2); + TRect clipRect = TRect(x1, y1, x2 + 1, y2 + 1); + + GLfloat modelView[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, modelView); + TAffine modelViewAff(modelView[0], modelView[4], modelView[12], modelView[1], + modelView[5], modelView[13]); + + TRectD cameraRect = getCameraRect(); + + TPointD clipCorner[] = { + modelViewAff.inv() * TPointD(clipRect.x0, clipRect.y0), + modelViewAff.inv() * TPointD(clipRect.x1, clipRect.y0), + modelViewAff.inv() * TPointD(clipRect.x1, clipRect.y1), + modelViewAff.inv() * TPointD(clipRect.x0, clipRect.y1)}; + + TRectD bounds; + bounds.x0 = bounds.x1 = clipCorner[0].x; + bounds.y0 = bounds.y1 = clipCorner[0].y; + int i; + for (i = 1; i < 4; i++) { + const TPointD &p = clipCorner[i]; + if (p.x < bounds.x0) + bounds.x0 = p.x; + else if (p.x > bounds.x1) + bounds.x1 = p.x; + if (p.y < bounds.y0) + bounds.y0 = p.y; + else if (p.y > bounds.y1) + bounds.y1 = p.y; + } + + double interval = 150; // *sc; + glEnable(GL_BLEND); // Enable blending. + glEnable(GL_LINE_SMOOTH); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + std::vector reds{0.0, 0.7, 1.0, 0.0, 0.3}; + std::vector greens{0.0, 0.0, 0.0, 0.4, 0.3}; + std::vector blues{1.0, 0.7, 0.0, 0.0, 0.3}; + + for (int j = 0; j < assistantPoints.size(); j++) { + TPointD p = assistantPoints.at(j); + if (j < 5) glColor4d(reds.at(j), greens.at(j), blues.at(j), 0.2); + TPointD end; + bool useX = true; + for (double i = bounds.x0; i < bounds.x1; i += interval) { + end.y = bounds.y0; + end.x = i; + tglDrawSegment(p, end); + } + for (double i = bounds.x0; i < bounds.x1; i += interval) { + end.y = bounds.y1; + end.x = i; + tglDrawSegment(p, end); + } + for (double i = bounds.y0; i < bounds.y1; i += interval) { + end.y = i; + end.x = bounds.x0; + tglDrawSegment(p, end); + } + for (double i = bounds.y0; i < bounds.y1; i += interval) { + end.y = i; + end.x = bounds.x1; + tglDrawSegment(p, end); + } + // double distanceToLeft = std::abs(p.x - bounds.x0); + // double distanceToRight = std::abs(p.x - bounds.x1); + // double distanceToTop = std::abs(p.y - bounds.y1); + // double distanceToBottom = std::abs(p.y - bounds.y0); + // double xDistance = std::max(distanceToLeft, distanceToRight); + // double yDistance = std::max(distanceToTop, distanceToBottom); + // double totalDistance = std::sqrt(std::pow(xDistance, 2) + + // std::pow(yDistance, 2)); + // for (int i = 0; i < 360; i += 15) { + // + // //double slope = std::tan(i * (3.14159 / 180)); + // double yLength = std::sin(i * (3.14159 / 180)) * totalDistance; + // double xLength = std::cos(i * (3.14159 / 180)) * totalDistance; + // end.x = p.x + xLength; + // end.y = p.y + yLength; + // tglDrawSegment(p, end); + //} + } + + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); +} + +//----------------------------------------------------------------------------- + void ViewerDraw::drawColorcard(UCHAR channel) { ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); TRectD rect = getCameraRect(); diff --git a/toonz/sources/toonz/viewerdraw.h b/toonz/sources/toonz/viewerdraw.h index 965e4e0f..03a33a1b 100644 --- a/toonz/sources/toonz/viewerdraw.h +++ b/toonz/sources/toonz/viewerdraw.h @@ -35,6 +35,8 @@ TRectD getCameraRect(); void drawCameraMask(SceneViewer *viewer); void drawGridAndGuides(SceneViewer *viewer, double viewerScale, Ruler *vRuler, Ruler *hRuler, bool gridEnabled); +void drawPerspectiveGuides(SceneViewer *viewer, double viewerScale, + std::vector assistantPoints); void draw3DCamera(unsigned long flags, double zmin, double phi); void drawCamera(unsigned long flags, double pixelSize);