Check-in [7c222a4184]
Not logged in
Overview
SHA1:7c222a418440d4b512c4e1de9395f2f06410dc2a
Date: 2012-12-24 03:52:54
User: Derek
Comment:moved globals to beginning of draw.html added some null checking to matrix_vector_lib.js fixed small bugs (zooming in to much messes up axis draw)
Timelines: family | ancestors | descendants | both | trunk
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2012-12-24
04:23
[17fe78b11b] (no comment) (user: Derek, tags: trunk)
03:52
[7c222a4184] moved globals to beginning of draw.html added some null checking to matrix_vector_lib.js fixed small bugs (zooming in to much messes up axis draw) (user: Derek, tags: trunk)
2012-12-23
19:18
[1bc6e97248] removed superfulous code and comments. updated TODOs (user: Derek, tags: trunk)
Changes

Modified draw.html from [d50a5e8508] to [97f687849d].

     1      1   <html>
     2      2   <script src='matrix_vector_lib.js' ></script>
     3      3   
     4      4   <script>
     5      5   
     6         -
            6  +//  TODO rotate selected points
     7      7   //  TODO control with zoom rotate or pan means that action is only applied to the camera not the selected points.
     8      8   
     9      9   
    10     10   //  TODO clicking and dragging on a line allows you to place a point somewhere on that line.  Perhaps with the modifier key it would break up the existing line into line segments.
    11     11   
    12     12   //  TODO when lines are deleted, readd the solo points to the solo_points list
    13     13   //  
    14     14   
    15     15   //  TODO z for undo shift + z for redo.
           16  +//
           17  +//  TODO 
    16     18   //
    17     19   
    18     20   //  TODO drop down minimalist menu in top right of canvas.
    19     21   
    20     22   
    21     23   //  drag to connect points
    22     24   
    23     25   
    24     26   var canvas;
    25     27   var origin = [0, 0, 0];
    26     28   var frame_rate = 20;
    27     29   var saveTimeout = 10*1000;
    28     30   
    29         -var no_rotate_area = 0.80;
    30         -            
    31         -            
           31  +var forward_axis_size = 0.1;
           32  +var vertical_axis_size = 0.05;      
           33  +
           34  +
           35  +
           36  +
           37  +// to prevent camera from rotating beyond straight vertical
           38  +var vertical_camera_rotation = 0;
           39  +var zoom_dist = 1;
           40  +var zoom_factor = 0.83;
           41  +var zoom_scale = 2.667;  // scalar zoom property.
           42  +var last_zoom_dist = 1;
           43  +
           44  +
           45  +// camera animation
           46  +var max_move_delta = 0.01;
           47  +var max_angle_delta = Math.PI;
           48  +
           49  +var delta_horizontal_angle = 0;
           50  +var delta_vertical_angle = 0;
           51  +var delta_position = [0,0,0];
           52  +
           53  +
           54  +//  Use to rotate selected points about a vector line
           55  +var selection_rotation_vector = null;
           56  +var rotation_center = origin.slice(0);
           57  +
           58  +
           59  +
           60  +
           61  +
           62  +var points = []; //global
           63  +var solo_points = {};
           64  +var lines = [];
           65  +
           66  +var point_projections = [];
           67  +var line_midpoint_projections = [];
           68  +
           69  +var highlight_object = null;
           70  +var mouse_dragging = false;
           71  +var last_mouse_down = null;
           72  +var mouse_loc = null;
           73  +var MIN_DRAG_DIST = 10;
           74  +var POINT_HIGHLIGHT_DIST = 10;
           75  +var LINE_HIGHLIGHT_DIST = 15;
           76  +
           77  +var selected_points = [];
           78  +var selected_lines = [];
           79  +
           80  +var msg = //"3D drawing tool\n\n" +
           81  +          "Select     Left Click\n" +
           82  +		  "Rotate     Right Click\n" +
           83  +		  "Move       wasd, qe\n" +
           84  +		  "Copy       Space\n" +
           85  +		  "Delete     x\n" +
           86  +		  "\n" +
           87  +		  "Click the red dot to create a point\n" +
           88  +	      "Spam a motion key to increase speed\n";		  
           89  +	
           90  +	
           91  +
           92  +
           93  +var view_transform =
           94  +    [[1, 0, 0],
           95  +     [0, 1, 0],
           96  +     [0, 0, 1]];
           97  +    
           98  +
           99  +
          100  +
          101  +
          102  +
          103  +
    32    104   
    33    105               
    34    106   
    35    107   var key_state = {};
    36         -var key_state_augmentation_delay = 150; // the permissible time in milliseconds since the last key event to still allow the key state to augment instead of clearing.
          108  +var key_state_augmentation_timeout = 150; // the permissible time in milliseconds since the last key event to still allow the key state to augment instead of clearing.
    37    109   
    38    110   function addKeyListener(keycode, func){
    39    111       if(!key_state[keycode]) key_state[keycode] = {};
    40    112       
    41    113       var key_obj = key_state[keycode];
    42    114       if(!key_obj.listeners) key_obj.listeners = [];
    43    115       
................................................................................
    60    132       var state = key_obj.state;
    61    133       if(state) return; //key is already pressed.
    62    134       
    63    135       state = 0;
    64    136       
    65    137       var latest = key_obj.latest;
    66    138   
    67         -    if(latest && time - latest < key_state_augmentation_delay)
          139  +    if(latest && time - latest < key_state_augmentation_timeout)
    68    140           state = key_obj.state = key_obj.lastState + 1;
    69    141       else
    70    142           state = key_obj.state = 1;
    71    143           
    72    144       key_obj.latest = time;
    73    145       
    74    146       key_obj.lastState = state;
................................................................................
   146    218       if(!positive) delta = -delta;
   147    219       
   148    220       var velocityChange = [0, 0, 0];
   149    221       velocityChange[direction] = delta;
   150    222       vector_add(delta_position, velocityChange, delta_position); }
   151    223       
   152    224   
   153         -//
   154         -//  This 
   155         -//
          225  +	
          226  +
   156    227       
   157    228   function leftPress(e, s, lasts){
   158    229       changeVelocity(0, false, s, lasts); }
   159    230       
   160    231   function rightPress(e, s, lasts){
   161    232        changeVelocity(0, true, s, lasts); }
   162    233        
