20 const QRectF unitRect(0, 0, 1, 1);
25 if (patch.dstBoundingRect().contains(pt)) {
28 if (unitRect.contains(localPos)) {
30 if (localPointResult) {
31 *localPointResult = localPos;
52 if (searchRect.isEmpty())
return QRect();
57 const auto topItY = prev(upper_bound(
m_rows.begin(), prev(
m_rows.end()), proportionalTL.y()));
60 const auto leftItX = prev(upper_bound(
m_columns.begin(), prev(
m_columns.end()), proportionalTL.x()));
63 const auto bottomItY = prev(upper_bound(
m_rows.begin(), prev(
m_rows.end()), proportionalBR.y()));
66 const auto rightItX = prev(upper_bound(
m_columns.begin(), prev(
m_columns.end()), proportionalBR.x()));
69 return QRect(leftColumn, topRow,
70 rightColumn - leftColumn + 1,
71 bottomRow - topRow + 1);
80 patch.
sampleRegularGrid(gridSize, originalPointsLocal, transformedPointsLocal, QPointF(8,8));
83 const QRect imageSize = QRect(dstQImageOffset, dstImage->size());
94 transformedPointsLocal);
104 patch.
sampleRegularGrid(gridSize, originalPointsLocal, transformedPointsLocal, QPointF(8,8));
114 transformedPointsLocal);
121 transformPatch(*it, srcQImageOffset, srcImage, dstQImageOffset, dstImage);
137 if (sampleRect.isEmpty())
return result;
139 const QRectF unitRect(0, 0, 1, 1);
140 const int samplesLimit = sampleRect.width() * sampleRect.height() / 2;
155 const QRectF dstRect = rc;
159 auto fetchLocalPoint =
167 const qreal totalLength = handleLength +
172 handleLength / totalLength);
175 if (dstRect.contains(patch.
points[controlType])) {
178 switch (controlType) {
183 localPoint = fetchLocalPoint(patch,
191 localPoint = fetchLocalPoint(patch,
201 localPoint = fetchLocalPoint(patch,
208 localPoint = fetchLocalPoint(patch,
219 localPoint = fetchLocalPoint(patch,
226 localPoint = fetchLocalPoint(patch,
236 localPoint = fetchLocalPoint(patch,
243 localPoint = fetchLocalPoint(patch,
284 for (
int i = 0; i < 10; i++) {
285 const QPointF
dstPoint = *dstRectSampler++;
289 if (unitRect.contains(localPoint)) {
309 QRect alignedRect = stepRect.toAlignedRect();
311 if (hitPoints > 20 && !alignedRect.isEmpty() && alignedRect == result) {
315 result = alignedRect;
317 if (dstRectSampler.
numSamples() > qMin(2000, samplesLimit)) {
322 if (!result.isEmpty()) {
323 qWarning() <<
"KisBezierTransformMesh::approxNeedRect: the algorithm hasn't converged!"
339 for (
int row = affectedPatches.top(); row <= affectedPatches.bottom(); row++) {
340 for (
int column = affectedPatches.left(); column <= affectedPatches.right(); column++) {
346 QRect patchResultRect;
350 for (
int i = 0; i < 10; i++) {
351 const QPointF sampledParamPoint = *paramRectSampler++;
352 const QPointF globalPoint = patch.
localToGlobal(sampledParamPoint);
356 const QRect alignedRect = stepRect.toAlignedRect();
358 if (!alignedRect.isEmpty() && alignedRect == patchResultRect) {
362 patchResultRect = alignedRect;
365 qWarning() <<
"KisBezierTransformMesh::approxChangeRect: the algorithm hasn't converged!"
371 result |= patchResultRect;
392 auto xSampler = [sampler] (qreal xParam) -> Range {
393 return sampler.
xRange(xParam);
396 auto ySampler = [sampler] (qreal yParam) -> Range {
397 return sampler.
yRange(yParam);
400 Range externalRangeX;
401 Range internalRangeX;
403 Range externalRangeY;
404 Range internalRangeY;
406 std::tie(externalRangeX, internalRangeX) =
407 calcTightSrcRectRangeInParamSpace1D({0.0, 1.0},
409 Range::fromRectX(srcSpaceRect),
410 xSampler, srcPrecision);
412 std::tie(externalRangeY, internalRangeY) =
413 calcTightSrcRectRangeInParamSpace1D({0.0, 1.0},
415 Range::fromRectY(srcSpaceRect),
416 ySampler, srcPrecision);
418 return Range::makeRectF(externalRangeX, externalRangeY);
425 QDomDocument doc = parent->ownerDocument();
426 QDomElement e = doc.createElement(tag);
427 parent->appendChild(e);
429 e.setAttribute(
"type",
"transform-mesh");
qreal distance(const QPointF &p1, const QPointF &p2)
Mesh::PatchIndex patchIndex() const
std::vector< qreal > m_rows
patch_iterator endPatches()
std::vector< qreal > m_columns
patch_iterator beginPatches()
control_point_iterator find(const ControlPointIndex &index)
std::vector< Node > m_nodes
QRectF dstBoundingRect() const
void sampleRegularGrid(QSize &gridSize, QVector< QPointF > &origPoints, QVector< QPointF > &transfPoints, const QPointF &dstStep) const
QPointF localToGlobal(const QPointF &pt) const
QRectF dstBoundingRect() const
std::array< QPointF, 12 > points
QPointF globalToLocal(const QPointF &pt) const
QRectF srcBoundingRect() const
#define KIS_ASSERT_RECOVER_NOOP(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
QPointF absoluteToRelative(const QPointF &pt, const QRectF &rc)
Point lerp(const Point &pt1, const Point &pt2, qreal t)
void accumulateBounds(const Point &pt, Rect *bounds)
QPointF calculateLocalPos(const std::array< QPointF, 12 > &points, const QPointF &globalPoint)
calculates local (u,v) coordinates of the patch corresponding to globalPoint
std::pair< Range, Range > calcTightSrcRectRangeInParamSpace1D(const Range &searchParamRange, const Range &searchSrcRange, const Range &rect, Func func, qreal srcPrecision, std::optional< Range > squeezeRange=std::nullopt)
bool checkType(const QDomElement &e, const QString &expectedType)
void saveValue(QDomElement *parent, const QString &tag, const QSize &size)
bool loadValue(const QDomElement &e, float *v)
Range xRange(qreal xParam) const
QPointF point(qreal xParam, qreal yParam) const
Range yRange(qreal yParam) const