packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/andrea-m2/lib/multiscope/plotter.mod

IMPLEMENTATION MODULE Plotter;
(*/NOWARN*)
FROM LewertsScale IMPORT Scale;
FROM VGAGraphics IMPORT BeginVGA, EndVGA,
   			EraseScreen, GetDimensions,
   			Move, LineColor, Text;
FROM CardArrays IMPORT CardArray, Build, Destroy, Put, Get;
FROM Terminal IMPORT Read;
 
  (* ---------------------------------------- *)
  PROCEDURE Plot( title :ARRAY OF CHAR; x, y :ARRAY OF REAL; n :CARDINAL );

  VAR
    x_min, x_max, y_min, y_max,
    x_scale_min, x_scale_max,
    y_scale_min, y_scale_max,
    x_scale_inc, y_scale_inc :REAL;

    i, j  :CARDINAL;
    index :CardArray;

    (* ------------------------------------------ *)
    PROCEDURE SetScale( min, max :REAL;
                        VAR scale_min, scale_max, scale_inc :REAL );
    VAR
      tenth :REAL;
    BEGIN
      IF min = max THEN
        (* its flat, so fake it *)
        tenth := min / 10.0;
        min := min - tenth;
        max := max + tenth; 
      END;

      (* get nice scaling parameters *)
      Scale( min, max, 7, scale_min, scale_max, scale_inc );
    END SetScale;
    
  BEGIN
  
    Build( index, 0, n-1 ); (* create a temporary array for sorting index *)
    
    XYSort( x, y, n, index );
    
    x_min := x[Get(index,0)];  x_max := x[Get(index,n-1)];
    
    (* but we must run over the array to get y range *)
    y_min := y[Get(index,0)];  y_max := y[Get(index,0)];
    FOR i := 1 TO n-1 DO
      j := Get( index, i );
      IF y[j] < y_min THEN y_min := y[j] END;
      IF y[j] > y_max THEN y_max := y[j] END;
    END;
    
    SetScale( x_min, x_max, x_scale_min, x_scale_max, x_scale_inc );
    SetScale( y_min, y_max, y_scale_min, y_scale_max, y_scale_inc );
    
    VGAPlot( title, x, y, n, index,
             x_scale_min, x_scale_max, y_scale_min, y_scale_max,
             x_scale_inc, y_scale_inc );
            
    Destroy( index ); (* all done, get rid of the temporary index *)
    
  END Plot;

  (* ---------------------------------------------------- *)
  PROCEDURE VGAPlot( title :ARRAY OF CHAR;
                     x, y :ARRAY OF REAL; n :CARDINAL; index :CardArray;
                     x_min, x_max, y_min, y_max, x_inc, y_inc :REAL );

  CONST
     tic_len = 11;
       
  VAR
    x_size, y_size :REAL;
    i, j           :CARDINAL; 
    z              :REAL;
    c		   :CHAR;

    x_range, y_range, x_scale, y_scale :REAL;
    x_pos, y_pos		       :REAL;

  BEGIN

    EraseScreen;
        
    GetDimensions( i, j );
    x_size := FLOAT( i );
    y_size := FLOAT( j );

    x_range := x_max - x_min;
    x_scale := x_size / x_range;

    y_range := y_max - y_min;
    y_scale := y_size / y_range;

    BeginVGA;
      
    (* draw the axis *)
    Move( 0, 0 ); LineColor( TRUNC( x_size ), 0, 12 );
    Move( 0, 0 ); LineColor( 0, TRUNC( y_size ), 12 );
      
    (* put in the tick marks *)
      
    (* run along the x axis, putting in the numbers *)
    (* run along the y axis, putting in the numbers *)
    (* now draw the actual data points *)

    (* go to the first data point *)

    i := 0;
    j := Get( index, i );
    x_pos := ( x[j] - x_min ) * x_scale;
    y_pos := ( y[j] - y_min ) * y_scale;
    Move( TRUNC(x_pos), TRUNC(y_pos) );

    FOR i := 1 TO n-1 DO

       j := Get( index, i );
       x_pos := ( x[j] - x_min ) * x_scale;
       y_pos := ( y[j] - y_min ) * y_scale;
               
       LineColor( TRUNC(x_pos), TRUNC(y_pos), 14 );

    END;

    Move( 200, 200 ); Text( title );

    Read( c );
    EndVGA;
      
  END VGAPlot;
    
  (* ----------------------------------------------------- *)
  PROCEDURE XYSort( x, y :ARRAY OF REAL; array_len :CARDINAL;
		    index :CardArray );
      
  CONST
    max_stack = 20;
    n_small   = 6; (* use a simple sort for this size and smaller *)

  VAR
    L, R, i, j, k, n :INTEGER;

    tos            :CARDINAL;
    Lstack, Rstack :ARRAY [1..max_stack] OF INTEGER;

    median :REAL;

    (* -------------------------------- *)
    PROCEDURE Swap( i, j :CARDINAL );
    VAR  ctemp :CARDINAL;
    BEGIN
      ctemp := Get(index,i);
      Put( index, i, Get(index,j) );
      Put( index, j, ctemp );
    END Swap;
    
  BEGIN

    n := INTEGER( array_len ) - 1; (* back to zero offset *)

    (* initialize the index *)
    FOR i := 0 TO n DO
       Put( index, i, i );
    END;

    tos := 0;

    L := 0;  R := n;

    (* PUSH very first set *)
    tos := tos + 1;  Lstack[tos] := L;  Rstack[tos] := R;

    REPEAT

      (* POP *)
      L := Lstack[tos];  R := Rstack[tos];  tos := tos - 1;

      IF R - L + 1 > n_small THEN

        REPEAT
          i := L;  j := R;    median := x[Get(index,( L + R ) DIV 2)];

          REPEAT
            WHILE x[Get(index,i)] < median DO
              i := i + 1;
            END;
            WHILE median < x[Get(index,j)] DO
              j := j - 1;
            END;

            IF i <= j THEN
              Swap( i, j );
              i := i + 1;  j := j - 1;
            END;
          UNTIL i > j;

          IF j - L < R - i THEN
            IF i < R THEN (* PUSH *)
              tos := tos + 1;  Lstack[tos] := i;  Rstack[tos] := R;
            END;
            R := j;
          ELSE
            IF L < j THEN (* push *)
              tos := tos + 1;  Lstack[tos] := L;  Rstack[tos] := j;
            END;
            L := i;
          END;

        UNTIL L >= R;

     ELSE

       (* small sort for small number of values *)
       FOR i := L TO R - 1 DO
          FOR j := i TO R DO
             IF x[Get(index,i)] > x[Get(index,j)] THEN
               Swap( i, j );
             END;
          END;
       END;

     END; (* check for small *)

   UNTIL tos = 0;
 
   (* now look for duplicates of x, and sort those by y *)
        
   k := 1; (* start at second element *)
   WHILE k <= n DO

     IF x[Get(index,k)] = x[Get(index,k-1)] THEN

       L := k - 1;    (* first of the duplicated x's *)

       (* search for more duplictes *)
       j := k;
       WHILE ( j <= n ) & ( x[Get(index,L)] = x[Get(index,j)] ) DO
         j := j + 1;
       END;
            
       R := j - 1;   (* last of the duplicated x's *)

       (* now sort between first and last by Y *)
       FOR i := L TO R - 1 DO
          FOR j := i TO R DO
             IF y[Get(index,i)] > y[Get(index,j)] THEN
               Swap( i, j );
             END;
          END;
       END;

       (* and advance the current index to the last of the duplicates *)
       (* because all these values have been examined *)

       k := R;
            
     END;
          
     k := k + 1;
   END;

 END XYSort;


BEGIN
END Plotter.