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