Initial import.
[Faustine.git] / interpretor / faust-0.9.47mr3 / compiler / draw / schema / recSchema.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
21
22
23 #include "recSchema.h"
24 #include <iostream>
25 #include <assert.h>
26
27 using namespace std;
28
29 /**
30 * Creates a new recursive schema (s1 ~ s2). The smallest component is
31 * enlarged to the width of the other. The left and right horizontal
32 * margins are computed according to the number of internal connections.
33 */
34 schema* makeRecSchema (schema* s1, schema* s2)
35 {
36 schema* a = makeEnlargedSchema(s1, s2->width());
37 schema* b = makeEnlargedSchema(s2, s1->width());
38 double m = dWire * max(b->inputs(), b->outputs());
39 double w = a->width() + 2*m;
40
41 return new recSchema(a,b,w);
42 }
43
44 /**
45 * Constructor of a recursive schema (s1 ~ s2). The two components
46 * are supposed to have the same width.
47 */
48 recSchema::recSchema (schema* s1, schema* s2, double width)
49 : schema( s1->inputs() - s2->outputs(),
50 s1->outputs(),
51 width,
52 s1->height() + s2->height() ),
53 fSchema1(s1),
54 fSchema2(s2)
55 {
56 // this version only accepts legal expressions of same width
57 assert(s1->inputs() >= s2->outputs());
58 assert(s1->outputs() >= s2->inputs());
59 assert(s1->width() >= s2->width());
60
61 // create the input and output points
62 for (unsigned int i=0; i<inputs(); i++) fInputPoint.push_back(point(0,0));
63 for (unsigned int i=0; i<outputs(); i++) fOutputPoint.push_back(point(0,0));
64
65 }
66
67 /**
68 * The two subschema are placed centered vertically, s2 on top of s1.
69 * The input and output points are computed.
70 */
71 void recSchema::place(double ox, double oy, int orientation)
72 {
73 beginPlace(ox, oy, orientation);
74
75 double dx1 = (width() - fSchema1->width())/2;
76 double dx2 = (width() - fSchema2->width())/2;
77
78 // place the two sub diagrams
79 if (orientation == kLeftRight) {
80 fSchema2->place(ox+dx2, oy, kRightLeft);
81 fSchema1->place(ox+dx1, oy+fSchema2->height(), kLeftRight);
82 } else {
83 fSchema1->place(ox+dx1, oy, kRightLeft);
84 fSchema2->place(ox+dx2, oy+fSchema1->height(), kLeftRight);
85 }
86
87
88 // adjust delta space to orientation
89 if (orientation == kRightLeft) { dx1 = -dx1; }
90
91 // place input points
92 for (unsigned int i=0; i<inputs(); i++) {
93 point p = fSchema1->inputPoint(i+fSchema2->outputs());
94 fInputPoint[i] = point(p.x-dx1, p.y);
95 }
96
97 // place output points
98 for (unsigned int i=0; i<outputs(); i++) {
99 point p = fSchema1->outputPoint(i);
100 fOutputPoint[i] = point(p.x+dx1, p.y);
101 }
102
103 endPlace();
104 }
105
106
107 /**
108 * The input points s1 ~ s2
109 */
110 point recSchema::inputPoint(unsigned int i) const
111 {
112 return fInputPoint[i];
113 }
114
115
116 /**
117 * The output points s1 ~ s2
118 */
119 point recSchema::outputPoint(unsigned int i) const
120 {
121 return fOutputPoint[i];
122 }
123
124
125 /**
126 * Draw the two subschema s1 and s2 as well as the feedback
127 * connections between s1 and s2, and the feedfrom connections
128 * beetween s2 and s1.
129 */
130 void recSchema::draw(device& dev)
131 {
132 assert(placed());
133
134 // draw the two subdiagrams
135 fSchema1->draw(dev);
136 fSchema2->draw(dev);
137
138 // draw the output lines
139 for (unsigned int i=0; i<outputs(); i++) {
140 point p = fSchema1->outputPoint(i);
141 point q = outputPoint(i);
142 //dev.trait(p.x, p.y, q.x, q.y);
143 }
144
145 // draw the input lines
146 unsigned int skip = fSchema2->outputs();
147 for (unsigned int i=0; i<inputs(); i++) {
148 point p = fSchema1->inputPoint(i+skip);
149 point q = inputPoint(i);
150 //dev.trait(p.x, p.y, q.x, q.y);
151 }
152
153 // draw the feedback connections to each fSchema2 input
154 for (unsigned int i=0; i<fSchema2->inputs(); i++) {
155 drawFeedback(dev, fSchema1->outputPoint(i), fSchema2->inputPoint(i), i*dWire);
156 }
157
158 // draw the feedfront connections from each fSchema2 output
159 for (unsigned int i=0; i<fSchema2->outputs(); i++) {
160 drawFeedfront(dev, fSchema2->outputPoint(i), fSchema1->inputPoint(i), i*dWire);
161 }
162 }
163
164
165 /**
166 * Draw the delay sign of a feedback connection
167 */
168 void recSchema::drawDelaySign(device& dev, double x, double y, double size)
169 {
170 dev.trait(x-size/2, y, x-size/2, y-size);
171 dev.trait(x-size/2, y-size, x+size/2, y-size);
172 dev.trait(x+size/2, y-size, x+size/2, y);
173 }
174
175
176 /**
177 * Draw the two subschema s1 and s2 as well as the feedback
178 * connections between s1 and s2, and the feedfrom connections
179 * beetween s2 and s1.
180 */
181 void recSchema::collectTraits(collector& c)
182 {
183 assert(placed());
184
185 // draw the two subdiagrams
186 fSchema1->collectTraits(c);
187 fSchema2->collectTraits(c);
188
189 // draw the feedback connections to each fSchema2 input
190 for (unsigned int i=0; i<fSchema2->inputs(); i++) {
191 collectFeedback(c, fSchema1->outputPoint(i), fSchema2->inputPoint(i), i*dWire, outputPoint(i));
192 }
193
194 // draw the non recursive output lines
195 for (unsigned int i=fSchema2->inputs(); i<outputs(); i++) {
196 point p = fSchema1->outputPoint(i);
197 point q = outputPoint(i);
198 c.addTrait(trait(p,q)); // in->out order
199 }
200
201 // draw the input lines
202 unsigned int skip = fSchema2->outputs();
203 for (unsigned int i=0; i<inputs(); i++) {
204 point p = inputPoint(i);
205 point q = fSchema1->inputPoint(i+skip);
206 c.addTrait(trait(p,q)); // in->out order
207 }
208
209 // draw the feedfront connections from each fSchema2 output
210 for (unsigned int i=0; i<fSchema2->outputs(); i++) {
211 collectFeedfront(c, fSchema2->outputPoint(i), fSchema1->inputPoint(i), i*dWire);
212 }
213 }
214
215
216
217 /**
218 * Draw a feedback connection between two points with an horizontal
219 * displacement dx
220 */
221 void recSchema::drawFeedback(device& dev, const point& src, const point& dst, double dx)
222 {
223 double ox = src.x + ((orientation()==kLeftRight) ? dx : -dx);
224 double ct = (orientation()==kLeftRight) ? dWire/2 : -dWire/2;
225
226 drawDelaySign(dev, ox, src.y, ct);
227 //dev.trait(ox, src.y-ct, ox, dst.y);
228 //dev.trait(ox, dst.y, dst.x, dst.y);
229 }
230
231
232
233 /**
234 * Draw a feedback connection between two points with an horizontal
235 * displacement dx
236 */
237 void recSchema::collectFeedback(collector& c, const point& src, const point& dst, double dx, const point& out)
238 {
239 double ox = src.x + ((orientation()==kLeftRight) ? dx : -dx);
240 double ct = (orientation()==kLeftRight) ? dWire/2 : -dWire/2;
241
242 point up(ox, src.y-ct);
243 point br(ox+ct/2.0, src.y);
244
245 c.addOutput(up);
246 c.addOutput(br);
247 c.addInput(br);
248
249 c.addTrait(trait(up, point(ox, dst.y)));
250 c.addTrait(trait(point(ox, dst.y), point(dst.x, dst.y)));
251 c.addTrait(trait(src,br));
252 c.addTrait(trait(br,out));
253
254 }
255
256
257 /**
258 * Draw a feedfrom connection between two points with an horizontal
259 * displacement dx
260 */
261 void recSchema::drawFeedfront(device& dev, const point& src, const point& dst, double dx)
262 {
263 // double ox = src.x + ((orientation()==kLeftRight) ? -dx : dx);
264
265 // dev.trait(ox, src.y, src.x, src.y);
266 // dev.trait(ox, src.y, ox, dst.y);
267 // dev.trait(ox, dst.y, dst.x, dst.y);
268 }
269
270
271 /**
272 * Draw a feedfrom connection between two points with an horizontal
273 * displacement dx
274 */
275 void recSchema::collectFeedfront(collector& c, const point& src, const point& dst, double dx)
276 {
277 double ox = src.x + ((orientation()==kLeftRight) ? -dx : dx);
278
279 c.addTrait(trait(point(src.x, src.y), point(ox, src.y)));
280 c.addTrait(trait(point(ox, src.y), point(ox, dst.y)));
281 c.addTrait(trait(point(ox, dst.y), point(dst.x, dst.y)));
282 }