Auto close and auto fill options for vector brush (#197)

* Auto close and auto fill for vector brush

* Fix undo

* Make frame range work

* Fix visual glitch

* Fix crash

* Add auto group to vector brush
This commit is contained in:
Jeremy Bullock 2020-09-25 22:55:33 -06:00 committed by GitHub
parent f90b1577b8
commit 80fcee15eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 159 additions and 27 deletions

View file

@ -164,6 +164,7 @@ int TVectorImage::addStroke(TStroke *stroke, bool discardPoints,
while ( while (
m_imp->m_insideGroup.isParentOf(m_imp->m_strokes[k]->m_groupId)) { m_imp->m_insideGroup.isParentOf(m_imp->m_strokes[k]->m_groupId)) {
k--; k--;
if (k < 0) break;
} }
m_imp->insertStrokeAt( m_imp->insertStrokeAt(
new VIStroke(stroke, m_imp->m_strokes[i]->m_groupId), k + 1); new VIStroke(stroke, m_imp->m_strokes[i]->m_groupId), k + 1);

View file

@ -530,7 +530,8 @@ class BrushToolOptionsBox final : public ToolOptionsBox {
ToolOptionPopupButton *m_joinStyleCombo; ToolOptionPopupButton *m_joinStyleCombo;
ToolOptionIntSlider *m_miterField; ToolOptionIntSlider *m_miterField;
ToolOptionCombo *m_presetCombo; ToolOptionCombo *m_presetCombo;
ToolOptionCheckbox *m_snapCheckbox, *m_drawOrderCheckbox; ToolOptionCheckbox *m_snapCheckbox, *m_drawOrderCheckbox,
*m_autoCloseCheckbox, *m_autoGroupCheckbox, *m_autoFillCheckbox;
ToolOptionCombo *m_snapSensitivityCombo; ToolOptionCombo *m_snapSensitivityCombo;
QPushButton *m_addPresetButton; QPushButton *m_addPresetButton;
QPushButton *m_removePresetButton; QPushButton *m_removePresetButton;

View file

@ -1894,6 +1894,12 @@ BrushToolOptionsBox::BrushToolOptionsBox(QWidget *parent, TTool *tool,
if (tool && tool->getProperties(1)) tool->getProperties(1)->accept(builder); if (tool && tool->getProperties(1)) tool->getProperties(1)->accept(builder);
m_drawOrderCheckbox = m_drawOrderCheckbox =
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Draw Under")); dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Draw Under"));
m_autoCloseCheckbox =
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Auto Close"));
m_autoGroupCheckbox =
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Auto Group"));
m_autoFillCheckbox =
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Auto Fill"));
m_snapCheckbox = m_snapCheckbox =
dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Snap")); dynamic_cast<ToolOptionCheckbox *>(m_controls.value("Snap"));
m_snapSensitivityCombo = m_snapSensitivityCombo =

View file

@ -1119,11 +1119,12 @@ void ToolUtils::UndoPencil::redo() const {
QMutexLocker sl(image->getMutex()); QMutexLocker sl(image->getMutex());
TStroke *stroke = new TStroke(*m_stroke); TStroke *stroke = new TStroke(*m_stroke);
stroke->setId(m_strokeId); stroke->setId(m_strokeId);
image->addStroke(stroke, true, m_sendToBack); int addedStrokeIndex = image->addStroke(stroke, true, m_sendToBack);
if (image->isComputedRegionAlmostOnce()) image->findRegions(); if (image->isComputedRegionAlmostOnce()) image->findRegions();
if (m_autogroup && stroke->isSelfLoop()) { if (m_autogroup && stroke->isSelfLoop()) {
int index = image->getStrokeCount() - 1; int index = image->getStrokeCount() - 1;
if (m_sendToBack) index = addedStrokeIndex;
image->group(index, 1); image->group(index, 1);
if (m_autofill) { if (m_autofill) {
// to avoid filling other strokes, I enter into the new stroke group // to avoid filling other strokes, I enter into the new stroke group

View file

@ -63,6 +63,9 @@ TEnv::IntVar V_VectorBrushFrameRange("VectorBrushFrameRange", 0);
TEnv::IntVar V_VectorBrushSnap("VectorBrushSnap", 0); TEnv::IntVar V_VectorBrushSnap("VectorBrushSnap", 0);
TEnv::IntVar V_VectorBrushSnapSensitivity("VectorBrushSnapSensitivity", 0); TEnv::IntVar V_VectorBrushSnapSensitivity("VectorBrushSnapSensitivity", 0);
TEnv::IntVar V_VectorBrushDrawBehind("VectorBrushDrawBehind", 0); TEnv::IntVar V_VectorBrushDrawBehind("VectorBrushDrawBehind", 0);
TEnv::IntVar V_VectorBrushAutoClose("VectorBrushAutoClose", 0);
TEnv::IntVar V_VectorBrushAutoFill("VectorBrushAutoFill", 0);
TEnv::IntVar V_VectorBrushAutoGroup("VectorBrushAutoGroup", 0);
TEnv::StringVar V_VectorBrushPreset("VectorBrushPreset", "<custom>"); TEnv::StringVar V_VectorBrushPreset("VectorBrushPreset", "<custom>");
//------------------------------------------------------------------- //-------------------------------------------------------------------
@ -370,6 +373,7 @@ static void addStroke(TTool::Application *application, const TVectorImageP &vi,
} }
TFrameId id = application->getCurrentTool()->getTool()->getCurrentFid(); TFrameId id = application->getCurrentTool()->getTool()->getCurrentFid();
if (id == TFrameId::NO_FRAME && fid != TFrameId::NO_FRAME) id = fid; if (id == TFrameId::NO_FRAME && fid != TFrameId::NO_FRAME) id = fid;
int addedStrokeIndex = -1;
if (!corners.empty()) { if (!corners.empty()) {
if (breakAngles) if (breakAngles)
split(stroke, corners, strokes); split(stroke, corners, strokes);
@ -384,8 +388,8 @@ static void addStroke(TTool::Application *application, const TVectorImageP &vi,
new std::vector<TFilledRegionInf>; new std::vector<TFilledRegionInf>;
ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation, ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation,
stroke->getBBox()); stroke->getBBox());
TStroke *str = new TStroke(*strokes[i]); TStroke *str = new TStroke(*strokes[i]);
vi->addStroke(str, true, sendToBack); addedStrokeIndex = vi->addStroke(str, true, sendToBack);
TUndoManager::manager()->add( TUndoManager::manager()->add(
new UndoPencil(str, fillInformation, sl, id, frameCreated, new UndoPencil(str, fillInformation, sl, id, frameCreated,
levelCreated, autoGroup, autoFill, sendToBack)); levelCreated, autoGroup, autoFill, sendToBack));
@ -396,15 +400,16 @@ static void addStroke(TTool::Application *application, const TVectorImageP &vi,
new std::vector<TFilledRegionInf>; new std::vector<TFilledRegionInf>;
ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation, ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation,
stroke->getBBox()); stroke->getBBox());
TStroke *str = new TStroke(*stroke); TStroke *str = new TStroke(*stroke);
vi->addStroke(str, true, sendToBack); addedStrokeIndex = vi->addStroke(str, true, sendToBack);
TUndoManager::manager()->add( TUndoManager::manager()->add(
new UndoPencil(str, fillInformation, sl, id, frameCreated, levelCreated, new UndoPencil(str, fillInformation, sl, id, frameCreated, levelCreated,
autoGroup, autoFill, sendToBack)); autoGroup, autoFill, sendToBack));
} }
if (autoGroup && stroke->isSelfLoop()) { if (autoGroup && stroke->isSelfLoop()) {
int index = vi->getStrokeCount() - 1; int index = vi->getStrokeCount() - 1;
if (sendToBack) index = addedStrokeIndex;
vi->group(index, 1); vi->group(index, 1);
if (autoFill) { if (autoFill) {
// to avoid filling other strokes, I enter into the new stroke group // to avoid filling other strokes, I enter into the new stroke group
@ -522,6 +527,9 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
, m_snap("Snap", false) , m_snap("Snap", false)
, m_snapSensitivity("Sensitivity:") , m_snapSensitivity("Sensitivity:")
, m_sendToBack("Draw Under", false) , m_sendToBack("Draw Under", false)
, m_autoClose("Auto Close", false)
, m_autoGroup("Auto Group", false)
, m_autoFill("Auto Fill", false)
, m_targetType(targetType) , m_targetType(targetType)
, m_workingFrameId(TFrameId()) { , m_workingFrameId(TFrameId()) {
bind(targetType); bind(targetType);
@ -534,6 +542,15 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
m_prop[0].bind(m_breakAngles); m_prop[0].bind(m_breakAngles);
m_prop[0].bind(m_pressure); m_prop[0].bind(m_pressure);
m_prop[0].bind(m_autoClose);
m_autoClose.setId("AutoClose");
m_prop[0].bind(m_autoGroup);
m_autoGroup.setId("AutoGroup");
m_prop[0].bind(m_autoFill);
m_autoFill.setId("AutoFill");
m_prop[0].bind(m_sendToBack); m_prop[0].bind(m_sendToBack);
m_sendToBack.setId("DrawUnder"); m_sendToBack.setId("DrawUnder");
@ -618,6 +635,9 @@ void ToonzVectorBrushTool::updateTranslation() {
m_joinStyle.setItemUIName(ROUNDJ_WSTR, tr("Round join")); m_joinStyle.setItemUIName(ROUNDJ_WSTR, tr("Round join"));
m_joinStyle.setItemUIName(BEVEL_WSTR, tr("Bevel join")); m_joinStyle.setItemUIName(BEVEL_WSTR, tr("Bevel join"));
m_sendToBack.setQStringName(tr("Draw Under")); m_sendToBack.setQStringName(tr("Draw Under"));
m_autoClose.setQStringName(tr("Auto Close"));
m_autoFill.setQStringName(tr("Auto Fill"));
m_autoGroup.setQStringName(tr("Auto Group"));
} }
//--------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------
@ -1140,6 +1160,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
stroke->insertControlPoints(0.5); stroke->insertControlPoints(0.5);
if (m_frameRange.getIndex()) { if (m_frameRange.getIndex()) {
if (m_firstFrameId == -1) { if (m_firstFrameId == -1) {
if (m_autoClose.getValue()) stroke->setSelfLoop(true);
m_firstStroke = new TStroke(*stroke); m_firstStroke = new TStroke(*stroke);
m_firstFrameId = getFrameId(); m_firstFrameId = getFrameId();
TTool::Application *application = TTool::getApplication(); TTool::Application *application = TTool::getApplication();
@ -1158,8 +1179,10 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
delete m_firstStroke; delete m_firstStroke;
m_firstStroke = 0; m_firstStroke = 0;
} }
if (m_autoClose.getValue()) stroke->setSelfLoop(true);
m_firstStroke = new TStroke(*stroke); m_firstStroke = new TStroke(*stroke);
m_rangeTrack = m_track; if (m_autoClose.getValue()) m_firstStroke->setSelfLoop(true);
m_rangeTrack = m_track;
} else { } else {
TFrameId currentId = getFrameId(); TFrameId currentId = getFrameId();
int curCol = 0, curFrame = 0; int curCol = 0, curFrame = 0;
@ -1168,10 +1191,13 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
curCol = application->getCurrentColumn()->getColumnIndex(); curCol = application->getCurrentColumn()->getColumnIndex();
curFrame = application->getCurrentFrame()->getFrame(); curFrame = application->getCurrentFrame()->getFrame();
} }
if (m_autoClose.getValue()) stroke->setSelfLoop(true);
bool success = doFrameRangeStrokes( bool success = doFrameRangeStrokes(
m_firstFrameId, m_firstStroke, getFrameId(), stroke, m_firstFrameId, m_firstStroke, getFrameId(), stroke,
m_frameRange.getIndex(), m_breakAngles.getValue(), false, false, m_frameRange.getIndex(), m_breakAngles.getValue(),
m_firstFrameRange, true, true, m_sendToBack.getValue() > 0); m_autoGroup.getValue(), m_autoFill.getValue(), m_firstFrameRange,
true, true, m_sendToBack.getValue() > 0);
if (e.isCtrlPressed() && e.isAltPressed() && e.isShiftPressed()) { if (e.isCtrlPressed() && e.isAltPressed() && e.isShiftPressed()) {
if (application) { if (application) {
if (m_firstFrameId > currentId) { if (m_firstFrameId > currentId) {
@ -1208,17 +1234,18 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
stroke->setSelfLoop(true); stroke->setSelfLoop(true);
m_snapSelf = false; m_snapSelf = false;
} }
// bool m_sendToBack =
// e.isAltPressed() && e.isShiftPressed() && !e.isCtrlPressed(); if (m_autoClose.getValue()) stroke->setSelfLoop(true);
//#ifdef Q_OS_WIN //#ifdef Q_OS_WIN
// m_sendToBack = (GetKeyState(VK_CAPITAL) & 0x0001); // m_sendToBack = (GetKeyState(VK_CAPITAL) & 0x0001);
//#endif //#endif
addStrokeToImage(getApplication(), vi, stroke, m_breakAngles.getValue(), addStrokeToImage(getApplication(), vi, stroke, m_breakAngles.getValue(),
false, false, m_isFrameCreated, m_isLevelCreated, 0, m_autoGroup.getValue(), m_autoFill.getValue(),
TFrameId::NO_FRAME, m_sendToBack.getValue() > 0); m_isFrameCreated, m_isLevelCreated, 0, TFrameId::NO_FRAME,
m_sendToBack.getValue() > 0);
TRectD bbox = stroke->getBBox().enlarge(2) + m_track.getModifiedRegion(); TRectD bbox = stroke->getBBox().enlarge(2) + m_track.getModifiedRegion();
invalidate(); // should use bbox? invalidate();
if ((Preferences::instance()->getGuidedDrawingType() == 1 || if ((Preferences::instance()->getGuidedDrawingType() == 1 ||
Preferences::instance()->getGuidedDrawingType() == 2) && Preferences::instance()->getGuidedDrawingType() == 2) &&
@ -1226,8 +1253,9 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
int fidx = getApplication()->getCurrentFrame()->getFrameIndex(); int fidx = getApplication()->getCurrentFrame()->getFrameIndex();
TFrameId fId = getFrameId(); TFrameId fId = getFrameId();
doGuidedAutoInbetween(fId, vi, stroke, m_breakAngles.getValue(), false, doGuidedAutoInbetween(fId, vi, stroke, m_breakAngles.getValue(),
false, false, m_sendToBack.getValue() > 0); m_autoGroup.getValue(), m_autoFill.getValue(),
false, m_sendToBack.getValue() > 0);
if (getApplication()->getCurrentFrame()->isEditingScene()) if (getApplication()->getCurrentFrame()->isEditingScene())
getApplication()->getCurrentFrame()->setFrame(fidx); getApplication()->getCurrentFrame()->setFrame(fidx);
@ -1246,6 +1274,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
bool ToonzVectorBrushTool::keyDown(QKeyEvent *event) { bool ToonzVectorBrushTool::keyDown(QKeyEvent *event) {
if (event->key() == Qt::Key_Escape) { if (event->key() == Qt::Key_Escape) {
resetFrameRange(); resetFrameRange();
invalidate();
} }
return false; return false;
} }
@ -1264,8 +1293,9 @@ bool ToonzVectorBrushTool::doFrameRangeStrokes(
TVectorImageP firstImage = new TVectorImage(); TVectorImageP firstImage = new TVectorImage();
TVectorImageP lastImage = new TVectorImage(); TVectorImageP lastImage = new TVectorImage();
*first = *firstStroke; *first = *firstStroke;
*last = *lastStroke; *last = *lastStroke;
bool swapped = false; bool swapped = false;
if (firstFrameId > lastFrameId) { if (firstFrameId > lastFrameId) {
std::swap(firstFrameId, lastFrameId); std::swap(firstFrameId, lastFrameId);
@ -1274,6 +1304,11 @@ bool ToonzVectorBrushTool::doFrameRangeStrokes(
swapped = true; swapped = true;
} }
if (m_autoClose.getValue()) {
first->setSelfLoop(true);
last->setSelfLoop(true);
}
firstImage->addStroke(first, false, sendToBack); firstImage->addStroke(first, false, sendToBack);
lastImage->addStroke(last, false, sendToBack); lastImage->addStroke(last, false, sendToBack);
assert(firstFrameId <= lastFrameId); assert(firstFrameId <= lastFrameId);
@ -1337,6 +1372,7 @@ bool ToonzVectorBrushTool::doFrameRangeStrokes(
assert(lastImage->getStrokeCount() == 1); assert(lastImage->getStrokeCount() == 1);
TVectorImageP vi = TInbetween(firstImage, lastImage).tween(s); TVectorImageP vi = TInbetween(firstImage, lastImage).tween(s);
assert(vi->getStrokeCount() == 1); assert(vi->getStrokeCount() == 1);
if (m_autoClose.getValue()) vi->getStroke(0)->setSelfLoop(true);
addStrokeToImage(getApplication(), img, vi->getStroke(0), breakAngles, addStrokeToImage(getApplication(), img, vi->getStroke(0), breakAngles,
autoGroup, autoFill, m_isFrameCreated, m_isLevelCreated, autoGroup, autoFill, m_isFrameCreated, m_isLevelCreated,
sl, fid, sendToBack); sl, fid, sendToBack);
@ -1894,7 +1930,64 @@ bool ToonzVectorBrushTool::onPropertyChanged(std::string propertyName) {
if (index == 0) resetFrameRange(); if (index == 0) resetFrameRange();
} else if (propertyName == m_sendToBack.getName()) { } else if (propertyName == m_sendToBack.getName()) {
V_VectorBrushDrawBehind = m_sendToBack.getValue(); V_VectorBrushDrawBehind = m_sendToBack.getValue();
} else if (propertyName == m_snap.getName()) { }
else if (propertyName == m_autoClose.getName()) {
if (!m_autoClose.getValue()) {
m_autoFill.setValue(false);
m_autoGroup.setValue(false);
V_VectorBrushAutoFill = 0;
V_VectorBrushAutoGroup = 0;
// this is ugly: it's needed to refresh the GUI of the toolbar after
// having set to false the autofill...
TTool::getApplication()->getCurrentTool()->setTool(
""); // necessary, otherwise next setTool is ignored...
TTool::getApplication()->getCurrentTool()->setTool(
QString::fromStdString(getName()));
}
V_VectorBrushAutoClose = m_autoClose.getValue();
} else if (propertyName == m_autoGroup.getName()) {
// We need close turned on if on,
// We need autofill off if off.
if (m_autoGroup.getValue()) {
m_autoClose.setValue(true);
V_VectorBrushAutoClose = 1;
// this is ugly: it's needed to refresh the GUI of the toolbar after
// having set to false the autofill...
TTool::getApplication()->getCurrentTool()->setTool(
""); // necessary, otherwise next setTool is ignored...
TTool::getApplication()->getCurrentTool()->setTool(
QString::fromStdString(getName()));
}
if (!m_autoGroup.getValue() && m_autoFill.getValue()) {
m_autoFill.setValue(false);
V_VectorBrushAutoFill = 0;
// this is ugly: it's needed to refresh the GUI of the toolbar after
// having set to false the autofill...
TTool::getApplication()->getCurrentTool()->setTool(
""); // necessary, otherwise next setTool is ignored...
TTool::getApplication()->getCurrentTool()->setTool(
QString::fromStdString(getName()));
}
V_VectorBrushAutoGroup = m_autoGroup.getValue();
} else if (propertyName == m_autoFill.getName()) {
// we need close and group on
if (m_autoFill.getValue()) {
m_autoClose.setValue(true);
m_autoGroup.setValue(true);
V_VectorBrushAutoClose = 1;
V_VectorBrushAutoGroup = 1;
// this is ugly: it's needed to refresh the GUI of the toolbar after
// having set to false the autofill...
TTool::getApplication()->getCurrentTool()->setTool(
""); // necessary, otherwise next setTool is ignored...
TTool::getApplication()->getCurrentTool()->setTool(
QString::fromStdString(getName()));
}
V_VectorBrushAutoFill = m_autoFill.getValue();
}
else if (propertyName == m_snap.getName()) {
V_VectorBrushSnap = m_snap.getValue(); V_VectorBrushSnap = m_snap.getValue();
} else if (propertyName == m_snapSensitivity.getName()) { } else if (propertyName == m_snapSensitivity.getName()) {
int index = m_snapSensitivity.getIndex(); int index = m_snapSensitivity.getIndex();
@ -2035,6 +2128,20 @@ void ToonzVectorBrushTool::loadLastBrush() {
m_snap.setValue(V_VectorBrushSnap); m_snap.setValue(V_VectorBrushSnap);
m_snapSensitivity.setIndex(V_VectorBrushSnapSensitivity); m_snapSensitivity.setIndex(V_VectorBrushSnapSensitivity);
m_sendToBack.setValue(V_VectorBrushDrawBehind); m_sendToBack.setValue(V_VectorBrushDrawBehind);
m_autoClose.setValue(V_VectorBrushAutoClose);
m_autoFill.setValue(V_VectorBrushAutoFill);
if (m_autoFill.getValue() && !m_autoClose.getValue()) {
m_autoClose.setValue(true);
V_VectorBrushAutoClose = 1;
}
if (m_autoFill.getValue() && !m_autoGroup.getValue()) {
m_autoGroup.setValue(true);
V_VectorBrushAutoGroup = 1;
}
if (m_autoGroup.getValue() && !m_autoClose.getValue()) {
m_autoClose.setValue(true);
V_VectorBrushAutoClose = 1;
}
switch (V_VectorBrushSnapSensitivity) { switch (V_VectorBrushSnapSensitivity) {
case 0: case 0:
m_minDistance2 = SNAPPING_LOW; m_minDistance2 = SNAPPING_LOW;

View file

@ -155,6 +155,9 @@ protected:
TBoolProperty m_pressure; TBoolProperty m_pressure;
TBoolProperty m_snap; TBoolProperty m_snap;
TBoolProperty m_sendToBack; TBoolProperty m_sendToBack;
TBoolProperty m_autoFill;
TBoolProperty m_autoClose;
TBoolProperty m_autoGroup;
TEnumProperty m_frameRange; TEnumProperty m_frameRange;
TEnumProperty m_snapSensitivity; TEnumProperty m_snapSensitivity;
TEnumProperty m_capStyle; TEnumProperty m_capStyle;
@ -203,7 +206,6 @@ protected:
//! substitution. //! substitution.
m_firstTime, m_isPath, m_presetsLoaded, m_firstFrameRange; m_firstTime, m_isPath, m_presetsLoaded, m_firstFrameRange;
TFrameId m_workingFrameId; TFrameId m_workingFrameId;
TPointD m_lastDragPos; //!< Position where mouse was last dragged. TPointD m_lastDragPos; //!< Position where mouse was last dragged.

View file

@ -119,6 +119,7 @@ void StrokeGenerator::drawFragments(int first, int last) {
TThickPoint a; TThickPoint a;
TThickPoint b; TThickPoint b;
TThickPoint c; TThickPoint c;
TThickPoint tempThickPoint;
TPointD v; TPointD v;
// If drawing a straight line, a stroke can have only two points // If drawing a straight line, a stroke can have only two points
@ -161,11 +162,21 @@ void StrokeGenerator::drawFragments(int first, int last) {
if (c.thick == 0) c.thick = 0.1; if (c.thick == 0) c.thick = 0.1;
} }
if (i - 1 == 0) { if (i - 1 == 0) {
v = a.thick * normalize(rotate90(b - a)); tempThickPoint = rotate90(b - a);
if (std::abs(tempThickPoint.x) == 0.0 &&
std::abs(tempThickPoint.y == 0.0)) {
v = a.thick * tempThickPoint;
} else
v = a.thick * normalize(tempThickPoint);
m_p0 = a + v; m_p0 = a + v;
m_p1 = a - v; m_p1 = a - v;
} }
v = b.thick * normalize(rotate90(c - a)); tempThickPoint = rotate90(c - a);
if (std::abs(tempThickPoint.x) == 0.0 &&
std::abs(tempThickPoint.y == 0.0)) {
v = b.thick * tempThickPoint;
} else
v = b.thick * normalize(tempThickPoint);
TPointD p0 = b + v; TPointD p0 = b + v;
TPointD p1 = b - v; TPointD p1 = b - v;
glBegin(GL_POLYGON); glBegin(GL_POLYGON);
@ -184,8 +195,11 @@ void StrokeGenerator::drawFragments(int first, int last) {
i++; i++;
} }
if (last < 2) return; if (last < 2) return;
v = m_points[last].thick * tempThickPoint = rotate90(m_points[last] - m_points[last - 1]);
normalize(rotate90(m_points[last] - m_points[last - 1])); if (std::abs(tempThickPoint.x) == 0.0 && std::abs(tempThickPoint.y == 0.0)) {
v = m_points[last].thick * tempThickPoint;
} else
v = m_points[last].thick * normalize(tempThickPoint);
TPointD p0 = m_points[last] + v; TPointD p0 = m_points[last] + v;
TPointD p1 = m_points[last] - v; TPointD p1 = m_points[last] - v;
glBegin(GL_POLYGON); glBegin(GL_POLYGON);
@ -222,7 +236,7 @@ void StrokeGenerator::drawLastFragments() {
//------------------------------------------------------------------- //-------------------------------------------------------------------
void StrokeGenerator::drawAllFragments() { void StrokeGenerator::drawAllFragments() {
if (m_points.empty()) return; if (m_points.empty() || m_points.size() == 0) return;
int n = m_points.size(); int n = m_points.size();
int i = 0; int i = 0;