................................................................................
   318    389   				
   319    390   				if(minx < _x && _x < maxx
   320    391   				 && miny < _y && _y < maxy){
   321    392   				   selected_points.push(i); }}}                
   322    393           }});
   323    394   
   324    395   
   325         -
   326         -
   327         -
   328         -// to prevent camera from rotating beyond straight vertical
   329         -var vertical_camera_rotation = 0;
   330         -var NAVIGATION_ZOOM_DIST = 0.01;
   331         -var zoom_dist = 1;
   332         -var zoom_factor = 0.83;
   333         -var zoom_scale = 2.667;  // scalar zoom property.
   334         -var last_zoom_dist = 1;
   335         -
   336         -
   337         -// camera animation
   338         -var max_move_delta = 0.01;
   339         -var max_angle_delta = Math.PI / 2;
   340         -
   341         -var delta_horizontal_angle = 0;
   342         -var delta_vertical_angle = 0;
   343         -var delta_position = [0,0,0];
   344         -
   345         -
   346         -
   347         -
   348         -
   349         -var points = []; //global
   350         -var solo_points = {};
   351         -var lines = [];
   352         -
   353         -var point_projections = [];
   354         -var line_midpoint_projections = [];
   355         -
   356         -var highlight_object = null;
   357         -var mouse_dragging = false;
   358         -var last_mouse_down = null;
   359         -var mouse_loc = null;
   360         -var MIN_DRAG_DIST = 10;
   361         -var POINT_HIGHLIGHT_DIST = 10;
   362         -var LINE_HIGHLIGHT_DIST = 15;
   363         -
   364         -var selected_points = [];
   365         -var selected_lines = [];
   366         -
   367         -var msg = "3D drawing tool";
   368         -
   369         -
   370         -var view_transform =
   371         -    [[1, 0, 0],
   372         -     [0, 1, 0],
   373         -     [0, 0, 1]];
   374         -    
          396  +// right click
          397  +addKeyListener(1002, function(e, s, lasts){
          398  +	if(s == 0){
          399  +		delta_horizontal_angle = 0;
          400  +		delta_vertical_angle = 0; }});
          401  +
          402  +
          403  +function writeMsg(canvas, msg){
          404  +	var lines = msg.split("\n");
          405  +	var ctx = canvas.getContext("2d");
          406  +	ctx.font = "9pt sans-serif"
          407  +	for(var i = 0; i < lines.length; ++i){
          408  +		ctx.fillText(lines[i], 5, 10 + 15 *  i); }}
   375    409   
   376    410       
   377    411   //  camera functions
   378    412   
   379    413   function rotateView(norm, theta, cameracentric){
   380    414   
   381    415       // camera centric uses the camera axes to perform the rotation instead of the space axes.   
................................................................................
   541    575           var x1 = _pt1[0];
   542    576           var y1 = _pt1[1];
   543    577           
   544    578           ctx.moveTo(x0, y0);
   545    579           ctx.lineTo(x1, y1); }
   546    580       
   547    581       ctx.clearRect(0, 0, w, h);
   548         -    var hoffset = h * (1 - no_rotate_area)/ 2;
   549         -    var woffset = w * (1 - no_rotate_area)/ 2;
          582  +	
   550    583       
   551         -    ctx.fillStyle = "rgba(128, 128, 128, 0.05)";
   552         -    ctx.fillRect(0, 0, w, hoffset);
   553         -    ctx.fillRect(0, hoffset, woffset, h - 2 * hoffset);
   554         -    ctx.fillRect(w - woffset, hoffset, woffset, h - 2 * hoffset);
   555         -    ctx.fillRect(0, h - hoffset, w, hoffset);
   556         -    
   557         -    ctx.fillStyle = "rgb(0, 0, 128)";
          584  +	ctx.strokeStyle = "rgba(0, 0, 0, 0.9)";
   558    585       ctx.stroke();
   559    586       
          587  +	ctx.fillStyle = "rgba(0, 0, 0, 0.9)";
   560    588       for(var k in solo_points){
   561    589          var pt = point_projections[k];
   562    590          if(pt) ctx.fillRect(pt[0] - 2, pt[1] - 2, 4, 4); }
   563    591           
   564    592       
   565         -    
   566         -    
          593  +
          594  +	// axis lines and dots
          595  +	ctx.beginPath();
          596  +    var faxis_pt = project(canvas, vector_add(origin, [0, 0, forward_axis_size, 0, 0]), view_transform, origin);
          597  +	var vaxis_pt = project(canvas, vector_add(origin, [0, -vertical_axis_size, 0]), view_transform, origin);
          598  +	
          599  +	ctx.fillStyle = "rgba(0,0,0,0.9)";
          600  +	
          601  +	if(faxis_pt){
          602  +		ctx.moveTo(w/2, h/2);
          603  +		ctx.lineTo(faxis_pt[0], faxis_pt[1]);
          604  +		ctx.fillRect(faxis_pt[0] - 2, faxis_pt[1] - 2, 4, 4); }
          605  +		
          606  +	if(vaxis_pt){
          607  +		ctx.moveTo(w/2, h/2);
          608  +		ctx.lineTo(vaxis_pt[0], vaxis_pt[1]);
          609  +		ctx.fillRect(vaxis_pt[0] - 2, vaxis_pt[1] - 2, 4, 4); }
          610  +		
          611  +	ctx.stroke();	
          612  +	
          613  +	
          614  +
          615  +    // red center dot.
   567    616   	ctx.fillStyle = "rgba(250, 0, 0, 0.9)";
   568    617   	ctx.fillRect(w/2 - 2, h/2 - 2, 4, 4);
          618  +		
   569    619   	
   570    620   	for(var i = 0; i < selected_points.length; ++i){
   571    621   		var pt;
   572    622   		
   573    623   		if(selected_points[i] == -1)
   574    624   			pt = [w/2, h/2];
   575    625   		else pt = point_projections[selected_points[i]];
................................................................................
   614    664   		
   615    665   	else{
   616    666   		document.body.style.cursor = "crosshair"; }
   617    667   	
   618    668   	if(mouse_dragging){
   619    669   	
   620    670   		if(selected_points.length && (!key_state[16] || !key_state[16].state)){  // if shift is held, we are selecting more points.
   621         -			if(mouse_loc){
          671  +			if(mouse_loc && key_state[1000] && key_state[1000].state){
   622    672   				ctx.beginPath();
   623         -				for(var i = 0; i < selected_points.length; ++i){
   624         -					var pt = point_projections[selected_points[i]];
   625         -					if(pt){
   626         -						ctx.moveTo(mouse_loc[0], mouse_loc[1]);
   627         -						ctx.lineTo(pt[0], pt[1]); }}
          673  +				var pt = point_projections[selected_points[0]];
          674  +				if(pt){
          675  +					ctx.moveTo(mouse_loc[0], mouse_loc[1]);
          676  +					ctx.lineTo(pt[0], pt[1]); }
   628    677   				ctx.stroke(); }}
          678  +				
          679  +		else if(mouse_loc && last_mouse_down){  
          680  +		
   629    681   		
   630         -		else if(mouse_loc && last_mouse_down){  // select points inside square            
   631         -			var minx = Math.min(mouse_loc[0], last_mouse_down[0]);
   632         -			var maxx = Math.max(mouse_loc[0], last_mouse_down[0]);
   633         -			var miny = Math.min(mouse_loc[1], last_mouse_down[1]);
   634         -			var maxy = Math.max(mouse_loc[1], last_mouse_down[1]);
   635         -			ctx.beginPath();
   636         -			ctx.rect(minx, miny, maxx-minx, maxy-miny);
   637         -			ctx.stroke(); }
          682  +		    if(key_state[1000] && key_state[1000].state){     // select points inside square
          683  +				var minx = Math.min(mouse_loc[0], last_mouse_down[0]);
          684  +				var maxx = Math.max(mouse_loc[0], last_mouse_down[0]);
          685  +				var miny = Math.min(mouse_loc[1], last_mouse_down[1]);
          686  +				var maxy = Math.max(mouse_loc[1], last_mouse_down[1]);
          687  +				ctx.beginPath();
          688  +				ctx.rect(minx, miny, maxx - minx, maxy - miny);
          689  +				ctx.stroke(); }}
   638    690   	}
   639    691       
   640    692       ctx.fillStyle = "rgb(0,0,0)";
   641         -    ctx.fillText(msg, 5, 20); }
          693  +	writeMsg(canvas, msg); }
   642    694   
   643    695       
   644    696       
   645    697   window.onload = function(){
   646    698   
   647    699       // load localStorage saved state.
   648    700       if(localStorage.points && localStorage.lines){
................................................................................
   660    712           canvas.width = window.innerWidth - 20;
   661    713           canvas.height = window.innerHeight - 20; }
   662    714   
   663    715       
   664    716       
   665    717       function getRotationAngle(x, size, max, center_size){
   666    718   
   667         -        if(!center_size) center_size = 0.25;  // the proportional size of the area in which no rotation is effected by the mouse movement
          719  +        if(!center_size) center_size = 0.05;  // the proportional size of the area in which no rotation is effected by the mouse movement
   668    720           if(!max) max = Math.PI/128;
   669         -        x -= size/2;
   670    721           
   671    722           //  center does nothing
   672    723           if(Math.abs(x) < size * center_size/2) x = 0;
   673    724           else if(x < 0) x += size * center_size/2;
   674    725           else           x -= size * center_size/2;
   675    726           
   676    727           return max * x / ((1 - center_size) * size/2); }
................................................................................
   695    746               var dist2 = _x*_x + _y*_y;
   696    747               
   697    748               if(dist2 > MIN_DRAG_DIST * MIN_DRAG_DIST){
   698    749                   mouse_dragging = true; }}
   699    750                   
   700    751   
   701    752   				
   702         -		delta_horizontal_angle = getRotationAngle(x, w, max_angle_delta/frame_rate, no_rotate_area);
   703         -		delta_vertical_angle = -getRotationAngle(y, h, max_angle_delta/frame_rate, no_rotate_area);
   704         -		
          753  +	    if(key_state[1002] && key_state[1002].state && last_mouse_down){
          754  +			delta_horizontal_angle = getRotationAngle(x - last_mouse_down[0], w, max_angle_delta/frame_rate, 0);
          755  +			delta_vertical_angle = -getRotationAngle(y - last_mouse_down[1], h, max_angle_delta/frame_rate, 0); }
          756  +			
          757  +			
   705    758   		var min_point_dist2 = LINE_HIGHLIGHT_DIST * LINE_HIGHLIGHT_DIST;
   706    759   		highlight_object = null;
   707    760   		
   708    761   		var _x = canvas.width/2 - x;
   709    762   		var _y = canvas.height/2 - y;
   710    763   		var point_dist = _x*_x + _y*_y;
   711    764   		

