1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Sub-path Ordering functions for embroidery stitch LPE 4 * 5 * Copyright (C) 2016 Michael Soegtrop 6 * 7 * Released under GNU GPL v2+, read the file 'COPYING' for more information. 8 */ 9 10 #ifndef INKSCAPE_LPE_EMBRODERY_STITCH_ORDERING_H 11 #define INKSCAPE_LPE_EMBRODERY_STITCH_ORDERING_H 12 13 #include "live_effects/effect.h" 14 15 namespace Inkscape { 16 namespace LivePathEffect { 17 namespace LPEEmbroderyStitchOrdering { 18 19 // Structure keeping information on the ordering and reversing of sub paths 20 // Used for simple ordering functions like zig-zag 21 22 struct OrderingInfo { 23 int index; 24 bool reverse; 25 bool used; 26 bool connect; 27 Geom::Point begOrig; // begin point in original orientation 28 Geom::Point endOrig; // end point in original orientation 29 GetBegOrigOrderingInfo30 Geom::Point GetBegOrig() const 31 { 32 return begOrig; 33 } GetEndOrigOrderingInfo34 Geom::Point GetEndOrig() const 35 { 36 return endOrig; 37 } GetBegRevOrderingInfo38 Geom::Point GetBegRev() const 39 { 40 return reverse ? endOrig : begOrig; 41 } GetEndRevOrderingInfo42 Geom::Point GetEndRev() const 43 { 44 return reverse ? begOrig : endOrig; 45 } 46 }; 47 48 // Structure for a path end-point in OrderingInfoEx. 49 // This keeps information about the two nearest neighbor points. 50 51 struct OrderingInfoEx; 52 53 struct OrderingPoint { OrderingPointOrderingPoint54 OrderingPoint(const Geom::Point &pointIn, OrderingInfoEx *infoexIn, bool beginIn) : 55 point(pointIn), 56 infoex(infoexIn), 57 begin(beginIn) 58 { 59 nearest[0] = nearest[1] = nullptr; 60 } 61 62 // Check if both nearest values are valid IsNearestValidOrderingPoint63 bool IsNearestValid() const 64 { 65 return nearest[0] && nearest[1]; 66 } 67 // Check if at least one nearest values are valid HasNearestOrderingPoint68 bool HasNearest() const 69 { 70 return nearest[0] || nearest[1]; 71 } 72 // Find 2 nearest points to given point 73 void FindNearest2(const std::vector<OrderingInfoEx *> &infos); 74 // Check if "this" is among the nearest of its nearest 75 void EnforceMutual(); 76 // Check if the subpath indices of this and other are the same, otherwise zero both nearest 77 void EnforceSymmetric(const OrderingPoint &other); 78 // Dump point information 79 void Dump(); 80 81 Geom::Point point; 82 OrderingInfoEx *infoex; 83 bool begin; 84 const OrderingPoint *nearest[2]; 85 }; 86 87 // Structure keeping information on the ordering and reversing of sub paths 88 // Used for advanced ordering functions with block creation and Traveling Salesman Problem Optimization 89 // A OrderingInfoEx may contain several original sub-paths in case sub-paths are directly connected. 90 // Directly connected sub-paths happen e.g. after a slice boolean operation. 91 92 struct OrderingGroup; 93 94 struct OrderingInfoEx { OrderingInfoExOrderingInfoEx95 OrderingInfoEx(const OrderingInfo &infoIn, int idxIn) : 96 beg(infoIn.begOrig, this, true), 97 end(infoIn.endOrig, this, false), 98 idx(idxIn), 99 grouped(false) 100 { 101 origIndices.push_back(infoIn.index); 102 } 103 104 // If this element can be grouped (has neighbours) but is not yet grouped, create a new group 105 void MakeGroup(std::vector<OrderingInfoEx *> &infos, std::vector<OrderingGroup *> *groups); 106 // Add this and all connected elements to the group 107 void AddToGroup(std::vector<OrderingInfoEx *> &infos, OrderingGroup *group); 108 109 int idx; 110 bool grouped; // true if this element has been grouped 111 OrderingPoint beg; // begin point in original orientation 112 OrderingPoint end; // end point in original orientation 113 std::vector<int> origIndices; // Indices of the original OrderInfos (more than 1 if directly connected 114 }; 115 116 // Neighbor information for OrderingGroupPoint - a distance and a OrderingGroupPoint 117 118 struct OrderingGroupPoint; 119 120 struct OrderingGroupNeighbor { 121 OrderingGroupNeighbor(OrderingGroupPoint *me, OrderingGroupPoint *other); 122 123 // Distance from owner of this neighbor info 124 Geom::Coord distance; 125 // Neighbor point (which in turn contains a pointer to the neighbor group 126 OrderingGroupPoint *point; 127 128 // Comparison function for sorting by distance 129 static bool Compare(const OrderingGroupNeighbor &a, const OrderingGroupNeighbor &b); 130 }; 131 132 // An end point in an OrderingGroup, with nearest neighbor information 133 134 struct OrderingGroupConnection; 135 136 struct OrderingGroupPoint { OrderingGroupPointOrderingGroupPoint137 OrderingGroupPoint(const Geom::Point &pointIn, OrderingGroup *groupIn, int indexIn, bool beginIn, bool frontIn) : 138 point(pointIn), 139 group(groupIn), 140 indexInGroup(indexIn), 141 connection(nullptr), 142 indexInConnection(0), 143 begin(beginIn), 144 front(frontIn), 145 used(false) 146 { 147 } 148 149 // Find the nearest unused neighbor point 150 OrderingGroupNeighbor *FindNearestUnused(); 151 // Return the other end in the group of the point 152 OrderingGroupPoint *GetOtherEndGroup(); 153 // Return the alternate point (if one exists), 0 otherwise 154 OrderingGroupPoint *GetAltPointGroup(); 155 // Sets the rev flags in the group assuming that the group starts with this point 156 void SetRevInGroup(); 157 // Mark an end point as used and also mark the two other alternating points as used 158 // Returns the used point 159 void UsePoint(); 160 // Mark an end point as unused and possibly also mark the two other alternating points as unused 161 // Returns the used point 162 void UnusePoint(); 163 // Return the other end in the connection 164 OrderingGroupPoint *GetOtherEndConnection(); 165 166 // The coordinates of the point 167 Geom::Point point; 168 // The group to which the point belongs 169 OrderingGroup *group; 170 // The end-point index within the group 171 int indexInGroup; 172 // The connection, which connects this point 173 OrderingGroupConnection *connection; 174 // The end point index in the connection 175 int indexInConnection; 176 // True if this is a begin point (rather than an end point) 177 bool begin; 178 // True if this is a front point (rather than a back point) 179 bool front; 180 // True if the point is used/connected to another point 181 bool used; 182 // The nearest neighbors, to which this group end point may connect 183 std::vector<OrderingGroupNeighbor> nearest; 184 }; 185 186 // A connection between two points/groups 187 struct OrderingGroupConnection { OrderingGroupConnectionOrderingGroupConnection188 OrderingGroupConnection(OrderingGroupPoint *fromIn, OrderingGroupPoint *toIn, int indexIn) : 189 index(indexIn) 190 { 191 assert(fromIn->connection == 0); 192 assert(toIn->connection == 0); 193 points[0] = nullptr; 194 points[1] = nullptr; 195 Connect(0, fromIn); 196 Connect(1, toIn); 197 } 198 199 // Connect one of the connection endpoints to the given point ConnectOrderingGroupConnection200 void Connect(int index, OrderingGroupPoint *point) 201 { 202 assert(point); 203 points[index] = point; 204 point->connection = this; 205 point->indexInConnection = index; 206 } 207 208 // Get length of connection DistanceOrderingGroupConnection209 Geom::Coord Distance() 210 { 211 return Geom::distance(points[0]->point, points[1]->point); 212 } 213 214 OrderingGroupPoint *points[2]; 215 // index of connection in the connections vector (just for debugging) 216 int index; 217 }; 218 219 // A group of OrderingInfoEx, which build a block in path interconnect length optimization. 220 // A block can have two sets of endpoints. 221 // If a block has 2 sets of endpoints, one can swap between the two sets. 222 223 struct OrderingGroup { OrderingGroupOrderingGroup224 OrderingGroup(int indexIn) : 225 nEndPoints(0), 226 revItemList(false), 227 revItems(false), 228 index(indexIn) 229 { 230 for (auto & endpoint : endpoints) { 231 endpoint = nullptr; 232 } 233 } 234 ~OrderingGroupOrderingGroup235 ~OrderingGroup() 236 { 237 for (int i = 0; i < nEndPoints; i++) { 238 delete endpoints[i]; 239 } 240 } 241 242 // Set the endpoints of a group from the items 243 void SetEndpoints(); 244 // Add all points from another group as neighbors 245 void AddNeighbors(OrderingGroup *nghb); 246 // Mark an end point as used and also mark the two other alternating points as used 247 // Returns the used point 248 OrderingGroupPoint *UsePoint(int index); 249 // Mark an end point as unused and possibly also mark the two other alternating points as unused 250 // Returns the used point 251 void UnusePoint(int index); 252 253 // Items on the group 254 std::vector<OrderingInfoEx *> items; 255 // End points of the group 256 OrderingGroupPoint *endpoints[4]; 257 // Number of endpoints used (either 2 or 4) 258 int nEndPoints; 259 // Index of the group (just for debugging purposes) 260 int index; 261 // If true, the items in the group shall be output from back to front. 262 bool revItemList; 263 // If false, the individual items are output alternatingly normal-reversed 264 // If true, the individual items are output alternatingly reversed-normal 265 bool revItems; 266 }; 267 268 // A segment is either a OrderingGroup or a series of groups and connections. 269 // Usually a segment has just 2 end points. 270 // If a segment is just one ordering group, it has the same number of end points as the ordering group 271 // A main difference between a segment and a group is that the segment does not own the end points. 272 273 struct OrderingSegment { OrderingSegmentOrderingSegment274 OrderingSegment() : 275 nEndPoints(0), 276 endbit(0), 277 swapbit(0) 278 {} 279 280 // Add an end point 281 void AddPoint(OrderingGroupPoint *point); 282 // Get begin point (taking swap and end bit into account 283 OrderingGroupPoint *GetBeginPoint(unsigned int iSwap, unsigned int iEnd); 284 // Get end point (taking swap and end bit into account 285 OrderingGroupPoint *GetEndPoint(unsigned int iSwap, unsigned int iEnd); 286 287 // End points of the group 288 OrderingGroupPoint *endpoints[4]; 289 // Number of endpoints used (either 2 or 4) 290 int nEndPoints; 291 // bit index in the end counter 292 int endbit; 293 // bit index in the swap counter 294 int swapbit; 295 }; 296 297 298 // Sub-path reordering: do nothing - keep original order 299 void OrderingOriginal(std::vector<OrderingInfo> &infos); 300 301 // Sub-path reordering: reverse every other sub path 302 void OrderingZigZag(std::vector<OrderingInfo> &infos, bool revfirst); 303 304 // Sub-path reordering: continue with the neartest start or end point of yet unused sub paths 305 void OrderingClosest(std::vector<OrderingInfo> &infos, bool revfirst); 306 307 // Global optimization of path length 308 void OrderingAdvanced(std::vector<OrderingInfo> &infos, int nDims); 309 310 } //LPEEmbroderyStitchOrdering 311 } //namespace LivePathEffect 312 } //namespace Inkscape 313 314 #endif 315