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 315 316 317 318 319
|
/*****
* guide.h
* Andy Hammerlindl 2005/02/23
*
*****/
#ifndef GUIDE_H
#define GUIDE_H
#include <iostream>
#include "knot.h"
#include "flatguide.h"
#include "settings.h"
namespace camp {
// Abstract base class for guides.
class guide : public gc {
protected:
public:
virtual ~guide() {}
// Returns the path that the guide represents.
virtual path solve() {
return path();
}
// Add the information in the guide to the flatguide, so that it can be
// solved via the knotlist solving routines.
// Returns true if guide has an interior cycle token.
virtual void flatten(flatguide&, bool allowsolve=true)=0;
virtual bool cyclic() {return false;}
virtual void print(ostream& out) const {
out << "nullpath";
}
// Needed so that multiguide can know where to put in ".." symbols.
virtual side printLocation() const {
return END;
}
};
inline ostream& operator<< (ostream& out, const guide& g)
{
g.print(out);
return out;
}
// Draws dots between two printings of guides, if their locations are such that
// the dots are necessary.
inline void adjustLocation(ostream& out, side l1, side l2)
{
if (l1 == END)
out << endl;
if ((l1 == END || l1 == OUT) && (l2 == IN || l2 == END))
out << "..";
}
// A guide representing a pair.
class pairguide : public guide {
pair z;
public:
void flatten(flatguide& g, bool=true) {
g.add(z);
}
pairguide(pair z)
: z(z) {}
path solve() {
return path(z);
}
void print(ostream& out) const {
out << z;
}
side printLocation() const {
return END;
}
};
// A guide representing a path.
class pathguide : public guide {
path p;
public:
void flatten(flatguide& g, bool allowsolve=true) {
g.add(p,allowsolve);
}
pathguide(path p)
: p(p) {}
path solve() {
return p;
}
bool cyclic() {return p.cyclic();}
void print(ostream& out) const {
out << p;
}
side printLocation() const {
return END;
}
};
// Tension expressions are evaluated to this class before being cast to a guide,
// so that they can be cast to other types (such as guide3) instead.
class tensionSpecifier : public gc {
double out,in;
bool atleast;
public:
tensionSpecifier(double val, bool atleast=false)
: out(val), in(val), atleast(atleast) {}
tensionSpecifier(double out, double in, bool atleast=false)
: out(out), in(in), atleast(atleast) {}
double getOut() const { return out; }
double getIn() const { return in; }
bool getAtleast() const { return atleast; }
};
// A guide giving tension information (as part of a join).
class tensionguide : public guide {
tension tout,tin;
public:
void flatten(flatguide& g, bool=true) {
g.setTension(tin,IN);
g.setTension(tout,OUT);
}
tensionguide(tensionSpecifier spec)
: tout(spec.getOut(), spec.getAtleast()),
tin(spec.getIn(), spec.getAtleast()) {}
void print(ostream& out) const {
out << (tout.atleast ? ".. tension atleast " : ".. tension ")
<< tout.val << " and " << tin.val << " ..";
}
side printLocation() const {
return JOIN;
}
};
// Similar to tensionSpecifier, curl expression are evaluated to this type
// before being cast to guides.
class curlSpecifier : public gc {
double value;
side s;
public:
curlSpecifier(double value, side s)
: value(value), s(s) {}
double getValue() const { return value; }
side getSide() const { return s; }
};
// A guide giving a specifier.
class specguide : public guide {
spec *p;
side s;
public:
void flatten(flatguide& g, bool=true) {
g.setSpec(p,s);
}
specguide(spec *p, side s)
: p(p), s(s) {}
specguide(curlSpecifier spec)
: p(new curlSpec(spec.getValue())), s(spec.getSide()) {}
void print(ostream& out) const {
out << *p;
}
side printLocation() const {
return s;
}
};
// A guide for explicit control points between two knots. This could be done
// with two specguides, instead, but this prints nicer, and is easier to encode.
class controlguide : public guide {
pair zout, zin;
public:
void flatten(flatguide& g, bool=true) {
g.setSpec(new controlSpec(zout), OUT);
g.setSpec(new controlSpec(zin), IN);
}
controlguide(pair zout,pair zin)
: zout(zout),zin(zin) {}
controlguide(pair z)
: zout(z),zin(z) {}
void print(ostream& out) const {
out << ".. controls "
<< zout << " and " << zin << " ..";
}
side printLocation() const {
return JOIN;
}
};
// A guide that is a sequence of other guides. This is used, for instance is
// joins, where we have the left and right guide, and possibly specifiers and
// tensions in between.
typedef mem::vector<guide *> guidevector;
// A multiguide represents a guide given by the first "length" items of
// the vector pointed to by "base".
// The constructor, if given another multiguide as a first argument,
// will try to avoid allocating a new "base" array.
class multiguide : public guide {
guidevector *base;
size_t length;
guide *subguide(size_t i) const
{
assert(i < length);
assert(length <= base->size());
return (*base)[i];
}
public:
multiguide(guidevector& v);
void flatten(flatguide&, bool=true);
bool cyclic() {
size_t n=length;
if(n < 1) return false;
return subguide(n-1)->cyclic();
}
path solve() {
if (settings::verbose>3) {
cerr << "solving guide:\n";
print(cerr); cerr << "\n\n";
}
flatguide g;
this->flatten(g);
path p=g.solve(false);
if (settings::verbose>3)
cerr << "solved as:\n" << p << "\n\n";
return p;
}
void print(ostream& out) const;
side printLocation() const {
int n = length;
return subguide(n-1)->printLocation();
}
};
struct cycleToken : public gc {};
// A guide representing the cycle token.
class cycletokguide : public guide {
public:
void flatten(flatguide& g, bool allowsolve=true) {
// If cycles occur in the midst of a guide, the guide up to that point
// should be solved as a path. Any subsequent guide will work with that
// path locked in place.
if(allowsolve)
g.solve(true);
else
g.close();
}
bool cyclic() {return true;}
path solve() {
// Just a cycle on it's own makes an empty guide.
return path();
}
void print(ostream& out) const {
out << "cycle";
}
side printLocation() const {
return END;
}
};
} // namespace camp
GC_DECLARE_PTRFREE(camp::pairguide);
GC_DECLARE_PTRFREE(camp::tensionSpecifier);
GC_DECLARE_PTRFREE(camp::tensionguide);
GC_DECLARE_PTRFREE(camp::curlSpecifier);
GC_DECLARE_PTRFREE(camp::controlguide);
GC_DECLARE_PTRFREE(camp::cycleToken);
GC_DECLARE_PTRFREE(camp::cycletokguide);
#endif // GUIDE_H
|