Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAlgebra2D::VectorPath Class Reference

#include <kis_algebra_2d.h>

Classes

struct  Segment
 
struct  VectorPathPoint
 

Public Member Functions

QPainterPath asPainterPath () const
 
bool fuzzyComparePointsCyclic (const VectorPath &path, qreal eps=0.0f) const
 
int pathIndexToSegmentIndex (int index)
 
VectorPathPoint pointAt (int i) const
 
int pointsCount () const
 
VectorPath reversed () const
 
QList< VectorPathPointsegmentAt (int i) const
 
QLineF segmentAtAsLine (int i) const
 
std::optional< SegmentsegmentAtAsSegment (int i) const
 
int segmentIndexToPathIndex (int index)
 
int segmentsCount () const
 
VectorPath trulySimplified (qreal epsDegrees=0.5) const
 
 VectorPath (const QList< VectorPathPoint > path)
 
 VectorPath (const QPainterPath &path)
 

Static Public Member Functions

static QList< QPointF > intersectSegmentWithLineBounded (const QLineF &line, const Segment &segment)
 
static QList< QPointF > intersectSegmentWithLineBounded (const QLineF &line, const VectorPathPoint &p1, const VectorPathPoint &p2)
 

Private Attributes

QPainterPath m_originalPath
 
QList< VectorPathPointm_points
 

Detailed Description

Definition at line 586 of file kis_algebra_2d.h.

Constructor & Destructor Documentation

◆ VectorPath() [1/2]

KisAlgebra2D::VectorPath::VectorPath ( const QPainterPath & path)

Definition at line 2050 of file kis_algebra_2d.cpp.

2051{
2052 using VPoint = VectorPath::VectorPathPoint;
2053
2055 for (int i = 0; i < path.elementCount(); i++) {
2056 QPainterPath::Element el = path.elementAt(i);
2057 switch(el.type) {
2058 case QPainterPath::MoveToElement:
2059 m_points.append(VPoint(VPoint::MoveTo, el));
2060 break;
2061 case QPainterPath::LineToElement:
2062 m_points.append(VPoint(VPoint::LineTo, el));
2063 break;
2064 case QPainterPath::CurveToDataElement:
2066 break;
2067 case QPainterPath::CurveToElement:
2068 KIS_SAFE_ASSERT_RECOVER(i + 2 < path.elementCount()) { continue; }
2069 KIS_SAFE_ASSERT_RECOVER(path.elementAt(i + 1).type == QPainterPath::CurveToDataElement) { continue; }
2070 KIS_SAFE_ASSERT_RECOVER(path.elementAt(i + 2).type == QPainterPath::CurveToDataElement) { continue; }
2071 // Qt saves the data this way: [control point 1, CurveToElement] [control point 2, CurveToDataElement] [end point, CurveToDataElement]
2072 m_points.append(VPoint(VPoint::BezierTo, path.elementAt(i + 2), el, path.elementAt(i + 1)));
2073 i += 2; // skip next two points
2074 break;
2075 }
2076 }
2077}
QList< VectorPathPoint > m_points
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_BREAK(cond)
Definition kis_assert.h:127

References KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_BREAK, and m_points.

◆ VectorPath() [2/2]

KisAlgebra2D::VectorPath::VectorPath ( const QList< VectorPathPoint > path)

Definition at line 2079 of file kis_algebra_2d.cpp.

2080{
2081 m_points = path;
2082}

References m_points.

Member Function Documentation

◆ asPainterPath()

QPainterPath KisAlgebra2D::VectorPath::asPainterPath ( ) const

Definition at line 2367 of file kis_algebra_2d.cpp.

