1 /***** 2 * flatguide.h 3 * Andy Hammerlindl 2005/02/23 4 * 5 * The data structure that builds up a knotlist. This is done by calling in 6 * order the methods to set knots, specifiers, and tensions. 7 * Used by the guide solving routines. 8 * 9 * NOTE: figure out how nullpath{}..a should be handled. 10 *****/ 11 12 #ifndef FLATGUIDE_H 13 #define FLATGUIDE_H 14 15 #include "knot.h" 16 #include "guideflags.h" 17 18 namespace camp { 19 20 class flatguide 21 { 22 // A cached solution of the path. When traversing through a tree of guides, 23 // if a cycle tag is encountered, then the path is solved up to that point. 24 // If the guide continues from there (which rarely occurs in practice), all of 25 // the control points solved are added as control specifiers, and then solved 26 // into a path again. In the (usual) case that a cycle ends a path, the 27 // cached path avoids this second pass. 28 bool solved; 29 30 // Used by reverse(guide) to indicate the presence of an unresolved 31 // interior cycle. 32 bool precycle; 33 34 path p; 35 36 cvector<knot> nodes; 37 38 // Information before the first knot. For a non-cyclic guide, this is 39 // ignored. For a cyclic guide, it may be useful, but I can't determine a 40 // sensible way to use it yet. 41 tension tout; 42 spec *out; 43 44 // Information for the next knot to come. 45 tension tin; 46 spec *in; 47 48 static spec open; 49 tref(side s)50 tension& tref(side s) 51 { 52 switch (s) { 53 case OUT: 54 return nodes.empty() ? tout : nodes.back().tout; 55 case IN: 56 default: 57 return tin; 58 } 59 } 60 61 // Returns a reference to a spec* so that it may be assigned. sref(side s)62 spec*& sref(side s) 63 { 64 switch (s) { 65 case OUT: 66 return nodes.empty() ? out : nodes.back().out; 67 case IN: 68 default: 69 return in; 70 } 71 } 72 73 void addPre(path& p, Int j); 74 void addPoint(path& p, Int j); 75 void addPost(path& p, Int j); 76 clearNodes()77 void clearNodes() { 78 nodes.clear(); 79 in=&open; 80 tin=tension(); 81 } clearPath()82 void clearPath() { 83 p=path(); 84 solved=false; 85 } 86 87 void uncheckedAdd(path p, bool allowsolve=true); 88 89 // Sets solved to false, indicating that the path has been updated since last 90 // being solved. Also, copies a solved path back in as knots and control 91 // specifiers, as it will have to be solved again. update()92 void update() { 93 if (solved) { 94 solved=false; 95 clearNodes(); 96 add(p); 97 clearPath(); 98 } 99 } 100 101 public: flatguide()102 flatguide() 103 : solved(true), precycle(false), p(), out(&open), in(&open) {} 104 size()105 Int size() const { 106 return (Int) nodes.size(); 107 } 108 Nodes(Int i)109 knot Nodes(Int i) const { 110 return nodes[i]; 111 } 112 setTension(tension t,side s)113 void setTension(tension t, side s) { 114 update(); 115 tref(s)=t; 116 } setSpec(spec * p,side s)117 void setSpec(spec *p, side s) { 118 assert(p); 119 update(); 120 spec *&ref=sref(s); 121 // Control specifiers trump normal direction specifiers. 122 if (!ref || !ref->controlled() || p->controlled()) 123 ref=p; 124 } 125 add(pair z)126 void add(pair z) { 127 update(); 128 // Push the pair onto the vector as a knot, using the current in-specifier 129 // and in-tension for the in side for the knot. Use default values for the 130 // out side, as those will be set after the point is added. 131 nodes.push_back(knot(z,in,&open,tin,tension())); 132 133 // Reset the in-spec and in-tension to defaults; 134 tin=tension(); 135 in=&open; 136 } 137 138 // Reverts to an empty state. 139 void add(path p, bool allowsolve=true) { 140 update(); 141 uncheckedAdd(p,allowsolve); 142 } 143 clear()144 void clear() { 145 clearNodes(); 146 clearPath(); 147 } 148 close()149 void close() { 150 if(!nodes.empty()) { 151 nodes.front().in=in; 152 nodes.front().tin=tin; 153 } 154 } 155 resolvecycle()156 void resolvecycle() { 157 if(!nodes.empty()) 158 nodes.push_back(nodes.front()); 159 } 160 precyclic(bool b)161 void precyclic(bool b) { 162 precycle=b; 163 } 164 precyclic()165 bool precyclic() { 166 return precycle; 167 } 168 169 // Once all information has been added, release the flat result. 170 simpleknotlist list(bool cycles=false) { 171 if(cycles && !nodes.empty()) close(); 172 return simpleknotlist(nodes,cycles); 173 } 174 175 // Yield a path from the guide as represented here. 176 path solve(bool cycles=false) { 177 if (solved) 178 return p; 179 else { 180 simpleknotlist l=list(cycles); 181 p=camp::solve(l); 182 solved=true; 183 return p; 184 } 185 } 186 }; 187 188 } // namespace camp 189 190 #endif // FLATGUIDE_H 191