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
|
/*****
* flatguide.h
* Andy Hammerlindl 2005/02/23
*
* The data structure that builds up a knotlist. This is done by calling in
* order the methods to set knots, specifiers, and tensions.
* Used by the guide solving routines.
*
* NOTE: figure out how nullpath{}..a should be handled.
*****/
#ifndef FLATGUIDE_H
#define FLATGUIDE_H
#include "knot.h"
#include "guideflags.h"
namespace camp {
class flatguide
{
// A cached solution of the path. When traversing through a tree of guides,
// if a cycle tag is encountered, then the path is solved up to that point.
// If the guide continues from there (which rarely occurs in practice), all of
// the control points solved are added as control specifiers, and then solved
// into a path again. In the (usual) case that a cycle ends a path, the
// cached path avoids this second pass.
bool solved;
// Used by reverse(guide) to indicate the presence of an unresolved
// interior cycle.
bool precycle;
path p;
cvector<knot> nodes;
// Information before the first knot. For a non-cyclic guide, this is
// ignored. For a cyclic guide, it may be useful, but I can't determine a
// sensible way to use it yet.
tension tout;
spec *out;
// Information for the next knot to come.
tension tin;
spec *in;
static spec open;
tension& tref(side s)
{
switch (s) {
case OUT:
return nodes.empty() ? tout : nodes.back().tout;
case IN:
default:
return tin;
}
}
// Returns a reference to a spec* so that it may be assigned.
spec*& sref(side s)
{
switch (s) {
case OUT:
return nodes.empty() ? out : nodes.back().out;
case IN:
default:
return in;
}
}
void addPre(path& p, Int j);
void addPoint(path& p, Int j);
void addPost(path& p, Int j);
void clearNodes() {
nodes.clear();
in=&open;
tin=tension();
}
void clearPath() {
p=path();
solved=false;
}
void uncheckedAdd(path p, bool allowsolve=true);
// Sets solved to false, indicating that the path has been updated since last
// being solved. Also, copies a solved path back in as knots and control
// specifiers, as it will have to be solved again.
void update() {
if (solved) {
solved=false;
clearNodes();
add(p);
clearPath();
}
}
public:
flatguide()
: solved(true), precycle(false), p(), out(&open), in(&open) {}
Int size() const {
return (Int) nodes.size();
}
knot Nodes(Int i) const {
return nodes[i];
}
void setTension(tension t, side s) {
update();
tref(s)=t;
}
void setSpec(spec *p, side s) {
assert(p);
update();
spec *&ref=sref(s);
// Control specifiers trump normal direction specifiers.
if (!ref || !ref->controlled() || p->controlled())
ref=p;
}
void add(pair z) {
update();
// Push the pair onto the vector as a knot, using the current in-specifier
// and in-tension for the in side for the knot. Use default values for the
// out side, as those will be set after the point is added.
nodes.push_back(knot(z,in,&open,tin,tension()));
// Reset the in-spec and in-tension to defaults;
tin=tension();
in=&open;
}
// Reverts to an empty state.
void add(path p, bool allowsolve=true) {
update();
uncheckedAdd(p,allowsolve);
}
void clear() {
clearNodes();
clearPath();
}
void close() {
if(!nodes.empty()) {
nodes.front().in=in;
nodes.front().tin=tin;
}
}
void resolvecycle() {
if(!nodes.empty())
nodes.push_back(nodes.front());
}
void precyclic(bool b) {
precycle=b;
}
bool precyclic() {
return precycle;
}
// Once all information has been added, release the flat result.
simpleknotlist list(bool cycles=false) {
if(cycles && !nodes.empty()) close();
return simpleknotlist(nodes,cycles);
}
// Yield a path from the guide as represented here.
path solve(bool cycles=false) {
if (solved)
return p;
else {
simpleknotlist l=list(cycles);
p=camp::solve(l);
solved=true;
return p;
}
}
};
} // namespace camp
#endif // FLATGUIDE_H
|