From fa61b14844da893833e27642405fdbb740a9aaa3 Mon Sep 17 00:00:00 2001 From: manongjohn Date: Wed, 3 Nov 2021 23:46:49 -0400 Subject: [PATCH] Add brush snap to Grid toolbar option --- toonz/sources/tnztools/fullcolorbrushtool.cpp | 293 +++++++------ toonz/sources/tnztools/fullcolorbrushtool.h | 4 +- toonz/sources/tnztools/tooloptions.cpp | 4 +- .../sources/tnztools/toonzrasterbrushtool.cpp | 403 +++++++++--------- toonz/sources/tnztools/toonzrasterbrushtool.h | 4 +- .../sources/tnztools/toonzvectorbrushtool.cpp | 79 ++-- toonz/sources/tnztools/toonzvectorbrushtool.h | 3 + 7 files changed, 424 insertions(+), 366 deletions(-) diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp index a55e757a..7a471712 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.cpp +++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp @@ -60,6 +60,7 @@ TEnv::DoubleVar FullcolorModifierOpacity("FullcolorModifierOpacity", 100); TEnv::IntVar FullcolorModifierEraser("FullcolorModifierEraser", 0); TEnv::IntVar FullcolorModifierLockAlpha("FullcolorModifierLockAlpha", 0); TEnv::StringVar FullcolorBrushPreset("FullcolorBrushPreset", ""); +TEnv::IntVar FullcolorBrushSnapGrid("FullcolorBrushSnapGrid", 0); //---------------------------------------------------------------------------------- @@ -135,7 +136,8 @@ FullColorBrushTool::FullColorBrushTool(std::string name) , m_tileSaver(0) , m_notifier(0) , m_presetsLoaded(false) - , m_firstTime(true) { + , m_firstTime(true) + , m_snapGrid("Grid", false) { bind(TTool::RasterImage | TTool::EmptyTarget); m_thickness.setNonLinearSlider(); @@ -148,12 +150,14 @@ FullColorBrushTool::FullColorBrushTool(std::string name) m_prop.bind(m_modifierEraser); m_prop.bind(m_modifierLockAlpha); m_prop.bind(m_pressure); + m_prop.bind(m_snapGrid); m_prop.bind(m_preset); m_preset.setId("BrushPreset"); m_modifierEraser.setId("RasterEraser"); m_modifierLockAlpha.setId("LockAlpha"); m_pressure.setId("PressureSensitivity"); + m_snapGrid.setId("SnapGrid"); m_brushTimer.start(); } @@ -192,6 +196,7 @@ void FullColorBrushTool::updateTranslation() { m_modifierOpacity.setQStringName(tr("Opacity")); m_modifierEraser.setQStringName(tr("Eraser")); m_modifierLockAlpha.setQStringName(tr("Lock Alpha")); + m_snapGrid.setQStringName(tr("Grid")); } //--------------------------------------------------------------------------------------------------- @@ -336,12 +341,16 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, } if (e.isAltPressed()) { - m_snapAssistant = true; m_isStraight = true; m_firstPoint = pos; m_lastPoint = pos; } + if (m_snapGrid.getValue()) { + m_firstPoint = pos; + m_lastPoint = pos; + } + /* update color here since the current style might be switched with numpad * shortcut keys */ updateCurrentStyle(); @@ -384,6 +393,7 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, invalidateRect += TRectD(previousBrushPos - thickOffset, previousBrushPos + thickOffset); invalidate(invalidateRect.enlarge(2.0)); + m_perspectiveIndex = -1; } //------------------------------------------------------------------------------------------------------------- @@ -391,16 +401,27 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, void FullColorBrushTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) { TRectD invalidateRect; - if (m_isStraight) { - invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); - m_lastPoint = pos; - if (e.isAltPressed()) { - double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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); + invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); + m_lastPoint = pos; + TPointD usePos = pos; + if (e.isAltPressed() || m_snapGrid.getValue()) { + double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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); + + PerspectiveTool *perspectiveTool = dynamic_cast( + TTool::getTool("T_PerspectiveGrid", TTool::RasterImage)); + std::vector perspectiveObjs = + perspectiveTool->getPerspectiveObjects(); + TPointD pointToUse = TPointD(0.0, 0.0); + TPointD dpiScale = getViewer()->getDpiScale(); + TPointD refPoint = m_firstPoint; + refPoint.x *= dpiScale.x; + refPoint.y *= dpiScale.y; + if (e.isAltPressed() || m_perspectiveIndex < 0) { // let's get info about our current location double denominator = m_lastPoint.x - m_firstPoint.x; double numerator = m_lastPoint.y - m_firstPoint.y; @@ -415,140 +436,134 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos, // now let's get the angle of each of the assistant points std::vector anglesToAssistants; - TPointD pointToUse = TPointD(0.0, 0.0); - - PerspectiveTool *perspectiveTool = dynamic_cast( - TTool::getTool("T_PerspectiveGrid", TTool::RasterImage)); - if (perspectiveTool) { - TPointD dpiScale = getViewer()->getDpiScale(); - TPointD refPoint = m_firstPoint; - refPoint.x *= dpiScale.x; - refPoint.y *= dpiScale.y; - - std::vector perspectiveObjs = - perspectiveTool->getPerspectiveObjects(); - for (auto data : perspectiveObjs) { - TPointD point = data->getReferencePoint(refPoint); - point.x /= dpiScale.x; - point.y /= dpiScale.y; - 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); + for (auto data : perspectiveObjs) { + TPointD point = data->getReferencePoint(refPoint); + point.x /= dpiScale.x; + point.y /= dpiScale.y; + 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; } - // figure out which angle is closer - double difference = 360; - - 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 = perspectiveObjs.at(i)->getReferencePoint(refPoint); - pointToUse.x /= dpiScale.x; - pointToUse.y /= dpiScale.y; - } - } + double newSlope = (newNumerator / newDenominator); + double newAngle = std::atan(newSlope) * (180 / 3.14159); + anglesToAssistants.push_back(newAngle); } - 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)); + // figure out which angle is closer + double difference = 360; - 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()) { - double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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) - 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 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 = perspectiveObjs.at(i)->getReferencePoint(refPoint); + pointToUse.x /= dpiScale.x; + pointToUse.y /= dpiScale.y; + m_perspectiveIndex = i; } } + } else { + pointToUse = + perspectiveObjs.at(m_perspectiveIndex)->getReferencePoint(refPoint); + pointToUse.x /= dpiScale.x; + pointToUse.y /= dpiScale.y; } - // keep this here for possible eventual variable width - // if (getApplication()->getCurrentLevelStyle()->getTagId() == - // 4001) // mypaint brush case - // m_oldPressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; - // else - // m_oldPressure = m_enabledPressure ? e.m_pressure : 1.0; + 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); + } + + usePos = m_lastPoint = TPointD(newX, newY); + invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2); + } else if (e.isCtrlPressed()) { + double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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) + 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 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; + } + } + } + + // keep this here for possible eventual variable width + // if (getApplication()->getCurrentLevelStyle()->getTagId() == + // 4001) // mypaint brush case + // m_oldPressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + // else + // m_oldPressure = m_enabledPressure ? e.m_pressure : 1.0; + + if (m_isStraight) { m_mousePos = pos; m_brushPos = pos; invalidate(invalidateRect); @@ -565,7 +580,7 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos, TRasterP ras = ri->getRaster(); TPointD rasCenter = ras->getCenterD(); - TPointD point(pos + rasCenter); + TPointD point(usePos + rasCenter); double pressure; if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case @@ -602,7 +617,7 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos, TRasterP ras = ri->getRaster(); TPointD rasCenter = ras->getCenterD(); TPointD point; - if (e.isCtrlPressed() || m_snapAssistant || e.isAltPressed()) + if (e.isCtrlPressed() || m_snapGrid.getValue() || e.isAltPressed()) point = TPointD(m_lastPoint + rasCenter); else point = TPointD(pos + rasCenter); @@ -655,8 +670,8 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos, m_strokeRect.empty(); m_mousePressed = false; m_isStraight = false; - m_snapAssistant = false; m_oldPressure = -1.0; + m_perspectiveIndex = -1; } //--------------------------------------------------------------------------------------------------------------- @@ -838,6 +853,7 @@ bool FullColorBrushTool::onPropertyChanged(std::string propertyName) { FullcolorModifierOpacity = m_modifierOpacity.getValue(); FullcolorModifierEraser = m_modifierEraser.getValue() ? 1 : 0; FullcolorModifierLockAlpha = m_modifierLockAlpha.getValue() ? 1 : 0; + FullcolorBrushSnapGrid = m_snapGrid.getValue() ? 1 : 0; if (m_preset.getValue() != CUSTOM_WSTR) { m_preset.setValue(CUSTOM_WSTR); @@ -952,6 +968,7 @@ void FullColorBrushTool::loadLastBrush() { m_modifierOpacity.setValue(FullcolorModifierOpacity); m_modifierEraser.setValue(FullcolorModifierEraser ? true : false); m_modifierLockAlpha.setValue(FullcolorModifierLockAlpha ? true : false); + m_snapGrid.setValue(FullcolorBrushSnapGrid ? true : false); } //------------------------------------------------------------------ diff --git a/toonz/sources/tnztools/fullcolorbrushtool.h b/toonz/sources/tnztools/fullcolorbrushtool.h index 2473ae18..839acd8a 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.h +++ b/toonz/sources/tnztools/fullcolorbrushtool.h @@ -95,6 +95,7 @@ protected: TBoolProperty m_modifierEraser; TBoolProperty m_modifierLockAlpha; TEnumProperty m_preset; + TBoolProperty m_snapGrid; TPixel32 m_currentColor; bool m_enabledPressure; @@ -126,10 +127,11 @@ protected: bool m_isStraight = false; TPointD m_firstPoint; TPointD m_lastPoint; - bool m_snapAssistant = false; double m_oldPressure = -1.0; bool m_propertyUpdating = false; + + int m_perspectiveIndex = -1; }; //------------------------------------------------------------ diff --git a/toonz/sources/tnztools/tooloptions.cpp b/toonz/sources/tnztools/tooloptions.cpp index 4ac49c99..e78c69f7 100644 --- a/toonz/sources/tnztools/tooloptions.cpp +++ b/toonz/sources/tnztools/tooloptions.cpp @@ -2114,7 +2114,7 @@ void BrushToolOptionsBox::filterControls() { it != m_labels.end(); it++) { bool isModifier = (it.key().substr(0, 8) == "Modifier"); bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" || - it.key() == "Preset:"); + it.key() == "Preset:" || it.key() == "Grid"); bool visible = isCommon || (isModifier == showModifiers); it.value()->setVisible(visible); } @@ -2123,7 +2123,7 @@ void BrushToolOptionsBox::filterControls() { it != m_controls.end(); it++) { bool isModifier = (it.key().substr(0, 8) == "Modifier"); bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" || - it.key() == "Preset:"); + it.key() == "Preset:" || it.key() == "Grid"); bool visible = isCommon || (isModifier == showModifiers); if (QWidget *widget = dynamic_cast(it.value())) widget->setVisible(visible); diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.cpp b/toonz/sources/tnztools/toonzrasterbrushtool.cpp index f07d00a6..9d9316e2 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.cpp +++ b/toonz/sources/tnztools/toonzrasterbrushtool.cpp @@ -61,6 +61,7 @@ TEnv::DoubleVar RasterBrushHardness("RasterBrushHardness", 100); TEnv::DoubleVar RasterBrushModifierSize("RasterBrushModifierSize", 0); TEnv::StringVar RasterBrushPreset("RasterBrushPreset", ""); TEnv::IntVar BrushLockAlpha("InknpaintBrushLockAlpha", 0); +TEnv::IntVar BrushSnapGrid("InknpaintBrushSnapGrid", 0); //------------------------------------------------------------------- #define CUSTOM_WSTR L"" @@ -890,7 +891,8 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) , m_targetType(targetType) , m_workingFrameId(TFrameId()) , m_notifier(0) - , m_modifierLockAlpha("Lock Alpha", false) { + , m_modifierLockAlpha("Lock Alpha", false) + , m_snapGrid("Grid", false) { bind(targetType); m_rasThickness.setNonLinearSlider(); @@ -911,6 +913,9 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) m_prop[0].bind(m_pressure); + m_prop[0].bind(m_snapGrid); + m_snapGrid.setId("SnapGrid"); + m_prop[0].bind(m_preset); m_preset.setId("BrushPreset"); m_preset.addValue(CUSTOM_WSTR); @@ -1110,6 +1115,7 @@ void ToonzRasterBrushTool::updateTranslation() { m_pencil.setQStringName(tr("Pencil")); m_pressure.setQStringName(tr("Pressure")); m_modifierLockAlpha.setQStringName(tr("Lock Alpha")); + m_snapGrid.setQStringName(tr("Grid")); } //--------------------------------------------------------------------------------------------------- @@ -1301,12 +1307,16 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, } if (e.isAltPressed()) { - m_snapAssistant = true; m_isStraight = true; m_firstPoint = pos; m_lastPoint = pos; } + if (m_snapGrid.getValue()) { + m_firstPoint = pos; + m_lastPoint = pos; + } + // assert(0<=m_styleId && m_styleId<2); TImageP img = getImage(true); TToonzImageP ri(img); @@ -1442,6 +1452,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, // updating m_brushPos is needed to refresh viewer properly m_mousePos = pos; m_brushPos = getCenteredCursorPos(pos); + m_perspectiveIndex = -1; } //------------------------------------------------------------------------------------------------------------- @@ -1455,16 +1466,27 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos, } TRectD invalidateRect; - if (m_isStraight) { - invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); - m_lastPoint = pos; - if (e.isAltPressed()) { - double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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); + invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); + m_lastPoint = pos; + TPointD usePos = pos; + if (e.isAltPressed() || m_snapGrid.getValue()) { + double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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); + + PerspectiveTool *perspectiveTool = dynamic_cast( + TTool::getTool("T_PerspectiveGrid", TTool::ToonzImage)); + std::vector perspectiveObjs = + perspectiveTool->getPerspectiveObjects(); + TPointD pointToUse = TPointD(0.0, 0.0); + TPointD dpiScale = getViewer()->getDpiScale(); + TPointD refPoint = m_firstPoint; + refPoint.x *= dpiScale.x; + refPoint.y *= dpiScale.y; + if (e.isAltPressed() || m_perspectiveIndex < 0) { // let's get info about our current location double denominator = m_lastPoint.x - m_firstPoint.x; double numerator = m_lastPoint.y - m_firstPoint.y; @@ -1479,210 +1501,201 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos, // now let's get the angle of each of the assistant points std::vector anglesToAssistants; - TPointD pointToUse = TPointD(0.0, 0.0); - PerspectiveTool *perspectiveTool = dynamic_cast( - TTool::getTool("T_PerspectiveGrid", TTool::ToonzImage)); - if (perspectiveTool) { - TPointD dpiScale = getViewer()->getDpiScale(); - TPointD refPoint = m_firstPoint; - refPoint.x *= dpiScale.x; - refPoint.y *= dpiScale.y; - - std::vector perspectiveObjs = - perspectiveTool->getPerspectiveObjects(); - for (auto data : perspectiveObjs) { - TPointD point = data->getReferencePoint(refPoint); - point.x /= dpiScale.x; - point.y /= dpiScale.y; - 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); + for (auto data : perspectiveObjs) { + TPointD point = data->getReferencePoint(refPoint); + point.x /= dpiScale.x; + point.y /= dpiScale.y; + 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; } - // figure out which angle is closer - double difference = 360; - - 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 = perspectiveObjs.at(i)->getReferencePoint(refPoint); - pointToUse.x /= dpiScale.x; - pointToUse.y /= dpiScale.y; - } - } + double newSlope = (newNumerator / newDenominator); + double newAngle = std::atan(newSlope) * (180 / 3.14159); + anglesToAssistants.push_back(newAngle); } - 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)); + // figure out which angle is closer + double difference = 360; - 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()) { - double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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 = perspectiveObjs.at(i)->getReferencePoint(refPoint); + pointToUse.x /= dpiScale.x; + pointToUse.y /= dpiScale.y; + m_perspectiveIndex = i; } } + } else { + pointToUse = + perspectiveObjs.at(m_perspectiveIndex)->getReferencePoint(refPoint); + pointToUse.x /= dpiScale.x; + pointToUse.y /= dpiScale.y; } - int maxThickness = m_rasThickness.getValue().second; - double thickness = (m_pressure.getValue()) - ? computeThickness(e.m_pressure, m_rasThickness) * 2 - : maxThickness; - // if (m_dragCount < 3 && !m_isMyPaintStyleSelected && thickness > 0.0) { - // if (m_hardness.getValue() == 100 || m_pencil.getValue()) { - // std::vector sequence = - // m_rasterTrack->getPointsSequence(); - // if (sequence.size() > 0) sequence[0].thick = thickness; - // m_rasterTrack->setPointsSequence(sequence); - // } else if (m_points.size() > 0) { - // m_points[0].thick == thickness; - // // below is code to allow variable thickess - // // but it causes artifacting at the start of the stroke. - // TToonzImageP ti = TImageP(getImage(true)); - // TPointD rasCenter = ti->getRaster()->getCenterD(); - // TThickPoint point(getCenteredCursorPos(m_firstPoint) + rasCenter, - // thickness); - // m_points.push_back(point); - // m_bluredBrush->addPoint(point, 1); - // DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex(); + 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)); - // TImageP img = getImage(true); - // TToonzImageP ri(img); - // m_strokeRect = m_bluredBrush->getBoundFromPoints(m_points); - // updateWorkAndBackupRasters(m_strokeRect); - // m_tileSaver->save(m_strokeRect); - // m_bluredBrush->updateDrawing(ri->getRaster(), m_backupRas, - // m_strokeRect, - // m_styleId, drawOrder); - // m_points.erase(m_points.begin()); - // } - //} + if (distanceFirstToAssistant == 0.0) distanceFirstToAssistant = 0.001; - // if (m_dragCount < 3 && m_isMyPaintStyleSelected) { - // TToonzImageP ti = TImageP(getImage(true)); - // TRasterP ras = ti->getRaster(); - // TPointD rasCenter = ti->getRaster()->getCenterD(); - // TPointD point(getCenteredCursorPos(m_firstPoint) + rasCenter); - // double pressure = - // m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; + double ratio = distanceFirstToLast / distanceFirstToAssistant; - // m_strokeSegmentRect.empty(); - // m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); - // TRect updateRect = m_strokeSegmentRect * ras->getBounds(); - // if (!updateRect.isEmpty()) { - // m_toonz_brush->updateDrawing(ras, m_backupRas, m_strokeSegmentRect, - // m_styleId); - // } - // m_lastRect = m_strokeRect; + double newX; + double newY; - // TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5); - // invalidateRect = convert(m_strokeSegmentRect) - rasCenter; - // invalidateRect += - // TRectD(getCenteredCursorPos(m_firstPoint) - thickOffset, - // getCenteredCursorPos(m_firstPoint) + thickOffset); - // invalidateRect += - // TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset); - //} + // 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_oldThickness = thickness; - // double pressure = - // m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; - // m_oldPressure = pressure; + usePos = m_lastPoint = TPointD(newX, newY); + invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2); + } else if (e.isCtrlPressed()) { + double distance = (m_brushPos.x - m_maxCursorThick + 1) * 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); - // m_dragCount++; + 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; + } + } + } + + // if (m_dragCount < 3 && !m_isMyPaintStyleSelected && thickness > 0.0) { + // if (m_hardness.getValue() == 100 || m_pencil.getValue()) { + // std::vector sequence = + // m_rasterTrack->getPointsSequence(); + // if (sequence.size() > 0) sequence[0].thick = thickness; + // m_rasterTrack->setPointsSequence(sequence); + // } else if (m_points.size() > 0) { + // m_points[0].thick == thickness; + // // below is code to allow variable thickess + // // but it causes artifacting at the start of the stroke. + // TToonzImageP ti = TImageP(getImage(true)); + // TPointD rasCenter = ti->getRaster()->getCenterD(); + // TThickPoint point(getCenteredCursorPos(m_firstPoint) + rasCenter, + // thickness); + // m_points.push_back(point); + // m_bluredBrush->addPoint(point, 1); + // DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex(); + + // TImageP img = getImage(true); + // TToonzImageP ri(img); + // m_strokeRect = m_bluredBrush->getBoundFromPoints(m_points); + // updateWorkAndBackupRasters(m_strokeRect); + // m_tileSaver->save(m_strokeRect); + // m_bluredBrush->updateDrawing(ri->getRaster(), m_backupRas, + // m_strokeRect, + // m_styleId, drawOrder); + // m_points.erase(m_points.begin()); + // } + //} + + // if (m_dragCount < 3 && m_isMyPaintStyleSelected) { + // TToonzImageP ti = TImageP(getImage(true)); + // TRasterP ras = ti->getRaster(); + // TPointD rasCenter = ti->getRaster()->getCenterD(); + // TPointD point(getCenteredCursorPos(m_firstPoint) + rasCenter); + // double pressure = + // m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; + + // m_strokeSegmentRect.empty(); + // m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); + // TRect updateRect = m_strokeSegmentRect * ras->getBounds(); + // if (!updateRect.isEmpty()) { + // m_toonz_brush->updateDrawing(ras, m_backupRas, m_strokeSegmentRect, + // m_styleId); + // } + // m_lastRect = m_strokeRect; + + // TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5); + // invalidateRect = convert(m_strokeSegmentRect) - rasCenter; + // invalidateRect += + // TRectD(getCenteredCursorPos(m_firstPoint) - thickOffset, + // getCenteredCursorPos(m_firstPoint) + thickOffset); + // invalidateRect += + // TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset); + //} + + // m_oldThickness = thickness; + // double pressure = + // m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; + // m_oldPressure = pressure; + + // m_dragCount++; + + if (m_isStraight) { m_mousePos = pos; m_brushPos = getCenteredCursorPos(pos); invalidate(invalidateRect); return; } - TPointD centeredPos = getCenteredCursorPos(pos); + TPointD centeredPos = getCenteredCursorPos(usePos); TToonzImageP ti = TImageP(getImage(true)); TPointD rasCenter = ti->getRaster()->getCenterD(); @@ -1819,7 +1832,7 @@ void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos, return; } TPointD centeredPos = getCenteredCursorPos(pos); - if (e.isCtrlPressed() || m_snapAssistant || e.isAltPressed()) + if (e.isCtrlPressed() || m_snapGrid.getValue() || e.isAltPressed()) centeredPos = getCenteredCursorPos(m_lastPoint); double pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; // if (!e.isTablet()) m_oldThickness = -1.0; @@ -1828,6 +1841,7 @@ void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos, finishRasterBrush(centeredPos, pressure); int tc = ToonzCheck::instance()->getChecks(); if (tc & ToonzCheck::eGap || tc & ToonzCheck::eAutoclose) invalidate(); + m_perspectiveIndex = -1; } //--------------------------------------------------------------------------------------------------------------- @@ -2069,7 +2083,6 @@ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, } delete m_tileSaver; m_isStraight = false; - m_snapAssistant = false; m_oldPressure = -1.0; // m_oldThickness = -1.0; // m_dragCount = 0; @@ -2321,6 +2334,7 @@ bool ToonzRasterBrushTool::onPropertyChanged(std::string propertyName) { RasterBrushHardness = m_hardness.getValue(); RasterBrushModifierSize = m_modifierSize.getValue(); BrushLockAlpha = m_modifierLockAlpha.getValue(); + BrushSnapGrid = m_snapGrid.getValue(); // Recalculate/reset based on changed settings if (propertyName == m_rasThickness.getName()) { @@ -2459,6 +2473,7 @@ void ToonzRasterBrushTool::loadLastBrush() { m_smooth.setValue(BrushSmooth); m_modifierSize.setValue(RasterBrushModifierSize); m_modifierLockAlpha.setValue(BrushLockAlpha ? 1 : 0); + m_snapGrid.setValue(BrushSnapGrid ? 1 : 0); // Recalculate based on prior values m_minThick = m_rasThickness.getValue().first; diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.h b/toonz/sources/tnztools/toonzrasterbrushtool.h index faa5d932..4937aeb0 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.h +++ b/toonz/sources/tnztools/toonzrasterbrushtool.h @@ -183,6 +183,7 @@ protected: TBoolProperty m_pressure; TDoubleProperty m_modifierSize; TBoolProperty m_modifierLockAlpha; + TBoolProperty m_snapGrid; RasterStrokeGenerator *m_rasterTrack; TTileSetCM32 *m_tileSet; @@ -230,13 +231,14 @@ protected: bool m_propertyUpdating = false; bool m_isStraight = false; - bool m_snapAssistant = false; TPointD m_firstPoint; TPointD m_lastPoint; double m_oldPressure = -1.0; // double m_oldThickness = -1.0; // int m_dragCount = 0; + int m_perspectiveIndex = -1; + protected: static void drawLine(const TPointD &point, const TPointD ¢re, bool horizontal, bool isDecimal); diff --git a/toonz/sources/tnztools/toonzvectorbrushtool.cpp b/toonz/sources/tnztools/toonzvectorbrushtool.cpp index 6e2b6448..cd1c345b 100644 --- a/toonz/sources/tnztools/toonzvectorbrushtool.cpp +++ b/toonz/sources/tnztools/toonzvectorbrushtool.cpp @@ -71,6 +71,7 @@ TEnv::IntVar V_VectorBrushAutoClose("VectorBrushAutoClose", 0); TEnv::IntVar V_VectorBrushAutoFill("VectorBrushAutoFill", 0); TEnv::IntVar V_VectorBrushAutoGroup("VectorBrushAutoGroup", 0); TEnv::StringVar V_VectorBrushPreset("VectorBrushPreset", ""); +TEnv::IntVar V_VectorBrushSnapGrid("VectorBrushSnapGrid", 0); //------------------------------------------------------------------- @@ -535,7 +536,8 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType) , m_autoGroup("Auto Group", false) , m_autoFill("Auto Fill", false) , m_targetType(targetType) - , m_workingFrameId(TFrameId()) { + , m_workingFrameId(TFrameId()) + , m_snapGrid("Grid", false) { bind(targetType); m_thickness.setNonLinearSlider(); @@ -572,6 +574,8 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType) m_snapSensitivity.addValue(MEDIUM_WSTR); m_snapSensitivity.addValue(HIGH_WSTR); + m_prop[0].bind(m_snapGrid); + m_prop[0].bind(m_preset); m_preset.addValue(CUSTOM_WSTR); @@ -597,6 +601,7 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType) m_capStyle.setId("Cap"); m_joinStyle.setId("Join"); m_miterJoinLimit.setId("Miter"); + m_snapGrid.setId("SnapGrid"); } //------------------------------------------------------------------------------------------------------- @@ -777,6 +782,7 @@ void ToonzVectorBrushTool::leftButtonDown(const TPointD &pos, // updating m_brushPos is needed to refresh viewer properly m_brushPos = m_mousePos = pos; + m_perspectiveIndex = -1; } //------------------------------------------------------------------------------------------------------------- @@ -792,42 +798,44 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos, m_lastPoint = pos; bool nonShiftStraight = false; + TPointD usePos = pos; + if (!m_isPath && - (e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed())) { + ((e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) || + m_snapGrid.getValue())) { invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); - nonShiftStraight = true; + if (!m_snapGrid.getValue()) 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; - } - 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; - TPointD pointToUse = TPointD(0.0, 0.0); - PerspectiveTool *perspectiveTool = dynamic_cast( TTool::getTool("T_PerspectiveGrid", TTool::VectorImage)); - if (perspectiveTool) { - TPointD dpiScale = getViewer()->getDpiScale(); - TPointD refPoint = m_firstPoint; - refPoint.x *= dpiScale.x; - refPoint.y *= dpiScale.y; + std::vector perspectiveObjs = + perspectiveTool->getPerspectiveObjects(); + TPointD pointToUse = TPointD(0.0, 0.0); + TPointD dpiScale = getViewer()->getDpiScale(); + TPointD refPoint = m_firstPoint; + refPoint.x *= dpiScale.x; + refPoint.y *= dpiScale.y; + if ((e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) || + m_perspectiveIndex < 0) { + // 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); - std::vector perspectiveObjs = - perspectiveTool->getPerspectiveObjects(); + // now let's get the angle of each of the assistant points + std::vector anglesToAssistants; for (auto data : perspectiveObjs) { TPointD point = data->getReferencePoint(refPoint); point.x /= dpiScale.x; @@ -856,8 +864,14 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos, pointToUse = perspectiveObjs.at(i)->getReferencePoint(refPoint); pointToUse.x /= dpiScale.x; pointToUse.y /= dpiScale.y; + m_perspectiveIndex = i; } } + } else { + pointToUse = + perspectiveObjs.at(m_perspectiveIndex)->getReferencePoint(refPoint); + pointToUse.x /= dpiScale.x; + pointToUse.y /= dpiScale.y; } double distanceFirstToLast = @@ -887,7 +901,7 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos, newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y); } - m_lastPoint = TPointD(newX, newY); + usePos = 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); @@ -947,7 +961,7 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos, } } - m_lastDragPos = pos; + m_lastDragPos = usePos; m_lastDragEvent = e; double thickness = (m_pressure.getValue() || m_isPath) @@ -994,7 +1008,8 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos, m_track.removeMiddlePoints(); invalidateRect += m_track.getModifiedRegion(); } else if (m_dragDraw) { - addTrackPoint(TThickPoint(pos, thickness), getPixelSize() * getPixelSize()); + addTrackPoint(TThickPoint(usePos, thickness), + getPixelSize() * getPixelSize()); invalidateRect += m_track.getLastModifiedRegion(); } @@ -1076,6 +1091,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos, notifyImageChanged(); TUndoManager::manager()->add(undo); + m_perspectiveIndex = -1; return; } @@ -1083,7 +1099,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos, if (m_track.isEmpty()) { m_styleId = 0; m_track.clear(); - + m_perspectiveIndex = -1; return; } @@ -1237,6 +1253,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos, assert(stroke); m_track.clear(); m_toggleSnap = false; + m_perspectiveIndex = -1; } //-------------------------------------------------------------------------------------------------- @@ -1891,6 +1908,7 @@ bool ToonzVectorBrushTool::onPropertyChanged(std::string propertyName) { V_VectorBrushSnap = m_snap.getValue(); int snapSensitivityIndex = m_snapSensitivity.getIndex(); V_VectorBrushSnapSensitivity = snapSensitivityIndex; + V_VectorBrushSnapGrid = m_snapGrid.getValue(); // Recalculate/reset based on changed settings m_minThick = m_thickness.getValue().first; @@ -2067,6 +2085,7 @@ void ToonzVectorBrushTool::loadLastBrush() { m_autoGroup.setValue(V_VectorBrushAutoGroup); m_autoClose.setValue(V_VectorBrushAutoClose); m_autoFill.setValue(V_VectorBrushAutoFill); + m_snapGrid.setValue(V_VectorBrushSnapGrid); // Recalculate based on prior values m_minThick = m_thickness.getValue().first; diff --git a/toonz/sources/tnztools/toonzvectorbrushtool.h b/toonz/sources/tnztools/toonzvectorbrushtool.h index e76571d6..8d7d9eed 100644 --- a/toonz/sources/tnztools/toonzvectorbrushtool.h +++ b/toonz/sources/tnztools/toonzvectorbrushtool.h @@ -163,6 +163,7 @@ protected: TEnumProperty m_capStyle; TEnumProperty m_joinStyle; TIntProperty m_miterJoinLimit; + TBoolProperty m_snapGrid; StrokeGenerator m_track; StrokeGenerator m_rangeTrack; @@ -215,6 +216,8 @@ protected: TPointD m_firstPoint; TPointD m_lastPoint; + + int m_perspectiveIndex = -1; }; #endif // TOONZVECTORBRUSHTOOL_H