fix vector picker range and onion skin fill
This commit is contained in:
parent
af3d141dba
commit
6c76dd8d1e
16 changed files with 178 additions and 129 deletions
|
@ -57,14 +57,15 @@ public:
|
|||
|
||||
/*-- (StylePickerTool内で)LineとAreaを切り替えてPickできる。mode: 0=Area,
|
||||
* 1=Line, 2=Line&Areas(default) --*/
|
||||
int pickStyleId(const TPointD &point, double radius2 = 1, int mode = 2) const;
|
||||
int pickStyleId(const TPointD &point, double radius, double scale2,
|
||||
int mode = 2) const;
|
||||
|
||||
/*--- Toonz Raster LevelのToneを拾う。 ---*/
|
||||
int pickTone(const TPointD &pos) const;
|
||||
|
||||
// per pli come sopra, ma ritorna il maincolor
|
||||
// per tzp e fullcolor ritorna il colore effettivo del pixel
|
||||
TPixel32 pickColor(const TPointD &point, double radius2 = 1) const;
|
||||
TPixel32 pickColor(const TPointD &point, double radius, double scale2) const;
|
||||
TPixel32 pickAverageColor(const TRectD &rect) const;
|
||||
|
||||
// ritorna il colore medio presente nell'area della finestra corrente openGL
|
||||
|
|
|
@ -466,8 +466,9 @@ return true if the method execution can have changed the current tool
|
|||
const TAffine &getMatrix() const { return m_matrix; }
|
||||
void setMatrix(const TAffine &matrix) { m_matrix = matrix; }
|
||||
|
||||
TAffine getCurrentColumnMatrix()
|
||||
TAffine getCurrentColumnMatrix(int frame = -1)
|
||||
const; //!< Returns the current column matrix transformation.
|
||||
//! if frame = -1 then it uses the current frame
|
||||
//! \sa TXsheet::getPlacement.
|
||||
|
||||
TAffine getCurrentColumnParentMatrix()
|
||||
|
@ -480,9 +481,10 @@ return true if the method execution can have changed the current tool
|
|||
Returns the matrix transformation of the stage object with column
|
||||
index equal to \p index
|
||||
and frame as the current frame.
|
||||
\sa TXsheet::getPlacement.
|
||||
if frame = -1 then it uses the current frame
|
||||
\sa TXsheet::getPlacement.
|
||||
*/
|
||||
TAffine getColumnMatrix(int index) const;
|
||||
TAffine getColumnMatrix(int index, int frame = -1) const;
|
||||
|
||||
/*!
|
||||
Updates the current matrix transformation with the actual column matrix
|
||||
|
|
|
@ -302,14 +302,16 @@ class DVAPI Picker final : public Visitor {
|
|||
TPointD m_point;
|
||||
TAffine m_viewAff;
|
||||
double m_minDist2;
|
||||
int m_devPixRatio;
|
||||
|
||||
int m_currentColumnIndex = -1;
|
||||
|
||||
public:
|
||||
Picker(const TAffine &viewAff, const TPointD &p,
|
||||
const ImagePainter::VisualSettings &vs);
|
||||
const ImagePainter::VisualSettings &vs, int devPixRatio = 1);
|
||||
|
||||
void setDistance(double d);
|
||||
// minimum distance to pick thin vector strokes.
|
||||
void setMinimumDistance(double d);
|
||||
|
||||
void onImage(const Stage::Player &data) override;
|
||||
void onRasterImage(TRasterImage *ri, const Stage::Player &data) override{};
|
||||
|
|
|
@ -576,8 +576,7 @@ void ControlPointEditorTool::leftButtonDown(const TPointD &pos,
|
|||
if (m_autoSelectDrawing.getValue()) {
|
||||
// Non sono in nessun gadget
|
||||
std::vector<int> columnIndexes;
|
||||
getViewer()->posToColumnIndexes(e.m_pos, columnIndexes,
|
||||
getPixelSize() * 5, false);
|
||||
getViewer()->posToColumnIndexes(e.m_pos, columnIndexes, 5.0, false);
|
||||
getNearestStrokeColumnIndexes(columnIndexes, pos);
|
||||
if (!columnIndexes.empty()) {
|
||||
int currentColumnIndex = app->getCurrentColumn()->getColumnIndex();
|
||||
|
|
|
@ -1059,8 +1059,7 @@ void EditTool::onEditAllLeftButtonDown(TPointD &pos, const TMouseEvent &e) {
|
|||
|
||||
if (selectedDevice < 0 && m_autoSelect.getValue() != L"None") {
|
||||
pos = getMatrix() * pos;
|
||||
int columnIndex =
|
||||
getViewer()->posToColumnIndex(e.m_pos, 5 * getPixelSize(), false);
|
||||
int columnIndex = getViewer()->posToColumnIndex(e.m_pos, 5.0, false);
|
||||
if (columnIndex >= 0) {
|
||||
TStageObjectId id = TStageObjectId::ColumnId(columnIndex);
|
||||
int currentColumnIndex = getColumnIndex();
|
||||
|
|
|
@ -1812,6 +1812,8 @@ void AreaFillTool::onEnter() {
|
|||
// getApplication()->editImage();
|
||||
}
|
||||
|
||||
bool descending(int i, int j) { return (i > j); }
|
||||
|
||||
} // namespace
|
||||
|
||||
//=============================================================================
|
||||
|
@ -2457,14 +2459,30 @@ void FillTool::draw() {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int FillTool::pick(const TImageP &image, const TPointD &pos) {
|
||||
int FillTool::pick(const TImageP &image, const TPointD &pos, const int frame) {
|
||||
TToonzImageP ti = image;
|
||||
TVectorImageP vi = image;
|
||||
if (!ti && !vi) return 0;
|
||||
|
||||
StylePicker picker(image);
|
||||
double pixelSize2 = getPixelSize() * getPixelSize();
|
||||
return picker.pickStyleId(pos, pixelSize2);
|
||||
double scale2 = 1.0;
|
||||
if (vi) {
|
||||
TAffine aff = getViewer()->getViewMatrix() * getCurrentColumnMatrix(frame);
|
||||
scale2 = aff.det();
|
||||
}
|
||||
TPointD pickPos = pos;
|
||||
// in case that the column is animated in scene-editing mode
|
||||
if (frame > 0) {
|
||||
TPointD dpiScale = getViewer()->getDpiScale();
|
||||
pickPos.x *= dpiScale.x;
|
||||
pickPos.y *= dpiScale.y;
|
||||
TPointD worldPos = getCurrentColumnMatrix() * pickPos;
|
||||
pickPos = getCurrentColumnMatrix(frame).inv() * worldPos;
|
||||
pickPos.x /= dpiScale.x;
|
||||
pickPos.y /= dpiScale.y;
|
||||
}
|
||||
// thin stroke can be picked with 10 pixel range
|
||||
return picker.pickStyleId(pickPos, 10.0, scale2);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -2481,32 +2499,53 @@ int FillTool::pickOnionColor(const TPointD &pos) {
|
|||
if (!sl) return 0;
|
||||
|
||||
std::vector<int> rows;
|
||||
osMask.getAll(sl->guessIndex(fid), rows);
|
||||
// level editing case
|
||||
if (app->getCurrentFrame()->isEditingLevel()) {
|
||||
osMask.getAll(sl->guessIndex(fid), rows);
|
||||
int i, j;
|
||||
for (i = 0; i < (int)rows.size(); i++)
|
||||
if (sl->index2fid(rows[i]) > fid) break;
|
||||
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < (int)rows.size(); i++)
|
||||
if (sl->index2fid(rows[i]) > fid) break;
|
||||
|
||||
int onionStyleId = 0;
|
||||
for (j = i - 1; j >= 0; j--) {
|
||||
TFrameId onionFid = sl->index2fid(rows[j]);
|
||||
if (onionFid != fid &&
|
||||
((onionStyleId =
|
||||
pick(m_level->getFrame(onionFid, ImageManager::none, 1), pos)) >
|
||||
0)) // subsabling must be 1, otherwise onionfill does not work
|
||||
break;
|
||||
}
|
||||
if (onionStyleId == 0)
|
||||
for (j = i; j < (int)rows.size(); j++) {
|
||||
int onionStyleId = 0;
|
||||
for (j = i - 1; j >= 0; j--) {
|
||||
TFrameId onionFid = sl->index2fid(rows[j]);
|
||||
if (onionFid != fid &&
|
||||
((onionStyleId =
|
||||
pick(m_level->getFrame(onionFid, ImageManager::none, 1), pos)) >
|
||||
0)) // subsabling must be 1, otherwise onionfill does not work
|
||||
0)) // subsampling must be 1, otherwise onionfill does not work
|
||||
break;
|
||||
}
|
||||
return onionStyleId;
|
||||
if (onionStyleId == 0)
|
||||
for (j = i; j < (int)rows.size(); j++) {
|
||||
TFrameId onionFid = sl->index2fid(rows[j]);
|
||||
if (onionFid != fid &&
|
||||
((onionStyleId = pick(
|
||||
m_level->getFrame(onionFid, ImageManager::none, 1), pos)) >
|
||||
0)) // subsampling must be 1, otherwise onionfill does not work
|
||||
break;
|
||||
}
|
||||
return onionStyleId;
|
||||
} else { // scene editing case
|
||||
TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
|
||||
int colId = app->getCurrentColumn()->getColumnIndex();
|
||||
int row = app->getCurrentFrame()->getFrame();
|
||||
osMask.getAll(row, rows);
|
||||
std::vector<int>::iterator it = rows.begin();
|
||||
while (it != rows.end() && *it < row) it++;
|
||||
std::sort(rows.begin(), it, descending);
|
||||
int onionStyleId = 0;
|
||||
for (int i = 0; i < (int)rows.size(); i++) {
|
||||
if (rows[i] == row) continue;
|
||||
TXshCell cell = xsh->getCell(rows[i], colId);
|
||||
TXshLevel *xl = cell.m_level.getPointer();
|
||||
if (!xl || xl->getSimpleLevel() != sl) continue;
|
||||
TFrameId onionFid = cell.getFrameId();
|
||||
onionStyleId = pick(m_level->getFrame(onionFid, ImageManager::none, 1),
|
||||
pos, rows[i]);
|
||||
if (onionStyleId > 0) break;
|
||||
}
|
||||
return onionStyleId;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
void onActivate();
|
||||
void onEnter();
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
class FillTool final : public QObject, public TTool {
|
||||
// Q_DECLARE_TR_FUNCTIONS(FillTool)
|
||||
Q_OBJECT
|
||||
|
@ -135,7 +135,8 @@ public:
|
|||
void onImageChanged() override;
|
||||
void draw() override;
|
||||
|
||||
int pick(const TImageP &image, const TPointD &pos);
|
||||
// if frame = -1 it uses current frame
|
||||
int pick(const TImageP &image, const TPointD &pos, const int frame = -1);
|
||||
int pickOnionColor(const TPointD &pos);
|
||||
|
||||
void onEnter() override;
|
||||
|
|
|
@ -450,8 +450,7 @@ void ShiftTraceTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
|
|||
m_gadget = RotateGadget;
|
||||
}
|
||||
|
||||
int row = getViewer()->posToRow(e.m_pos, getPixelSize() * getPixelSize(),
|
||||
false, true);
|
||||
int row = getViewer()->posToRow(e.m_pos, 5.0, false, true);
|
||||
if (row >= 0) {
|
||||
int index = -1;
|
||||
TApplication *app = TTool::getApplication();
|
||||
|
|
|
@ -180,7 +180,7 @@ DragPositionTool::DragPositionTool(SkeletonTool *tool)
|
|||
|
||||
void DragPositionTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
|
||||
start();
|
||||
m_firstPos = pos;
|
||||
m_firstPos = pos;
|
||||
m_firstDrag = true;
|
||||
}
|
||||
|
||||
|
@ -190,9 +190,9 @@ void DragPositionTool::leftButtonDrag(const TPointD &pos,
|
|||
const TMouseEvent &e) {
|
||||
TPointD delta = pos - m_firstPos;
|
||||
if (m_firstDrag && (delta.x > 2.0 || delta.y > 2.0)) {
|
||||
m_firstPos = pos;
|
||||
delta = TPointD(0.0, 0.0);
|
||||
m_firstDrag = false;
|
||||
m_firstPos = pos;
|
||||
delta = TPointD(0.0, 0.0);
|
||||
m_firstDrag = false;
|
||||
}
|
||||
if (e.isShiftPressed()) {
|
||||
if (fabs(delta.x) > fabs(delta.y))
|
||||
|
@ -300,10 +300,10 @@ void ParentChangeTool::leftButtonDown(const TPointD &pos,
|
|||
// registro alcune informazioni relative a colId:
|
||||
// placement, bbox, centro, hooks, name, ecc.
|
||||
Element element;
|
||||
element.m_columnIndex = col;
|
||||
TImageP img = cell.getImage(false);
|
||||
element.m_columnIndex = col;
|
||||
TImageP img = cell.getImage(false);
|
||||
if (img) element.m_bbox = img->getBBox();
|
||||
element.m_aff = xsh->getPlacement(colId, currentFrame);
|
||||
element.m_aff = xsh->getPlacement(colId, currentFrame);
|
||||
Peer peer;
|
||||
peer.m_columnIndex = col;
|
||||
peer.m_handle = 0;
|
||||
|
@ -352,7 +352,7 @@ void ParentChangeTool::leftButtonDrag(const TPointD &pos,
|
|||
if (m_snapped) return;
|
||||
getTool()->setParentProbe(getTool()->getCurrentColumnParentMatrix() * pos);
|
||||
|
||||
m_index = m_viewer->posToColumnIndex(e.m_pos, m_pixelSize * 5, false);
|
||||
m_index = m_viewer->posToColumnIndex(e.m_pos, 5.0, false);
|
||||
|
||||
m_lastPos = m_viewer->winToWorld(e.m_pos);
|
||||
|
||||
|
@ -425,16 +425,13 @@ void ParentChangeTool::draw() { getTool()->drawHooks(); }
|
|||
//
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
// This needs some clarification.
|
||||
namespace {
|
||||
class Graph {
|
||||
|
||||
// local variables defined below are:
|
||||
// Nodes m_nodes;
|
||||
// std::map<int, int> m_leaves;
|
||||
|
||||
|
||||
public:
|
||||
typedef std::set<int> Links;
|
||||
typedef Links::const_iterator LinkIter;
|
||||
|
@ -455,7 +452,7 @@ public:
|
|||
|
||||
// check if a node is found in m_nodes
|
||||
bool isNode(int id) const { return m_nodes.count(id) > 0; }
|
||||
|
||||
|
||||
int getNodeCount() const { return (int)m_nodes.size(); }
|
||||
|
||||
void link(int a, int b) {
|
||||
|
@ -468,7 +465,7 @@ public:
|
|||
NodeIter it = m_nodes.find(a);
|
||||
return it == m_nodes.end() ? false : it->second.count(b);
|
||||
}
|
||||
|
||||
|
||||
const Links &getLinks(int id) const {
|
||||
static const Links empty;
|
||||
NodeIter it = m_nodes.find(id);
|
||||
|
@ -501,7 +498,7 @@ public:
|
|||
LeaveIter it = m_leaves.find(id);
|
||||
return it == m_leaves.end() ? 0 : it->second;
|
||||
}
|
||||
|
||||
|
||||
void setLeaveType(int id, int type) { m_leaves[id] = type; }
|
||||
|
||||
|
||||
|
@ -509,7 +506,7 @@ public:
|
|||
void remove(int id) {
|
||||
NodeIter it = m_nodes.find(id);
|
||||
if (it != m_nodes.end()) {
|
||||
// iterate over the links
|
||||
// iterate over the links
|
||||
for (LinkIter j = it->second.begin(); j != it->second.end(); ++j)
|
||||
m_nodes[*j].erase(id);
|
||||
m_nodes.erase(it->first);
|
||||
|
@ -536,15 +533,15 @@ bool hasPinned(const Skeleton::Bone *bone, const Skeleton::Bone *prevBone) {
|
|||
|
||||
if (bone->getParent() && bone->getParent() != prevBone &&
|
||||
hasPinned(bone->getParent(), bone)) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bone->getChildCount(); i++) {
|
||||
if (bone->getChild(i) != prevBone) {
|
||||
if (hasPinned(bone->getChild(i), bone)) {
|
||||
return true;
|
||||
}
|
||||
if (bone->getChild(i) != prevBone) {
|
||||
if (hasPinned(bone->getChild(i), bone)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -556,9 +553,9 @@ bool hasPinned(const Skeleton::Bone *bone, const Skeleton::Bone *prevBone) {
|
|||
bool addToActiveChain(Graph &tree, const Skeleton::Bone *bone,
|
||||
const Skeleton::Bone *prevBone) {
|
||||
if (!bone) return false;
|
||||
|
||||
|
||||
// The handle is what you grabbed
|
||||
bool isHandle = prevBone == 0;
|
||||
bool isHandle = prevBone == 0;
|
||||
|
||||
bool isChild = prevBone != 0 && prevBone == bone->getParent();
|
||||
bool isParent = prevBone != 0 && prevBone->getParent() == bone;
|
||||
|
@ -571,19 +568,19 @@ bool addToActiveChain(Graph &tree, const Skeleton::Bone *bone,
|
|||
|
||||
// Go up the chain from what you grabbed and add bones
|
||||
if (!isChild && isFree) {
|
||||
if (bone->getParent()) {
|
||||
propagate |= addToActiveChain(tree, bone->getParent(), bone);
|
||||
}
|
||||
if (bone->getParent()) {
|
||||
propagate |= addToActiveChain(tree, bone->getParent(), bone);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> children;
|
||||
// Once you reach the top parent, add the other children
|
||||
if (isHandle || isFree) {
|
||||
for (int i = 0; i < bone->getChildCount(); i++) {
|
||||
if (bone->getChild(i) != prevBone) {
|
||||
propagate |= addToActiveChain(tree, bone->getChild(i), bone);
|
||||
}
|
||||
for (int i = 0; i < bone->getChildCount(); i++) {
|
||||
if (bone->getChild(i) != prevBone) {
|
||||
propagate |= addToActiveChain(tree, bone->getChild(i), bone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool insert = false;
|
||||
|
@ -856,8 +853,9 @@ void IKTool::initEngine(const TPointD &pos) {
|
|||
Skeleton::Bone *next = m_skeleton->getBoneByColumnIndex(*it++);
|
||||
for (; it != links.end(); ++it)
|
||||
stack.push_back(std::make_pair(*it, prev));
|
||||
if (links.size() > 1 || (prev && next && (prev->getParent() == bone &&
|
||||
next->getParent() == bone))) {
|
||||
if (links.size() > 1 ||
|
||||
(prev && next &&
|
||||
(prev->getParent() == bone && next->getParent() == bone))) {
|
||||
bone = next;
|
||||
} else {
|
||||
m_joints.push_back(Joint(bone, prev, sign));
|
||||
|
@ -918,11 +916,12 @@ void IKTool::computeIHateIK() {
|
|||
int n = (int)objs.size();
|
||||
int frame = TTool::getApplication()->getCurrentFrame()->getFrame();
|
||||
m_foot = m_firstFoot = 0;
|
||||
m_frameOnNewPin = false;
|
||||
m_frameOnNewPin = false;
|
||||
|
||||
// this just finds the first pin
|
||||
int i;
|
||||
for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(frame); i++) {}
|
||||
for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(frame); i++) {
|
||||
}
|
||||
if (i == n) return;
|
||||
|
||||
// this makes m_foot to be the current pin
|
||||
|
@ -940,7 +939,8 @@ void IKTool::computeIHateIK() {
|
|||
// the frame is the start of a new pinned frame, find the previous pin
|
||||
for (;;) {
|
||||
for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(firstFrame);
|
||||
i++) {}
|
||||
i++) {
|
||||
}
|
||||
|
||||
if (i == n) break;
|
||||
m_firstFoot = objs[i];
|
||||
|
|
|
@ -383,8 +383,7 @@ void SkeletonTool::leftButtonDown(const TPointD &ppos, const TMouseEvent &e) {
|
|||
if (m_device < 0) {
|
||||
// No gadget clicked. Select the column
|
||||
std::vector<int> columnIndexes;
|
||||
getViewer()->posToColumnIndexes(e.m_pos, columnIndexes, getPixelSize() * getPixelSize(),
|
||||
false);
|
||||
getViewer()->posToColumnIndexes(e.m_pos, columnIndexes, 5.0, false);
|
||||
if (!columnIndexes.empty()) {
|
||||
int columnIndex;
|
||||
columnIndex = columnIndexes.back();
|
||||
|
@ -1056,8 +1055,7 @@ void SkeletonTool::drawHooks() {
|
|||
// otherColumn = "picked" column not connected
|
||||
TPointD parentProbePos = getViewer()->worldToPos(m_parentProbe);
|
||||
std::vector<int> indexes;
|
||||
getViewer()->posToColumnIndexes(parentProbePos, indexes,
|
||||
getPixelSize() * 10, false);
|
||||
getViewer()->posToColumnIndexes(parentProbePos, indexes, 10.0, false);
|
||||
for (int i = (int)indexes.size() - 1; i >= 0; i--) {
|
||||
if (connectedColumns.count(indexes[i]) == 0) {
|
||||
otherColumn = indexes[i];
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "toonz/dpiscale.h"
|
||||
#include "tpixelutils.h"
|
||||
#include "tregion.h"
|
||||
#include "toonzqt/gutil.h"
|
||||
|
||||
#include <QRect>
|
||||
|
||||
|
@ -44,7 +45,7 @@ TPoint StylePicker::getRasterPoint(const TPointD &p) const {
|
|||
//---------------------------------------------------------
|
||||
/*-- (StylePickerTool内で)LineとAreaを切り替えてPickできる。mode: 0=Area,
|
||||
* 1=Line, 2=Line&Areas(default) --*/
|
||||
int StylePicker::pickStyleId(const TPointD &pos, double radius2,
|
||||
int StylePicker::pickStyleId(const TPointD &pos, double radius, double scale2,
|
||||
int mode) const {
|
||||
int styleId = 0;
|
||||
if (TToonzImageP ti = m_image) {
|
||||
|
@ -78,11 +79,6 @@ int StylePicker::pickStyleId(const TPointD &pos, double radius2,
|
|||
// prima cerca lo stile della regione piu' vicina
|
||||
TRegion *r = vi->getRegion(pos);
|
||||
if (r) styleId = r->getStyle();
|
||||
// poi cerca quello della stroke, ma se prima aveva trovato una regione,
|
||||
// richiede che
|
||||
// il click sia proprio sopra la stroke, altrimenti cerca la stroke piu'
|
||||
// vicina (max circa 10 pixel)
|
||||
const double maxDist2 = (styleId == 0) ? 100.0 * radius2 : 0;
|
||||
bool strokeFound;
|
||||
double dist2, w, thick;
|
||||
UINT index;
|
||||
|
@ -90,9 +86,16 @@ int StylePicker::pickStyleId(const TPointD &pos, double radius2,
|
|||
// la thickness, cioe' la min distance dalla outline e non dalla centerLine
|
||||
strokeFound = vi->getNearestStroke(pos, w, index, dist2);
|
||||
if (strokeFound) {
|
||||
int devPixRatio = getDevPixRatio();
|
||||
dist2 *= scale2;
|
||||
TStroke *stroke = vi->getStroke(index);
|
||||
thick = stroke->getThickPoint(w).thick;
|
||||
if (dist2 - thick * thick < maxDist2) {
|
||||
double len2 = thick * thick * scale2;
|
||||
const double minDist2 =
|
||||
(styleId == 0) ? radius * radius * (double)(devPixRatio * devPixRatio)
|
||||
: 0;
|
||||
double checkDist = std::max(minDist2, len2);
|
||||
if (dist2 < checkDist) {
|
||||
assert(stroke);
|
||||
styleId = stroke->getStyle();
|
||||
}
|
||||
|
@ -118,7 +121,8 @@ int StylePicker::pickTone(const TPointD &pos) const {
|
|||
|
||||
//---------------------------------------------------------
|
||||
|
||||
TPixel32 StylePicker::pickColor(const TPointD &pos, double radius2) const {
|
||||
TPixel32 StylePicker::pickColor(const TPointD &pos, double radius,
|
||||
double scale2) const {
|
||||
TToonzImageP ti = m_image;
|
||||
TRasterImageP ri = m_image;
|
||||
TVectorImageP vi = m_image;
|
||||
|
@ -141,14 +145,14 @@ TPixel32 StylePicker::pickColor(const TPointD &pos, double radius2) const {
|
|||
} else if (vi) {
|
||||
const TPalette *palette = m_palette.getPointer();
|
||||
if (!palette) return TPixel32::Transparent;
|
||||
int styleId = pickStyleId(pos, radius2);
|
||||
int styleId = pickStyleId(pos, radius, scale2);
|
||||
if (0 <= styleId && styleId < palette->getStyleCount())
|
||||
return palette->getStyle(styleId)->getAverageColor();
|
||||
} else if (ti) {
|
||||
const TPalette *palette = m_palette.getPointer();
|
||||
if (!palette) return TPixel32::Transparent;
|
||||
int paintId = pickStyleId(pos, radius2, 0);
|
||||
int inkId = pickStyleId(pos, radius2, 1);
|
||||
int paintId = pickStyleId(pos, radius, scale2, 0);
|
||||
int inkId = pickStyleId(pos, radius, scale2, 1);
|
||||
int tone = pickTone(pos);
|
||||
TPixel32 ink, paint;
|
||||
if (0 <= inkId && inkId < palette->getStyleCount())
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// TnzQt includes
|
||||
#include "toonzqt/tselectionhandle.h"
|
||||
#include "toonzqt/styleselection.h"
|
||||
#include "toonzqt/gutil.h"
|
||||
|
||||
// TnzLib includes
|
||||
#include "toonz/txshsimplelevel.h"
|
||||
|
@ -86,13 +87,13 @@ void StylePickerTool::pick(const TPointD &pos, const TMouseEvent &e,
|
|||
---*/
|
||||
if (Preferences::instance()->isMultiLayerStylePickerEnabled() &&
|
||||
getApplication()->getCurrentFrame()->isEditingScene()) {
|
||||
int superPickedColumnId = getViewer()->posToColumnIndex(
|
||||
e.m_pos, getPixelSize() * getPixelSize(), false);
|
||||
double pickRange = 10.0;
|
||||
int superPickedColumnId =
|
||||
getViewer()->posToColumnIndex(e.m_pos, pickRange, false);
|
||||
|
||||
if (superPickedColumnId >= 0 /*-- 何かColumnに当たった場合 --*/
|
||||
&&
|
||||
getApplication()->getCurrentColumn()->getColumnIndex() !=
|
||||
superPickedColumnId) /*-- かつ、Current Columnでない場合 --*/
|
||||
&& getApplication()->getCurrentColumn()->getColumnIndex() !=
|
||||
superPickedColumnId) /*-- かつ、Current Columnでない場合 --*/
|
||||
{
|
||||
/*-- そのColumnからPickを試みる --*/
|
||||
int currentFrame = getApplication()->getCurrentFrame()->getFrame();
|
||||
|
@ -112,13 +113,16 @@ void StylePickerTool::pick(const TPointD &pos, const TMouseEvent &e,
|
|||
tmpMousePosition.x /= tmpDpiScale.x;
|
||||
tmpMousePosition.y /= tmpDpiScale.y;
|
||||
|
||||
TAffine aff =
|
||||
getViewer()->getViewMatrix() * getColumnMatrix(superPickedColumnId);
|
||||
double scale2 = aff.det();
|
||||
StylePicker superPicker(pickedImage);
|
||||
int picked_subsampling =
|
||||
picked_level->getImageSubsampling(pickedCell.getFrameId());
|
||||
int superPicked_StyleId = superPicker.pickStyleId(
|
||||
TScale(1.0 / picked_subsampling) * tmpMousePosition +
|
||||
TPointD(-0.5, -0.5),
|
||||
getPixelSize() * getPixelSize(), modeValue);
|
||||
pickRange, scale2, modeValue);
|
||||
/*-- 何かStyleが拾えて、Transparentでない場合 --*/
|
||||
if (superPicked_StyleId > 0) {
|
||||
/*-- Levelの移動 --*/
|
||||
|
@ -152,25 +156,26 @@ void StylePickerTool::pick(const TPointD &pos, const TMouseEvent &e,
|
|||
/*-- 画面外をpickしても拾えないようにする --*/
|
||||
if (!m_viewer->getGeometry().contains(pos)) return;
|
||||
|
||||
TAffine aff = getViewer()->getViewMatrix() * getCurrentColumnMatrix();
|
||||
double scale2 = aff.det();
|
||||
int subsampling = level->getImageSubsampling(getCurrentFid());
|
||||
StylePicker picker(image);
|
||||
int styleId =
|
||||
picker.pickStyleId(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5),
|
||||
getPixelSize() * getPixelSize(), modeValue);
|
||||
10.0, scale2, modeValue);
|
||||
|
||||
if (styleId < 0) return;
|
||||
|
||||
if (modeValue == 1) // LINES
|
||||
{
|
||||
/*-- pickLineモードのとき、取得Styleが0の場合はカレントStyleを変えない。
|
||||
* --*/
|
||||
* --*/
|
||||
if (styleId == 0) return;
|
||||
/*--
|
||||
* pickLineモードのとき、PurePaintの部分をクリックしてもカレントStyleを変えない
|
||||
* --*/
|
||||
if (ti &&
|
||||
picker.pickTone(TScale(1.0 / subsampling) * pos +
|
||||
TPointD(-0.5, -0.5)) == 255)
|
||||
* pickLineモードのとき、PurePaintの部分をクリックしてもカレントStyleを変えない
|
||||
* --*/
|
||||
if (ti && picker.pickTone(TScale(1.0 / subsampling) * pos +
|
||||
TPointD(-0.5, -0.5)) == 255)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -207,13 +212,13 @@ void StylePickerTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
|
|||
return;
|
||||
}
|
||||
|
||||
TAffine aff = getViewer()->getViewMatrix() * getCurrentColumnMatrix();
|
||||
double scale2 = aff.det();
|
||||
int subsampling = level->getImageSubsampling(getCurrentFid());
|
||||
StylePicker picker(image);
|
||||
TPointD pickPos(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5));
|
||||
int inkStyleId =
|
||||
picker.pickStyleId(pickPos, getPixelSize() * getPixelSize(), 1);
|
||||
int paintStyleId =
|
||||
picker.pickStyleId(pickPos, getPixelSize() * getPixelSize(), 0);
|
||||
int inkStyleId = picker.pickStyleId(pickPos, 10.0, scale2, 1);
|
||||
int paintStyleId = picker.pickStyleId(pickPos, 10.0, scale2, 0);
|
||||
int tone = picker.pickTone(pickPos);
|
||||
controller->notifyStylePassivePicked(inkStyleId, paintStyleId, tone);
|
||||
}
|
||||
|
|
|
@ -721,8 +721,9 @@ TFrameId TTool::getCurrentFid() const {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TAffine TTool::getCurrentColumnMatrix() const {
|
||||
return getColumnMatrix(m_application->getCurrentColumn()->getColumnIndex());
|
||||
TAffine TTool::getCurrentColumnMatrix(int frame) const {
|
||||
return getColumnMatrix(m_application->getCurrentColumn()->getColumnIndex(),
|
||||
frame);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -759,12 +760,12 @@ TAffine TTool::getCurrentObjectParentMatrix() const {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TAffine TTool::getColumnMatrix(int columnIndex) const {
|
||||
TAffine TTool::getColumnMatrix(int columnIndex, int frame) const {
|
||||
if (!m_application) return TAffine();
|
||||
|
||||
TFrameHandle *fh = m_application->getCurrentFrame();
|
||||
if (fh->isEditingLevel()) return TAffine();
|
||||
int frame = fh->getFrame();
|
||||
if (frame < 0) frame = fh->getFrame();
|
||||
TXsheet *xsh = m_application->getCurrentXsheet()->getXsheet();
|
||||
TStageObjectId columnObjId =
|
||||
(columnIndex >= 0)
|
||||
|
|
|
@ -954,9 +954,11 @@ void ImageViewer::pickColor(QMouseEvent *event, bool putValueToStyleEditor) {
|
|||
TPointD(0.5 * imgRect.getLx() + pos.x, 0.5 * imgRect.getLy() + pos.y);
|
||||
|
||||
TPixel32 pix;
|
||||
if (m_lutCalibrator && m_lutCalibrator->isValid())
|
||||
pix = picker.pickColor(pos + TPointD(-0.5, -0.5));
|
||||
else
|
||||
if (m_lutCalibrator && m_lutCalibrator->isValid()) {
|
||||
// for specifiying pixel range on picking vector
|
||||
double scale2 = getViewAff().det();
|
||||
pix = picker.pickColor(pos + TPointD(-0.5, -0.5), 10.0, scale2);
|
||||
} else
|
||||
pix = picker.pickColor(area);
|
||||
|
||||
if (!img->raster() || imgRect.contains(imagePos)) {
|
||||
|
|
|
@ -3117,8 +3117,9 @@ void SceneViewer::posToColumnIndexes(const TPointD &p,
|
|||
OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
|
||||
|
||||
TPointD pos = TPointD(p.x - width() / 2, p.y - height() / 2);
|
||||
Stage::Picker picker(getViewMatrix(), pos, m_visualSettings);
|
||||
picker.setDistance(distance);
|
||||
Stage::Picker picker(getViewMatrix(), pos, m_visualSettings,
|
||||
getDevPixRatio());
|
||||
picker.setMinimumDistance(distance);
|
||||
|
||||
TXshSimpleLevel::m_rasterizePli = 0;
|
||||
|
||||
|
@ -3156,8 +3157,9 @@ int SceneViewer::posToRow(const TPointD &p, double distance,
|
|||
OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
|
||||
|
||||
TPointD pos = TPointD(p.x - width() / 2, p.y - height() / 2);
|
||||
Stage::Picker picker(getViewMatrix(), pos, m_visualSettings);
|
||||
picker.setDistance(distance);
|
||||
Stage::Picker picker(getViewMatrix(), pos, m_visualSettings,
|
||||
getDevPixRatio());
|
||||
picker.setMinimumDistance(distance);
|
||||
|
||||
if (app->getCurrentFrame()->isEditingLevel()) {
|
||||
Stage::visit(picker, app->getCurrentLevel()->getLevel(),
|
||||
|
|
|
@ -215,16 +215,20 @@ void onPlasticDeformedImage(TStageObject *playerObj,
|
|||
//**********************************************************************************************
|
||||
|
||||
Picker::Picker(const TAffine &viewAff, const TPointD &point,
|
||||
const ImagePainter::VisualSettings &vs)
|
||||
const ImagePainter::VisualSettings &vs, int devPixRatio)
|
||||
: Visitor(vs)
|
||||
, m_viewAff(viewAff)
|
||||
, m_point(point)
|
||||
, m_columnIndexes()
|
||||
, m_minDist2(1.0e10) {}
|
||||
, m_minDist2(25.0)
|
||||
, m_devPixRatio(devPixRatio) {}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Picker::setDistance(double d) { m_minDist2 = d * d; }
|
||||
void Picker::setMinimumDistance(double d) {
|
||||
m_minDist2 = (double)(m_devPixRatio * m_devPixRatio) * d * d;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -251,21 +255,12 @@ void Picker::onImage(const Stage::Player &player) {
|
|||
if (styleId != 0)
|
||||
picked = true;
|
||||
else if (vi->getNearestStroke(point, w, strokeIndex, dist2)) {
|
||||
// based on TTool::Viewer::doPickGuideStroke
|
||||
|
||||
// m_minDist2 seems to be the pixel size to the power 4, so take the
|
||||
// square root of the square root.
|
||||
// Use abs() just in case m_minDist2 is negative, to avoid math errors.
|
||||
double pixelSize = sqrt(sqrt(abs(m_minDist2)));
|
||||
double maxDist = 5 * pixelSize;
|
||||
double maxDist2 = maxDist * maxDist;
|
||||
double checkDist = maxDist2 * 4;
|
||||
dist2 *= aff.det();
|
||||
|
||||
TStroke *stroke = vi->getStroke(strokeIndex);
|
||||
TThickPoint thickPoint = stroke->getThickPoint(w);
|
||||
double thickness = thickPoint.thick;
|
||||
double len = thickness * pixelSize * sqrt(m_viewAff.det());
|
||||
checkDist = std::max(checkDist, (len * len));
|
||||
double len2 = thickPoint.thick * thickPoint.thick * aff.det();
|
||||
double checkDist = std::max(m_minDist2, len2);
|
||||
if (dist2 < checkDist) picked = true;
|
||||
}
|
||||
} else if (TRasterImageP ri = img) {
|
||||
|
|
Loading…
Reference in a new issue