diff options
Diffstat (limited to 'Build/source/utils/asymptote/flatguide.h')
-rw-r--r-- | Build/source/utils/asymptote/flatguide.h | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/flatguide.h b/Build/source/utils/asymptote/flatguide.h new file mode 100644 index 00000000000..c4d5c9bce67 --- /dev/null +++ b/Build/source/utils/asymptote/flatguide.h @@ -0,0 +1,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 |