-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoptimizer.cpp
More file actions
183 lines (147 loc) · 5.05 KB
/
optimizer.cpp
File metadata and controls
183 lines (147 loc) · 5.05 KB
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
#include "optimizer.h"
#include "codeblock.h"
#include "virtualmachine.h"
#include "move.h"
Optimizer::Optimizer(QList<CodeBlock*> original) :
_hasDiagonals(false),
_numLayers(0)
{
// Deep copy the original list
for(int i=0; i<original.size(); i++)
{
CodeBlock* old = original.at(i);
CodeBlock* neu = new CodeBlock(old);
_original.append(neu);
// Run the blocks through the virtual machine as we do this
_vm.doBlock(neu);
}
// And now let's organize the moves into layers
for (int i=0; i<_vm._moves.size(); i++)
{
Move* move = _vm._moves.at(i);
// If all 3 axis change, that is whack
if (!move->isZOnly() && move->changesZ()) _hasDiagonals = true;
// Find a layer to put this in
double z = move->_start._z;
QList<Move*>* layer = _layers.value(z);
if (!layer)
{
layer = new QList<Move*>();
_layers[z] = layer;
_numLayers++;
}
layer->append(move);
}
}
Optimizer::~Optimizer()
{
QList< QList<Move*>* > all = _layers.values();
for(int i=0; i<all.size(); i++)
{
QList<Move*>* layer = all.at(i);
delete layer;
}
for(int i=0; i<_original.size(); i++)
{
delete _original.at(i);
}
}
const QList<double>
Optimizer::layerZs() const
{
QList<double> list;
return _layers.keys();
}
// Everything above limit will be ignored and turned into moves that happen
// at safeLevel. Assuming the different layers below limit are different things
// i.e. one is lines and another is drills, we will do them in order from high
// to low, each time returning to safeLevel between lines.
QList<Word*>
Optimizer::optimize(double limit, double safeLevel, double plungeRate, double retractRate, double drawRate)
{
QList<Word*> out;
Word* cmd;
// Starting position is at 0,0,safeLevel from an analysis standpoint.
// The first move will be to x,y,safe of the first plunge
// Start with absolute coords
out.append(new Word('G',90));
// Move to the safe level
cmd = new Word('G',0);
cmd->addParameter(new Word('Z',INT_MAX,safeLevel));
out.append(cmd);
// Track x,y location
Position location;
// Iterate down through the layers ignoring anything above limit
QList<double> keys = _layers.keys();
for(int keyIx=0; keyIx<keys.size(); keyIx++)
{
double layerZ = keys.at(keyIx);
if (layerZ > limit) continue;
// Okay it's a layer we care about
QList<Move*> *layer = _layers.value(layerZ);
//if (!layer) continue; // weird...
// Duplicate the layer so we can pop things out of it
QList<Move*> dupe;
for(int i=0; i<layer->size(); i++)
{
dupe.append(layer->at(i));
}
// For each move that occurs within this layer, assume we start at safe level
// That means for each move in the layer we move to start of layer move, plunge, do layer move, retract
// The secret is to keep finding the closest layer move until we are done
Move* move = popClosestMove(*layer, location);
while(move)
{
// Okay, we have a move, which starts somewhere other than where we are, so fast move
// to above it.
cmd = new Word('G',0);
cmd->addParameter(new Word('X',INT_MAX,move->_start._x));
cmd->addParameter(new Word('Y',INT_MAX,move->_start._y));
out.append(cmd);
// Plunge down to the z depth of the current layer
cmd = new Word('G',1);
cmd->addParameter(new Word('Z',INT_MAX,layerZ));
cmd->addParameter(new Word('F',INT_MAX,plungeRate));
out.append(cmd);
// Do the move, proper rate, absolute. Nuke Z though
cmd = move->getCommand(drawRate, true);
cmd->removeParameter(QChar('Z'));
out.append(cmd);
// Update our location with the end of this move
cmd->parameterAsDouble(QChar('X'),&location._x);
cmd->parameterAsDouble(QChar('Y'),&location._y);
// Retract back to safe layer
cmd = new Word('G',1);
cmd->addParameter(new Word('Z',INT_MAX,safeLevel));
cmd->addParameter(new Word('F',INT_MAX,retractRate));
out.append(cmd);
// And iterate to the next move
move = popClosestMove(*layer, location);
}
// No more moves, so time to iterate to next layer down
}
// And that's it - awesome!
return out;
}
Move*
Optimizer::popClosestMove(QList<Move*>& layer, Position& loc)
{
double minDistance = DBL_MAX;
Move* move = NULL;
// Brute force bitches!!!
for(int i=0; i<layer.size(); i++)
{
Move* candidate = layer.at(i);
double distance = candidate->_start.distanceFrom(loc);
if (distance < minDistance)
{
minDistance = distance;
move = candidate;
}
}
if (move)
{
layer.removeAll(move);
}
return move;
}