1 /* 2 Copyright 2008,2009 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Alfred Wassermann, 8 Peter Wilfahrt 9 10 This file is part of JSXGraph. 11 12 JSXGraph is free software: you can redistribute it and/or modify 13 it under the terms of the GNU Lesser General Public License as published by 14 the Free Software Foundation, either version 3 of the License, or 15 (at your option) any later version. 16 17 JSXGraph is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public License 23 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>. 24 25 */ 26 27 /* Compatibility for <= 0.75.4 */ 28 /* 29 JXG.getReference = function(board, object) { 30 return JXG.GetReferenceFromParameter(board, object); 31 }; 32 */ 33 34 JXG.IntergeoReader = new function() { 35 this.board = null; 36 /** 37 * this.objects holds all objects from the XML file. 38 * Every object hets an attribute "exists" 39 */ 40 this.objects = {}; 41 42 this.readIntergeo = function(tree,board) { 43 this.board = board; 44 this.board.origin = {}; 45 this.board.origin.usrCoords = [1, 0, 0]; 46 this.board.origin.scrCoords = [1, 400, 300]; 47 this.board.unitX = 30; 48 this.board.unitY = 30; 49 50 this.readElements(tree.getElementsByTagName("elements")); 51 this.readConstraints(tree.getElementsByTagName("constraints")); 52 this.cleanUp(); 53 this.board.fullUpdate(); 54 this.readDisplay(tree.getElementsByTagName("display")); 55 this.board.fullUpdate(); 56 }; 57 58 /** 59 * Element part 60 */ 61 this.readElements = function(tree) { 62 var s; 63 for (var s=0;s<tree[0].childNodes.length;s++) (function(s) { 64 var node; 65 node = tree[0].childNodes[s]; 66 if (node.nodeType>1) { return; } // not an element node 67 if (node.nodeName=='point') { 68 JXG.IntergeoReader.storePoint(node); //addPoint(node); 69 } 70 else if (node.nodeName=='line' 71 || node.nodeName=='line_segment' 72 || node.nodeName=='ray' 73 || node.nodeName=='vector' 74 ) { 75 JXG.IntergeoReader.storeLine(node); 76 } 77 else if (node.nodeName=='circle') { 78 JXG.IntergeoReader.storeConic(node); 79 } 80 else if (node.nodeName=='conic') { 81 JXG.IntergeoReader.storeConic(node); 82 } 83 else if (node.nodeName=='polygon') { 84 // ignore, see this.addPolygonByVertices 85 } 86 else { 87 JXG.debug('Not implemented: '+node.nodeName + ' ' + node.getAttribute('id')); 88 } 89 })(s); 90 }; 91 92 /** 93 * Points are created instantly via create 94 */ 95 this.addPointOld = function(node) { 96 var i = 0, 97 j = 0, 98 l = 0, 99 el, 100 p = node.childNodes[i], 101 c = [], 102 attributes = {strokeColor:'red', fillColor:'red', withLabel:true}, 103 parents = []; 104 105 while (p.nodeType>1) { // skip non element nodes 106 i++; 107 p = node.childNodes[i]; 108 } 109 110 attributes['name'] = node.getAttribute('id'); 111 112 if (p.nodeName == 'homogeneous_coordinates') { 113 for (j=0;j<p.childNodes.length;j++) { 114 if (p.childNodes[j].nodeType==1) { 115 if (p.childNodes[j].nodeName=='double') { 116 c.push(p.childNodes[j].firstChild.data); // content of <double>...</double> 117 } else if (p.childNodes[j].nodeName=='complex') { 118 for (l=0;l<p.childNodes[j].childNodes.length;l++) { 119 if (p.childNodes[j].childNodes[l].nodeName=='double') { 120 c.push(p.childNodes[j].childNodes[l].firstChild.data); 121 } 122 } 123 } else { 124 JXG.debug('Not implemented: '+ p.childNodes[j].nodeName); // <complex> 125 return; 126 } 127 } 128 } 129 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 130 if (c.length==3) { // Real 131 parents = [c[2],c[0],c[1]]; 132 } else if (c.length==6 && Math.abs(c[1])<1e-10 && Math.abs(c[3])<1e-10 && Math.abs(c[5])<1e-10) { // complex, but real 133 parents = [c[4],c[0],c[2]]; 134 } else { 135 JXG.debug('type not supported, yet'); // <complex> 136 return; 137 } 138 } else if (p.nodeName == 'euclidean_coordinates') { 139 for (j=0;j<p.childNodes.length;j++) { 140 if (p.childNodes[j].nodeType==1) { 141 c.push(p.childNodes[j].firstChild.data); // content of <double>...</double> 142 } 143 } 144 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 145 parents = [c[0],c[1]]; 146 } else if (p.nodeName == 'polar_coordinates') { 147 for (j=0;j<p.childNodes.length;j++) { 148 if (p.childNodes[j].nodeType==1) { 149 c.push(p.childNodes[j].firstChild.data); // content of <double>...</double> 150 } 151 } 152 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 153 parents = [c[0]*Math.cos(c[1]),c[0]*Math.sin(c[1])]; 154 } else { 155 JXG.debug('This coordinate type is not yet implemented: ' +p.nodeName); 156 return; 157 } 158 159 el = this.board.create('point', parents, attributes); 160 this.objects[node.getAttribute('id')] = el; 161 }; 162 163 /** 164 * Points are created instantly via create 165 */ 166 this.storePoint = function(node) { 167 var i = 0, 168 j = 0, 169 l = 0, 170 p = node.childNodes[i], 171 c = [], 172 parents = []; 173 174 while (p.nodeType>1) { // skip non element nodes 175 i++; 176 p = node.childNodes[i]; 177 } 178 179 if (p.nodeName == 'homogeneous_coordinates') { 180 for (j=0;j<p.childNodes.length;j++) { 181 if (p.childNodes[j].nodeType==1) { 182 if (p.childNodes[j].nodeName=='double') { 183 c.push(p.childNodes[j].firstChild.data); // content of <double>...</double> 184 } else if (p.childNodes[j].nodeName=='complex') { 185 for (l=0;l<p.childNodes[j].childNodes.length;l++) { 186 if (p.childNodes[j].childNodes[l].nodeName=='double') { 187 c.push(p.childNodes[j].childNodes[l].firstChild.data); 188 } 189 } 190 } else { 191 JXG.debug('Not implemented: '+ p.childNodes[j].nodeName); // <complex> 192 return; 193 } 194 } 195 } 196 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 197 if (c.length==3) { // Real 198 parents = [c[2],c[0],c[1]]; 199 } else if (c.length==6 && Math.abs(c[1])<1e-10 && Math.abs(c[3])<1e-10 && Math.abs(c[5])<1e-10) { // complex, but real 200 parents = [c[4],c[0],c[2]]; 201 } else { 202 JXG.debug('type not supported, yet'); // <complex> 203 return; 204 } 205 } else if (p.nodeName == 'euclidean_coordinates' || p.nodeName == 'euclidian_coordinates') { // the latter one is a workaround for faulty i2g construction exported by DynaGeo 206 for (j=0;j<p.childNodes.length;j++) { 207 if (p.childNodes[j].nodeType==1) { 208 c.push(p.childNodes[j].firstChild.data); // content of <double>...</double> 209 } 210 } 211 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 212 parents = [c[0],c[1]]; 213 } else if (p.nodeName == 'polar_coordinates') { 214 for (j=0;j<p.childNodes.length;j++) { 215 if (p.childNodes[j].nodeType==1) { 216 c.push(p.childNodes[j].firstChild.data); // content of <double>...</double> 217 } 218 } 219 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 220 parents = [c[0]*Math.cos(c[1]),c[0]*Math.sin(c[1])]; 221 } else { 222 JXG.debug('This coordinate type is not yet implemented: ' +p.nodeName); 223 return; 224 } 225 226 this.objects[node.getAttribute('id')] = {'id':node.getAttribute('id'), 'coords':null}; 227 this.objects[node.getAttribute('id')].coords = parents; 228 this.objects[node.getAttribute('id')].id = node.getAttribute('id'); 229 this.objects[node.getAttribute('id')].exists = false; 230 //el = this.board.create('point', parents, attributes); 231 //this.objects[node.getAttribute('id')] = el; 232 this.objects[node.getAttribute('id')].i2geoType = 'point'; 233 }; 234 235 /** 236 * Line data is stored in an array 237 * for further access during the reading of constraints. 238 * There, id and name are needed. 239 **/ 240 this.storeLine = function(node) { 241 var i, p, c, j; 242 243 this.objects[node.getAttribute('id')] = {'id':node.getAttribute('id'), 'coords':null}; 244 i = 0; 245 p = node.childNodes[i]; 246 while (p.nodeType>1) { // skip non element nodes 247 i++; 248 p = node.childNodes[i]; 249 } 250 if (p.nodeName == 'homogeneous_coordinates') { 251 c = []; 252 for (j=0;j<p.childNodes.length;j++) { 253 if (p.childNodes[j].nodeType==1) { 254 if (p.childNodes[j].nodeName=='double') { 255 c.push(parseFloat(p.childNodes[j].firstChild.data)); // content of <double>...</double> 256 } else { 257 //$('debug').innerHTML += 'Not: '+ p.childNodes[j].nodeName + '<br>'; // <complex> 258 } 259 } 260 } 261 this.objects[node.getAttribute('id')].coords = c; 262 this.objects[node.getAttribute('id')].id = node.getAttribute('id'); 263 this.objects[node.getAttribute('id')].exists = false; 264 this.objects[node.getAttribute('id')].i2geoType = 'line'; 265 } 266 //this.addLine(node.getAttribute('id')); 267 }; 268 269 /** 270 * Circle / conic data is stored in an array 271 * for further access during the reading of constraints. 272 * There, id and name are needed. 273 * Concretely, the circle (x-1)^2 + (y-3)^2 = 4 has matrix 274 * ( 1 0 -1 ) 275 * ( 0 1 -3 ) 276 * ( -1 -3 6 ) 277 * 278 * In general 279 * Ax^2+Bxy+Cy^2+Dx+Ey+F = 0 280 * is stored as 281 * ( A B/2 D/2 ) 282 * ( B/2 C E/2 ) 283 * ( D/2 E/2 F ) 284 * 285 * Mx = D/A 286 * My = E/C 287 * r = A*Mx^2+B*My^2-F 288 **/ 289 this.storeConic = function(node) { 290 var i, j, p, c; 291 292 this.objects[node.getAttribute('id')] = {'id':node.getAttribute('id'), 'coords':null}; 293 i = 0; 294 p = node.childNodes[i]; 295 while (p.nodeType>1) { // skip non element nodes 296 i++; 297 p = node.childNodes[i]; 298 } 299 if (p.nodeName == 'matrix') { 300 c = []; 301 for (j=0;j<p.childNodes.length;j++) { 302 if (p.childNodes[j].nodeType==1) { 303 if (p.childNodes[j].nodeName=='double') { 304 c.push(parseFloat(p.childNodes[j].firstChild.data)); // content of <double>...</double> 305 } else { 306 //$('debug').innerHTML += 'Not: '+ p.childNodes[j].nodeName + '<br>'; // <complex> 307 } 308 } 309 } 310 this.objects[node.getAttribute('id')].coords = c; 311 this.objects[node.getAttribute('id')].id = node.getAttribute('id'); 312 this.objects[node.getAttribute('id')].exists = false; 313 this.objects[node.getAttribute('id')].i2geoType = 'conic'; 314 } 315 }; 316 317 /** 318 * Constraint part 319 */ 320 this.readConstraints = function(tree) { 321 var s, param; 322 323 // Set the default colors of dependent elements 324 this.board.options.point.strokeColor = 'blue'; 325 this.board.options.point.fillColor = 'blue'; 326 327 for (s=0;s<tree[0].childNodes.length;s++) (function(s) { 328 var node; 329 node = tree[0].childNodes[s]; 330 if (node.nodeType>1) { return; } // not an element node 331 if (node.nodeName=='line_through_two_points') { 332 JXG.IntergeoReader.addLineThroughTwoPoints(node, false); 333 } 334 else if (node.nodeName=='ray_from_point_through_point') { 335 JXG.IntergeoReader.addLineThroughTwoPoints(node, true); 336 } 337 else if (node.nodeName=='line_through_point') { 338 JXG.IntergeoReader.addLineThroughPoint(node); 339 } 340 else if (node.nodeName=='line_parallel_to_line_through_point') { 341 JXG.IntergeoReader.addLineParallelToLineThroughPoint(node, false); 342 } 343 else if (node.nodeName=='ray_from_point_and_vector') { 344 JXG.IntergeoReader.addLineParallelToLineThroughPoint(node, true); 345 } 346 else if (node.nodeName=='line_perpendicular_to_line_through_point') { 347 JXG.IntergeoReader.addLinePerpendicularToLineThroughPoint(node); 348 } 349 else if (node.nodeName=='line_segment_by_points') { 350 JXG.IntergeoReader.addLineSegmentByTwoPoints(node); 351 } 352 else if (node.nodeName=='vector_from_point_to_point') { 353 JXG.IntergeoReader.addVectorFromPointToPoint(node); 354 } 355 else if (node.nodeName=='endpoints_of_line_segment') { 356 JXG.IntergeoReader.addEndpointsOfLineSegment(node); 357 } 358 else if (node.nodeName=='free_point') { 359 // do nothing 360 } 361 else if (node.nodeName=='free_line') { 362 JXG.IntergeoReader.addFreeLine(node); 363 } 364 else if (node.nodeName=='point_on_line') { 365 JXG.IntergeoReader.addPointOnLine(node); 366 } 367 else if (node.nodeName=='point_on_line_segment') { 368 JXG.IntergeoReader.addPointOnLine(node); 369 } 370 else if (node.nodeName=='point_on_circle') { 371 JXG.IntergeoReader.addPointOnCircle(node); 372 } 373 else if (node.nodeName=='angular_bisector_of_three_points') { 374 JXG.IntergeoReader.addAngularBisectorOfThreePoints(node, false); 375 } 376 else if (node.nodeName=='angular_bisectors_of_two_lines') { 377 JXG.IntergeoReader.addAngularBisectorsOfTwoLines(node, false); 378 } 379 else if (node.nodeName=='line_angular_bisector_of_three_points') { 380 JXG.IntergeoReader.addAngularBisectorOfThreePoints(node, true); 381 } 382 else if (node.nodeName=='line_angular_bisectors_of_two_lines') { 383 JXG.IntergeoReader.addAngularBisectorsOfTwoLines(node, true); 384 } 385 else if (node.nodeName=='midpoint_of_two_points') { 386 JXG.IntergeoReader.addMidpointOfTwoPoints(node); 387 } 388 else if (node.nodeName=='midpoint') { 389 JXG.IntergeoReader.addMidpointOfTwoPoints(node); 390 } 391 else if (node.nodeName=='midpoint_of_line_segment' || node.nodeName=='midpoint_line_segment') { 392 JXG.IntergeoReader.addMidpointOfLineSegment(node); 393 } 394 else if (node.nodeName=='point_intersection_of_two_lines') { 395 JXG.IntergeoReader.addPointIntersectionOfTwoLines(node); 396 } 397 else if (node.nodeName=='locus_defined_by_point') { 398 JXG.IntergeoReader.addLocusDefinedByPoint(node); 399 } 400 else if (node.nodeName=='locus_defined_by_point_on_line') { 401 JXG.IntergeoReader.addLocusDefinedByPointOnLine(node); 402 } 403 else if (node.nodeName=='locus_defined_by_point_on_line_segment') { 404 JXG.IntergeoReader.addLocusDefinedByPointOnLine(node); 405 } 406 else if (node.nodeName=='locus_defined_by_line_through_point') { 407 JXG.IntergeoReader.addLocusDefinedByLineThroughPoint(node); 408 } 409 else if (node.nodeName=='locus_defined_by_point_on_circle') { 410 JXG.IntergeoReader.addLocusDefinedByPointOnCircle(node); 411 } 412 else if (node.nodeName=='circle_by_three_points') { 413 JXG.IntergeoReader.addCircleByThreePoints(node); 414 } 415 else if (node.nodeName=='circle_by_center_and_point') { 416 JXG.IntergeoReader.addCircleByCenterAndPoint(node); 417 } 418 else if (node.nodeName=='center_of_circle') { 419 JXG.IntergeoReader.addCenterOfCircle(node); 420 } 421 else if (node.nodeName=='intersection_points_of_two_circles') { 422 JXG.IntergeoReader.addIntersectionPointsOfTwoCircles(node); 423 } 424 else if (node.nodeName=='intersection_points_of_circle_and_line') { 425 JXG.IntergeoReader.addIntersectionPointsOfCircleAndLine(node); 426 } 427 else if (node.nodeName=='other_intersection_point_of_two_circles') { 428 JXG.IntergeoReader.addOtherIntersectionPointOfTwoCircles(node); 429 } 430 else if (node.nodeName=='other_intersection_point_of_circle_and_line') { 431 JXG.IntergeoReader.addOtherIntersectionPointOfCircleAndLine(node); 432 } 433 else if (node.nodeName=='circle_tangent_lines_by_point') { 434 JXG.IntergeoReader.addCircleTangentLinesByPoint(node); 435 } 436 else if (node.nodeName=='polygon_by_vertices') { 437 JXG.IntergeoReader.addPolygonByVertices(node); 438 } 439 else { 440 param = JXG.IntergeoReader.readParams(node); 441 JXG.debug('readConstraints: not implemented: ' + node.nodeName + ': ' + param[0]); 442 } 443 })(s); 444 }; 445 446 this.setAttributes = function(o) { 447 o.setProperty({strokecolor:this.board.options.point.strokeColor,fillColor:this.board.options.point.fillColor}); 448 }; 449 450 this.readParams = function(node) { 451 var param = [], j; 452 for (j=0;j<node.childNodes.length;j++) { 453 if (node.childNodes[j].nodeType==1) { 454 param.push(node.childNodes[j].firstChild.data); 455 } 456 } 457 return param; 458 }; 459 460 this.addPoint = function(p) { 461 if (!p.exists) { 462 p.exists = true; 463 p = this.board.create('point',p.coords,{name:p.id}); 464 p.setProperty({strokecolor:'red',fillColor:'red'}); 465 466 //this.setAttributes(p); 467 } 468 return p; 469 }; 470 471 /** 472 * Direct construction of a line 473 * in read elements 474 **/ 475 this.addLine = function(id) { 476 var j, 477 c = this.objects[id].coords, 478 el; 479 480 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 481 el = this.board.create('line',[c[2],c[0],c[1]],{name:id, strokeColor:'black', withLabel:true}); 482 this.objects[id] = el; 483 }; 484 485 this.addConic = function(p) { 486 var c; 487 if (!p.exists) { 488 c = p.coords; 489 // (a_00,a_11,a_22,a_01,a_12,a_22) 490 p = this.board.create('conic',[c[0],c[4],c[8],c[1],c[5],c[2]],{name:p.id}); 491 //p.setProperty({strokecolor:'blue',fillColor:'none'}); 492 //this.setAttributes(p); 493 p.exists = true; 494 } 495 return p; 496 }; 497 498 this.cleanUp = function() { 499 var p; 500 for (p in this.objects) { 501 if (this.objects[p].exists==false) { 502 if (this.objects[p].i2geoType=='point') { 503 this.addPoint(this.objects[p]); 504 } else if (this.objects[p].i2geoType=='line') { 505 this.addLine(this.objects[p]); 506 } else if (this.objects[p].i2geoType=='conic') { 507 this.addConic(this.objects[p]); 508 } else { 509 JXG.debug('forgotten: '+ this.objects[p].id +' of type ' + this.objects[p].i2geoType); 510 } 511 } 512 } 513 }; 514 515 this.addLineThroughTwoPoints = function(node, isRay) { 516 var param = JXG.IntergeoReader.readParams(node), 517 el1, el2, el; 518 519 el1 = this.addPoint(this.objects[param[1]]); 520 el2 = this.addPoint(this.objects[param[2]]); 521 el = this.board.create('line', [el1.id,el2.id], {name:param[0],withLabel:true, straightFirst:!isRay, straightLast:true}); 522 this.objects[param[0]] = el; 523 this.objects[param[0]].exists = true; 524 }; 525 526 this.addLineThroughPoint = function(node) { 527 var param = JXG.IntergeoReader.readParams(node), 528 j, 529 c = this.objects[param[0]].coords, 530 p = this.addPoint(this.objects[param[1]]), 531 el; 532 533 for (j=0;j<c.length;j++) { c[j] = parseFloat(c[j]); } 534 el = this.board.create('line',[ 535 function() { return c[2]-c[0]*p.X()-c[1]*p.Y()-c[2]*p.Z(); }, c[0], c[1] 536 ],{name:param[0], strokeColor:'black', withLabel:true}); 537 this.objects[param[0]] = el; 538 this.objects[param[0]].exists = true; 539 }; 540 541 this.addLineParallelToLineThroughPoint = function(node, isRay) { 542 var param = JXG.IntergeoReader.readParams(node), 543 el1, el2, el; 544 545 el1 = this.addPoint(this.objects[param[1]]); 546 el2 = this.addPoint(this.objects[param[2]]); 547 el = this.board.create('parallel',[el1.id,el2.id], {name:param[0],withLabel:true, straightFirst:!isRay, straightLast:true}); 548 this.objects[param[0]] = el; 549 this.objects[param[0]].exists = true; 550 }; 551 552 this.addLinePerpendicularToLineThroughPoint = function(node) { 553 var param = JXG.IntergeoReader.readParams(node), 554 el1, el2, el; 555 556 el1 = this.addPoint(this.objects[param[1]]); 557 el2 = this.addPoint(this.objects[param[2]]); 558 el = this.board.create('perpendicular',[el1.id,el2.id], 559 {name:param[0], id:param[0], 560 straightFirst:true, straightLast:true, 561 point: {name:param[0]+'foot',id:param[0]+'foot'}, 562 withLabel:true}); 563 this.objects[param[0]] = el; 564 this.objects[param[0]].exists = true; 565 }; 566 567 this.addLineSegmentByTwoPoints = function(node) { 568 var param = JXG.IntergeoReader.readParams(node), 569 el1, el2, el; 570 571 el1 = this.addPoint(this.objects[param[1]]); 572 el2 = this.addPoint(this.objects[param[2]]); 573 el = this.board.create('line',[el1.id,el2.id], 574 {name:param[0], 575 straightFirst:false, straightLast:false, 576 strokeColor:'black', 577 withLabel:true}); 578 this.objects[param[0]] = el; 579 this.objects[param[0]].exists = true; 580 }; 581 582 this.addPointIntersectionOfTwoLines = function(node) { 583 var param = JXG.IntergeoReader.readParams(node), 584 l1 = this.objects[param[1]], 585 l2 = this.objects[param[2]]; 586 587 this.objects[param[0]] = this.board.create('intersection',[l1,l2,0], {name:param[0],id:param[0], withLabel:true}); 588 this.setAttributes(this.objects[param[0]]); 589 this.objects[param[0]].exists = true; 590 }; 591 592 this.addFreeLine = function(node) { 593 var param = JXG.IntergeoReader.readParams(node), 594 a = this.objects[param[0]].coords[0], 595 b = this.objects[param[0]].coords[1], 596 c = this.objects[param[0]].coords[2], 597 el = this.board.create('line',[c,a,b],{name:param[0],id:param[0],withLabel:true}); 598 this.objects[param[0]] = el; 599 this.objects[param[0]].exists = true; 600 }; 601 602 this.addPointOnLine = function(node) { 603 var param = JXG.IntergeoReader.readParams(node), 604 l = JXG.getReference(this.board,param[1]), 605 el; 606 el = this.board.create('glider',[0,0,l],{name:param[0],id:param[0],withLabel:true}); 607 //this.setAttributes(p); 608 this.objects[param[0]].exists = true; 609 }; 610 611 this.addPointOnCircle = function(node) { 612 var param = JXG.IntergeoReader.readParams(node), 613 c = JXG.getReference(this.board,param[1]), 614 el; 615 c.update(); 616 el = this.board.create('glider',[this.objects[param[0]].coords[1],this.objects[param[0]].coords[2],c], 617 {name:param[0],id:param[0],withLabel:true}); 618 //this.setAttributes(p); 619 this.objects[param[0]].exists = true; 620 }; 621 622 this.addEndpointsOfLineSegment = function(node) { 623 var param = JXG.IntergeoReader.readParams(node), 624 line = this.objects[param[2]], 625 p = this.addPoint(this.objects[param[0]]), 626 q = this.addPoint(this.objects[param[1]]); 627 628 p.addConstraint([ 629 function(){return line.point1.Z();}, 630 function(){return line.point1.X();}, 631 function(){return line.point1.Y();} 632 ]); 633 q.addConstraint([ 634 function(){return line.point2.Z();}, 635 function(){return line.point2.X();}, 636 function(){return line.point2.Y();} 637 ]); 638 this.setAttributes(p); 639 this.setAttributes(q); 640 }; 641 642 this.addAngularBisectorOfThreePoints = function(node, isLine) { 643 var param = JXG.IntergeoReader.readParams(node), 644 el1, el2, el3, el; 645 646 el1 = this.addPoint(this.objects[param[1]]); 647 el2 = this.addPoint(this.objects[param[2]]); 648 el3 = this.addPoint(this.objects[param[3]]); 649 el = this.board.create('bisector',[el1.id,el2.id,el3.id], 650 {name:param[0], id:param[0], withLabel:true, 651 straightFirst:isLine, straightLast:true, strokeColor:'#000000' 652 }); 653 //{name:[param[0]+'_1',param[0]+'_2'], id:[param[0]+'_1',param[0]+'_2'], withLabel:false}); 654 this.objects[param[0]] = el; 655 this.objects[param[0]].exists = true; 656 }; 657 658 this.addMidpointOfTwoPoints = function(node) { 659 var param = JXG.IntergeoReader.readParams(node), 660 el1, el2, el; 661 662 el1 = this.addPoint(this.objects[param[1]]); 663 el2 = this.addPoint(this.objects[param[2]]); 664 el = this.board.create('midpoint',[el1.id,el2.id],{name:param[0]}); 665 this.setAttributes(el); 666 this.objects[param[0]].exists = true; 667 }; 668 669 this.addMidpointOfLineSegment = function(node) { 670 var param = JXG.IntergeoReader.readParams(node), 671 l = JXG.getReference(this.board,param[1]); 672 el = this.board.create('midpoint',[l.point1,l.point2],{name:param[0]}); 673 this.setAttributes(el); 674 this.objects[param[0]].exists = true; 675 }; 676 677 this.addCircleByThreePoints = function(node) { 678 var param = JXG.IntergeoReader.readParams(node), 679 p = [], i, ar; 680 for (i=0;i<3;i++) { 681 p[i] = this.addPoint(this.objects[param[i+1]]); //JXG.getReference(this.board,param[i+1]); 682 } 683 ar = this.board.create('circumcircle',p, 684 {name: param[0], id:param[0], 685 point: {name: param[0]+'c', id: param[0]+'c'}, 686 withLabel:true}); 687 this.objects[param[0]].exists = true; 688 }; 689 690 this.addCenterOfCircle = function(node) { 691 var param = JXG.IntergeoReader.readParams(node), 692 c = JXG.getReference(this.board,param[1]), 693 el = this.board.create('point',[function(){return c.center.X();},function(){return c.center.Y();}], 694 {name:param[0], id:param[0],withLabel:true}); 695 this.setAttributes(el); 696 this.objects[param[0]].exists = true; 697 }; 698 699 this.addCircleTangentLinesByPoint = function(node) { 700 var param = JXG.IntergeoReader.readParams(node), 701 c = JXG.getReference(this.board,param[2]), 702 p = this.addPoint(this.objects[param[3]]), 703 //t1 = this.objects[param[0]], 704 //t2 = this.objects[param[1]]; 705 m, polar, i1, i2, t1, t2; 706 707 polar = this.board.create('line', [ 708 function(){ return JXG.Math.matVecMult(c.quadraticform,p.coords.usrCoords)[0]; }, 709 function(){ return JXG.Math.matVecMult(c.quadraticform,p.coords.usrCoords)[1]; }, 710 function(){ return JXG.Math.matVecMult(c.quadraticform,p.coords.usrCoords)[2]; } 711 ] , {visible:false}); 712 713 i1 = this.board.create('intersection', [c,polar,0],{visible:false}); 714 i2 = this.board.create('intersection', [c,polar,1],{visible:false}); 715 //t1 = this.board.create('line', [p,i1]); 716 //t2 = this.board.create('line', [p,i2]); 717 t1 = this.board.create('tangent', [i1,c]); 718 t2 = this.board.create('tangent', [i2,c]); 719 this.objects[param[0]] = t1; 720 this.objects[param[1]] = t2; 721 this.objects[param[0]].exists = true; 722 this.objects[param[1]].exists = true; 723 }; 724 725 this.addIntersectionPointsOfTwoCircles = function(node) { 726 var param = JXG.IntergeoReader.readParams(node), 727 c1 = JXG.getReference(this.board,param[2]), 728 c2 = JXG.getReference(this.board,param[3]), 729 p1, p2; 730 //p1 = this.objects[param[0]], 731 //p2 = this.objects[param[1]]; 732 //p1.addConstraint([this.board.intersection(c1,c2,0)]); 733 //p2.addConstraint([this.board.intersection(c1,c2,1)]); 734 p1 = this.board.create('intersection',[c1,c2,0], {name:param[0], id:param[0],withLabel:true}); 735 p2 = this.board.create('intersection',[c1,c2,1], {name:param[1], id:param[1],withLabel:true}); 736 this.setAttributes(p1); 737 this.setAttributes(p2); 738 this.objects[param[0]].exists = true; 739 this.objects[param[1]].exists = true; 740 }; 741 742 this.addIntersectionPointsOfCircleAndLine = function(node) { 743 var param = JXG.IntergeoReader.readParams(node), 744 c1 = JXG.getReference(this.board,param[2]), 745 c2 = JXG.getReference(this.board,param[3]), 746 p1, p2; 747 //p1 = this.objects[param[0]], 748 //p2 = this.objects[param[1]]; 749 750 p1 = this.board.create('intersection',[c1,c2,0], {name:param[0], id:param[0],withLabel:true}); 751 p2 = this.board.create('intersection',[c1,c2,1], {name:param[1], id:param[1],withLabel:true}); 752 this.setAttributes(p1); 753 this.setAttributes(p2); 754 this.objects[param[0]].exists = true; 755 this.objects[param[1]].exists = true; 756 }; 757 758 this.addCircleByCenterAndPoint = function(node) { 759 var param = JXG.IntergeoReader.readParams(node), 760 el1 = this.addPoint(this.objects[param[1]]), 761 el2 = this.addPoint(this.objects[param[2]]); 762 763 el = this.board.create('circle', 764 [el1.id,el2.id], 765 {name:param[0],id:param[0],withLabel:true}); 766 this.objects[param[0]].exists = true; 767 }; 768 769 this.addOtherIntersectionPointOfTwoCircles = function(node) { 770 var param = JXG.IntergeoReader.readParams(node), 771 c1 = JXG.getReference(this.board,param[2]), 772 c2 = JXG.getReference(this.board,param[3]), 773 p1 = JXG.getReference(this.board,param[1]), // Should exist by now 774 p2; 775 //p1 = this.objects[param[1]], 776 //p2 = this.objects[param[0]]; // output 777 778 //p2.addConstraint([this.board.otherIntersection(c1,c2,p1)]); 779 p2 = this.board.create('otherintersection',[c1,c2,p1], {name:param[0], id:param[0],withLabel:true}); 780 this.setAttributes(p2); 781 this.objects[param[0]].exists = true; 782 }; 783 784 this.addOtherIntersectionPointOfCircleAndLine = function(node) { 785 this.addOtherIntersectionPointOfTwoCircles(node); 786 }; 787 788 /** 789 * The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation: 790 * (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2) 791 */ 792 this.addAngularBisectorsOfTwoLines = function(node, isLine) { 793 var param = JXG.IntergeoReader.readParams(node), 794 l1 = this.objects[param[2]], 795 l2 = this.objects[param[3]], 796 ar; 797 798 ar = this.board.create('bisectorlines', 799 [l1,l2], 800 { 801 line1:{name:param[0], id:param[0], straightFirst:true, straightLast:true}, 802 line2:{name:param[1], id:param[1], straightFirst:true, straightLast:true}, 803 withLabel:true 804 }); 805 this.objects[param[0]].exists = true; 806 this.objects[param[1]].exists = true; 807 }; 808 809 this.addPolygonByVertices = function(node) { 810 var j, n, param2 = [], p = [], el, 811 param = JXG.IntergeoReader.readParams(node); 812 813 for (j=0;j<node.childNodes.length;j++) { 814 if (node.childNodes[j].nodeType==1) { 815 if (node.childNodes[j].nodeName=='list_of_vertices') { 816 n = node.childNodes[j]; 817 param2 = JXG.IntergeoReader.readParams(n); 818 break; 819 } 820 } 821 } 822 for (j=0;j<param2.length;j++) { 823 p.push(this.addPoint(this.objects[param2[j]])); 824 } 825 826 el = this.board.create('polygon', p, {name:param[0],id:param[0],withLabel:true}); 827 this.objects[param[0]].exists = true; 828 }; 829 830 this.addVectorFromPointToPoint = function(node) { 831 var param = JXG.IntergeoReader.readParams(node), 832 el1, el2; 833 834 el1 = this.addPoint(this.objects[param[1]]); 835 el2 = this.addPoint(this.objects[param[2]]); 836 el = this.board.create('arrow',[el1.id,el2.id],{name:param[0]}); 837 this.setAttributes(el); 838 this.objects[param[0]].exists = true; 839 }; 840 841 // ---------------------------------------------------------------------------------------------------- 842 843 this.addLocusDefinedByPoint = function(node) { 844 var param = JXG.IntergeoReader.readParams(node), 845 el = JXG.getReference(this.board,param[1]); 846 el.setProperty({trace:true}); 847 this.objects[param[1]] = el; 848 this.setAttributes(el); 849 }; 850 851 this.addLocusDefinedByPointOnLine = function(node) { 852 var param = JXG.IntergeoReader.readParams(node), 853 el = JXG.getReference(this.board,param[1]); 854 el.setProperty({trace:true}); 855 this.objects[param[1]] = el; 856 this.setAttributes(el); 857 }; 858 859 this.addLocusDefinedByLineThroughPoint = function(node) { 860 var param = JXG.IntergeoReader.readParams(node), 861 el = JXG.getReference(this.board,param[1]); 862 el.setProperty({trace:true}); 863 this.objects[param[1]] = el; 864 this.setAttributes(el); 865 }; 866 867 this.addLocusDefinedByPointOnCircle = function(node) { 868 var param = JXG.IntergeoReader.readParams(node), 869 el = JXG.getReference(this.board,param[1]); 870 el.setProperty({trace:true}); 871 this.objects[param[1]] = el; 872 this.setAttributes(el); 873 }; 874 875 /** 876 * Extract the xml-code as String from the zipped Intergeo archive. 877 * @return {string} xml code 878 */ 879 this.prepareString = function(fileStr){ 880 var bA = [], i; 881 882 if (fileStr.indexOf('<')!=0) { 883 //binary = false; 884 for (i=0;i<fileStr.length;i++) 885 bA[i]=JXG.Util.asciiCharCodeAt(fileStr,i); 886 887 fileStr = (new JXG.Util.Unzip(bA)).unzipFile("construction/intergeo.xml"); // Unzip 888 // Extract "construction/intergeo.xml" from 889 // the zip-archive in bA. 890 } 891 892 return fileStr; 893 }; 894 895 /** 896 * Displpay part 897 */ 898 this.readDisplay = function(tree) { 899 var s, j; 900 901 if (!JXG.exists(tree) || !JXG.isArray(tree)) { 902 return; 903 } 904 905 for (s=0;s<tree[0].childNodes.length;s++) (function(s) { 906 var node, el, prop = {}, key, val; 907 node = tree[0].childNodes[s]; 908 if (node.nodeType>1) { return; } // not an element node 909 if (node.nodeName=='background-color') { 910 this.board.containerObj.style.backgroundColor = node.firstChild.data; 911 } 912 else if (node.nodeName=='style') { 913 el = JXG.getReference(this.board,node.getAttribute('ref')); // get the element 914 var param = [], j; 915 for (j=0;j<node.childNodes.length;j++) { 916 if (node.childNodes[j].nodeType==1) { 917 key = node.childNodes[j].nodeName; 918 val = node.childNodes[j].firstChild.data; 919 if (key=='stroke') { 920 key = 'strokeColor'; 921 } else if (key=='stroke-width' || key=='border-width') { 922 key = 'strokeWidth'; 923 } else if (key=='fill') { 924 key = 'fillColor'; 925 } else if (key=='fill-opacity') { 926 key = 'fillOpacity'; 927 } else if (key=='border-opacity') { 928 key = 'strokeOpacity'; 929 } else if (key=='point-size') { 930 key = 'size'; 931 } else if (key=='label') { 932 key = 'name'; 933 } else if (key=='point-style') { 934 key = 'face'; 935 if (val=='circle') { 936 val = 'o'; 937 } else if (val=='cross') { 938 val = '+'; 939 } else if (val=='x-mark') { 940 val = 'x'; 941 } else if (val=='square') { 942 val = '[]'; 943 } else if (val=='triangle') { 944 val = 'triangleup'; 945 } else if (val=='point') { // Setting size to 1 is missing 946 val = 'o'; 947 } 948 else { 949 JXG.debug('Display: not implemented' + node.nodeName); 950 // Missing: 951 // circumference, image 952 } 953 } 954 prop[key] = val; 955 } 956 } 957 el.setProperty(prop); 958 } 959 else { 960 JXG.debug('Display: not implemented' + node.nodeName); 961 } 962 })(s); 963 }; 964 965 }; 966 967 968