2368{
2369 using VPoint = VectorPath::VectorPathPoint;
2370 if (m_originalPath.elementCount() > 0) {
2371 return m_originalPath;
2372 }
2373 QPainterPath response;
2374 for (int i = 0; i < pointsCount(); i++) {
2375 switch(m_points[i].type) {
2376 case VPoint::MoveTo:
2377 response.moveTo(m_points[i].endPoint);
2378 break;
2379 case VPoint::LineTo:
2380 response.lineTo(m_points[i].endPoint);
2381 break;
2382 case VPoint::BezierTo:
2383 response.cubicTo(m_points[i].controlPoint1, m_points[i].controlPoint2, m_points[i].endPoint);
2384 break;
2385 }
2386 }
2387 response.closeSubpath();
2388 return response;
2389}

References KisAlgebra2D::VectorPath::VectorPathPoint::lineTo(), m_originalPath, m_points, KisAlgebra2D::VectorPath::VectorPathPoint::moveTo(), and pointsCount().

◆ fuzzyComparePointsCyclic()

bool KisAlgebra2D::VectorPath::fuzzyComparePointsCyclic ( const VectorPath & path,
qreal eps = 0.0f ) const

Definition at line 2313 of file kis_algebra_2d.cpp.

2314{
2315 using VPoint = VectorPath::VectorPathPoint;
2316
2317 if (segmentsCount() != path.segmentsCount()) {
2318 return false;
2319 }
2320
2321 bool fuzzy = qFuzzyIsNull(eps);
2322
2323 auto comparePoints = [fuzzy, eps] (QPointF left, QPointF right) {
2324 if (fuzzy) {
2325 return fuzzyPointCompare(left, right);
2326 } else {
2327 return fuzzyPointCompare(left, right, eps);
2328 }
2329 };
2330
2331
2332 VPoint leftStart = path.pointAt(0);
2333 QList<int> rightStartingPoints;
2334 for (int i = 0; i < path.pointsCount(); i++) {
2335 if (comparePoints(leftStart.endPoint, path.pointAt(i).endPoint)) {
2336 rightStartingPoints << i;
2337 }
2338 }
2339
2340 Q_FOREACH(int startId, rightStartingPoints) {
2341 bool isEqual = true;
2342 for (int i = 0; i < pointsCount(); i++) {
2343 int rightId = wrapValue(i + startId, 0, pointsCount());
2344 if (!comparePoints(pointAt(i).endPoint, path.pointAt(rightId).endPoint)) {
2345 isEqual = false;
2346 break;
2347 }
2348 }
2349 if (isEqual) {
2350 return true;
2351 }
2352 for (int i = 0; i < pointsCount(); i++) {
2353 int rightId = wrapValue(startId - i, 0, pointsCount());
2354 if (!comparePoints(pointAt(i).endPoint, path.pointAt(rightId).endPoint)) {
2355 isEqual = false;
2356 break;
2357 }
2358 }
2359 if (isEqual) {
2360 return true;
2361 }
2362 }
2363
2364 return false;
2365}
VectorPathPoint pointAt(int i) const
static bool qFuzzyIsNull(half h)
const qreal eps
T wrapValue(T value, T wrapBounds)
bool fuzzyPointCompare(const QPointF &p1, const QPointF &p2)

References KisAlgebra2D::VectorPath::VectorPathPoint::endPoint, eps, KisAlgebra2D::fuzzyPointCompare(), pointAt(), pointsCount(), qFuzzyIsNull(), segmentsCount(), and KisAlgebra2D::wrapValue().

◆ intersectSegmentWithLineBounded() [1/2]

QList< QPointF > KisAlgebra2D::VectorPath::intersectSegmentWithLineBounded ( const QLineF & line,
const Segment & segment )
static

Definition at line 2127 of file kis_algebra_2d.cpp.