Modified matrix_vector_lib.js from [8300025cc5] to [0be33777c1].

     2      2   
     3      3   //  matrix and vector functions.
     4      4   //
     5      5   //
     6      6   
     7      7   function vector_add(a, b, result){
     8      8       if(!result) result = [];
            9  +	if(!a) throw "first argument to vector_add missing";
           10  +	if(!b) throw "second argument to vector_add missing";
     9     11   
    10     12       if(a.length > b.lemgth){
    11     13           var tmp = a;
    12     14           a = b; b = tmp; }
    13     15   
    14     16       for(var i = 0; i < a.length; ++i){
    15     17           result[i] = a[i] + b[i]; }
................................................................................
    17     19       for(var i = a.length; i < b.length; ++i){
    18     20           result[i] = b[i]; }
    19     21   
    20     22       return result; }
    21     23   
    22     24       
    23     25   function vector_cpy(result, a){
           26  +	if(!a) throw "first argument to vector_cpy missing";
    24     27       for(var i = 0; i < a.length; ++i){
    25     28           result[i] = a[i]; }
    26     29   }
    27     30   
    28     31   
    29     32   
    30     33   function vector_minus(a, b, result){
    31     34       if(!result) result = [];
           35  +	if(!a) throw "first argument to vector_minus missing";
           36  +	if(!b) throw "second argument to vector_minus missing";
    32     37   
    33     38       var lim = Math.max(a.length, b.length);
    34     39       
    35     40       for(var i = 0; i < lim; ++i){
    36     41   		var aValue, bValue;
    37     42   		if(i < a.length)
    38     43   			aValue = a[i];
................................................................................
    49     54           
    50     55       return result; }
    51     56      
    52     57   
    53     58   
    54     59   function vector_dot(a, b){
    55     60       var lim = Math.min(a.length, b.length);
           61  +	if(!a) throw "first argument to vector_dot missing";
           62  +	if(!b) throw "second argument to vector_dot missing";
           63  +	
    56     64       var result = 0;
    57     65   
    58     66       for(var i = 0; i < lim; ++i){
    59     67           result += a[i] * b[i]; }
    60     68   
    61     69       return result; }
    62     70       
    63     71       
    64     72   function vector_norm(a){
           73  +	if(!a) throw "argument to vector_norm missing";
    65     74       return Math.sqrt(vector_dot(a,a)); }
    66     75   
    67     76       
    68     77       
    69     78       
    70     79   function vector_scale(a, s, result){
           80  +	if(!a) throw "first argument to vector_scale missing";
           81  +	if(s === undefined || s === null) throw "scalar argument to vector_scale missing";
    71     82   
    72     83       if(!result) result = [];
    73     84       
    74     85       for(var i = 0; i < a.length; ++i){
    75     86           result[i] = s * a[i]; }
    76     87   
    77     88       return result; }
    78     89   
    79     90   
    80     91   
    81     92   // returns true iff the zero tail padded vectors match
    82     93   function vector_cmp(a, b){
           94  +	if(!a) throw "first argument to vector_cmp missing";
           95  +	if(!b) throw "second argument to vector_cmp missing";
    83     96   
    84     97       if(a.length > b.length){
    85     98            var tmp = a;
    86     99            a = b; b = tmp; }
    87    100   
    88    101       for(var i = 0; i < a.length; ++i){
    89    102           if(a[i] != b[i]) 
................................................................................
    93    106           if(b[i] != 0) 
    94    107   			return false; }
    95    108               
    96    109       return true; }
    97    110       
    98    111       
    99    112       
   100         -function midpoint(a, b, result){
          113  +function vector_midpoint(a, b, result){
          114  +	if(!a) throw "first argument to vector_midpoint missing";
          115  +	if(!b) throw "second argument to vector_midpoint missing";
   101    116   
   102    117       if(b.length > a.length){
   103    118           var tmp = a;
   104    119           a = b; b = tmp; }
   105    120           
   106    121       if(!result) result = new Array(b.length);
   107    122           
................................................................................
   115    130   }
   116    131   
   117    132   
   118    133   
   119    134   
   120    135   //this function may not care, but the expected matrix format in this project is a list of column vectors.
   121    136   function matrix_transpose(matrix){
          137  +	if(!matrix) throw "argument to matrix_transpose missing";
   122    138   
   123    139       var result = [];
   124    140       var dim0 = matrix.length;
   125    141       if(!dim0) 
   126    142   		return result;
   127    143   
   128    144       var dim1 = matrix[0].length;
................................................................................
   139    155       
   140    156   
   141    157   
   142    158       
   143    159       
   144    160   
   145    161   function matrix_mult(a, b){
          162  +	if(!a) throw "first argument to matrix_mult missing";
          163  +	if(!b) throw "second argument to matrix_mult missing";
   146    164   
   147    165       var result = [];
   148    166       var a = matrix_transpose(a);
   149    167       var dim0 = a.length;
   150    168       var dim1 = b.length;
   151    169   
   152    170       for(var i = 0; i < dim1; ++i){
................................................................................
   160    178   
   161    179   
   162    180       
   163    181   // finds the inverse of a 3 by 3 matrix, returns false if matrix has determinant zero.
   164    182   //
   165    183   
   166    184   function matrix33inv(m){
          185  +    if(!m) throw "argument to matrix33inv missing";
   167    186   
   168    187       // the matrix format is a list of column vectors.
   169    188       var a = m[0][0];
   170    189   	var b = m[1][0];
   171    190   	var c = m[2][0];
   172    191   	var d = m[0][1];
   173    192   	var e = m[1][1];
................................................................................
   203    222   	// the matrix format is a list of column vectors.
   204    223   	var result = [[di*A, di*B, di*C],
   205    224   		          [di*D, di*E, di*F],
   206    225   		          [di*G, di*H, di*K]];
   207    226   
   208    227   	return result;  }
   209    228   
   210         -    
          229  +	
          230  +// does not check if function is differentiable.
          231  +
   211    232   function compute_gradient(func, point, error){
          233  +	if(!func) throw "function argument to compute_gradient missing";
          234  +	if(!point) throw "point argument to compute_gradient missing";
   212    235   
   213    236       if(!error) error = 0.00001;
   214    237   
   215    238       // find gradient
   216    239       var otherpoint = point.slice(0);
   217    240       var gradient = new Array(point.length);
   218    241       var pointvalue = func(point);
................................................................................
   232    255   
   233    256   //
   234    257   // equation at:
   235    258   // http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.html
   236    259   // creates a rotation matrix about the given vector.
   237    260   //
   238    261   function vector_rotation(vector, s){
   239         -
          262  +	if(!vector) throw "vector argument to vector_rotation missing";
          263  +	if(!s) throw "angle argument to vector_rotation missing";
          264  +	
   240    265       var len = Math.sqrt(vector[0]*vector[0]
   241    266                           + vector[1]*vector[1]
   242    267                           + vector[2]*vector[2]);
   243    268   
   244    269       var u = vector[0]/len;
   245    270       var v = vector[1]/len;
   246    271       var w = vector[2]/len;