/* The 2D view extension to X graphics */ #include "pixels.h" #include "views.h" /****************************************************************************/ /* vdraw_line will maintain the last arguments to draw_line: */ /* This permits a redraw and a drawto (command) */ float last_x1 = 0.0; float last_y1 = 0.0; float last_x2 = 0.0; float last_y2 = 0.0; /****************************************************************************/ /* Call this routine main() to debug this file alone. */ c_views_main() /* main() */ { View v, *pv; printf( "Hello, World\n" ); init_window(); /* Clear screen. */ clear_window(); pv = &v; pv->user_left_x = -1.0; pv->user_right_x = 1.0; pv->user_bottom_y = -1.0; pv->user_top_y = 1.0; pv->display_left_x = 0.0; pv->display_right_x = 496.0; pv->display_bottom_y = 844.0; pv->display_top_y = 0.0; pv->display = 0.0; pv->x_conversion_factor = 248.0; pv->y_conversion_factor = -422.0; describe_view( pv ); vdraw_line( -0.9, -0.9, 0.9, 0.9, SET, pv); vdraw_line( 0.9, -0.9, -0.9, 0.9, SET, pv); vdraw_line( -0.9, -0.9, 0.9, -0.9, SET, pv); vdraw_line( 0.9, -0.9, 0.9, 0.9, SET, pv); vdraw_line( 0.9, 0.9, -0.9, 0.9, SET, pv); vdraw_line( -0.9, 0.9, -0.9, -0.9, SET, pv); printf( "Press return to continue\n" ); getchar(); done_with_window(); } /****************************************************************************/ describe_view( pv ) pView pv; { printf( "View %d:\n \ user_left_x: %f\n \ user_right_x: %f\n \ user_bottom_y: %f\n \ user_top_y: %f\n \ display_left_x: %f\n \ display_right_x: %f\n \ display_bottom_y: %f\n \ display_top_y: %f\n \ display: %f\n \ x_conversion_factor: %f\n \ y_conversion_factor: %f\n", pv, pv->user_left_x, pv->user_right_x, pv->user_bottom_y, pv->user_top_y, pv->display_left_x, pv->display_right_x, pv->display_bottom_y, pv->display_top_y, pv->display, pv->x_conversion_factor, pv->y_conversion_factor ); return( (int) pv); } /****************************************************************************/ set_up_view( pv, x1, y1, x2, y2 ) pView pv; float x1, y1, x2, y2; { pv->user_left_x = x1; pv->user_right_x = x2; pv->user_bottom_y = y1; pv->user_top_y = y2; pv->display_left_x = 0.0; pv->display_right_x = (float) (width_of_window() - 1); pv->display_bottom_y = (float) (height_of_window() - 1); pv->display_top_y = 0.0; pv->display = 0.0; pv->x_conversion_factor = (pv->display_right_x - pv->display_left_x) / (pv->user_right_x - pv->user_left_x); pv->y_conversion_factor = (pv->display_top_y - pv->display_bottom_y) / (pv->user_top_y - pv->user_bottom_y); } /****************************************************************************/ /* This truncates negative numbers upwards (-1.8 -> -1), but pixels are always at positive locations (famous last words) */ #define pos_round(f) ((int) ((f) + 0.5)) /* GCC COMPILER BUG: SOMETIMES THESE ROUTINES DON'T COMPILE CORRECTLY IF COMPILED WITH CC AND CALLER COMPILED WITH GCC. */ float user_x_to_display( x, pv ) double x; register pView pv; { float result; result = (((x - pv->user_left_x) * pv->x_conversion_factor ) + pv->display_left_x ); /* printf( "uxtd: %lg %g\n", x, result ); */ return result; } float user_y_to_display( y, pv ) double y; register pView pv; { return(((y - pv->user_bottom_y) * pv->y_conversion_factor ) + pv->display_bottom_y ); } float display_x_to_user( x, pv ) double x; register pView pv; { return(((x - pv->display_left_x) / pv->x_conversion_factor ) + pv->user_left_x ); } float display_y_to_user( y, pv ) double y; register pView pv; { return(((y - pv->display_bottom_y) / pv->y_conversion_factor ) + pv->user_bottom_y ); } /****************************************************************************/ vdraw_line( x1, y1, x2, y2, operation, pv ) double x1, y1, x2, y2; int operation; pView pv; { /* We always convert points before clipping, since our floating point representation allows us to handle off screen points in redraw and drawto commands. */ last_x1 = user_x_to_display( x1, pv ); last_y1 = user_y_to_display( y1, pv ); last_x2 = user_x_to_display( x2, pv ); last_y2 = user_y_to_display( y2, pv ); /* CLIP, since x_draw_line seems to have a clipping bug. */ if ( (last_x1 < pv->display_left_x) && (last_x2 < pv->display_left_x ) ) return (int) pv; if ( (last_x1 > pv->display_right_x) && (last_x2 > pv->display_right_x ) ) return (int) pv; if ( (last_y1 > pv->display_bottom_y) && (last_y2 > pv->display_bottom_y ) ) return (int) pv; if ( (last_y1 < pv->display_top_y) && (last_y2 < pv->display_top_y ) ) return (int) pv; draw_line( pos_round( last_x1 ), pos_round( last_y1 ), pos_round( last_x2 ), pos_round( last_y2 ), operation ); return( (int) pv); } /****************************************************************************/ /* This is useful to draw a line using last_x1, last_y1, ... */ _vdraw_line( x1, y1, x2, y2, operation ) double x1, y1, x2, y2; int operation; { /* printf( "_vdraw_line: %lf %lf %lf %lf\n", x1, y1, x2, y2 ); */ /* CLIP, since x_draw_line seems to have a clipping bug. */ /* NO PV, so make up borders */ if ( (x1 < -1000000) && (x2 < -1000000) ) return; if ( (x1 > 1000000) && (x2 > 1000000 ) ) return; if ( (y1 > 1000000) && (y2 > 1000000 ) ) return; if ( (y1 < -1000000) && (y2 < -1000000 ) ) return; draw_line( pos_round( x1 ), pos_round( y1 ), pos_round( x2 ), pos_round( y2 ), operation ); } /****************************************************************************/ double distance_2( x1, y1, x2, y2 ) double x1, y1, x2, y2; { return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2); } /****************************************************************************/ vdraw_array( array, n_points, operation, pv ) float *array; int n_points; int operation; pView pv; { /* Plot an array against its indices */ float last_x, last_y; int index = 0; int actual_operation; float dash_x, dash_y; if ( n_points < 1 ) return (int) pv; if ( n_points == 1 ) { last_x1 = user_x_to_display( 0.0, pv ); last_y1 = user_y_to_display( array[0], pv ); last_x2 = last_x1; last_y2 = last_y1; /* CLIP, since x_draw_line seems to have a clipping bug. */ if ( (last_x1 < pv->display_left_x) && (last_x2 < pv->display_left_x ) ) return (int) pv; if ((last_x1 > pv->display_right_x) && (last_x2 > pv->display_right_x) ) return (int) pv; if ((last_y1 > pv->display_bottom_y) && (last_y2 > pv->display_bottom_y)) return (int) pv; if ( (last_y1 < pv->display_top_y) && (last_y2 < pv->display_top_y ) ) return (int) pv; draw_line( pos_round( last_x1 ), pos_round( last_y1 ), pos_round( last_x2 ), pos_round( last_y2 ), operation ); return (int) pv; } index = 0; last_x2 = user_x_to_display( (float) index, pv ); last_y2 = user_y_to_display( array[index], pv ); actual_operation = operation; if ( operation == DASHED ) { actual_operation = SET; dash_x = last_x2; dash_y = last_y2; } for( index = 1; index < n_points; index++ ) { last_x1 = last_x2; last_y1 = last_y2; last_x2 = user_x_to_display( (float) index, pv ); last_y2 = user_y_to_display( array[index], pv ); if ( operation == DASHED ) { if ( distance_2( dash_x, dash_y, last_x2, last_y2 ) > DASH_THRESHOLD ) { dash_x = last_x2; dash_y = last_y2; if ( actual_operation == SET ) actual_operation = CLEAR; else actual_operation = SET; } } /* CLIP, since x_draw_line seems to have a clipping bug. */ if ( (last_x1 < pv->display_left_x) && (last_x2 < pv->display_left_x ) ) continue; if ( (last_x1 > pv->display_right_x) && (last_x2 > pv->display_right_x )) continue; if ((last_y1 > pv->display_bottom_y) && (last_y2 > pv->display_bottom_y)) continue; if ( (last_y1 < pv->display_top_y) && (last_y2 < pv->display_top_y ) ) continue; draw_line( pos_round( last_x1 ), pos_round( last_y1 ), pos_round( last_x2 ), pos_round( last_y2 ), actual_operation ); /* printf( "%d: %g; %d %d %d %d %d\n", index, array[index], pos_round( last_x1 ), pos_round( last_y1 ), pos_round( last_x2 ), pos_round( last_y2 ), operation ); */ } return( (int) pv); } /****************************************************************************/ vdraw_array2( array1, array2, n_points, operation, pv ) float *array1, *array2; int n_points; int operation; pView pv; { /* Plot one array against another. */ } /***************************************************************************/ box( x1, y1, x2, y2, operation, pv ) float x1, y1, x2, y2; int operation; pView pv; { vdraw_line( x1, y1, x2, y1, operation, pv ); vdraw_line( x2, y1, x2, y2, operation, pv ); vdraw_line( x2, y2, x1, y2, operation, pv ); vdraw_line( x1, y2, x1, y1, operation, pv ); } /****************************************************************************/ draw_cross( x, y, dx, dy, operation, pv ) float x, y, dx, dy; int operation; pView pv; { vdraw_line( x - dx, y, x + dx, y, operation, pv ); vdraw_line( x, y - dy, x, y + dy, operation, pv ); } /****************************************************************************/ /****************************************************************************/