📄 layout.c
字号:
/****************************************************************************** DYNAMIC LAYOUT ALGORITHM OF GENERAL GRAPHS**** Author: dr. Szirmay-Kalos Laszlo (szirmay@fsz.bme.hu)** Technical University of Budapest, Hungary*****************************************************************************/#ifdef MSWINDOWS#include "graph.hxx"#else#include "graph.hxx"#endif/** CONSTANTS*/const double TIME_STEP = 0.1; // time step of diff equconst double MAX_FORCE = 500.0; // force shows instabilityconst double MIN_FORCE = 2.0; // force cosidered as 0const double MAX_TIME_SCALE = 10.0; // scale of max time of solutionconst double MINFRICTION = 0.6; // friction boundariesconst double MAXFRICTION = 0.9;const double MINIINERTIA = 0.1; // inverse inertia boundariesconst double MAXIINERTIA = 0.4;const double ZERO_DIST = 10.0; // distance considered as 0const double WALL_OUT_DRIVE = 80.0; // forces of the wallconst double WALL_MARGIN_DRIVE = 1.0;const double SCALECONSTRAINT = OVERWINDOW_X / 3.5 / MAXRELATION;const double MINCONSTRAINT = OVERWINDOW_X / 7.0; // minimal constraint/****************************************************************************//* DYNAMIC LAYOUT base on MECHANICAL SYSTEM ANALOGY *//* IN : The serial number of the maximal moveable node to be considered *//* OUT : STOPPED = All objects stopped *//* INSTABLE = Instable, force goes to infinity *//* TOO_LONG = Too much time elapsed *//****************************************************************************/int Graph :: DynamicLayout( int maxsernum )/*--------------------------------------------------------------------------*/{/** LOCALS*/ double constraint, friction, iinertia, dist; vector drive; // drive forces vector direction; // direction of drives double MAX_TIME = MAX_TIME_SCALE * (nmovnode + nfixnode + 1);/** INIT SPEED OF MOVEABLE NODES TO 0*/ if ( !FirstMoveNode() ) return STOPPED; do currnode -> Speed( ) = vector(0.0, 0.0); while ( NextNode( maxsernum ) );/** MAIN CYCLE OF TIME IN THE SOLUTION OF DIFF EQUATION*/ for ( double t = 0.0 ; t < MAX_TIME ; t += TIME_STEP ) {/** INITIALIZE FORCE IN NODES TO 0*/ FirstNode(); do currnode -> Force( ) = vector( 0.0, 0.0 ); while ( NextNode( maxsernum ) );/** CALCULATE FRICTION AND RESPONSE VALUES FROM t*/ friction = MINFRICTION + (MAXFRICTION - MINFRICTION) * t / MAX_TIME; iinertia = MAXIINERTIA - (MAXIINERTIA - MINIINERTIA) * t / MAX_TIME;/** CALCULATE DRIVE FORCE BETWEEN EACH PAIR OF NODES*/ FirstNode(); do { relatenode = currnode -> GetNext(); while ( relatenode != NULL && relatenode -> GetSerNum() <= maxsernum ) { direction = currnode -> Position( ) - relatenode -> Position( ); dist = direction.Size(); if ( dist < ZERO_DIST ) dist = ZERO_DIST;/** CALCULATE FORCE FROM THEIR RELATION*/ switch( SearchRelation() ) { case EMPTY_LIST: case NOT_FOUND: constraint = MINCONSTRAINT + MAXRELATION * SCALECONSTRAINT; break; case FOUND: case FIRST_FOUND: constraint = MINCONSTRAINT + (MAXRELATION - currelation->GetRelation()) * SCALECONSTRAINT; break; } // SET FORCE drive = (constraint - dist) / dist * direction; drive /= (double)(maxsernum + nfixnode); currnode -> AddForce(drive); relatenode -> AddForce(-drive); relatenode = relatenode -> GetNext(); } } while ( NextNode( maxsernum ) );/** ADD ADDITIONAL FORCES AND DETERMINE MAXIMAL FORCE*/ double max_force = 0.0; FirstMoveNode(); do {/** CALCULATE DRIVE FORCE OF BOUNDARIES AND ADD TO RELATION FORCES*/ dist = currnode -> Position().X(); /* * FORCE OF LEFT WALL */ if (dist < 0) { // OUT LEFT drive = vector( -dist * WALL_OUT_DRIVE + WALL_MARGIN * WALL_MARGIN_DRIVE, 0.0 ); currnode -> AddForce(drive); } else if (dist < WALL_MARGIN) { // IN LEFT MARGIN drive = vector((WALL_MARGIN - dist) * WALL_MARGIN_DRIVE, 0.0); currnode -> AddForce(drive); } /* * FORCE OF THE RIGHT WALL */ dist = currnode -> Position().X() - OVERWINDOW_X; if (dist > 0) { // OUT RIGHT drive = vector( -dist * WALL_OUT_DRIVE + WALL_MARGIN * WALL_MARGIN_DRIVE, 0.0); currnode -> AddForce(drive); } else if (-dist < WALL_MARGIN) { // IN RIGHT MARGIN drive = vector((-WALL_MARGIN - dist) * WALL_MARGIN_DRIVE, 0.0); currnode -> AddForce(drive); } dist = currnode -> Position().Y(); /* * FORCE OF BOTTOM WALL */ if (dist < 0) { // OUT BOTTOM drive = vector(0.0, -dist * WALL_OUT_DRIVE + WALL_MARGIN * WALL_MARGIN_DRIVE ); currnode -> AddForce(drive); } else if (dist < WALL_MARGIN) { // IN BOTTOM MARGIN drive = vector(0.0, (WALL_MARGIN - dist) * WALL_MARGIN_DRIVE); currnode -> AddForce(drive); } /* * FORCE OF THE TOP WALL */ dist = currnode -> Position().Y() - OVERWINDOW_Y; if (dist > 0) { // OUT TOP drive = vector( 0.0, -dist * WALL_OUT_DRIVE + WALL_MARGIN * WALL_MARGIN_DRIVE ); currnode -> AddForce(drive); } else if (-dist < WALL_MARGIN) { // IN TOP MARGIN drive = vector(0.0, (-WALL_MARGIN - dist) * WALL_MARGIN_DRIVE); currnode -> AddForce(drive); }/** MOVE NODE BY FORCE*/ vector old_speed = currnode -> Speed( ); currnode -> Speed( ) = (1.0 - friction) * old_speed + iinertia * currnode -> Force( ); currnode -> Position( ) += 0.5 * (old_speed + currnode -> Speed( ) );/** CALCULATE MAXIMUM FORCE*/ double abs_force = currnode -> Force().Size( ); if ( abs_force > max_force) max_force = abs_force; } while ( NextNode( maxsernum ) );/** STOP CALCULATION IF*/ if ( max_force < MIN_FORCE ) return STOPPED; // All objects stopped if ( max_force > MAX_FORCE ) return INSTABLE; // Instable, force goes to infinity } return TOO_LONG; // Too much time elapsed}/************************************************************************//* INITIAL PLACEMENT ALGORITHM *//* OUT : STOPPED = All objects stopped *//* INSTABLE = Instable, force goes to infinity *//* TOO_LONG = Too much time elapsed *//************************************************************************/int Graph :: Placement( )/*----------------------------------------------------------------------*/{ vector candidate; // candidate position vector relate_cent; // center related objects vector notrel_cent; // center of related object vector center( OVERWINDOW_X / 2, OVERWINDOW_Y / 2 ); int nrel; // number of related objects int nnotrel; // displayed nodes double perturb_x = OVERWINDOW_X / (double)RAND_MAX ; double perturb_y = OVERWINDOW_Y / (double)RAND_MAX ;/** SKIP FIXED NODES*/ if ( !FirstMoveNode() ) return STOPPED;/** MAIN CYCLE OF INTRODUCING MOVABLE NODES STEP-BY-STEP*/ for( int inode = 1; ; inode++ ) {/** CALCULATE THE CENTER OF GRAVITY OF ALREADY INTRODUCED NODES* relate_cent IS FOR RELATED NODES* notrel_cent IS FOR NON_RELATED NODES*/ relate_cent = vector(0.0, 0.0); notrel_cent = vector(0.0, 0.0); nrel = 0; nnotrel = 0; // displayed nodes relatenode = currnode; for( FirstNode(); currnode != relatenode; NextNode() ) { switch ( SearchRelation() ) { case EMPTY_LIST: case NOT_FOUND: notrel_cent += currnode -> Position(); nnotrel++; break; case FIRST_FOUND: case FOUND: relate_cent += currnode -> Position(); nrel++; break; } } if ( nrel != 0 ) relate_cent /= (double)nrel; if ( nnotrel != 0 ) notrel_cent /= (double)nnotrel;/** IF THIS IS THE FIRST POINT -> PUT TO THE MIDDLE*/ if (nrel == 0 && nnotrel == 0) candidate = center; else/** IF NO NOT_RELATED NODE -> PUT TO THE CENTRE OF GRAVITY OF RELATED NODES*/ if ( nnotrel == 0 ) candidate = relate_cent; else/** IF NO RELATED NODE -> PUT TO THE MIRROR OF THE nrel_cent ON THE CENTRE*/ if ( nrel == 0 ) candidate = 2.0 * center - notrel_cent; else/** BOTH TYPE OF NODES EXIST ->* CALCULATE THE CANDIDATE POINT AS THE HALF MIRROR OF notrel_cent TO relate_cent*/ candidate = 2.0 * relate_cent - 1.0 * notrel_cent;/** PERTURBATE RANDOMLY*/ candidate += vector( perturb_x / (double)(nfixnode + inode + 5) * (double)( rand() - RAND_MAX / 2), perturb_y / (double)(nfixnode + inode + 5) * (double)( rand() - RAND_MAX / 2 ));/** DECIDE IF IT IS OUTSIDE -> FIND THE NEAREST INSIDE POINT*/ if ( candidate.X() < WALL_MARGIN) candidate = vector( 2.0 * WALL_MARGIN, candidate.Y() ); if ( candidate.X() > OVERWINDOW_X - WALL_MARGIN) candidate = vector(OVERWINDOW_X - 2.0 * WALL_MARGIN, candidate.Y()); if ( candidate.Y() < WALL_MARGIN) candidate = vector( candidate.X(), 2.0 * WALL_MARGIN ); if ( candidate.Y() > OVERWINDOW_Y - WALL_MARGIN) candidate = vector(candidate.X(), OVERWINDOW_Y - 2.0 * WALL_MARGIN );/** SET POSITION OF THE NEW NODE*/ relatenode -> Position( ) = candidate;/** ARRANGE ALREADY DEFINED NODES BY DYNAMIC LAYOUT -> IGNORE EDGE CONSTRAINTS*/ NodeElem * oldcurrnode = currnode; char ret = DynamicLayout( inode ); currnode = oldcurrnode; if ( ret != STOPPED || !NextNode() ) return ret; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -