FAUST compiler  0.9.9.6b8
seqSchema.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003     FAUST compiler
00004     Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
00005     ---------------------------------------------------------------------
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021 
00022 
00023 #include "seqSchema.h"
00024 #include <iostream>
00025 #include <assert.h>
00026 
00027 using namespace std;
00028 
00029 enum {kHorDir, kUpDir, kDownDir}; 
00030 
00031 static double computeHorzGap(schema* a, schema* b);
00032 static int direction(const point& a, const point& b);
00033 
00034 
00035 //----------------------------INTERFACE--------------------------------
00036 
00043 schema * makeSeqSchema (schema* s1, schema* s2)
00044 {
00045     unsigned int o = s1->outputs();
00046     unsigned int i = s2->inputs();
00047 
00048     schema* a = (o < i) ? makeParSchema(s1, makeCableSchema(i-o)) : s1;
00049     schema* b = (o > i) ? makeParSchema(s2, makeCableSchema(o-i)) : s2;
00050 
00051     return new seqSchema(a, b, computeHorzGap(a,b));
00052 }
00053 
00054 
00055 
00056 //-----------------------IMPLEMENTATION------------------------------
00057 
00062 seqSchema::seqSchema (schema* s1, schema* s2, double hgap)
00063     :   schema( s1->inputs(),
00064                 s2->outputs(),
00065                 s1->width() + hgap + s2->width(),
00066                 max(s1->height(), s2->height()) ),
00067         fSchema1(s1),
00068         fSchema2(s2),
00069         fHorzGap(hgap)
00070 {
00071     assert(s1->outputs() == s2->inputs());
00072 }
00073 
00074 
00075 //-----------------------placement------------------------------
00076 
00077 
00082 void seqSchema::place(double ox, double oy, int orientation)
00083 {
00084     beginPlace(ox, oy, orientation);
00085 
00086     double y1 = max(0.0, 0.5*(fSchema2->height() - fSchema1->height()));
00087     double y2 = max(0.0, 0.5*(fSchema1->height() - fSchema2->height()));
00088 
00089     if (orientation == kLeftRight) {
00090         fSchema1->place(ox, oy+y1, orientation);
00091         fSchema2->place(ox+fSchema1->width()+fHorzGap, oy+y2, orientation);
00092     } else {
00093         fSchema2->place(ox, oy+y2, orientation);
00094         fSchema1->place(ox+fSchema2->width()+fHorzGap, oy+y1, orientation);
00095     }
00096     endPlace();
00097 }
00098 
00099 
00103 point seqSchema::inputPoint(unsigned int i) const
00104 {
00105     return fSchema1->inputPoint(i);
00106 }
00107 
00108 
00112 point seqSchema::outputPoint(unsigned int i) const
00113 {
00114     return fSchema2->outputPoint(i);
00115 }
00116 
00117 
00118 
00119 //--------------------------drawing------------------------------
00120 
00121 
00125 void seqSchema::draw(device& dev)
00126 {
00127     assert(placed());
00128     assert(fSchema1->outputs() == fSchema2->inputs());
00129 
00130     fSchema1->draw(dev);
00131     fSchema2->draw(dev);
00132     //drawInternalWires(dev);
00133 }
00134 
00138 void seqSchema::collectTraits(collector& c)
00139 {
00140     assert(placed());
00141     assert(fSchema1->outputs() == fSchema2->inputs());
00142 
00143     fSchema1->collectTraits(c);
00144     fSchema2->collectTraits(c);
00145     collectInternalWires(c);
00146 }
00147 
00148 
00154 void seqSchema::drawInternalWires(device& dev)
00155 {
00156     assert (fSchema1->outputs() == fSchema2->inputs());
00157 
00158     const int   N   = fSchema1->outputs();
00159     double      dx  = 0;
00160     double      mx  = 0;
00161     int         dir =-1;
00162 
00163     if (orientation() == kLeftRight) {
00164         // draw left right cables
00165         for (int i=0; i<N; i++) {
00166             point src = fSchema1->outputPoint(i);
00167             point dst = fSchema2->inputPoint(i);
00168 
00169             int d = direction(src,dst);
00170             if (d != dir) {
00171                 // compute attributes of new direction
00172                 switch (d) {
00173                     case kUpDir     : mx = 0; dx = dWire; break;
00174                     case kDownDir   : mx = fHorzGap; dx = -dWire; break;
00175                     default         : mx = 0; dx = 0; break;
00176                 }
00177                 dir = d;
00178             } else {
00179                 // move in same direction
00180                 mx = mx +dx;
00181             }
00182             if (src.y == dst.y) {
00183                 // draw straight cable
00184                 dev.trait(src.x, src.y, dst.x, dst.y);
00185             } else {
00186                 // draw zizag cable
00187                 dev.trait(src.x, src.y, src.x+mx, src.y);
00188                 dev.trait(src.x+mx, src.y, src.x+mx, dst.y);
00189                 dev.trait(src.x+mx, dst.y, dst.x, dst.y);
00190             }
00191 
00192         }
00193     } else {
00194         // draw right left cables
00195         for (int i=0; i<N; i++) {
00196             point src = fSchema1->outputPoint(i);
00197             point dst = fSchema2->inputPoint(i);
00198 
00199             int d = direction(src,dst);
00200             if (d != dir) {
00201                 // compute attributes of new direction
00202                 switch (d) {
00203                     case kUpDir     : mx = -fHorzGap; dx = dWire; break;
00204                     case kDownDir   : mx = 0; dx = -dWire; break;
00205                     default         : mx = 0; dx = 0; break;
00206                 }
00207                 dir = d;
00208             } else {
00209                 // move in same direction
00210                 mx = mx +dx;
00211             }
00212             if (src.y == dst.y) {
00213                 // draw straight cable
00214                 dev.trait(src.x, src.y, dst.x, dst.y);
00215             } else {
00216                 // draw zizag cable
00217                 dev.trait(src.x, src.y, src.x+mx, src.y);
00218                 dev.trait(src.x+mx, src.y, src.x+mx, dst.y);
00219                 dev.trait(src.x+mx, dst.y, dst.x, dst.y);
00220             }
00221 
00222         }
00223     }
00224 }
00225 
00226 
00227 
00233 void seqSchema::collectInternalWires(collector& c)
00234 {
00235     assert (fSchema1->outputs() == fSchema2->inputs());
00236 
00237     const int   N   = fSchema1->outputs();
00238     double      dx  = 0;
00239     double      mx  = 0;
00240     int         dir =-1;
00241 
00242     if (orientation() == kLeftRight) {
00243         // draw left right cables
00244         for (int i=0; i<N; i++) {
00245             point src = fSchema1->outputPoint(i);
00246             point dst = fSchema2->inputPoint(i);
00247 
00248             int d = direction(src,dst);
00249             if (d != dir) {
00250                 // compute attributes of new direction
00251                 switch (d) {
00252                     case kUpDir     : mx = 0; dx = dWire; break;
00253                     case kDownDir   : mx = fHorzGap; dx = -dWire; break;
00254                     default         : mx = 0; dx = 0; break;
00255                 }
00256                 dir = d;
00257             } else {
00258                 // move in same direction
00259                 mx = mx +dx;
00260             }
00261             if (src.y == dst.y) {
00262                 // draw straight cable
00263                 c.addTrait(trait(point(src.x, src.y), point(dst.x, dst.y)));
00264             } else {
00265                 // draw zizag cable
00266                 c.addTrait(trait(point(src.x, src.y), point(src.x+mx, src.y)));
00267                 c.addTrait(trait(point(src.x+mx, src.y), point(src.x+mx, dst.y)));
00268                 c.addTrait(trait(point(src.x+mx, dst.y), point(dst.x, dst.y)));
00269             }
00270 
00271         }
00272     } else {
00273         // draw right left cables
00274         for (int i=0; i<N; i++) {
00275             point src = fSchema1->outputPoint(i);
00276             point dst = fSchema2->inputPoint(i);
00277 
00278             int d = direction(src,dst);
00279             if (d != dir) {
00280                 // compute attributes of new direction
00281                 switch (d) {
00282                     case kUpDir     : mx = -fHorzGap; dx = dWire; break;
00283                     case kDownDir   : mx = 0; dx = -dWire; break;
00284                     default         : mx = 0; dx = 0; break;
00285                 }
00286                 dir = d;
00287             } else {
00288                 // move in same direction
00289                 mx = mx +dx;
00290             }
00291             if (src.y == dst.y) {
00292                 // draw straight cable
00293                 c.addTrait(trait(point(src.x, src.y), point(dst.x, dst.y)));
00294             } else {
00295                 // draw zizag cable
00296                 c.addTrait(trait(point(src.x, src.y), point(src.x+mx, src.y)));
00297                 c.addTrait(trait(point(src.x+mx, src.y), point(src.x+mx, dst.y)));
00298                 c.addTrait(trait(point(src.x+mx, dst.y), point(dst.x, dst.y)));
00299             }
00300 
00301         }
00302     }
00303 }
00304 
00305 //--------------------------helpers------------------------------
00306 
00307 
00308 
00313 static int direction(const point& a, const point& b)
00314 {
00315     if (a.y > b.y) return kUpDir;       // upward connections
00316     if (a.y < b.y) return kDownDir;     // downward connection
00317     return kHorDir;                     // horizontal connections
00318 }
00319 
00325 static double computeHorzGap(schema* a, schema* b)
00326 {
00327     assert(a->outputs() == b->inputs());
00328 
00329     if (a->outputs() == 0) {
00330         return 0;
00331     } else {
00332         // store here the size of the largest group for each direction
00333         int MaxGroupSize[3]; for(int i=0; i<3; i++) MaxGroupSize[i]=0;
00334 
00335         // place a and b to have valid connection points
00336         double ya = max(0.0, 0.5*(b->height() - a->height()));
00337         double yb = max(0.0, 0.5*(a->height() - b->height()));
00338         a->place(0,ya,kLeftRight);
00339         b->place(0,yb,kLeftRight);
00340 
00341         // init current group direction and size
00342         int gdir    = direction(a->outputPoint(0), b->inputPoint(0));
00343         int gsize   = 1;
00344 
00345         // analyze direction of remaining points
00346         for (unsigned int i=1; i<a->outputs(); i++) {
00347             int d = direction(a->outputPoint(i), b->inputPoint(i));
00348             if (d == gdir) {
00349                 gsize++;
00350             } else {
00351                 if (gsize > MaxGroupSize[gdir])  MaxGroupSize[gdir]=gsize;
00352                 gsize = 1;
00353                 gdir = d;
00354             }
00355         }
00356 
00357         // update for last group
00358         if (gsize > MaxGroupSize[gdir])  MaxGroupSize[gdir]=gsize;
00359 
00360         // the gap required for the connections
00361         return dWire * max(MaxGroupSize[kUpDir],MaxGroupSize[kDownDir]);
00362     }
00363 }