summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/guide.h
blob: a25e7ffa9e718176cf019e8cefec3dd894c43bdf (plain)
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