1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2018 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 #include <algorithm>
23 #include <iostream>
24
25 #include "exception.hh"
26 #include "global.hh"
27 #include "routeSchema.h"
28
29 using namespace std;
30
31 /**
32 * Build n x m cable routing
33 */
34
makeRouteSchema(unsigned int inputs,unsigned int outputs,const std::vector<int> & routes)35 schema* makeRouteSchema(unsigned int inputs, unsigned int outputs, const std::vector<int>& routes)
36 {
37 // determine the optimal size of the box
38 double minimal = 3 * dWire;
39 double h = 2 * dVert + max(minimal, max(inputs, outputs) * dWire);
40 double w = 2 * dHorz + max(minimal, h * 0.75);
41
42 return new routeSchema(inputs, outputs, w, h, routes);
43 }
44
45 /**
46 * Build a simple colored routeSchema with a certain number of
47 * inputs and outputs, a text to be displayed, and an optional link.
48 * The length of the text as well as the number of inputs and outputs
49 * are used to compute the size of the routeSchema
50 */
routeSchema(unsigned int inputs,unsigned int outputs,double width,double height,const std::vector<int> & routes)51 routeSchema::routeSchema(unsigned int inputs, unsigned int outputs, double width, double height,
52 const std::vector<int>& routes)
53
54 : schema(inputs, outputs, width, height), fText(""), fColor("#EEEEAA"), fLink(""), fRoutes(routes)
55 {
56 for (unsigned int i = 0; i < inputs; i++) fInputPoint.push_back(point(0, 0));
57 for (unsigned int i = 0; i < outputs; i++) fOutputPoint.push_back(point(0, 0));
58 }
59
60 /**
61 * Define the graphic position of the routeSchema. Computes the graphic
62 * position of all the elements, in particular the inputs and outputs.
63 * This method must be called before draw(), otherwise draw is not allowed
64 */
place(double x,double y,int orientation)65 void routeSchema::place(double x, double y, int orientation)
66 {
67 beginPlace(x, y, orientation);
68
69 placeInputPoints();
70 placeOutputPoints();
71
72 endPlace();
73 }
74
75 /**
76 * Returns an input point
77 */
inputPoint(unsigned int i) const78 point routeSchema::inputPoint(unsigned int i) const
79 {
80 faustassert(placed());
81 faustassert(i < inputs());
82 return fInputPoint[i];
83 }
84
85 /**
86 * Returns an output point
87 */
outputPoint(unsigned int i) const88 point routeSchema::outputPoint(unsigned int i) const
89 {
90 faustassert(placed());
91 faustassert(i < outputs());
92 return fOutputPoint[i];
93 }
94
95 /**
96 * Computes the input points according to the position and the
97 * orientation of the routeSchema
98 */
placeInputPoints()99 void routeSchema::placeInputPoints()
100 {
101 int N = inputs();
102
103 if (orientation() == kLeftRight) {
104 double px = x();
105 double py = y() + (height() - dWire * (N - 1)) / 2;
106
107 for (int i = 0; i < N; i++) {
108 fInputPoint[i] = point(px, py + i * dWire);
109 }
110
111 } else {
112 double px = x() + width();
113 double py = y() + height() - (height() - dWire * (N - 1)) / 2;
114
115 for (int i = 0; i < N; i++) {
116 fInputPoint[i] = point(px, py - i * dWire);
117 }
118 }
119 }
120
121 /**
122 * Computes the output points according to the position and the
123 * orientation of the routeSchema
124 */
placeOutputPoints()125 void routeSchema::placeOutputPoints()
126 {
127 int N = outputs();
128
129 if (orientation() == kLeftRight) {
130 double px = x() + width();
131 double py = y() + (height() - dWire * (N - 1)) / 2;
132
133 for (int i = 0; i < N; i++) {
134 fOutputPoint[i] = point(px, py + i * dWire);
135 }
136
137 } else {
138 double px = x();
139 double py = y() + height() - (height() - dWire * (N - 1)) / 2;
140
141 for (int i = 0; i < N; i++) {
142 fOutputPoint[i] = point(px, py - i * dWire);
143 }
144 }
145 }
146
147 /**
148 * Draw the routeSchema on the device. This method can only
149 * be called after the routeSchema have been placed
150 */
draw(device & dev)151 void routeSchema::draw(device& dev)
152 {
153 faustassert(placed());
154
155 if (gGlobal->gDrawRouteFrame) {
156 drawRectangle(dev);
157 // drawText(dev);
158 drawOrientationMark(dev);
159 drawInputArrows(dev);
160 }
161 }
162
163 /**
164 * Draw the colored rectangle with the optional link
165 */
drawRectangle(device & dev)166 void routeSchema::drawRectangle(device& dev)
167 {
168 dev.rect(x() + dHorz, y() + dVert, width() - 2 * dHorz, height() - 2 * dVert, fColor.c_str(), fLink.c_str());
169 }
170
171 /**
172 * Draw the text centered on the box
173 */
drawText(device & dev)174 void routeSchema::drawText(device& dev)
175 {
176 dev.text(x() + width() / 2, y() + height() / 2, fText.c_str(), fLink.c_str());
177 }
178
179 /**
180 * Draw the orientation mark, a small point that indicates
181 * the first input (like integrated circuits)
182 */
drawOrientationMark(device & dev)183 void routeSchema::drawOrientationMark(device& dev)
184 {
185 double px, py;
186
187 if (orientation() == kLeftRight) {
188 px = x() + dHorz;
189 py = y() + dVert;
190 } else {
191 px = x() + width() - dHorz;
192 py = y() + height() - dVert;
193 }
194
195 dev.markSens(px, py, orientation());
196 }
197
198 /**
199 * Draw horizontal arrows from the input points to the
200 * routeSchema rectangle
201 */
drawInputArrows(device & dev)202 void routeSchema::drawInputArrows(device& dev)
203 {
204 double dx = (orientation() == kLeftRight) ? dHorz : -dHorz;
205
206 for (unsigned int i = 0; i < inputs(); i++) {
207 point p = fInputPoint[i];
208 dev.fleche(p.x + dx, p.y, 0, orientation());
209 }
210 }
211
212 /**
213 * Draw horizontal arrows from the input points to the
214 * routeSchema rectangle
215 */
collectTraits(collector & c)216 void routeSchema::collectTraits(collector& c)
217 {
218 collectInputWires(c);
219 collectOutputWires(c);
220 // additional routing traits
221 for (unsigned int i = 0; i < fRoutes.size() - 1; i += 2) {
222 int src = fRoutes[i] - 1;
223 int dst = fRoutes[i + 1] - 1;
224 point p1 = fInputPoint[src];
225 point p2 = fOutputPoint[dst];
226 // cerr << "add traits: " << p1.x << 'x' << p1.y << " -> " << p2.x << "x" << p2.y << endl;
227 double dx = (orientation() == kLeftRight) ? dHorz : -dHorz;
228 c.addTrait(trait(point(p1.x + dx, p1.y), point(p2.x - dx, p2.y)));
229 }
230 }
231
232 /**
233 * Draw horizontal arrows from the input points to the
234 * routeSchema rectangle
235 */
collectInputWires(collector & c)236 void routeSchema::collectInputWires(collector& c)
237 {
238 double dx = (orientation() == kLeftRight) ? dHorz : -dHorz;
239
240 for (unsigned int i = 0; i < inputs(); i++) {
241 point p = fInputPoint[i];
242 c.addTrait(trait(point(p.x, p.y), point(p.x + dx, p.y))); // in->out direction
243 c.addInput(point(p.x + dx, p.y));
244 }
245 }
246
247 /**
248 * Draw horizontal line from the routeSchema rectangle to the
249 * output points
250 */
collectOutputWires(collector & c)251 void routeSchema::collectOutputWires(collector& c)
252 {
253 double dx = (orientation() == kLeftRight) ? dHorz : -dHorz;
254
255 for (unsigned int i = 0; i < outputs(); i++) {
256 point p = fOutputPoint[i];
257 c.addTrait(trait(point(p.x - dx, p.y), point(p.x, p.y))); // in->out direction
258 c.addOutput(point(p.x - dx, p.y));
259 }
260 }
261
262 #if 0
263 /**
264 * Build n x m cable routing
265 */
266 routeSchema::routeSchema(unsigned int n, unsigned int m, const std::vector<int>& routes)
267 : schema(n, m, max(n, m) * dWire, max(n, m) * dWire)
268 {
269 fRoutes = routes;
270 for (unsigned int i = 0; i < n; i++) fInputPoints.push_back(point(0, 0));
271 for (unsigned int i = 0; i < m; i++) fOutputPoints.push_back(point(0, 0));
272 }
273
274 /**
275 * Place the communication points vertically spaced by dWire
276 */
277 void routeSchema::place(double ox, double oy, int orientation)
278 {
279 // std::cerr << "\nENTER route place of " << this << " at " << ox << 'x' << oy << endl;
280 double diy = (height() - inputs() * dWire + dWire) / 2.0;
281 double doy = (height() - outputs() * dWire + dWire) / 2.0;
282
283 beginPlace(ox, oy, orientation);
284 if (orientation == kLeftRight) {
285 // std::cerr << "orientation == kLeftRight" << endl;
286 for (unsigned int i = 0; i < inputs(); i++) {
287 fInputPoints[i] = point(ox, oy + diy + i * dWire);
288 // std::cerr << "input point :" << fInputPoints[i].x << 'x' << fInputPoints[i].y << endl;
289 }
290 for (unsigned int i = 0; i < outputs(); i++) {
291 fOutputPoints[i] = point(ox + width(), oy + doy + i * dWire);
292 // std::cerr << "output point: " << fInputPoints[i].x << 'x' << fInputPoints[i].y << endl;
293 }
294 } else {
295 // std::cerr << "orientation == kRightLeft" << endl;
296 for (unsigned int i = 0; i < outputs(); i++) {
297 fOutputPoints[i] = point(ox, oy + height() - doy - i * dWire);
298 // std::cerr << "output point: " << fInputPoints[i].x << 'x' << fInputPoints[i].y << endl;
299 }
300 for (unsigned int i = 0; i < inputs(); i++) {
301 fInputPoints[i] = point(ox + width(), oy + height() - diy - i * dWire);
302 // std::cerr << "input point :" << fInputPoints[i].x << 'x' << fInputPoints[i].y << endl;
303 }
304 }
305 endPlace();
306 // std::cerr << "EXIT route place " << ox << 'x' << oy << "\n" << endl;
307 }
308
309 /**
310 * Nothing to draw. Actual drawing will take place when the wires
311 * are enlargered
312 */
313 void routeSchema::draw(device& dev)
314 {
315 }
316
317 /**
318 * Nothing to collect. Actual collect will take place when the wires
319 * are enlargered
320 */
321 void routeSchema::collectTraits(collector& c)
322 {
323 faustassert(placed());
324
325 // draw the connections between them
326 // std::cerr << "fRoutes.size() = " << fRoutes.size() << endl;
327 if (fRoutes.size() >= 2) {
328 unsigned int m = fRoutes.size() - 1;
329 for (unsigned int i = 0; i < m; i += 2) {
330 unsigned int src = fRoutes[i];
331 unsigned int dst = fRoutes[i + 1];
332 if ((src > 0) && (src <= inputs()) && (dst > 0) && (dst <= outputs())) {
333 c.addTrait(trait(point(fInputPoints[src].x, fInputPoints[src].y),
334 point(fOutputPoints[dst].x, fOutputPoints[dst].y)));
335
336 // c.addInput(fInputPoints[src]);
337 // c.addOutput(fOutputPoints[dst]);
338 }
339 }
340 }
341 }
342
343 /**
344 *input and output points are the same as the width is 0
345 */
346 point routeSchema::inputPoint(unsigned int i) const
347 {
348 faustassert(i < inputs());
349 return fInputPoints[i];
350 }
351
352 /**
353 *input and output points are the same as the width is 0
354 */
355 point routeSchema::outputPoint(unsigned int i) const
356 {
357 faustassert(i < outputs());
358 return fOutputPoints[i];
359 }
360
361 #endif
362