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