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