2128{
2129 qreal eps = 1e-5;
2130 if (segment.type != VectorPath::VectorPathPoint::BezierTo) {
2131 QLineF segLine = QLineF(segment.startPoint, segment.endPoint);
2132 QPointF intersection;
2133 if (segLine.intersects(line, &intersection) == QLineF::BoundedIntersection) {
2134 return QList<QPointF> {intersection};
2135 } else {
2136 return QList<QPointF>();
2137 }
2138
2139 } else {
2140 QList<QPointF> result;
2141 // check for intersections
2142 QVector<qreal> intersections = KisBezierUtils::intersectWithLine(segment.startPoint, segment.controlPoint1, segment.controlPoint2, segment.endPoint, line, eps);
2143 for (int i = 0; i < intersections.count(); i++) {
2144 QPointF p = KisBezierUtils::bezierCurve(segment.startPoint, segment.controlPoint1, segment.controlPoint2, segment.endPoint, intersections[i]);
2145 bool onLine = isOnLine(line, p, eps, true, true, true);
2146 if (onLine) {
2147 result << p;
2148 }
2149 }
2150
2151 return result;
2152 }
2153
2154}
const Params2D p
bool isOnLine(const QLineF &line, const QPointF &point, const qreal eps, bool boundedStart, bool boundedEnd, bool includeEnds)
QVector< qreal > intersectWithLine(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QLineF &line, qreal eps)
QPointF bezierCurve(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t)

References KisBezierUtils::bezierCurve(), KisAlgebra2D::VectorPath::VectorPathPoint::BezierTo, KisAlgebra2D::VectorPath::Segment::controlPoint1, KisAlgebra2D::VectorPath::Segment::controlPoint2, KisAlgebra2D::VectorPath::Segment::endPoint, eps, KisBezierUtils::intersectWithLine(), KisAlgebra2D::isOnLine(), p, KisAlgebra2D::VectorPath::Segment::startPoint, and KisAlgebra2D::VectorPath::Segment::type.

◆ intersectSegmentWithLineBounded() [2/2]

QList< QPointF > KisAlgebra2D::VectorPath::intersectSegmentWithLineBounded ( const QLineF & line,
const VectorPathPoint & p1,
const VectorPathPoint & p2 )
static

Definition at line 2156 of file kis_algebra_2d.cpp.

2157{
2158 return intersectSegmentWithLineBounded(line, VectorPath::Segment(p1, p2));
2159}
QPointF p2
QPointF p1
static QList< QPointF > intersectSegmentWithLineBounded(const QLineF &line, const Segment &segment)

References intersectSegmentWithLineBounded(), p1, and p2.

◆ pathIndexToSegmentIndex()

int KisAlgebra2D::VectorPath::pathIndexToSegmentIndex ( int index)

Definition at line 2161 of file kis_algebra_2d.cpp.

2162{
2163 // first should be MoveTo
2164 int pathIndex = 0;
2165 for (int i = 1; i < m_points.length(); i++) {
2166 if (index < pathIndex) {
2167 // it was the previous segment, it's just a control point
2168 return i - 1;
2169 }
2170 if (index == pathIndex) {
2171 return i - 1;
2172 }
2173 if (m_points[i].type == VectorPathPoint::BezierTo) {
2174 pathIndex += 2; // add space for control points
2175 }
2176 pathIndex++;
2177 }
2178 return m_points.length() - 1;
2179}

References KisAlgebra2D::VectorPath::VectorPathPoint::BezierTo, and m_points.

◆ pointAt()

VectorPath::VectorPathPoint KisAlgebra2D::VectorPath::pointAt ( int i) const

Definition at line 2089 of file kis_algebra_2d.cpp.

2090{
2091 return m_points[i];
2092}

References m_points.

◆ pointsCount()

int KisAlgebra2D::VectorPath::pointsCount ( ) const

Definition at line 2084 of file kis_algebra_2d.cpp.

2085{
2086 return m_points.length();
2087}

References m_points.

◆ reversed()

VectorPath KisAlgebra2D::VectorPath::reversed ( ) const

Definition at line 2299 of file kis_algebra_2d.cpp.

