1 /************************************************************************
2 ************************************************************************
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.
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.
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 ************************************************************************/
23 #include "recSchema.h"
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.
34 schema
* makeRecSchema (schema
* s1
, schema
* s2
)
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
;
41 return new recSchema(a
,b
,w
);
45 * Constructor of a recursive schema (s1 ~ s2). The two components
46 * are supposed to have the same width.
48 recSchema::recSchema (schema
* s1
, schema
* s2
, double width
)
49 : schema( s1
->inputs() - s2
->outputs(),
52 s1
->height() + s2
->height() ),
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());
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));
68 * The two subschema are placed centered vertically, s2 on top of s1.
69 * The input and output points are computed.
71 void recSchema::place(double ox
, double oy
, int orientation
)
73 beginPlace(ox
, oy
, orientation
);
75 double dx1
= (width() - fSchema1
->width())/2;
76 double dx2
= (width() - fSchema2
->width())/2;
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
);
83 fSchema1
->place(ox
+dx1
, oy
, kRightLeft
);
84 fSchema2
->place(ox
+dx2
, oy
+fSchema1
->height(), kLeftRight
);
88 // adjust delta space to orientation
89 if (orientation
== kRightLeft
) { dx1
= -dx1
; }
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
);
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
);
108 * The input points s1 ~ s2
110 point
recSchema::inputPoint(unsigned int i
) const
112 return fInputPoint
[i
];
117 * The output points s1 ~ s2
119 point
recSchema::outputPoint(unsigned int i
) const
121 return fOutputPoint
[i
];
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.
130 void recSchema::draw(device
& dev
)
134 // draw the two subdiagrams
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);
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);
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
);
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
);
166 * Draw the delay sign of a feedback connection
168 void recSchema::drawDelaySign(device
& dev
, double x
, double y
, double size
)
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
);
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.
181 void recSchema::collectTraits(collector
& c
)
185 // draw the two subdiagrams
186 fSchema1
->collectTraits(c
);
187 fSchema2
->collectTraits(c
);
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
));
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
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
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
);
218 * Draw a feedback connection between two points with an horizontal
221 void recSchema::drawFeedback(device
& dev
, const point
& src
, const point
& dst
, double dx
)
223 double ox
= src
.x
+ ((orientation()==kLeftRight
) ? dx
: -dx
);
224 double ct
= (orientation()==kLeftRight
) ? dWire
/2 : -dWire
/2;
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);
234 * Draw a feedback connection between two points with an horizontal
237 void recSchema::collectFeedback(collector
& c
, const point
& src
, const point
& dst
, double dx
, const point
& out
)
239 double ox
= src
.x
+ ((orientation()==kLeftRight
) ? dx
: -dx
);
240 double ct
= (orientation()==kLeftRight
) ? dWire
/2 : -dWire
/2;
242 point
up(ox
, src
.y
-ct
);
243 point
br(ox
+ct
/2.0, src
.y
);
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
));
258 * Draw a feedfrom connection between two points with an horizontal
261 void recSchema::drawFeedfront(device
& dev
, const point
& src
, const point
& dst
, double dx
)
263 // double ox = src.x + ((orientation()==kLeftRight) ? -dx : dx);
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);
272 * Draw a feedfrom connection between two points with an horizontal
275 void recSchema::collectFeedfront(collector
& c
, const point
& src
, const point
& dst
, double dx
)
277 double ox
= src
.x
+ ((orientation()==kLeftRight
) ? -dx
: dx
);
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
)));