10#include <kritaglobal_export.h>
17#include <boost/iterator/iterator_facade.hpp>
18#include <boost/operators.hpp>
29struct BaseMeshNode :
public boost::equality_comparable<BaseMeshNode> {
113 const QRectF &srcRect,
126template<
typename NodeArg = BaseMeshNode,
128class Mesh :
public boost::equality_comparable<Mesh<NodeArg, PatchArg>>
134 struct PatchIndex :
public QPoint, boost::additive<PatchIndex, QPoint>
136 using QPoint::QPoint;
138 QPoint::operator+=(rhs);
142 QPoint::operator-=(rhs);
147 struct NodeIndex :
public QPoint, boost::additive<NodeIndex, QPoint>
149 using QPoint::QPoint;
151 QPoint::operator+=(rhs);
155 QPoint::operator-=(rhs);
191 template <
class NodeType,
212 dbg.nospace() <<
"ControlPointIndex ("
216 case Mesh::ControlType::Node:
217 dbg.nospace() <<
"Node";
219 case Mesh::ControlType::LeftControl:
220 dbg.nospace() <<
"LeftControl";
222 case Mesh::ControlType::RightControl:
223 dbg.nospace() <<
"RightControl";
225 case Mesh::ControlType::TopControl:
226 dbg.nospace() <<
"TopControl";
228 case Mesh::ControlType::BottomControl:
229 dbg.nospace() <<
"BottomControl";
233 dbg.nospace() <<
")";
241 template<
bool is_const>
244 template<
bool is_const>
247 template<
bool is_const>
249 public boost::iterator_facade <patch_iterator_impl<is_const>,
251 boost::random_access_traversal_tag,
326 return otherIndex - index;
346 template<
bool is_const>
348 public boost::iterator_facade <control_point_iterator_impl<is_const>,
349 std::add_const_if_t<is_const, QPointF>,
350 boost::bidirectional_traversal_tag>
451 it =
m_mesh->endControlPoints();
540 template<
bool is_const>
542 public boost::iterator_facade <segment_iterator_impl<is_const>,
544 boost::bidirectional_traversal_tag,
613 Mesh::ControlType::RightControl :
614 Mesh::ControlType::BottomControl));
620 Mesh::ControlType::LeftControl :
621 Mesh::ControlType::TopControl));
633 const qreal
eps = 1e-3;
718 :
Mesh(QRectF(0.0, 0.0, 1.0, 1.0))
722 Mesh(
const QRectF &mapRect,
const QSize &
size = QSize(2,2))
726 const qreal xControlOffset = 0.2 * (mapRect.width() /
size.width());
727 const qreal yControlOffset = 0.2 * (mapRect.height() /
size.height());
729 for (
int row = 0; row <
m_size.height(); row++) {
730 const qreal yPos = qreal(row) / (
size.height() - 1) * mapRect.height() + mapRect.y();
732 for (
int col = 0; col <
m_size.width(); col++) {
733 const qreal xPos = qreal(col) / (
size.width() - 1) * mapRect.width() + mapRect.x();
736 node.setLeftControlRelative(QPointF(-xControlOffset, 0));
737 node.setRightControlRelative(QPointF(xControlOffset, 0));
738 node.setTopControlRelative(QPointF(0, -yControlOffset));
739 node.setBottomControlRelative(QPointF(0, yControlOffset));
745 for (
int col = 0; col <
m_size.width(); col++) {
749 for (
int row = 0; row <
m_size.height(); row++) {
750 m_rows.push_back(qreal(row) / (
size.height() - 1));
773 return node(index.x(), index.y());
777 return node(index.x(), index.y());
785 auto existing = std::find(
m_rows.begin(),
m_rows.end(), proportionalT);
786 if (existing !=
m_rows.end()) {
791 const auto it = prev(upper_bound(
m_rows.begin(),
m_rows.end(), proportionalT));
793 const qreal relT = (proportionalT - *it) / (*next(it) - *it);
799 const auto it =
m_rows.begin() + topRow;
800 const int bottomRow = topRow + 1;
803 std::vector<Node> newRow;
804 newRow.resize(
m_size.width());
805 for (
int col = 0; col <
m_size.width(); col++) {
808 node(col, topRow).bottomControl,
809 node(col, bottomRow).topControl,
818 newRow.begin(), newRow.end());
821 auto insertedIt =
m_rows.insert(next(it), absProportionalT);
838 const qreal relT = (proportionalT - *it) / (*next(it) - *it);
844 const auto it =
m_columns.begin() + leftColumn;
845 const int rightColumn = leftColumn + 1;
848 std::vector<Node> newColumn;
849 newColumn.resize(
m_size.height());
850 for (
int row = 0; row <
m_size.height(); row++) {
853 node(leftColumn, row).rightControl,
854 node(rightColumn, row).leftControl,
862 auto dstIt =
m_nodes.begin() + rightColumn;
863 for (
auto columnIt = newColumn.begin(); columnIt != newColumn.end(); ++columnIt) {
864 dstIt =
m_nodes.insert(dstIt, *columnIt);
865 dstIt +=
m_size.width() + 1;
869 auto insertedIt =
m_columns.insert(next(it), absProportionalT);
874 const bool hasNeighbours = column > 0 || column <
m_size.width() - 1;
877 for (
int row = 0; row <
m_size.height(); row++) {
882 auto it =
m_nodes.begin() + column;
883 for (
int row = 0; row <
m_size.height(); row++) {
893 const bool hasNeighbours = row > 0 || row <
m_size.height() - 1;
896 for (
int column = 0; column <
m_size.width(); column++) {
917 auto it =
find(index);
920 if (it.isHorizontal()) {
934 const Node &tr =
node(col + 1, row);
935 const Node &bl =
node(col, row + 1);
936 const Node &br =
node(col + 1, row + 1);
940 patch.points[Patch::TL] = tl.
node;
941 patch.points[Patch::TL_HC] = tl.rightControl;
942 patch.points[Patch::TL_VC] = tl.bottomControl;
944 patch.points[Patch::TR] = tr.
node;
945 patch.points[Patch::TR_HC] = tr.leftControl;
946 patch.points[Patch::TR_VC] = tr.bottomControl;
948 patch.points[Patch::BL] = bl.
node;
949 patch.points[Patch::BL_HC] = bl.rightControl;
950 patch.points[Patch::BL_VC] = bl.topControl;
952 patch.points[Patch::BR] = br.
node;
953 patch.points[Patch::BR_HC] = br.leftControl;
954 patch.points[Patch::BR_VC] = br.topControl;
1027 result |= it->dstBoundingRect();
1034 return *
this == identityMesh;
1039 it->translate(offset);
1065 qreal minDistance = std::numeric_limits<qreal>::max();
1069 qreal foundDistance = 0.0;
1072 if (foundDistance < minDistance && foundDistance < distanceThreshold) {
1074 minDistance = foundDistance;
1081 return result.segmentIndex();
1084 template <
typename T>
1092 std::vector<int> insertedIndexes;
1094 for (
int i = 1; i < numColumns - 1; i++) {
1095 const qreal pos = qreal(i) / (numColumns - 1);
1099 insertedIndexes.push_back(inserted);
1102 for (
int i =
m_columns.size() - 2; i >= 1; i--) {
1103 if (std::find(insertedIndexes.begin(), insertedIndexes.end(), i) == insertedIndexes.end()) {
1112 std::vector<int> insertedIndexes;
1114 for (
int i = 1; i < numRows - 1; i++) {
1115 const qreal pos = qreal(i) / (numRows - 1);
1119 insertedIndexes.push_back(inserted);
1122 for (
int i =
m_rows.size() - 2; i >= 1; i--) {
1123 if (std::find(insertedIndexes.begin(), insertedIndexes.end(), i) == insertedIndexes.end()) {
1139 left.rightControl =
p1;
1140 newNode.leftControl =
p2;
1142 newNode.rightControl =
q1;
1143 right.leftControl =
q2;
1145 newNode.topControl = newNode.
node +
lerp(left.topControl - left.
node, right.topControl - right.
node, t);
1146 newNode.bottomControl = newNode.
node +
lerp(left.bottomControl - left.
node, right.bottomControl - right.
node, t);
1160 top.bottomControl =
p1;
1161 newNode.topControl =
p2;
1163 newNode.bottomControl =
q1;
1164 bottom.topControl =
q2;
1166 newNode.leftControl = newNode.
node +
lerp(top.leftControl - top.
node, bottom.leftControl - bottom.
node, t);
1167 newNode.rightControl = newNode.
node +
lerp(top.rightControl - top.
node, bottom.rightControl - bottom.
node, t);
1174 std::tie(left.rightControl, right.leftControl) =
1177 right.leftControl, right.
node);
1182 std::tie(top.bottomControl, bottom.topControl) =
1185 bottom.topControl, bottom.
node);
1189 const qreal distanceThresholdSq =
pow2(distanceThreshold);
1192 qreal minDistanceSq = std::numeric_limits<qreal>::max();
1195 if (onlyNodeMode != (it.type() == ControlType::Node))
continue;
1198 if (distSq < minDistanceSq && distSq < distanceThresholdSq) {
1200 minDistanceSq = distSq;
1204 return result.controlIndex();
1208 template <
class MeshType,
1209 class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1213 return it.isValid() ? it : mesh.endControlPoints();
1216 template <
class MeshType,
1217 class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1220 IteratorType it(&mesh, index.x(), index.y(), Mesh::ControlType::Node);
1221 return it.isValid() ? it : mesh.endControlPoints();
1224 template <
class MeshType,
1225 class IteratorType = segment_iterator_impl<std::is_const<MeshType>::value>>
1228 IteratorType it(&mesh, index.first.x(), index.first.y(), index.second);
1229 return it.isValid() ? it : mesh.endSegments();
1232 template <
class MeshType,
1233 class IteratorType = patch_iterator_impl<std::is_const<MeshType>::value>>
1236 IteratorType it(&mesh, index.x(), index.y());
1237 return it.isValid() ? it : mesh.endPatches();
1240 template <
class MeshType,
1241 class IteratorType = patch_iterator_impl<std::is_const<MeshType>::value>>
1244 return IteratorType(&mesh, 0, 0);
1247 template <
class MeshType,
1248 class IteratorType = patch_iterator_impl<std::is_const<MeshType>::value>>
1251 return IteratorType(&mesh, 0, mesh.m_size.height() - 1);
1254 template <
class MeshType,
1255 class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1258 return IteratorType(&mesh, 0, 0, ControlType::RightControl);
1261 template <
class MeshType,
1262 class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1265 return IteratorType(&mesh, 0, mesh.m_size.height(), 0);
1268 template <
class MeshType,
1269 class IteratorType = segment_iterator_impl<std::is_const<MeshType>::value>>
1272 return IteratorType(&mesh, 0, 0, 0);
1275 template <
class MeshType,
1276 class IteratorType = segment_iterator_impl<std::is_const<MeshType>::value>>
1279 return IteratorType(&mesh, 0, mesh.m_size.height(), 0);
1292template<
typename Node,
typename Patch>
1295 dbg.nospace() <<
"Mesh " << mesh.
size() <<
"\n";
1297 for (
int y = 0; y < mesh.
size().height(); y++) {
1298 for (
int x = 0; x < mesh.
size().width(); x++) {
1299 dbg.nospace() <<
" node(" << x <<
", " << y <<
") " << mesh.
node(x, y) <<
"\n";
1305template<
typename NodeArg,
typename PatchArg>
1306template<
bool is_const>
1307typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType
1314template<
typename NodeArg,
typename PatchArg>
1315template<
bool is_const>
1323template<
typename NodeArg,
typename PatchArg>
1324template<
bool is_const>
1332template<
typename NodeArg,
typename PatchArg>
1333template<
bool is_const>
1341template<
typename NodeArg,
typename PatchArg>
1342template<
bool is_const>
1350template<
typename NodeArg,
typename PatchArg>
1351template<
bool is_const>
1359template<
typename NodeArg,
typename PatchArg>
1360template<
bool is_const>
1368template<
typename NodeArg,
typename PatchArg>
1369template<
bool is_const>
1378template<
typename NodeArg,
typename PatchArg>
1379template<
bool is_const>
1385 if (isTopBorder()) {
1386 return m_mesh->endSegments();
1392template<
typename NodeArg,
typename PatchArg>
1393template<
bool is_const>
1399 if (isBottomBorder()) {
1400 return m_mesh->endSegments();
1406template<
typename NodeArg,
typename PatchArg>
1407template<
bool is_const>
1413 if (isLeftBorder()) {
1414 return m_mesh->endSegments();
1420template<
typename NodeArg,
typename PatchArg>
1421template<
bool is_const>
1427 if (isRightBorder()) {
1428 return m_mesh->endSegments();
1440template<
typename NodeArg,
typename PatchArg>
1443 const QPointF &move,
1445 bool scaleNodeMoves)
1452 auto it = mesh.
find(index);
1458 const QPointF &normalizedOffset) {
1462 const QPointF base1 = it.p3() - it.p0();
1463 const QPointF base2 = it.p3() - it.p0() - normalizedOffset;
1466 const QPointF control = it.p1() - it.p0();
1469 const qreal coeff = dist1 / dist0;
1471 it.p1() = it.p0() + coeff * (control);
1474 const QPointF control = it.p2() - it.p3();
1477 const qreal coeff = dist1 / dist0;
1479 it.p2() = it.p3() + coeff * (control);
1483 if (scaleNodeMoves) {
1484 preAdjustSegment(mesh, it.topSegment(), -move);
1485 preAdjustSegment(mesh, it.leftSegment(), -move);
1486 preAdjustSegment(mesh, it.bottomSegment(), move);
1487 preAdjustSegment(mesh, it.rightSegment(), move);
1490 it.
node().translate(move);
1493 const QPointF newPos = *it + move;
1497 newPos - it.node().node);
1499 R.rotateRadians(rotation);
1501 const QTransform t =
1502 QTransform::fromTranslate(-it.node().node.x(), -it.node().node.y()) *
1504 QTransform::fromTranslate(it.node().node.x(), it.node().node.y());
1507 for (
int intType = 0; intType < 4; intType++) {
1508 ControlType type =
static_cast<ControlType
>(intType);
1510 if (type == ControlType::Node ||
1516 auto neighbourIt = mesh.
find(ControlPointIndex(index.
nodeIndex, type));
1519 *neighbourIt = t.map(*neighbourIt);
1524 *neighbourIt = t.map(*neighbourIt);
1534QDebug
operator<<(QDebug dbg,
const BaseMeshNode &n);
1537void saveValue(QDomElement *parent,
const QString &tag,
const BaseMeshNode &node);
1540bool loadValue(
const QDomElement &parent, BaseMeshNode *node);
1549template <
typename Node,
typename Patch>
float value(const T *src, size_t ch)
Eigen::Matrix< double, 4, 2 > R
qreal distance(const QPointF &p1, const QPointF &p2)
QPointF lerp(const QPointF &p1, const QPointF &p2, qreal t)
void deCasteljau(const std::array< QPointF, 4 > &points, qreal t, QPointF *p1, QPointF *p2, QPointF *p3, QPointF *p4, QPointF *p5)
control_point_iterator_impl()
std::add_const_if_t< is_const, Node > NodeType
bool equal(control_point_iterator_impl const &other) const
Mesh::ControlPointIndex controlIndex() const
bool isBorderNode() const
segment_iterator_impl< is_const > SegmentIteratorType
control_point_iterator_impl(MeshType *mesh, int col, int row, int controlIndex)
SegmentIteratorType topSegment() const
std::add_const_if_t< is_const, Mesh > MeshType
bool isLeftBorder() const
bool isCornerNode() const
bool controlIsValid() const
SegmentIteratorType rightSegment() const
SegmentIteratorType leftSegment() const
control_point_iterator_impl symmetricControl() const
std::add_const_if_t< is_const, QPointF > PointType
Mesh::NodeIndex nodeIndex() const
friend class boost::iterator_core_access
SegmentIteratorType bottomSegment() const
Mesh::ControlType type() const
bool isBottomBorder() const
PointType & dereference() const
bool isRightBorder() const
Mesh::PatchIndex patchIndex() const
SegmentIteratorType segmentQ() const
patch_iterator_impl(MeshType *mesh, int col, int row)
SegmentIteratorType segmentR() const
Patch dereference() const
ControlPointIteratorType nodeTopLeft() const
std::add_const_if_t< is_const, QPointF > PointType
segment_iterator_impl< is_const > SegmentIteratorType
SegmentIteratorType segmentP() const
ControlPointIteratorType nodeBottomLeft() const
friend class boost::iterator_core_access
control_point_iterator_impl< is_const > ControlPointIteratorType
int distance_to(const patch_iterator_impl &z) const
SegmentIteratorType segmentS() const
ControlPointIteratorType nodeBottomRight() const
ControlPointIteratorType nodeTopRight() const
bool equal(patch_iterator_impl const &other) const
std::add_const_if_t< is_const, Mesh > MeshType
NodeType & secondNode() const
ControlPointIteratorType itP3() const
Mesh::NodeIndex firstNodeIndex() const
segment_iterator_impl(MeshType *mesh, int col, int row, int isHorizontal)
Mesh::SegmentIndex segmentIndex() const
ControlPointIteratorType itP2() const
bool isHorizontal() const
QPointF pointAtParam(qreal t) const
ControlPointIteratorType itP0() const
Mesh::SegmentIndex dereference() const
std::add_const_if_t< is_const, Mesh > MeshType
Mesh::NodeIndex secondNodeIndex() const
ControlPointIteratorType itP1() const
NodeType & firstNode() const
friend class boost::iterator_core_access
bool equal(segment_iterator_impl const &other) const
bool controlIsValid() const
std::add_const_if_t< is_const, QPointF > PointType
std::add_const_if_t< is_const, Node > NodeType
control_point_const_iterator find(const NodeIndex &index) const
segment_const_iterator find(const SegmentIndex &index) const
typename ControlPointIndex::ControlType ControlType
void removeColumnOrRow(NodeIndex index, bool row)
Patch makePatch(int col, int row) const
const Node & node(int col, int row) const
patch_const_iterator constBeginPatches() const
Mesh(const QRectF &mapRect, const QSize &size=QSize(2, 2))
control_point_iterator find(const NodeIndex &index)
segment_iterator find(const SegmentIndex &index)
patch_const_iterator endPatches() const
static IteratorType beginPatches(MeshType &mesh)
control_point_const_iterator constFind(const ControlPointIndex &index) const
segment_const_iterator constFind(const SegmentIndex &index) const
void unlinkNodeVertically(Mesh::Node &top, const Mesh::Node &node, Mesh::Node &bottom)
segment_const_iterator constEndSegments() const
std::vector< qreal > m_rows
patch_iterator find(const PatchIndex &index)
static IteratorType find(MeshType &mesh, const ControlPointIndex &index)
QRectF originalRect() const
std::pair< NodeIndex, int > SegmentIndex
patch_iterator endPatches()
void reshapeMeshVertically(int numRows)
control_point_const_iterator constEndControlPoints() const
void splitCurveHorizontally(Node &left, Node &right, qreal t, Node &newNode)
void subdivideSegment(SegmentIndex index, qreal proportionalT)
std::vector< qreal > m_columns
ControlPointIndex hitTestControlPoint(const QPointF &pt, qreal distanceThreshold) const
segment_const_iterator endSegments() const
void transform(const QTransform &t)
void unlinkNodeHorizontally(Mesh::Node &left, const Mesh::Node &node, Mesh::Node &right)
patch_iterator beginPatches()
static IteratorType endPatches(MeshType &mesh)
ControlPointIndex hitTestNode(const QPointF &pt, qreal distanceThreshold) const
segment_const_iterator beginSegments() const
control_point_iterator find(const ControlPointIndex &index)
control_point_const_iterator endControlPoints() const
control_point_const_iterator beginControlPoints() const
segment_const_iterator constBeginSegments() const
bool isIndexValid(const T &index) const
patch_const_iterator constEndPatches() const
static IteratorType find(MeshType &mesh, const PatchIndex &index)
bool operator==(const Mesh &rhs) const
SegmentIndex hitTestSegment(const QPointF &pt, qreal distanceThreshold, qreal *t=0) const
int subdivideRow(int topRow, qreal relProportionalT)
static IteratorType beginSegments(MeshType &mesh)
control_point_const_iterator constBeginControlPoints() const
void transformSrcAndDst(const QTransform &t)
control_point_iterator beginControlPoints()
std::vector< Node > m_nodes
int subdivideColumn(int leftColumn, qreal relProportionalT)
patch_const_iterator beginPatches() const
void translate(const QPointF &offset)
const Node & node(const NodeIndex &index) const
void removeColumn(int column)
static IteratorType endControlPoints(MeshType &mesh)
patch_const_iterator constFind(const PatchIndex &index) const
Patch makePatch(const PatchIndex &index) const
control_point_const_iterator find(const ControlPointIndex &index) const
control_point_iterator endControlPoints()
control_point_const_iterator constFind(const NodeIndex &index) const
ControlPointIndex hitTestPointImpl(const QPointF &pt, qreal distanceThreshold, bool onlyNodeMode) const
void reshapeMeshHorizontally(int numColumns)
static IteratorType beginControlPoints(MeshType &mesh)
void splitCurveVertically(Node &top, Node &bottom, qreal t, Node &newNode)
Node & node(int col, int row)
segment_iterator endSegments()
QRectF dstBoundingRect() const
segment_iterator beginSegments()
Node & node(const NodeIndex &index)
patch_const_iterator find(const PatchIndex &index) const
static IteratorType endSegments(MeshType &mesh)
int subdivideRow(qreal proportionalT)
static IteratorType find(MeshType &mesh, const SegmentIndex &index)
int subdivideColumn(qreal proportionalT)
static IteratorType find(MeshType &mesh, const NodeIndex &index)
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
QPointF relativeToAbsolute(const QPointF &pt, const QRectF &rc)
Point lerp(const Point &pt1, const Point &pt2, qreal t)
qreal angleBetweenVectors(const QPointF &v1, const QPointF &v2)
PointTypeTraits< T >::value_type dotProduct(const T &a, const T &b)
void smartMoveControl(Mesh< NodeArg, PatchArg > &mesh, typename Mesh< NodeArg, PatchArg >::ControlPointIndex index, const QPointF &move, SmartMoveMeshControlMode mode, bool scaleNodeMoves)
KRITAGLOBAL_EXPORT void saveValue(QDomElement *parent, const QString &tag, const BaseMeshNode &node)
QDebug operator<<(QDebug dbg, const Mesh< Node, Patch > &mesh)
void assignPatchData(KisBezierPatch *patch, const QRectF &srcRect, const BaseMeshNode &tl, const BaseMeshNode &tr, const BaseMeshNode &bl, const BaseMeshNode &br)
void lerpNodeData(const BaseMeshNode &left, const BaseMeshNode &right, qreal t, BaseMeshNode &dst)
KRITAGLOBAL_EXPORT bool loadValue(const QDomElement &parent, BaseMeshNode *node)
qreal curveParamByProportion(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal proportion, const qreal error)
void deCasteljau(const QPointF &q0, const QPointF &q1, const QPointF &q2, const QPointF &q3, qreal t, QPointF *p0, QPointF *p1, QPointF *p2, QPointF *p3, QPointF *p4)
QPointF bezierCurve(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t)
qreal nearestPoint(const QList< QPointF > controlPoints, const QPointF &point, qreal *resultDistance, QPointF *resultPoint)
std::pair< QPointF, QPointF > removeBezierNode(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &q1, const QPointF &q2, const QPointF &q3)
Adjusts position for the bezier control points after removing a node.
qreal curveLength(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, const qreal error)
int bezierDegree(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3)
typename copy_const< Src, Dst >::type copy_const_t
typename add_const_if< is_const, T >::type add_const_if_t
QPointF topControlRelative() const
void setRightControlRelative(const QPointF &value)
void translate(const QPointF &offset)
bool operator==(const BaseMeshNode &rhs) const
void setBottomControlRelative(const QPointF &value)
QPointF bottomControlRelative() const
QPointF rightControlRelative() const
void setTopControlRelative(const QPointF &value)
void transform(const QTransform &t)
QPointF leftControlRelative() const
void setLeftControlRelative(const QPointF &value)
BaseMeshNode(const QPointF &_node)
bool isControlPoint() const
QPointF & controlPoint(Mesh::Node &node)
ControlPointIndex(NodeIndex _nodeIndex, ControlType _controlType)
ControlPointIndex()=default
static PointType & controlPoint(NodeType &node, ControlType controlType)
friend bool operator==(const ControlPointIndex &lhs, const ControlPointIndex &rhs)
friend QDebug operator<<(QDebug dbg, const Mesh::ControlPointIndex &index)
NodeIndex & operator+=(const QPoint &rhs)
NodeIndex & operator-=(const QPoint &rhs)
PatchIndex & operator-=(const QPoint &rhs)
PatchIndex & operator+=(const QPoint &rhs)