2300{
2301 using VPoint = VectorPath::VectorPathPoint;
2302 QList<VPoint> response;
2303 response.append(VPoint(VPoint::MoveTo, m_points[m_points.length() - 1].endPoint));
2304 for (int i = m_points.length() - 1; i > 0; i--) {
2305 // to reverse a segment, we take the end VPoint and change the .endPoint to the start VPoint coords
2306 VPoint point = m_points[i];
2307 point.endPoint = m_points[i - 1].endPoint;
2308 response.append(point);
2309 }
2310 return VectorPath(response);
2311}
VectorPath(const QPainterPath &path)

References m_points, and VectorPath().

◆ segmentAt()

QList< VectorPath::VectorPathPoint > KisAlgebra2D::VectorPath::segmentAt ( int i) const

Definition at line 2099 of file kis_algebra_2d.cpp.

2100{
2102 if (i < 0 || i >= segmentsCount()) {
2103 return response;
2104 }
2105 response << m_points[i] << m_points[i + 1];
2106 return response;
2107}

References m_points, and segmentsCount().

◆ segmentAtAsLine()

QLineF KisAlgebra2D::VectorPath::segmentAtAsLine ( int i) const

Definition at line 2118 of file kis_algebra_2d.cpp.

2119{
2121 if (points.length() < 1) {
2122 return QLineF();
2123 }
2124 return QLineF(points[0].endPoint, points[1].endPoint);
2125}
QList< VectorPathPoint > segmentAt(int i) const

References segmentAt().

◆ segmentAtAsSegment()

std::optional< VectorPath::Segment > KisAlgebra2D::VectorPath::segmentAtAsSegment ( int i) const

Definition at line 2109 of file kis_algebra_2d.cpp.

2110{
2112 if (segment.count() == 2) {
2113 return VectorPath::Segment(segment[0], segment[1]);
2114 }
2115 return std::nullopt;
2116}

References segmentAt().

◆ segmentIndexToPathIndex()

int KisAlgebra2D::VectorPath::segmentIndexToPathIndex ( int index)

Definition at line 2181 of file kis_algebra_2d.cpp.

2182{
2183 // first should be MoveTo
2184 int pathIndex = 0;
2185 for (int i = 1; i < m_points.length(); i++) {
2186 if (i - 1 == index) {
2187 if (m_points[i - 1].type == VectorPathPoint::BezierTo) {
2188 return pathIndex - 2;
2189 }
2190 return pathIndex;
2191 }
2192 if (m_points[i].type == VectorPathPoint::BezierTo) {
2193 pathIndex += 2; // add space for control points
2194 }
2195 pathIndex++;
2196 }
2197 if (m_points.length() > 0 && m_points[m_points.length() - 1].type == VectorPathPoint::BezierTo) {
2198 return pathIndex - 2;
2199 }
2200 return pathIndex;
2201}

References KisAlgebra2D::VectorPath::VectorPathPoint::BezierTo, and m_points.

◆ segmentsCount()

int KisAlgebra2D::VectorPath::segmentsCount ( ) const

Definition at line 2094 of file kis_algebra_2d.cpp.

2095{
2096 return m_points.length() - 1 >= 0 ? m_points.length() - 1 : 0;
2097}

References m_points.

◆ trulySimplified()

VectorPath KisAlgebra2D::VectorPath::trulySimplified ( qreal epsDegrees = 0.5) const

Definition at line 2203 of file kis_algebra_2d.cpp.

