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 * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together 28 * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here 29 * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the 30 * following compositions can be found: <ul> 31 * <li>{@link Arrowparallel} (currently private)</li> 32 * <li>{@link Bisector}</li> 33 * <li>{@link Circumcircle}</li> 34 * <li>{@link Circumcirclemidpoint}</li> 35 * <li>{@link Integral}</li> 36 * <li>{@link Midpoint}</li> 37 * <li>{@link Mirrorpoint}</li> 38 * <li>{@link Normal}</li> 39 * <li>{@link Parallel}</li> 40 * <li>{@link Perpendicular}</li> 41 * <li>{@link Perpendicularpoint}</li> 42 * <li>{@link Reflection}</li></ul> 43 */ 44 45 /** 46 * @class This is used to construct a perpendicular point. 47 * @pseudo 48 * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point 49 * orthogonal onto the given line. 50 * @constructor 51 * @name Perpendicularpoint 52 * @type JXG.Point 53 * @augments JXG.Point 54 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 55 * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l. 56 * @example 57 * var p1 = board.create('point', [0.0, 4.0]); 58 * var p2 = board.create('point', [6.0, 1.0]); 59 * var l1 = board.create('line', [p1, p2]); 60 * var p3 = board.create('point', [3.0, 3.0]); 61 * 62 * var pp1 = board.create('perpendicularpoint', [p3, l1]); 63 * </pre><div id="ded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div> 64 * <script type="text/javascript"> 65 * var ppex1_board = JXG.JSXGraph.initBoard('ded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 66 * var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]); 67 * var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]); 68 * var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]); 69 * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); 70 * var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]); 71 * </script><pre> 72 */ 73 JXG.createPerpendicularPoint = function(board, parentArr, atts) { 74 var l, p, t; 75 76 if(JXG.isPoint(parentArr[0]) && parentArr[1].type == JXG.OBJECT_TYPE_LINE) { 77 p = parentArr[0]; 78 l = parentArr[1]; 79 } 80 else if(JXG.isPoint(parentArr[1]) && parentArr[0].type == JXG.OBJECT_TYPE_LINE) { 81 p = parentArr[1]; 82 l = parentArr[0]; 83 } 84 else { 85 throw new Error("JSXGraph: Can't create perpendicular point with parent types '" + 86 (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." + 87 "\nPossible parent types: [point,line]"); 88 } 89 90 // no need to call create, the properties will be set through the create('perpendicular') call 91 t = JXG.createPoint(board, [function () { return JXG.Math.Geometry.perpendicular(l, p, board)[0]; }], {fixed: true, name: atts['name'], id: atts['id']}); 92 p.addChild(t); // notwendig, um auch den Punkt upzudaten 93 l.addChild(t); 94 95 t.update(); 96 97 t.generatePolynomial = function() { 98 /* 99 * Perpendicular takes point P and line L and creates point T and line M: 100 * 101 * | M 102 * | 103 * x P (p1,p2) 104 * | 105 * | 106 * L | 107 * ----------x-------------x------------------------x-------- 108 * A (a1,a2) |T (t1,t2) B (b1,b2) 109 * | 110 * | 111 * 112 * So we have two conditions: 113 * 114 * (a) AT || TB (collinearity condition) 115 * (b) PT _|_ AB (orthogonality condition) 116 * 117 * a2-t2 t2-b2 118 * ------- = ------- (1) 119 * a1-t1 t1-b1 120 * 121 * p2-t2 a1-b1 122 * ------- = - ------- (2) 123 * p1-t1 a2-b2 124 * 125 * Multiplying (1) and (2) with denominators and simplifying gives 126 * 127 * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') 128 * 129 * p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0 (2') 130 * 131 */ 132 133 var a1 = l.point1.symbolic.x; 134 var a2 = l.point1.symbolic.y; 135 var b1 = l.point2.symbolic.x; 136 var b2 = l.point2.symbolic.y; 137 var p1 = p.symbolic.x; 138 var p2 = p.symbolic.y; 139 var t1 = t.symbolic.x; 140 var t2 = t.symbolic.y; 141 142 var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')'; 143 var poly2 = '('+p2+')*('+a2+')-('+p2+')*('+b2+')-('+t2+')*('+a2+')+('+t2+')*('+b2+')+('+p1+')*('+a1+')-('+p1+')*('+b1+')-('+t1+')*('+a1+')+('+t1+')*('+b1+')'; 144 145 return [poly1, poly2]; 146 }; 147 148 return t; 149 }; 150 151 152 /** 153 * @class This element is used to provide a constructor for a perpendicular. 154 * @pseudo 155 * @description A perpendicular is a composition of two elements: a line and a point. The line is orthogonal 156 * to a given line and contains a given point and meets the given line in the perpendicular point. 157 * @name Perpendicular 158 * @constructor 159 * @type Array 160 * @return An array containing two elements: A {@link JXG.Line} object in the first component and a 161 * {@link JXG.Point} element in the second component. The line is orthogonal to the given line and meets it 162 * in the returned point. 163 * @throws {Exception} If the elements cannot be constructed with the given parent objects an exception is thrown. 164 * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and 165 * will contain p. The perpendicular point is the intersection point of the two lines. 166 * @example 167 * // Create a perpendicular 168 * var p1 = board.create('point', [0.0, 2.0]); 169 * var p2 = board.create('point', [2.0, 1.0]); 170 * var l1 = board.create('line', [p1, p2]); 171 * 172 * var p3 = board.create('point', [3.0, 3.0]); 173 * var perp1 = board.create('perpendicular', [l1, p3]); 174 * </pre><div id="037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div> 175 * <script type="text/javascript"> 176 * var pex1_board = JXG.JSXGraph.initBoard('037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 177 * var pex1_p1 = pex1_board.create('point', [0.0, 2.0]); 178 * var pex1_p2 = pex1_board.create('point', [2.0, 1.0]); 179 * var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]); 180 * var pex1_p3 = pex1_board.create('point', [3.0, 3.0]); 181 * var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]); 182 * </script><pre> 183 */ 184 JXG.createPerpendicular = function(board, parentArr, atts) { 185 var p, l, pd, t, ret; 186 187 parentArr[0] = JXG.getReference(board, parentArr[0]); 188 parentArr[1] = JXG.getReference(board, parentArr[1]); 189 190 if(JXG.isPoint(parentArr[0]) && parentArr[1].elementClass == JXG.OBJECT_CLASS_LINE) { 191 l = parentArr[1]; 192 p = parentArr[0]; 193 } 194 else if(JXG.isPoint(parentArr[1]) && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) { 195 l = parentArr[0]; 196 p = parentArr[1]; 197 } 198 else { 199 throw new Error("JSXGraph: Can't create perpendicular with parent types '" + 200 (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." + 201 "\nPossible parent types: [line,point]"); 202 } 203 204 if(!JXG.isArray(atts['id'])) { 205 atts['id'] = ['','']; 206 } 207 if(!JXG.isArray(atts['name'])) { 208 atts['name'] = ['','']; 209 } 210 211 // no need to call create, the properties will be set through the create('perpendicular') call 212 t = JXG.createPerpendicularPoint(board, [l, p], {fixed: true, name: atts['name'][1], id: atts['id'][1], visible: false}); 213 pd = JXG.createSegment(board, [function () { return (JXG.Math.Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]); }], {name: atts['name'][0], id: atts['id'][0]}); 214 215 ret = [pd, t]; 216 ret.line = pd; 217 ret.point = t; 218 ret.multipleElements = true; 219 220 return ret; 221 }; 222 223 /** 224 * @class The midpoint element constructs a point in the middle of two given points. 225 * @pseudo 226 * @description A midpoint is given by two points. It is collinear to the given points and the distance 227 * is the same to each of the given points, i.e. it is in the middle of the given points. 228 * @constructor 229 * @name Midpoint 230 * @type JXG.Point 231 * @augments JXG.Point 232 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 233 * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2. 234 * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of 235 * the given line l. 236 * @example 237 * // Create base elements: 2 points and 1 line 238 * var p1 = board.create('point', [0.0, 2.0]); 239 * var p2 = board.create('point', [2.0, 1.0]); 240 * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]); 241 * 242 * var mp1 = board.create('midpoint', [p1, p2]); 243 * var mp2 = board.create('midpoint', [l1]); 244 * </pre><div id="7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div> 245 * <script type="text/javascript"> 246 * var mpex1_board = JXG.JSXGraph.initBoard('7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 247 * var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]); 248 * var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]); 249 * var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]); 250 * var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]); 251 * var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]); 252 * </script><pre> 253 */ 254 JXG.createMidpoint = function(board, parentArr, atts) { 255 var a, b, t; 256 if(parentArr.length == 2 && JXG.isPoint(parentArr[0]) && JXG.isPoint(parentArr[1])) { 257 a = parentArr[0]; 258 b = parentArr[1]; 259 } 260 else if(parentArr.length == 1 && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) { 261 a = parentArr[0].point1; 262 b = parentArr[0].point2; 263 } 264 else { 265 throw new Error("JSXGraph: Can't create midpoint." + 266 "\nPossible parent types: [point,point], [line]"); 267 } 268 269 if(atts) { 270 atts['fixed'] = true; 271 } else { 272 atts = {fixed: true}; 273 } 274 275 t = board.create('point', [function () { return (a.coords.usrCoords[1] + b.coords.usrCoords[1])/2.; }, 276 function () { return (a.coords.usrCoords[2] + b.coords.usrCoords[2])/2.; }], atts); 277 a.addChild(t); 278 b.addChild(t); 279 280 t.update(); 281 282 t.generatePolynomial = function() { 283 /* 284 * Midpoint takes two point A and B or line L (with points P and Q) and creates point T: 285 * 286 * L (not necessarily) 287 * ----------x------------------x------------------x-------- 288 * A (a1,a2) T (t1,t2) B (b1,b2) 289 * 290 * So we have two conditions: 291 * 292 * (a) AT || TB (collinearity condition) 293 * (b) [AT] == [TB] (equidistant condition) 294 * 295 * a2-t2 t2-b2 296 * ------- = ------- (1) 297 * a1-t1 t1-b1 298 * 299 * (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2 (2) 300 * 301 * 302 * Multiplying (1) with denominators and simplifying (1) and (2) gives 303 * 304 * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') 305 * 306 * a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0 (2') 307 * 308 */ 309 310 var a1 = a.symbolic.x; 311 var a2 = a.symbolic.y; 312 var b1 = b.symbolic.x; 313 var b2 = b.symbolic.y; 314 var t1 = t.symbolic.x; 315 var t2 = t.symbolic.y; 316 317 var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')'; 318 var poly2 = '('+a1+')^2 - 2*('+a1+')*('+t1+')+('+a2+')^2-2*('+a2+')*('+t2+')-('+b1+')^2+2*('+b1+')*('+t1+')-('+b2+')^2+2*('+b2+')*('+t2+')'; 319 320 return [poly1, poly2]; 321 }; 322 323 // 2009/10/11, mg: 324 // * this is just a test: we're forming three closures in here: One with generatePolynomial and two when we create the 325 // point by using function objects as positions. So a reference to the current Activation object is held in the scope of 326 // those three functions. But we don't need a reference to the atts object in any of them, so we're deleting the 327 // reference to it. Hence, the garbage collector can remove it from memory, if there's no reference to it left. 328 // * first test successful: attributes will be set properly. it remains to test, if this helps us to reduce memory usage. 329 // for the test we'll query a JXG attribute "nullAtts" which has to be set to true to null the atts parameter. Then 330 // 50,000 midpoints will be created in an example file with resp. without nulling the atts parameter and after that chrome 331 // will be used to compare the memory usage. 332 if(JXG.nullAtts) 333 atts = null; 334 335 return t; 336 }; 337 338 /** 339 * @class This element is used to construct a parallel point. 340 * @pseudo 341 * @description A parallel point is given by three points. Taking the euclidean vector from the first to the 342 * second point, the parallel point is determined by adding that vector to the third point. 343 * The line determined by the first two points is parallel to the line determined by the third point and the constructed point. 344 * @constructor 345 * @name Parallelpoint 346 * @type JXG.Point 347 * @augments JXG.Point 348 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 349 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 Taking the euclidean vector <tt>v=p2-p1</tt> the parallel point is determined by 350 * <tt>p4 = p3+v</tt> 351 * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l. 352 * @example 353 * var p1 = board.create('point', [0.0, 2.0]); 354 * var p2 = board.create('point', [2.0, 1.0]); 355 * var p3 = board.create('point', [3.0, 3.0]); 356 * 357 * var pp1 = board.create('parallelpoint', [p1, p2, p3]); 358 * </pre><div id="488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div> 359 * <script type="text/javascript"> 360 * var ppex1_board = JXG.JSXGraph.initBoard('488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 361 * var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]); 362 * var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]); 363 * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); 364 * var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]); 365 * </script><pre> 366 */ 367 JXG.createParallelPoint = function(board, parentArr, atts) { 368 var a, b, c, p; 369 370 if(parentArr.length == 3 && parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[2].elementClass == JXG.OBJECT_CLASS_POINT) { 371 a = parentArr[0]; 372 b = parentArr[1]; 373 c = parentArr[2]; 374 } else if (parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_LINE) { 375 c = parentArr[0]; 376 a = parentArr[1].point1; 377 b = parentArr[1].point2; 378 } else if (parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) { 379 c = parentArr[1]; 380 a = parentArr[0].point1; 381 b = parentArr[0].point2; 382 } 383 else { 384 throw new Error("JSXGraph: Can't create parallel point with parent types '" + 385 (typeof parentArr[0]) + "', '" + (typeof parentArr[1]) + "' and '" + (typeof parentArr[2]) + "'." + 386 "\nPossible parent types: [line,point], [point,point,point]"); 387 } 388 389 p = board.create('point', [function () { return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1]; }, 390 function () { return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2]; }], 391 atts); 392 // required for algorithms requiring dependencies between elements 393 a.addChild(p); 394 b.addChild(p); 395 c.addChild(p); 396 397 // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update. 398 // can be removed if the above issue is resolved. 399 p.update(); 400 401 p.generatePolynomial = function() { 402 /* 403 * Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T: 404 * 405 * 406 * C (c1,c2) T (t1,t2) 407 * x x 408 * / / 409 * / / 410 * / / 411 * / / 412 * / / 413 * / / 414 * / / 415 * / / 416 * L (opt) / / 417 * ----------x-------------------------------------x-------- 418 * A (a1,a2) B (b1,b2) 419 * 420 * So we have two conditions: 421 * 422 * (a) CT || AB (collinearity condition I) 423 * (b) BT || AC (collinearity condition II) 424 * 425 * The corresponding equations are 426 * 427 * (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0 (1) 428 * (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0 (2) 429 * 430 * Simplifying (1) and (2) gives 431 * 432 * b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0 (1') 433 * t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0 (2') 434 * 435 */ 436 437 var a1 = a.symbolic.x; 438 var a2 = a.symbolic.y; 439 var b1 = b.symbolic.x; 440 var b2 = b.symbolic.y; 441 var c1 = c.symbolic.x; 442 var c2 = c.symbolic.y; 443 var t1 = p.symbolic.x; 444 var t2 = p.symbolic.y; 445 446 var poly1 = '('+b2+')*('+t1+')-('+b2+')*('+c1+')-('+a2+')*('+t1+')+('+a2+')*('+c1+')-('+t2+')*('+b1+')+('+t2+')*('+a1+')+('+c2+')*('+b1+')-('+c2+')*('+a1+')'; 447 var poly2 = '('+t2+')*('+a1+')-('+t2+')*('+c1+')-('+b2+')*('+a1+')+('+b2+')*('+c1+')-('+t1+')*('+a2+')+('+t1+')*('+c2+')+('+b1+')*('+a2+')-('+b1+')*('+c2+')'; 448 449 return [poly1, poly2]; 450 }; 451 452 return p; 453 }; 454 455 /** 456 * @class Constructor for a parallel line. 457 * @pseudo 458 * @description A parallel is a line through a given point with the same slope as a given line. 459 * @constructor 460 * @name Parallel 461 * @type JXG.Line 462 * @augments JXG.Line 463 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 464 * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l. 465 * @example 466 * // Create a parallel 467 * var p1 = board.create('point', [0.0, 2.0]); 468 * var p2 = board.create('point', [2.0, 1.0]); 469 * var l1 = board.create('line', [p1, p2]); 470 * 471 * var p3 = board.create('point', [3.0, 3.0]); 472 * var pl1 = board.create('parallel', [l1, p3]); 473 * </pre><div id="24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div> 474 * <script type="text/javascript"> 475 * var plex1_board = JXG.JSXGraph.initBoard('24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 476 * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]); 477 * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]); 478 * var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]); 479 * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]); 480 * var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]); 481 * </script><pre> 482 */ 483 JXG.createParallel = function(board, parents, atts) { 484 var p, pp, pl, cAtts; 485 486 /* parallel point polynomials are done in createParallelPoint */ 487 488 cAtts = {name: null, id: null, fixed: true, visible: false}; 489 if(JXG.isArray(atts['name']) && atts['name'].length == 2) { 490 cAtts['name'] = atts['name'][1]; 491 atts['name'] = atts['name'][0]; 492 } else 493 cAtts['name'] = atts['name'] + 'p2'; 494 495 if(JXG.isArray(atts['id']) && atts['id'].length == 2) { 496 cAtts['id'] = atts['id'][1]; 497 atts['id'] = atts['id'][0]; 498 } else if (JXG.exists(atts['id'])) 499 cAtts['id'] = atts['id'] + 'p2'; 500 501 try { 502 pp = JXG.createParallelPoint(board, parents, cAtts); // non-visible point 503 } catch (e) { 504 throw new Error("JSXGraph: Can't create parallel with parent types '" + 505 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 506 "\nPossible parent types: [line,point], [point,point,point]"); 507 } 508 509 p = null; 510 if(parents.length == 3) 511 p = parents[2]; 512 else if (parents[0].elementClass == JXG.OBJECT_CLASS_POINT) 513 p = parents[0]; 514 else if (parents[1].elementClass == JXG.OBJECT_CLASS_POINT) 515 p = parents[1]; 516 517 pl = board.create('line', [p, pp], atts); 518 519 return pl; 520 }; 521 522 /** 523 * TODO is this really required? it is the same as 'parallel', except that it doesn't touch the first/lastarrow properties and it returns 524 * the parallel point. for now it is set to private. please review the docs-comment before making it public. especially the example section 525 * isn't done by now. --michael 526 * @private 527 * @class Constructs two elements: an arrow and a point. 528 * @pseudo 529 * @description An arrow parallel is an arrow through a given point with the same slope as another given arrow. 530 * @constructor 531 * @name Arrowparallel 532 * @type JXG.Line 533 * @augments JXG.Line 534 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 535 * @param {Arrow_JXG.Point} a,p The constructed arrow contains p and has the same slope as a. 536 * @example 537 * // Create a parallel 538 * var p1 = board.create('point', [0.0, 2.0]); 539 * var p2 = board.create('point', [2.0, 1.0]); 540 * var l1 = board.create('line', [p1, p2]); 541 * 542 * var p3 = board.create('point', [3.0, 3.0]); 543 * var pl1 = board.create('parallel', [l1, p3]); 544 * </pre><div id="qwe" style="width: 400px; height: 400px;"></div> 545 * <script type="text/javascript"> 546 * var plex1_board = JXG.JSXGraph.initBoard('asd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 547 * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]); 548 * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]); 549 * var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]); 550 * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]); 551 * var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]); 552 * </script><pre> 553 */ 554 JXG.createArrowParallel = function(board, parents, atts) { 555 var l, cAtts; 556 557 /* parallel arrow point polynomials are done in createParallelPoint */ 558 try { 559 // we don't have to get onto that whole create stack here 560 // because that'll be run for the line l right after leaving that function. 561 l = JXG.createParallel(board, parents, atts); 562 } catch (e) { 563 throw new Error("JSXGraph: Can't create arrowparallel with parent types '" + 564 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 565 "\nPossible parent types: [line,point], [point,point,point]"); 566 } 567 568 // Select the default behavior. If the user wants something else he would set it in atts. 569 // That gets parsed and set right after this function. 570 l.setStraight(false, false); 571 l.setArrow(false,true); 572 return l; 573 }; 574 575 /** 576 * @class Constructs a normal. 577 * @pseudo 578 * @description A normal is a line through a given point on a element of type line, circle, curve, or turtle and orthogonal to that object. 579 * @constructor 580 * @name Normal 581 * @type JXG.Line 582 * @augments JXG.Line 583 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 584 * @param {JXG.Line,JXG.Circle,JXG.Curve,JXG.Turtle_JXG.Point} o,p The constructed line contains p which lies on the object and is orthogonal 585 * to the tangent to the object in the given point. 586 * @param {Glider} p Works like above, however the object is given by {@link Glider#slideObject}. 587 * @example 588 * // Create a normal to a circle. 589 * var p1 = board.create('point', [2.0, 2.0]); 590 * var p2 = board.create('point', [3.0, 2.0]); 591 * var c1 = board.create('circle', [p1, p2]); 592 * 593 * var norm1 = board.create('normal', [c1, p2]); 594 * </pre><div id="4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div> 595 * <script type="text/javascript"> 596 * var nlex1_board = JXG.JSXGraph.initBoard('4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 597 * var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]); 598 * var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]); 599 * var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]); 600 * 601 * // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]); 602 * var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]); 603 * </script><pre> 604 */ 605 JXG.createNormal = function(board, parents, attributes) { 606 /* TODO normal polynomials */ 607 var p; 608 var c; 609 if (parents.length==1) { // One arguments: glider on line, circle or curve 610 p = parents[0]; 611 c = p.slideObject; 612 } else if (parents.length==2) { // Two arguments: (point,line), (point,circle), (line,point) or (circle,point) 613 if (JXG.isPoint(parents[0])) { 614 p = parents[0]; 615 c = parents[1]; 616 } else if (JXG.isPoint(parents[1])) { 617 c = parents[0]; 618 p = parents[1]; 619 } else { 620 throw new Error("JSXGraph: Can't create normal with parent types '" + 621 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 622 "\nPossible parent types: [point,line], [point,circle], [glider]"); 623 } 624 } else { 625 throw new Error("JSXGraph: Can't create normal with parent types '" + 626 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 627 "\nPossible parent types: [point,line], [point,circle], [glider]"); 628 } 629 630 if(c.elementClass==JXG.OBJECT_CLASS_LINE) { 631 // return board.addNormal(c,p, attributes['id'], attributes['name']); // GEONExT-Style: problems with ideal point 632 // If not needed, then board.addNormal and maybe JXG.Math.Geometry.perpendicular can be removed. 633 634 // Homogeneous version: 635 // orthogonal(l,p) = (F^\delta\cdot l)\times p 636 return board.create('line', [ 637 function(){ return c.stdform[1]*p.Y()-c.stdform[2]*p.X();}, 638 function(){ return c.stdform[2]*p.Z();}, 639 function(){ return -c.stdform[1]*p.Z();} 640 ], attributes ); 641 } 642 else if(c.elementClass == JXG.OBJECT_CLASS_CIRCLE) { 643 /* 644 var Dg = function(t){ return -c.Radius()*Math.sin(t); }; 645 var Df = function(t){ return c.Radius()*Math.cos(t); }; 646 return board.create('line', [ 647 function(){ return -p.X()*Dg(p.position)-p.Y()*Df(p.position);}, 648 function(){ return Dg(p.position);}, 649 function(){ return Df(p.position);} 650 ], attributes ); 651 */ 652 return board.create('line', [c.midpoint,p], attributes); 653 } else if (c.elementClass == JXG.OBJECT_CLASS_CURVE) { 654 if (c.curveType!='plot') { 655 var g = c.X; 656 var f = c.Y; 657 return board.create('line', [ 658 function(){ return -p.X()*board.D(g)(p.position)-p.Y()*board.D(f)(p.position);}, 659 function(){ return board.D(g)(p.position);}, 660 function(){ return board.D(f)(p.position);} 661 ], attributes ); 662 } else { // curveType 'plot' 663 return board.create('line', [ 664 function(){ var i=Math.floor(p.position); 665 var lbda = p.position-i; 666 if (i==c.numberPoints-1) {i--; lbda=1; } 667 if (i<0) return 1.0; 668 return (c.Y(i)+lbda*(c.Y(i+1)-c.Y(i)))*(c.Y(i)-c.Y(i+1))-(c.X(i)+lbda*(c.X(i+1)-c.X(i)))*(c.X(i+1)-c.X(i));}, 669 function(){ var i=Math.floor(p.position); 670 if (i==c.numberPoints-1) i--; 671 if (i<0) return 0.0; 672 return c.X(i+1)-c.X(i);}, 673 function(){ var i=Math.floor(p.position); 674 if (i==c.numberPoints-1) i--; 675 if (i<0) return 0.0; 676 return c.Y(i+1)-c.Y(i);} 677 ], attributes ); 678 } 679 } else if (c.type == JXG.OBJECT_TYPE_TURTLE) { 680 return board.create('line', [ 681 function(){ var i=Math.floor(p.position); 682 var lbda = p.position-i; 683 var el,j; 684 for(j=0;j<c.objects.length;j++) { // run through all curves of this turtle 685 el = c.objects[j]; 686 if (el.type==JXG.OBJECT_TYPE_CURVE) { 687 if (i<el.numberPoints) break; 688 i-=el.numberPoints; 689 } 690 } 691 if (i==el.numberPoints-1) { i--; lbda=1.0; } 692 if (i<0) return 1.0; 693 return (el.Y(i)+lbda*(el.Y(i+1)-el.Y(i)))*(el.Y(i)-el.Y(i+1))-(el.X(i)+lbda*(el.X(i+1)-el.X(i)))*(el.X(i+1)-el.X(i));}, 694 function(){ var i=Math.floor(p.position); 695 var el,j; 696 for(j=0;j<c.objects.length;j++) { // run through all curves of this turtle 697 el = c.objects[j]; 698 if (el.type==JXG.OBJECT_TYPE_CURVE) { 699 if (i<el.numberPoints) break; 700 i-=el.numberPoints; 701 } 702 } 703 if (i==el.numberPoints-1) i--; 704 if (i<0) return 0.0; 705 return el.X(i+1)-el.X(i);}, 706 function(){ var i=Math.floor(p.position); 707 var el,j; 708 for(j=0;j<c.objects.length;j++) { // run through all curves of this turtle 709 el = c.objects[j]; 710 if (el.type==JXG.OBJECT_TYPE_CURVE) { 711 if (i<el.numberPoints) break; 712 i-=el.numberPoints; 713 } 714 } 715 if (i==el.numberPoints-1) i--; 716 if (i<0) return 0.0; 717 return el.Y(i+1)-el.Y(i);} 718 ], attributes ); 719 } 720 else { 721 throw new Error("JSXGraph: Can't create normal with parent types '" + 722 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 723 "\nPossible parent types: [point,line], [point,circle], [glider]"); 724 } 725 }; 726 727 /** 728 * @class Provides a constructor for an angle bisector. 729 * @pseudo 730 * @description A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and C and divides the angle ABC into two 731 * equal sized parts. 732 * @constructor 733 * @name Bisector 734 * @type JXG.Line 735 * @augments JXG.Line 736 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 737 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by p3 will be divided into two equal angles. 738 * @example 739 * // Create a normal to a circle. 740 * var p1 = board.create('point', [6.0, 4.0]); 741 * var p2 = board.create('point', [3.0, 2.0]); 742 * var p3 = board.create('point', [1.0, 7.0]); 743 * 744 * var bi1 = board.create('bisector', [p1, p2, p3]); 745 * </pre><div id="0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div> 746 * <script type="text/javascript"> 747 * var biex1_board = JXG.JSXGraph.initBoard('0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 748 * var biex1_p1 = biex1_board.create('point', [6.0, 4.0]); 749 * var biex1_p2 = biex1_board.create('point', [3.0, 2.0]); 750 * var biex1_p3 = biex1_board.create('point', [1.0, 7.0]); 751 * var biex1_bi1 = biex1_board.create('bisector', [biex1_p1, biex1_p2, biex1_p3]); 752 * </script><pre> 753 */ 754 JXG.createBisector = function(board, parentArr, atts) { 755 var p, l, cAtts, i; 756 /* TODO bisector polynomials */ 757 if(parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[2].elementClass == JXG.OBJECT_CLASS_POINT) { 758 759 cAtts = {name: '', id: null, fixed: true, visible: false}; 760 if(atts) { 761 cAtts = JXG.cloneAndCopy(atts, cAtts); 762 } 763 764 // hidden and fixed helper 765 p = board.create('point', [function () { return JXG.Math.Geometry.angleBisector(parentArr[0], parentArr[1], parentArr[2], board); }], cAtts); 766 767 for(i=0; i<3; i++) 768 parentArr[i].addChild(p); // required for algorithm requiring dependencies between elements 769 770 if(typeof atts['straightFirst'] == 'undefined') 771 atts['straightFirst'] = false; 772 if(typeof atts['straightLast'] == 'undefined') 773 atts['straightLast'] = true; 774 // no need to fire up the create stack because only attributes need to be set and they 775 // will be set for l after returning. 776 l = JXG.createLine(board, [parentArr[1], p], atts); 777 return l; 778 } 779 else { 780 throw new Error("JSXGraph: Can't create angle bisector with parent types '" + 781 (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." + 782 "\nPossible parent types: [point,point,point]"); 783 } 784 }; 785 786 /** 787 * TODO Is it possible to merge this with createBisector? --michael 788 * The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation: 789 * (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2) 790 * @private 791 */ 792 JXG.createAngularBisectorsOfTwoLines = function(board, parents, attributes) { 793 var l1 = JXG.getReference(board,parents[0]), 794 l2 = JXG.getReference(board,parents[1]), 795 id1 = '', 796 id2 = '', 797 n1 = '', 798 n2 = '', 799 ret; 800 801 if(l1.elementClass != JXG.OBJECT_CLASS_LINE || l2.elementClass != JXG.OBJECT_CLASS_LINE) { 802 throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" + 803 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 804 "\nPossible parent types: [line,line]"); 805 } 806 807 attributes = JXG.checkAttributes(attributes,{}); 808 if (attributes['id']!=null) { 809 if (JXG.isArray(attributes['id'])) { 810 id1 = attributes['id'][0]; 811 id2 = attributes['id'][1]; 812 } else { 813 id1 = attributes['id']; 814 id2 = attributes['id']; 815 } 816 } 817 if (attributes['name']!=null) { 818 if (JXG.isArray(attributes['name'])) { 819 n1 = attributes['name'][0]; 820 n2 = attributes['name'][1]; 821 } else { 822 n1 = attributes['name']; 823 n2 = attributes['name']; 824 } 825 } 826 827 attributes['id'] = id1; 828 attributes['name'] = n1; 829 var g1 = board.create('line',[ 830 function(){ 831 var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]); 832 var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]); 833 return l1.stdform[0]/d1-l2.stdform[0]/d2; 834 }, 835 function(){ 836 var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]); 837 var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]); 838 return l1.stdform[1]/d1-l2.stdform[1]/d2; 839 }, 840 function(){ 841 var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]); 842 var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]); 843 return l1.stdform[2]/d1-l2.stdform[2]/d2; 844 } 845 ], attributes); 846 attributes['id'] = id2; 847 attributes['name'] = n2; 848 var g2 = board.create('line',[ 849 function(){ 850 var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]); 851 var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]); 852 return l1.stdform[0]/d1+l2.stdform[0]/d2; 853 }, 854 function(){ 855 var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]); 856 var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]); 857 return l1.stdform[1]/d1+l2.stdform[1]/d2; 858 }, 859 function(){ 860 var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]); 861 var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]); 862 return l1.stdform[2]/d1+l2.stdform[2]/d2; 863 } 864 ], attributes); 865 866 ret = [g1, g2]; 867 ret.lines = [g1, g2]; 868 ret.line1 = g1; 869 ret.line2 = g2; 870 871 ret.multipleElements = true; 872 873 return ret; 874 }; 875 876 /** 877 * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter 878 * is constructed by providing three points. 879 * @pseudo 880 * @description A circumcenter is given by three points which are all lying on the circle with the 881 * constructed circumcenter as the midpoint. 882 * @constructor 883 * @name Circumcenter 884 * @type JXG.Point 885 * @augments JXG.Point 886 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 887 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined 888 * by p1, p2, and p3. 889 * @example 890 * var p1 = board.create('point', [0.0, 2.0]); 891 * var p2 = board.create('point', [2.0, 1.0]); 892 * var p3 = board.create('point', [3.0, 3.0]); 893 * 894 * var cc1 = board.create('circumcenter', [p1, p2, p3]); 895 * </pre><div id="e8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div> 896 * <script type="text/javascript"> 897 * var ccmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 898 * var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]); 899 * var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]); 900 * var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]); 901 * var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]); 902 * </script><pre> 903 */ 904 JXG.createCircumcircleMidpoint = function(board, parents, atts) { 905 var p, i; 906 907 /* TODO circumcircle polynomials */ 908 909 if(parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) { 910 atts['fixed'] = atts['fixed'] || true; 911 p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.circumcenterMidpoint(parents[0], parents[1], parents[2], board); }], atts); 912 913 for(i=0; i<3; i++) 914 parents[i].addChild(p); 915 916 p.generatePolynomial = function() { 917 /* 918 * CircumcircleMidpoint takes three points A, B and C and creates point M, which is the circumcenter of A, B, and C. 919 * 920 * 921 * So we have two conditions: 922 * 923 * (a) CT == AT (distance condition I) 924 * (b) BT == AT (distance condition II) 925 * 926 */ 927 928 var a1 = a.symbolic.x; 929 var a2 = a.symbolic.y; 930 var b1 = b.symbolic.x; 931 var b2 = b.symbolic.y; 932 var c1 = c.symbolic.x; 933 var c2 = c.symbolic.y; 934 var t1 = p.symbolic.x; 935 var t2 = p.symbolic.y; 936 937 var poly1 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',b1,'))^2-((',t2,')-(',b2,'))^2'].join(''); 938 var poly2 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',c1,'))^2-((',t2,')-(',c2,'))^2'].join(''); 939 940 return [poly1, poly2]; 941 }; 942 943 return p; 944 } 945 else { 946 throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" + 947 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + 948 "\nPossible parent types: [point,point,point]"); 949 } 950 }; 951 952 /** 953 * @class Constructs the incenter of the triangle described by the three given points. 954 * @pseudo 955 * @description http://mathworld.wolfram.com/Incenter.html 956 * @constructor 957 * @name Incenter 958 * @type JXG.Point 959 * @returns An array containing the midpoint in the first component and the circumcircle in the second component. 960 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 961 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described 962 * by p1, p2, and p3. 963 * @example 964 * var p1 = board.create('point', [0.0, 2.0]); 965 * var p2 = board.create('point', [2.0, 1.0]); 966 * var p3 = board.create('point', [3.0, 3.0]); 967 * 968 * var ic1 = board.create('incenter', [p1, p2, p3]); 969 * </pre><div id="e8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div> 970 * <script type="text/javascript"> 971 * var icmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 972 * var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]); 973 * var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]); 974 * var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]); 975 * var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]); 976 * </script><pre> 977 */ 978 JXG.createIncenter = function(board, parents, atts) { 979 var p, c, ret, 980 A, B, C; 981 982 if(parents.length >= 3 && JXG.isPoint(parents[0]) && JXG.isPoint(parents[1]) && JXG.isPoint(parents[2])) { 983 A = parents[0]; 984 B = parents[1]; 985 C = parents[2]; 986 987 p = board.create('point', [function() { 988 var a, b, c; 989 990 a = Math.sqrt((B.X() - C.X())*(B.X() - C.X()) + (B.Y() - C.Y())*(B.Y() - C.Y())); 991 b = Math.sqrt((A.X() - C.X())*(A.X() - C.X()) + (A.Y() - C.Y())*(A.Y() - C.Y())); 992 c = Math.sqrt((B.X() - A.X())*(B.X() - A.X()) + (B.Y() - A.Y())*(B.Y() - A.Y())); 993 994 return new JXG.Coords(JXG.COORDS_BY_USER, [(a*A.X()+b*B.X()+c*C.X())/(a+b+c), (a*A.Y()+b*B.Y()+c*C.Y())/(a+b+c)], board); 995 }], atts); 996 } else { 997 throw new Error("JSXGraph: Can't create incenter with parent types '" + 998 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + 999 "\nPossible parent types: [point,point,point]"); 1000 } 1001 1002 return p; 1003 }; 1004 1005 /** 1006 * @class Constructs two elements: a point and a circle. The circle is given by three points which lie on the circle, 1007 * the point is the midpoint of the circle. 1008 * @pseudo 1009 * @description A circumcircle is given by three points which are all lying on the circle. 1010 * @constructor 1011 * @name Circumcircle 1012 * @type array 1013 * @returns An array containing the midpoint in the first component and the circumcircle in the second component. 1014 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 1015 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined 1016 * by p1, p2, and p3. 1017 * @example 1018 * var p1 = board.create('point', [0.0, 2.0]); 1019 * var p2 = board.create('point', [2.0, 1.0]); 1020 * var p3 = board.create('point', [3.0, 3.0]); 1021 * 1022 * var cc1 = board.create('circumcircle', [p1, p2, p3]); 1023 * </pre><div id="e65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div> 1024 * <script type="text/javascript"> 1025 * var ccex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 1026 * var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]); 1027 * var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]); 1028 * var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]); 1029 * var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]); 1030 * </script><pre> 1031 */ 1032 JXG.createCircumcircle = function(board, parentArr, atts) { 1033 var p, c, cAtts, ret; 1034 1035 cAtts = JXG.clone(atts); 1036 if(atts['name'] && JXG.isArray(atts['name'])) { 1037 cAtts['name'] = atts['name'][0]; 1038 atts['name'] = atts['name'][1]; 1039 } 1040 if(atts['id'] && JXG.isArray(atts['id'])) { 1041 cAtts['id'] = atts['id'][0]; 1042 atts['id'] = atts['id'][1]; 1043 } 1044 1045 try { 1046 p = JXG.createCircumcircleMidpoint(board, parentArr, cAtts); 1047 c = JXG.createCircle(board, [p, parentArr[0]], atts); 1048 } catch(e) { 1049 throw new Error("JSXGraph: Can't create circumcircle with parent types '" + 1050 (typeof parentArr[0]) + "', '" + (typeof parentArr[1]) + "' and '" + (typeof parentArr[2]) + "'." + 1051 "\nPossible parent types: [point,point,point]"); 1052 } 1053 1054 ret = [p, c]; 1055 1056 ret.point = p; 1057 ret.circle = c; 1058 1059 ret.multipleElements = true; 1060 1061 return ret; 1062 }; 1063 1064 /** 1065 * @class Constructs two elements: a point and a circle. The circle is given by three points, 1066 * the point is the midpoint of the circle. 1067 * @pseudo 1068 * @description A incircle is given by three points. 1069 * @constructor 1070 * @name Incircle 1071 * @type array 1072 * @returns An array containing the midpoint in the first component and the incircle in the second component. 1073 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 1074 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of 1075 * p1, p2, and p3. 1076 * @example 1077 * var p1 = board.create('point', [0.0, 2.0]); 1078 * var p2 = board.create('point', [2.0, 1.0]); 1079 * var p3 = board.create('point', [3.0, 3.0]); 1080 * 1081 * var ic1 = board.create('incircle', [p1, p2, p3]); 1082 * </pre><div id="e65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div> 1083 * <script type="text/javascript"> 1084 * var icex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 1085 * var icex1_p1 = icex1_board.create('point', [0.0, 2.0]); 1086 * var icex1_p2 = icex1_board.create('point', [6.0, 1.0]); 1087 * var icex1_p3 = icex1_board.create('point', [3.0, 7.0]); 1088 * var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]); 1089 * </script><pre> 1090 */ 1091 JXG.createIncircle = function(board, parents, atts) { 1092 var p, c, cAtts, ret; 1093 1094 cAtts = JXG.clone(atts); 1095 if(atts['name'] && JXG.isArray(atts['name'])) { 1096 cAtts['name'] = atts['name'][0]; 1097 atts['name'] = atts['name'][1]; 1098 } 1099 if(atts['id'] && JXG.isArray(atts['id'])) { 1100 cAtts['id'] = atts['id'][0]; 1101 atts['id'] = atts['id'][1]; 1102 } 1103 1104 try { 1105 p = JXG.createIncenter(board, parents, cAtts); 1106 c = JXG.createCircle(board, [p, function() { 1107 var a = Math.sqrt((parents[1].X() - parents[2].X())*(parents[1].X() - parents[2].X()) + (parents[1].Y() - parents[2].Y())*(parents[1].Y() - parents[2].Y())), 1108 b = Math.sqrt((parents[0].X() - parents[2].X())*(parents[0].X() - parents[2].X()) + (parents[0].Y() - parents[2].Y())*(parents[0].Y() - parents[2].Y())), 1109 c = Math.sqrt((parents[1].X() - parents[0].X())*(parents[1].X() - parents[0].X()) + (parents[1].Y() - parents[0].Y())*(parents[1].Y() - parents[0].Y())), 1110 s = (a+b+c)/2; 1111 1112 return Math.sqrt(((s-a)*(s-b)*(s-c))/s); 1113 }], atts); 1114 } catch(e) { 1115 throw new Error("JSXGraph: Can't create circumcircle with parent types '" + 1116 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + 1117 "\nPossible parent types: [point,point,point]"); 1118 } 1119 1120 ret = [p, c]; 1121 1122 ret.point = p; 1123 ret.circle = c; 1124 1125 ret.multipleElements = true; 1126 1127 return ret; 1128 }; 1129 1130 /** 1131 * @class This element is used to construct a reflected point. 1132 * @pseudo 1133 * @description A reflected point is given by a point and a line. It is determined by the reflection of the given point 1134 * against the given line. 1135 * @constructor 1136 * @name Reflection 1137 * @type JXG.Point 1138 * @augments JXG.Point 1139 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 1140 * @param {JXG.Point_JXG.Line} p,l The reflection point is the reflection of p against l. 1141 * @example 1142 * var p1 = board.create('point', [0.0, 4.0]); 1143 * var p2 = board.create('point', [6.0, 1.0]); 1144 * var l1 = board.create('line', [p1, p2]); 1145 * var p3 = board.create('point', [3.0, 3.0]); 1146 * 1147 * var rp1 = board.create('reflection', [p3, l1]); 1148 * </pre><div id="087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div> 1149 * <script type="text/javascript"> 1150 * var rpex1_board = JXG.JSXGraph.initBoard('087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 1151 * var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]); 1152 * var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]); 1153 * var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]); 1154 * var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]); 1155 * var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]); 1156 * </script><pre> 1157 */ 1158 JXG.createReflection = function(board, parentArr, atts) { 1159 var l, p, r; 1160 1161 if(parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_LINE) { 1162 p = parentArr[0]; 1163 l = parentArr[1]; 1164 } 1165 else if(parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) { 1166 p = parentArr[1]; 1167 l = parentArr[0]; 1168 } 1169 else { 1170 throw new Error("JSXGraph: Can't create reflection point with parent types '" + 1171 (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." + 1172 "\nPossible parent types: [line,point]"); 1173 } 1174 1175 // force a fixed point 1176 //atts['fixed'] = true; 1177 r = JXG.createPoint(board, [function () { return JXG.Math.Geometry.reflection(l, p, board); }], atts); 1178 p.addChild(r); 1179 l.addChild(r); 1180 1181 r.update(); 1182 1183 r.generatePolynomial = function() { 1184 /* 1185 * Reflection takes a point R and a line L and creates point P, which is the reflection of R on L. 1186 * L is defined by two points A and B. 1187 * 1188 * So we have two conditions: 1189 * 1190 * (a) RP _|_ AB (orthogonality condition) 1191 * (b) AR == AP (distance condition) 1192 * 1193 */ 1194 1195 var a1 = l.point1.symbolic.x; 1196 var a2 = l.point1.symbolic.y; 1197 var b1 = l.point2.symbolic.x; 1198 var b2 = l.point2.symbolic.y; 1199 var p1 = p.symbolic.x; 1200 var p2 = p.symbolic.y; 1201 var r1 = r.symbolic.x; 1202 var r2 = r.symbolic.y; 1203 1204 var poly1 = ['((',r2,')-(',p2,'))*((',a2,')-(',b2,'))+((',a1,')-(',b1,'))*((',r1,')-(',p1,'))'].join(''); 1205 var poly2 = ['((',r1,')-(',a1,'))^2+((',r2,')-(',a2,'))^2-((',p1,')-(',a1,'))^2-((',p2,')-(',a2,'))^2'].join(''); 1206 1207 return [poly1, poly2]; 1208 }; 1209 1210 return r; 1211 }; 1212 1213 // here we have to continue with replacing board.add* stuff 1214 1215 /** 1216 * @class A mirror point will be constructed. 1217 * @pseudo 1218 * @description A mirror point is determined by the reflection of a given point against another given point. 1219 * @constructor 1220 * @name Mirrorpoint 1221 * @type JXG.Point 1222 * @augments JXG.Point 1223 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 1224 * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1. 1225 * @example 1226 * var p1 = board.create('point', [3.0, 3.0]); 1227 * var p2 = board.create('point', [6.0, 1.0]); 1228 * 1229 * var mp1 = board.create('mirrorpoint', [p1, p2]); 1230 * </pre><div id="7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div> 1231 * <script type="text/javascript"> 1232 * var mpex1_board = JXG.JSXGraph.initBoard('7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 1233 * var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]); 1234 * var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]); 1235 * var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]); 1236 * </script><pre> 1237 */ 1238 JXG.createMirrorPoint = function(board, parentArr, atts) { 1239 var p, i; 1240 1241 /* TODO mirror polynomials */ 1242 if(JXG.isPoint(parentArr[0]) && JXG.isPoint(parentArr[1])) { 1243 atts['fixed'] = atts['fixed'] || true; 1244 p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.rotation(parentArr[0], parentArr[1], Math.PI, board); }], atts); 1245 1246 for(i=0; i<2; i++) 1247 parentArr[i].addChild(p); 1248 } 1249 else { 1250 throw new Error("JSXGraph: Can't create mirror point with parent types '" + 1251 (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." + 1252 "\nPossible parent types: [point,point]"); 1253 } 1254 1255 p.update(); 1256 1257 return p; 1258 }; 1259 1260 /** 1261 * @class This element is used to visualize the integral of a given curve over a given interval. 1262 * @pseudo 1263 * @description The Integral element is used to visualize the area under a given curve over a given interval 1264 * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area, 1265 * the gliders are used to change the interval dynamically. 1266 * @constructor 1267 * @name Integral 1268 * @type JXG.Polygon 1269 * @augments JXG.Polygon 1270 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 1271 * @param {array_JXG.Curve} p,l The constructed point is the orthogonal projection of p onto l. 1272 * @example 1273 * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]); 1274 * var i1 = board.create('integral', [[-1.0, 4.0], c1]); 1275 * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div> 1276 * <script type="text/javascript"> 1277 * var intex1_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}); 1278 * var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return t*t*t; }]); 1279 * var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]); 1280 * </script><pre> 1281 */ 1282 JXG.createIntegral = function(board, parents, attributes) { 1283 var interval, curve, attribs = {}, 1284 start = 0, end = 0, startx, starty, endx, endy, factor = 1, 1285 pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis, 1286 Int, t, p; 1287 1288 if(!JXG.isArray(attributes['id']) || (attributes['id'].length != 5)) { 1289 attributes['id'] = ['','','','','']; 1290 } 1291 if(!JXG.isArray(attributes['name']) || (attributes['name'].length != 5)) { 1292 attributes['name'] = ['','','','','']; 1293 } 1294 1295 if(JXG.isArray(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_CURVE) { 1296 interval = parents[0]; 1297 curve = parents[1]; 1298 } else if(JXG.isArray(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_CURVE) { 1299 interval = parents[1]; 1300 curve = parents[0]; 1301 } else { 1302 throw new Error("JSXGraph: Can't create integral with parent types '" + 1303 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 1304 "\nPossible parent types: [[number|function,number|function],curve]"); 1305 } 1306 1307 if( (typeof attributes != 'undefined') && (attributes != null)) 1308 attribs = JXG.cloneAndCopy(attributes, {name: attributes.name[0], id: attributes.id[0]}); 1309 1310 // Correct the interval if necessary - NOT ANYMORE, GGB's fault 1311 start = interval[0]; 1312 end = interval[1]; 1313 1314 if(JXG.isFunction(start)) { 1315 startx = start; 1316 starty = function () { return curve.yterm(startx()); }; 1317 start = startx(); 1318 } else { 1319 startx = start; 1320 starty = curve.yterm(start); 1321 } 1322 1323 if(JXG.isFunction(start)) { 1324 endx = end; 1325 endy = function () { return curve.yterm(endx()); }; 1326 end = endx(); 1327 } else { 1328 endx = end; 1329 endy = curve.yterm(end); 1330 } 1331 1332 if(end < start) 1333 factor = -1; 1334 1335 pa_on_curve = board.create('glider', [startx, starty, curve], attribs); 1336 if(JXG.isFunction(startx)) 1337 pa_on_curve.hideElement(); 1338 1339 attribs.name = attributes.name[1]; 1340 attribs.id = attributes.id[1]; 1341 attribs.visible = false; 1342 pa_on_axis = board.create('point', [function () { return pa_on_curve.X(); }, 0], attribs); 1343 1344 //pa_on_curve.addChild(pa_on_axis); 1345 1346 attribs.name = attributes.name[2]; 1347 attribs.id = attributes.id[2]; 1348 attribs.visible = attributes.visible || true; 1349 pb_on_curve = board.create('glider', [endx, endy, curve], attribs); 1350 if(JXG.isFunction(endx)) 1351 pb_on_curve.hideElement(); 1352 1353 attribs.name = attributes.name[3]; 1354 attribs.id = attributes.id[3]; 1355 attribs.visible = false; 1356 pb_on_axis = board.create('point', [function () { return pb_on_curve.X(); }, 0], attribs); 1357 1358 //pb_on_curve.addChild(pb_on_axis); 1359 1360 Int = JXG.Math.Numerics.I([start, end], curve.yterm); 1361 t = board.create('text', [ 1362 function () { return pb_on_curve.X() + 0.2; }, 1363 function () { return pb_on_curve.Y() - 0.8; }, 1364 function () { 1365 var Int = JXG.Math.Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.yterm); 1366 return '∫ = ' + (Int).toFixed(4); 1367 } 1368 ],{labelColor: attributes['labelColor']}); 1369 1370 attribs.name = attributes.name[4]; 1371 attribs.id = attributes.id[4]; 1372 attribs.visible = attributes.visible || true; 1373 attribs.fillColor = attribs.fillColor || board.options.polygon.fillColor; 1374 attribs.highlightFillColor = attribs.highlightFillColor || board.options.polygon.highlightFillColor; 1375 attribs.fillOpacity = attribs.fillOpacity || board.options.polygon.fillOpacity; 1376 attribs.highlightFillOpacity = attribs.highlightFillOpacity || board.options.polygon.highlightFillOpacity; 1377 attribs.strokeWidth = 0; 1378 attribs.highlightStrokeWidth = 0; 1379 attribs.strokeOpacity = 0; 1380 1381 p = board.create('curve', [[0],[0]], attribs); 1382 p.updateDataArray = function() { 1383 var x, y, 1384 i, left, right; 1385 1386 if(pa_on_axis.X() < pb_on_axis.X()) { 1387 left = pa_on_axis.X(); 1388 right = pb_on_axis.X(); 1389 } else { 1390 left = pb_on_axis.X(); 1391 right = pa_on_axis.X(); 1392 } 1393 1394 x = [left, left]; 1395 y = [0, curve.yterm(left)]; 1396 1397 for(i=0; i < curve.numberPoints; i++) { 1398 if( (left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right) ) { 1399 x.push(curve.points[i].usrCoords[1]); 1400 y.push(curve.points[i].usrCoords[2]); 1401 } 1402 } 1403 x.push(right); 1404 y.push(curve.yterm(right)); 1405 x.push(right); 1406 y.push(0); 1407 1408 x.push(left); // close the curve 1409 y.push(0); 1410 1411 this.dataX = x; 1412 this.dataY = y; 1413 }; 1414 pa_on_curve.addChild(p); 1415 pb_on_curve.addChild(p); 1416 pa_on_curve.addChild(t); 1417 pb_on_curve.addChild(t); 1418 1419 return p;//[pa_on_axis, pb_on_axis, p, t]; 1420 1421 }; 1422 1423 /** 1424 * @class This element is used to visualize the locus of a given dependent point. 1425 * @pseudo 1426 * @description The locus element is used to visualize the curve a given point describes. 1427 * @constructor 1428 * @name Locus 1429 * @type JXG.Curve 1430 * @augments JXG.Curve 1431 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 1432 * @param {JXG.Point} p The constructed curve is the geometric locus of the given point. 1433 * @example 1434 * // This examples needs JXG.Server up and running, otherwise it won't work. 1435 * p1 = board.create('point', [0, 0]); 1436 * p2 = board.create('point', [6, -1]); 1437 * c1 = board.create('circle', [p1, 2]); 1438 * c2 = board.create('circle', [p2, 1.5]); 1439 * g1 = board.create('glider', [6, 3, c1]); 1440 * c3 = board.create('circle', [g1, 4]); 1441 * g2 = board.create('intersection', [c2,c3,0]); 1442 * m1 = board.create('midpoint', [g1,g2]); 1443 * loc = board.create('locus', [m1], {strokeColor: 'red'}); 1444 * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div> 1445 * <script type="text/javascript"> 1446 * lcex_board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true}); 1447 * lcex_p1 = lcex_board.create('point', [0, 0]); 1448 * lcex_p2 = lcex_board.create('point', [6, -1]); 1449 * lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]); 1450 * lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]); 1451 * lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]); 1452 * lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]); 1453 * lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]); 1454 * lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]); 1455 * lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'}); 1456 * </script><pre> 1457 */ 1458 JXG.createLocus = function(board, parents, attributes) { 1459 var c, p; 1460 1461 if(JXG.isArray(parents) && parents.length == 1 && parents[0].elementClass == JXG.OBJECT_CLASS_POINT) { 1462 p = parents[0]; 1463 } else { 1464 throw new Error("JSXGraph: Can't create locus with parent of type other than point." + 1465 "\nPossible parent types: [point]"); 1466 } 1467 1468 c = board.create('curve', [[null], [null]], attributes); 1469 c.dontCallServer = false; 1470 1471 c.updateDataArray = function () { 1472 if(c.board.mode > 0) 1473 return; 1474 1475 var spe = JXG.Math.Symbolic.generatePolynomials(board, p, true).join(''); 1476 if(spe === c.spe) 1477 return; 1478 1479 c.spe = spe; 1480 1481 var cb = function(x, y, eq, t) { 1482 c.dataX = x; 1483 c.dataY = y; 1484 c.eq = eq; 1485 c.ctime = t; 1486 1487 // convert equation and use it to build a generatePolynomial-method 1488 c.generatePolynomial = (function(equations) { 1489 return function(point) { 1490 var x = '(' + point.symbolic.x + ')', 1491 y = '(' + point.symbolic.y + ')', 1492 res = [], i; 1493 1494 for(i=0; i<equations.length; i++) 1495 res[i] = equations[i].replace(/\*\*/g, '^').replace(/x/g, x).replace(/y/g, y); 1496 1497 return res; 1498 } 1499 })(eq); 1500 }, 1501 data = JXG.Math.Symbolic.geometricLocusByGroebnerBase(board, p, cb); 1502 1503 cb(data.datax, data.datay, data.polynomial, data.exectime); 1504 }; 1505 return c; 1506 }; 1507 1508 JXG.JSXGraph.registerElement('arrowparallel', JXG.createArrowParallel); 1509 JXG.JSXGraph.registerElement('bisector', JXG.createBisector); 1510 JXG.JSXGraph.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines); 1511 JXG.JSXGraph.registerElement('circumcircle', JXG.createCircumcircle); 1512 JXG.JSXGraph.registerElement('circumcirclemidpoint', JXG.createCircumcircleMidpoint); 1513 JXG.JSXGraph.registerElement('circumcenter', JXG.createCircumcircleMidpoint); 1514 JXG.JSXGraph.registerElement('incenter', JXG.createIncenter); 1515 JXG.JSXGraph.registerElement('incircle', JXG.createIncircle); 1516 JXG.JSXGraph.registerElement('integral', JXG.createIntegral); 1517 JXG.JSXGraph.registerElement('midpoint', JXG.createMidpoint); 1518 JXG.JSXGraph.registerElement('mirrorpoint', JXG.createMirrorPoint); 1519 JXG.JSXGraph.registerElement('normal', JXG.createNormal); 1520 JXG.JSXGraph.registerElement('parallel', JXG.createParallel); 1521 JXG.JSXGraph.registerElement('parallelpoint', JXG.createParallelPoint); 1522 JXG.JSXGraph.registerElement('perpendicular', JXG.createPerpendicular); 1523 JXG.JSXGraph.registerElement('perpendicularpoint', JXG.createPerpendicularPoint); 1524 JXG.JSXGraph.registerElement('reflection', JXG.createReflection); 1525 JXG.JSXGraph.registerElement('locus', JXG.createLocus); 1526