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 2053 of file kis_algebra_2d.cpp.

2054{
2055 using VPoint = VectorPath::VectorPathPoint;
2056
2058 for (int i = 0; i < path.elementCount(); i++) {
2059 QPainterPath::Element el = path.elementAt(i);
2060 switch(el.type) {
2061 case QPainterPath::MoveToElement:
2062 m_points.append(VPoint(VPoint::MoveTo, el));
2063 break;
2064 case QPainterPath::LineToElement:
2065 m_points.append(VPoint(VPoint::LineTo, el));
2066 break;
2067 case QPainterPath::CurveToDataElement:
2069 break;
2070 case QPainterPath::CurveToElement:
2071 KIS_SAFE_ASSERT_RECOVER(i + 2 < path.elementCount()) { continue; }
2072 KIS_SAFE_ASSERT_RECOVER(path.elementAt(i + 1).type == QPainterPath::CurveToDataElement) { continue; }
2073 KIS_SAFE_ASSERT_RECOVER(path.elementAt(i + 2).type == QPainterPath::CurveToDataElement) { continue; }
2074 // Qt saves the data this way: [control point 1, CurveToElement] [control point 2, CurveToDataElement] [end point, CurveToDataElement]
2075 m_points.append(VPoint(VPoint::BezierTo, path.elementAt(i + 2), el, path.elementAt(i + 1)));
2076 i += 2; // skip next two points
2077 break;
2078 }
2079 }
2080}
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 2082 of file kis_algebra_2d.cpp.

2083{
2084 m_points = path;
2085}

References m_points.

Member Function Documentation

◆ asPainterPath()

QPainterPath KisAlgebra2D::VectorPath::asPainterPath ( ) const

Definition at line 2370 of file kis_algebra_2d.cpp.

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

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 2316 of file kis_algebra_2d.cpp.

2317{
2318 using VPoint = VectorPath::VectorPathPoint;
2319
2320 if (segmentsCount() != path.segmentsCount()) {
2321 return false;
2322 }
2323
2324 bool fuzzy = qFuzzyIsNull(eps);
2325
2326 auto comparePoints = [fuzzy, eps] (QPointF left, QPointF right) {
2327 if (fuzzy) {
2328 return fuzzyPointCompare(left, right);
2329 } else {
2330 return fuzzyPointCompare(left, right, eps);
2331 }
2332 };
2333
2334
2335 VPoint leftStart = path.pointAt(0);
2336 QList<int> rightStartingPoints;
2337 for (int i = 0; i < path.pointsCount(); i++) {
2338 if (comparePoints(leftStart.endPoint, path.pointAt(i).endPoint)) {
2339 rightStartingPoints << i;
2340 }
2341 }
2342
2343 Q_FOREACH(int startId, rightStartingPoints) {
2344 bool isEqual = true;
2345 for (int i = 0; i < pointsCount(); i++) {
2346 int rightId = wrapValue(i + startId, 0, pointsCount());
2347 if (!comparePoints(pointAt(i).endPoint, path.pointAt(rightId).endPoint)) {
2348 isEqual = false;
2349 break;
2350 }
2351 }
2352 if (isEqual) {
2353 return true;
2354 }
2355 for (int i = 0; i < pointsCount(); i++) {
2356 int rightId = wrapValue(startId - i, 0, pointsCount());
2357 if (!comparePoints(pointAt(i).endPoint, path.pointAt(rightId).endPoint)) {
2358 isEqual = false;
2359 break;
2360 }
2361 }
2362 if (isEqual) {
2363 return true;
2364 }
2365 }
2366
2367 return false;
2368}
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 2130 of file kis_algebra_2d.cpp.

2131{
2132 qreal eps = 1e-5;
2133 if (segment.type != VectorPath::VectorPathPoint::BezierTo) {
2134 QLineF segLine = QLineF(segment.startPoint, segment.endPoint);
2135 QPointF intersection;
2136 if (segLine.intersects(line, &intersection) == QLineF::BoundedIntersection) {
2137 return QList<QPointF> {intersection};
2138 } else {
2139 return QList<QPointF>();
2140 }
2141
2142 } else {
2143 QList<QPointF> result;
2144 // check for intersections
2145 QVector<qreal> intersections = KisBezierUtils::intersectWithLine(segment.startPoint, segment.controlPoint1, segment.controlPoint2, segment.endPoint, line, eps);
2146 for (int i = 0; i < intersections.count(); i++) {
2147 QPointF p = KisBezierUtils::bezierCurve(segment.startPoint, segment.controlPoint1, segment.controlPoint2, segment.endPoint, intersections[i]);
2148 bool onLine = isOnLine(line, p, eps, true, true, true);
2149 if (onLine) {
2150 result << p;
2151 }
2152 }
2153
2154 return result;
2155 }
2156
2157}
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 2159 of file kis_algebra_2d.cpp.

2160{
2161 return intersectSegmentWithLineBounded(line, VectorPath::Segment(p1, p2));
2162}
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 2164 of file kis_algebra_2d.cpp.

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

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

◆ pointAt()

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

Definition at line 2092 of file kis_algebra_2d.cpp.

2093{
2094 return m_points[i];
2095}

References m_points.

◆ pointsCount()

int KisAlgebra2D::VectorPath::pointsCount ( ) const

Definition at line 2087 of file kis_algebra_2d.cpp.

2088{
2089 return m_points.length();
2090}

References m_points.

◆ reversed()

VectorPath KisAlgebra2D::VectorPath::reversed ( ) const

Definition at line 2302 of file kis_algebra_2d.cpp.

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

References m_points, and VectorPath().

◆ segmentAt()

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

Definition at line 2102 of file kis_algebra_2d.cpp.

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

References m_points, and segmentsCount().

◆ segmentAtAsLine()

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

Definition at line 2121 of file kis_algebra_2d.cpp.

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

References segmentAt().

◆ segmentAtAsSegment()

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

Definition at line 2112 of file kis_algebra_2d.cpp.

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

References segmentAt().

◆ segmentIndexToPathIndex()

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

Definition at line 2184 of file kis_algebra_2d.cpp.

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

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

◆ segmentsCount()

int KisAlgebra2D::VectorPath::segmentsCount ( ) const

Definition at line 2097 of file kis_algebra_2d.cpp.

2098{
2099 return m_points.length() - 1 >= 0 ? m_points.length() - 1 : 0;
2100}

References m_points.

◆ trulySimplified()

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

Definition at line 2206 of file kis_algebra_2d.cpp.

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