2204{
2205 qreal eps = kisDegreesToRadians(epsDegrees);
2206
2207
2208 using VPoint = VectorPath::VectorPathPoint;
2209
2210 if (m_points.length() < 1) {
2212 }
2213
2214 QList<VPoint> response;
2215 VPoint lineBeginPoint = VPoint(VPoint::MoveTo, QPointF(0, 0));
2216 VPoint previousPoint = m_points[0];
2217
2218
2219 //qreal eps = 1e-05;
2220 auto onTheLine = [eps] (QPointF start, QPointF middle, QPointF end) {
2221 QLineF line1(start, end);
2222 QLineF line2(start, middle);
2223
2224 return (qAbs(crossProduct(end - start, middle - start)/line1.length()/line2.length()) < eps);
2225 };
2226
2227 for (int i = 1; i < m_points.length(); i++) {
2228 if (m_points[i].type == VPoint::MoveTo) {
2229 if (previousPoint.type == VPoint::MoveTo) {
2230 previousPoint = m_points[i]; // let's skip the previous point since they're both just moving
2231 continue;
2232 } else { // LineTo or BezierTo, both need to be added
2233 response << previousPoint;
2234 previousPoint = m_points[i];
2235 continue;
2236 }
2237 } else if (m_points[i].type == VPoint::LineTo) {
2238 if (previousPoint.type == VPoint::LineTo) {
2239 // check whether they're parallel
2240 if (!onTheLine(lineBeginPoint.endPoint, previousPoint.endPoint, m_points[i].endPoint)) {
2241 response << previousPoint;
2242 lineBeginPoint = previousPoint;
2243 }
2244 previousPoint = m_points[i]; // let's skip the previous point since they're parallel
2245 continue;
2246 } else { // MoveTo or BezierTo, both need to be added
2247 response << previousPoint;
2248 lineBeginPoint = previousPoint;
2249 previousPoint = m_points[i];
2250 continue;
2251 }
2252 } else { // currently in BezierTo
2253 response << previousPoint;
2254 previousPoint = m_points[i];
2255 continue;
2256 }
2257 }
2258 response << previousPoint;
2259
2260 // now eliminate additional point at the beginning of the shape if it's in the middle of a line
2261 // and wasn't simplified only because it's at the beginning
2262
2263 if (response.length() < 3) {
2264 return VectorPath(response);
2265 }
2266
2267 VPoint start = response[0];
2268 VPoint second = response[1];
2269
2270 if (start.type == VPoint::MoveTo) {
2271 if (fuzzyPointCompare(previousPoint.endPoint, start.endPoint)) {
2272 // they are the same point, now whether they're on the line
2273 if (second.type == VPoint::LineTo && onTheLine(response[response.length()-2].endPoint, start.endPoint, second.endPoint)) {
2274 response.pop_front();
2275 response[0].type = VPoint::MoveTo;
2276 response[response.length() - 1].endPoint = second.endPoint;
2277 }
2278 }
2279
2280 } else if (response[0].type == VPoint::LineTo) { // first point is then QPointF(0, 0)
2281 if (qFuzzyIsNull(previousPoint.endPoint.x()) && qFuzzyIsNull(previousPoint.endPoint.y())) {
2282 // they are the same point, now whether they're on the line
2283 if (second.type == VPoint::LineTo && onTheLine(previousPoint.endPoint, QPointF(0, 0), start.endPoint)) {
2284 // note: leaving this debug for future reference
2285 qCritical() << "We're in this case";
2286 //response.pop_front();
2287 //response[0].type = VPoint::MoveTo;
2288 //response[response.length() - 1].endPoint = start.endPoint;
2289 }
2290 }
2291 }
2292
2293
2294
2295
2296 return VectorPath(response);
2297}
T kisDegreesToRadians(T degrees)
Definition kis_global.h:176
PointTypeTraits< T >::value_type crossProduct(const T &a, const T &b)

References KisAlgebra2D::crossProduct(), eps, KisAlgebra2D::fuzzyPointCompare(), kisDegreesToRadians(), m_points, qFuzzyIsNull(), and VectorPath().

Member Data Documentation

◆ m_originalPath

QPainterPath KisAlgebra2D::VectorPath::m_originalPath
private

Definition at line 687 of file kis_algebra_2d.h.

◆ m_points

QList<VectorPathPoint> KisAlgebra2D::VectorPath::m_points
private

Definition at line 688 of file kis_algebra_2d.h.


The documentation for this class was generated from the following files: