1 /* 2 Copyright 2008-2015 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 dual licensed under the GNU LGPL or MIT License. 13 14 You can redistribute it and/or modify it under the terms of the 15 16 * GNU Lesser General Public License as published by 17 the Free Software Foundation, either version 3 of the License, or 18 (at your option) any later version 19 OR 20 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 21 22 JSXGraph is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 GNU Lesser General Public License for more details. 26 27 You should have received a copy of the GNU Lesser General Public License and 28 the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> 29 and <http://opensource.org/licenses/MIT/>. 30 */ 31 32 33 /*global JXG: true, define: true, console: true, window: true*/ 34 /*jslint nomen: true, plusplus: true*/ 35 36 /* depends: 37 jxg 38 options 39 math/math 40 math/geometry 41 math/numerics 42 base/coords 43 base/constants 44 base/element 45 parser/geonext 46 utils/type 47 elements: 48 transform 49 */ 50 51 /** 52 * @fileoverview The geometry object Point is defined in this file. Point stores all 53 * style and functional properties that are required to draw and move a point on 54 * a board. 55 */ 56 57 define([ 58 'jxg', 'options', 'math/math', 'math/geometry', 'math/numerics', 'base/coords', 'base/constants', 'base/element', 59 'parser/geonext', 'utils/type', 'base/transformation', 'base/coordselement' 60 ], function (JXG, Options, Mat, Geometry, Numerics, Coords, Const, GeometryElement, GeonextParser, Type, Transform, CoordsElement) { 61 62 "use strict"; 63 64 /** 65 * A point is the basic geometric element. Based on points lines and circles can be constructed which can be intersected 66 * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for 67 * all kind of points like free points, gliders, and intersection points. 68 * @class Creates a new point object. Do not use this constructor to create a point. Use {@link JXG.Board#create} with 69 * type {@link Point}, {@link Glider}, or {@link Intersection} instead. 70 * @augments JXG.GeometryElement 71 * @augments JXG.CoordsElement 72 * @param {string|JXG.Board} board The board the new point is drawn on. 73 * @param {Array} coordinates An array with the user coordinates of the point. 74 * @param {Object} attributes An object containing visual properties like in {@link JXG.Options#point} and 75 * {@link JXG.Options#elements}, and optional a name and an id. 76 * @see JXG.Board#generateName 77 */ 78 JXG.Point = function (board, coordinates, attributes) { 79 this.constructor(board, attributes, Const.OBJECT_TYPE_POINT, Const.OBJECT_CLASS_POINT); 80 this.element = this.board.select(attributes.anchor); 81 this.coordsConstructor(coordinates); 82 83 this.elType = 'point'; 84 85 /* Register point at board. */ 86 this.id = this.board.setId(this, 'P'); 87 this.board.renderer.drawPoint(this); 88 this.board.finalizeAdding(this); 89 90 this.createLabel(); 91 }; 92 93 /** 94 * Inherits here from {@link JXG.GeometryElement}. 95 */ 96 JXG.Point.prototype = new GeometryElement(); 97 Type.copyPrototypeMethods(JXG.Point, CoordsElement, 'coordsConstructor'); 98 99 JXG.extend(JXG.Point.prototype, /** @lends JXG.Point.prototype */ { 100 /** 101 * Checks whether (x,y) is near the point. 102 * @param {Number} x Coordinate in x direction, screen coordinates. 103 * @param {Number} y Coordinate in y direction, screen coordinates. 104 * @returns {Boolean} True if (x,y) is near the point, False otherwise. 105 * @private 106 */ 107 hasPoint: function (x, y) { 108 var coordsScr = this.coords.scrCoords, r; 109 r = parseFloat(this.visProp.size) + parseFloat(this.visProp.strokewidth) * 0.5; 110 if (r < this.board.options.precision.hasPoint) { 111 r = this.board.options.precision.hasPoint; 112 } 113 114 return ((Math.abs(coordsScr[1] - x) < r + 2) && (Math.abs(coordsScr[2] - y) < r + 2)); 115 }, 116 117 /** 118 * Updates the position of the point. 119 */ 120 update: function (fromParent) { 121 if (!this.needsUpdate) { 122 return this; 123 } 124 125 this.updateCoords(fromParent); 126 127 if (this.visProp.trace) { 128 this.cloneToBackground(true); 129 } 130 131 return this; 132 }, 133 134 /** 135 * Applies the transformations of the element to {@link JXG.Point#baseElement}. 136 * Point transformations are relative to a base element. 137 * @returns {JXG.CoordsElement} Reference to this object. 138 */ 139 updateTransform: function () { 140 var c, i; 141 142 if (this.transformations.length === 0 || this.baseElement === null) { 143 return this; 144 } 145 146 // case of bindTo 147 if (this === this.baseElement) { 148 c = this.transformations[0].apply(this.baseElement, 'self'); 149 // case of board.create('point',[baseElement,transform]); 150 } else { 151 c = this.transformations[0].apply(this.baseElement); 152 } 153 154 this.coords.setCoordinates(Const.COORDS_BY_USER, c); 155 156 for (i = 1; i < this.transformations.length; i++) { 157 this.coords.setCoordinates(Const.COORDS_BY_USER, this.transformations[i].apply(this)); 158 } 159 return this; 160 }, 161 162 /** 163 * Calls the renderer to update the drawing. 164 * @private 165 */ 166 updateRenderer: function () { 167 if (this.visProp.size > 0) { 168 this.updateRendererGeneric('updatePoint'); 169 } 170 return this; 171 }, 172 173 // documented in JXG.GeometryElement 174 bounds: function () { 175 return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1)); 176 }, 177 178 /** 179 * Convert the point to intersection point and update the construction. 180 * To move the point visual onto the intersection, a call of board update is necessary. 181 * TODO docu. 182 * @param {String|Object} el1, el2, i, j The intersecting objects and the numbers. 183 **/ 184 makeIntersection: function (el1, el2, i, j) { 185 var func; 186 187 el1 = this.board.select(el1); 188 el2 = this.board.select(el2); 189 190 func = Geometry.intersectionFunction(this.board, el1, el2, i, j, this.visProp.alwaysintersect); 191 this.addConstraint([func]); 192 193 try { 194 el1.addChild(this); 195 el2.addChild(this); 196 } catch (e) { 197 throw new Error("JSXGraph: Can't create 'intersection' with parent types '" + 198 (typeof el1) + "' and '" + (typeof el2) + "'."); 199 } 200 201 this.type = Const.OBJECT_TYPE_INTERSECTION; 202 this.elType = 'intersection'; 203 this.parents = [el1.id, el2.id, i, j]; 204 205 this.generatePolynomial = function () { 206 var poly1 = el1.generatePolynomial(this), 207 poly2 = el2.generatePolynomial(this); 208 209 if ((poly1.length === 0) || (poly2.length === 0)) { 210 return []; 211 } 212 213 return [poly1[0], poly2[0]]; 214 }; 215 216 this.prepareUpdate().update(); 217 }, 218 219 /** 220 * Set the style of a point. 221 * Used for GEONExT import and should not be used to set the point's face and size. 222 * @param {Number} i Integer to determine the style. 223 * @private 224 */ 225 setStyle: function (i) { 226 var facemap = [ 227 // 0-2 228 'cross', 'cross', 'cross', 229 // 3-6 230 'circle', 'circle', 'circle', 'circle', 231 // 7-9 232 'square', 'square', 'square', 233 // 10-12 234 'plus', 'plus', 'plus' 235 ], sizemap = [ 236 // 0-2 237 2, 3, 4, 238 // 3-6 239 1, 2, 3, 4, 240 // 7-9 241 2, 3, 4, 242 // 10-12 243 2, 3, 4 244 ]; 245 246 this.visProp.face = facemap[i]; 247 this.visProp.size = sizemap[i]; 248 249 this.board.renderer.changePointStyle(this); 250 return this; 251 }, 252 253 /** 254 * @deprecated Use JXG#normalizePointFace instead 255 * @param s 256 * @return {*} 257 */ 258 normalizeFace: function (s) { 259 return Options.normalizePointFace(s); 260 }, 261 262 /** 263 * Set the face of a point element. 264 * @param {String} f String which determines the face of the point. See {@link JXG.GeometryElement#face} for a list of available faces. 265 * @see JXG.GeometryElement#face 266 * @deprecated Use setAttribute() 267 */ 268 face: function (f) { 269 this.setAttribute({face: f}); 270 }, 271 272 /** 273 * Set the size of a point element 274 * @param {Number} s Integer which determines the size of the point. 275 * @see JXG.GeometryElement#size 276 * @deprecated Use setAttribute() 277 */ 278 size: function (s) { 279 this.setAttribute({size: s}); 280 }, 281 282 // already documented in GeometryElement 283 cloneToBackground: function () { 284 var copy = {}; 285 286 copy.id = this.id + 'T' + this.numTraces; 287 this.numTraces += 1; 288 289 copy.coords = this.coords; 290 copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true); 291 copy.visProp.layer = this.board.options.layer.trace; 292 copy.elementClass = Const.OBJECT_CLASS_POINT; 293 copy.board = this.board; 294 Type.clearVisPropOld(copy); 295 296 this.board.renderer.drawPoint(copy); 297 this.traces[copy.id] = copy.rendNode; 298 299 return this; 300 } 301 302 }); 303 304 305 /** 306 * @class This element is used to provide a constructor for a general point. A free point is created if the given parent elements are all numbers 307 * and the property fixed is not set or set to false. If one or more parent elements is not a number but a string containing a GEONE<sub>x</sub>T 308 * constraint or a function the point will be considered as constrained). That means that the user won't be able to change the point's 309 * position directly. 310 * @pseudo 311 * @description 312 * @name Point 313 * @augments JXG.Point 314 * @constructor 315 * @type JXG.Point 316 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 317 * @param {Number,string,function_Number,string,function_Number,string,function} z_,x,y Parent elements can be two or three elements of type number, a string containing a GEONE<sub>x</sub>T 318 * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is 319 * given by a number, the number determines the initial position of a free point. If given by a string or a function that coordinate will be constrained 320 * that means the user won't be able to change the point's position directly by mouse because it will be calculated automatically depending on the string 321 * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such 322 * parent elements are given they will be interpreted as homogeneous coordinates. 323 * @param {JXG.Point_JXG.Transformation} Point,Transformation A point can also be created providing a transformation. The resulting point is a clone of the base 324 * point transformed by the given Transformation. {@see JXG.Transformation}. 325 * @example 326 * // Create a free point using affine euclidean coordinates 327 * var p1 = board.create('point', [3.5, 2.0]); 328 * </pre><div id="672f1764-7dfa-4abc-a2c6-81fbbf83e44b" style="width: 200px; height: 200px;"></div> 329 * <script type="text/javascript"> 330 * var board = JXG.JSXGraph.initBoard('672f1764-7dfa-4abc-a2c6-81fbbf83e44b', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); 331 * var p1 = board.create('point', [3.5, 2.0]); 332 * </script><pre> 333 * @example 334 * // Create a constrained point using anonymous function 335 * var p2 = board.create('point', [3.5, function () { return p1.X(); }]); 336 * </pre><div id="4fd4410c-3383-4e80-b1bb-961f5eeef224" style="width: 200px; height: 200px;"></div> 337 * <script type="text/javascript"> 338 * var fpex1_board = JXG.JSXGraph.initBoard('4fd4410c-3383-4e80-b1bb-961f5eeef224', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); 339 * var fpex1_p1 = fpex1_board.create('point', [3.5, 2.0]); 340 * var fpex1_p2 = fpex1_board.create('point', [3.5, function () { return fpex1_p1.X(); }]); 341 * </script><pre> 342 * @example 343 * // Create a point using transformations 344 * var trans = board.create('transform', [2, 0.5], {type:'scale'}); 345 * var p3 = board.create('point', [p2, trans]); 346 * </pre><div id="630afdf3-0a64-46e0-8a44-f51bd197bb8d" style="width: 400px; height: 400px;"></div> 347 * <script type="text/javascript"> 348 * var fpex2_board = JXG.JSXGraph.initBoard('630afdf3-0a64-46e0-8a44-f51bd197bb8d', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 349 * var fpex2_trans = fpex2_board.create('transform', [2, 0.5], {type:'scale'}); 350 * var fpex2_p2 = fpex2_board.create('point', [3.5, 2.0]); 351 * var fpex2_p3 = fpex2_board.create('point', [fpex2_p2, fpex2_trans]); 352 * </script><pre> 353 */ 354 JXG.createPoint = function (board, parents, attributes) { 355 var el, attr; 356 357 attr = Type.copyAttributes(attributes, board.options, 'point'); 358 el = CoordsElement.create(JXG.Point, board, parents, attr); 359 if (!el) { 360 throw new Error("JSXGraph: Can't create point with parent types '" + 361 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 362 "\nPossible parent types: [x,y], [z,x,y], [element,transformation]"); 363 } 364 365 return el; 366 }; 367 368 /** 369 * @class This element is used to provide a constructor for a glider point. 370 * @pseudo 371 * @description A glider is a point which lives on another geometric element like a line, circle, curve, turtle. 372 * @name Glider 373 * @augments JXG.Point 374 * @constructor 375 * @type JXG.Point 376 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 377 * @param {Number_Number_Number_JXG.GeometryElement} z_,x_,y_,GlideObject Parent elements can be two or three elements of type number and the object the glider lives on. 378 * The coordinates are completely optional. If not given the origin is used. If you provide two numbers for coordinates they will be interpreted as affine euclidean 379 * coordinates, otherwise they will be interpreted as homogeneous coordinates. In any case the point will be projected on the glide object. 380 * @example 381 * // Create a glider with user defined coordinates. If the coordinates are not on 382 * // the circle (like in this case) the point will be projected onto the circle. 383 * var p1 = board.create('point', [2.0, 2.0]); 384 * var c1 = board.create('circle', [p1, 2.0]); 385 * var p2 = board.create('glider', [2.0, 1.5, c1]); 386 * </pre><div id="4f65f32f-e50a-4b50-9b7c-f6ec41652930" style="width: 300px; height: 300px;"></div> 387 * <script type="text/javascript"> 388 * var gpex1_board = JXG.JSXGraph.initBoard('4f65f32f-e50a-4b50-9b7c-f6ec41652930', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); 389 * var gpex1_p1 = gpex1_board.create('point', [2.0, 2.0]); 390 * var gpex1_c1 = gpex1_board.create('circle', [gpex1_p1, 2.0]); 391 * var gpex1_p2 = gpex1_board.create('glider', [2.0, 1.5, gpex1_c1]); 392 * </script><pre> 393 * @example 394 * // Create a glider with default coordinates (1,0,0). Same premises as above. 395 * var p1 = board.create('point', [2.0, 2.0]); 396 * var c1 = board.create('circle', [p1, 2.0]); 397 * var p2 = board.create('glider', [c1]); 398 * </pre><div id="4de7f181-631a-44b1-a12f-bc4d995609e8" style="width: 200px; height: 200px;"></div> 399 * <script type="text/javascript"> 400 * var gpex2_board = JXG.JSXGraph.initBoard('4de7f181-631a-44b1-a12f-bc4d995609e8', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); 401 * var gpex2_p1 = gpex2_board.create('point', [2.0, 2.0]); 402 * var gpex2_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]); 403 * var gpex2_p2 = gpex2_board.create('glider', [gpex2_c1]); 404 * </script><pre> 405 */ 406 JXG.createGlider = function (board, parents, attributes) { 407 var el, coords, 408 attr = Type.copyAttributes(attributes, board.options, 'glider'); 409 410 if (parents.length === 1) { 411 coords = [0, 0]; 412 } else { 413 coords = parents.slice(0, 2); 414 } 415 el = board.create('point', coords, attr); 416 417 // eltype is set in here 418 el.makeGlider(parents[parents.length - 1]); 419 420 return el; 421 }; 422 423 424 /** 425 * @class This element is used to provide a constructor for an intersection point. 426 * @pseudo 427 * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e. 428 * an intersection point of the two elements. 429 * @name Intersection 430 * @augments JXG.Point 431 * @constructor 432 * @type JXG.Point 433 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 434 * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2. i determines the 435 * intersection point if two points are available: <ul> 436 * <li>i==0: use the positive square root,</li> 437 * <li>i==1: use the negative square root.</li></ul> 438 * @example 439 * // Create an intersection point of circle and line 440 * var p1 = board.create('point', [2.0, 2.0]); 441 * var c1 = board.create('circle', [p1, 2.0]); 442 * 443 * var p2 = board.create('point', [2.0, 2.0]); 444 * var p3 = board.create('point', [2.0, 2.0]); 445 * var l1 = board.create('line', [p2, p3]); 446 * 447 * var i = board.create('intersection', [c1, l1, 0]); 448 * </pre><div id="e5b0e190-5200-4bc3-b995-b6cc53dc5dc0" style="width: 300px; height: 300px;"></div> 449 * <script type="text/javascript"> 450 * var ipex1_board = JXG.JSXGraph.initBoard('e5b0e190-5200-4bc3-b995-b6cc53dc5dc0', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); 451 * var ipex1_p1 = ipex1_board.create('point', [4.0, 4.0]); 452 * var ipex1_c1 = ipex1_board.create('circle', [ipex1_p1, 2.0]); 453 * var ipex1_p2 = ipex1_board.create('point', [1.0, 1.0]); 454 * var ipex1_p3 = ipex1_board.create('point', [5.0, 3.0]); 455 * var ipex1_l1 = ipex1_board.create('line', [ipex1_p2, ipex1_p3]); 456 * var ipex1_i = ipex1_board.create('intersection', [ipex1_c1, ipex1_l1, 0]); 457 * </script><pre> 458 */ 459 JXG.createIntersectionPoint = function (board, parents, attributes) { 460 var el, el1, el2, func, i, j, 461 attr = Type.copyAttributes(attributes, board.options, 'intersection'); 462 463 // make sure we definitely have the indices 464 parents.push(0, 0); 465 466 el1 = board.select(parents[0]); 467 el2 = board.select(parents[1]); 468 469 i = parents[2] || 0; 470 j = parents[3] || 0; 471 472 el = board.create('point', [0, 0, 0], attr); 473 474 func = Geometry.intersectionFunction(board, el1, el2, i, j, el.visProp.alwaysintersect); 475 el.addConstraint([func]); 476 477 try { 478 el1.addChild(el); 479 el2.addChild(el); 480 } catch (e) { 481 throw new Error("JSXGraph: Can't create 'intersection' with parent types '" + 482 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'."); 483 } 484 485 el.type = Const.OBJECT_TYPE_INTERSECTION; 486 el.elType = 'intersection'; 487 el.parents = [el1.id, el2.id, i, j]; 488 489 el.generatePolynomial = function () { 490 var poly1 = el1.generatePolynomial(el), 491 poly2 = el2.generatePolynomial(el); 492 493 if ((poly1.length === 0) || (poly2.length === 0)) { 494 return []; 495 } 496 497 return [poly1[0], poly2[0]]; 498 }; 499 500 return el; 501 }; 502 503 /** 504 * @class This element is used to provide a constructor for the "other" intersection point. 505 * @pseudo 506 * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e. 507 * an intersection point of the two elements. Additionally, one intersection point is provided. The function returns the other intersection point. 508 * @name OtherIntersection 509 * @augments JXG.Point 510 * @constructor 511 * @type JXG.Point 512 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 513 * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_JXG.Point} el1,el2,p The result will be a intersection point on el1 and el2. i determines the 514 * intersection point different from p: 515 * @example 516 * // Create an intersection point of circle and line 517 * var p1 = board.create('point', [2.0, 2.0]); 518 * var c1 = board.create('circle', [p1, 2.0]); 519 * 520 * var p2 = board.create('point', [2.0, 2.0]); 521 * var p3 = board.create('point', [2.0, 2.0]); 522 * var l1 = board.create('line', [p2, p3]); 523 * 524 * var i = board.create('intersection', [c1, l1, 0]); 525 * var j = board.create('otherintersection', [c1, l1, i]); 526 * </pre><div id="45e25f12-a1de-4257-a466-27a2ae73614c" style="width: 300px; height: 300px;"></div> 527 * <script type="text/javascript"> 528 * var ipex2_board = JXG.JSXGraph.initBoard('45e25f12-a1de-4257-a466-27a2ae73614c', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); 529 * var ipex2_p1 = ipex2_board.create('point', [4.0, 4.0]); 530 * var ipex2_c1 = ipex2_board.create('circle', [ipex2_p1, 2.0]); 531 * var ipex2_p2 = ipex2_board.create('point', [1.0, 1.0]); 532 * var ipex2_p3 = ipex2_board.create('point', [5.0, 3.0]); 533 * var ipex2_l1 = ipex2_board.create('line', [ipex2_p2, ipex2_p3]); 534 * var ipex2_i = ipex2_board.create('intersection', [ipex2_c1, ipex2_l1, 0], {name:'D'}); 535 * var ipex2_j = ipex2_board.create('otherintersection', [ipex2_c1, ipex2_l1, ipex2_i], {name:'E'}); 536 * </script><pre> 537 */ 538 JXG.createOtherIntersectionPoint = function (board, parents, attributes) { 539 var el, el1, el2, other; 540 541 if (parents.length !== 3 || 542 !Type.isPoint(parents[2]) || 543 (parents[0].elementClass !== Const.OBJECT_CLASS_LINE && parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE) || 544 (parents[1].elementClass !== Const.OBJECT_CLASS_LINE && parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE)) { 545 // Failure 546 throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '" + 547 (typeof parents[0]) + "', '" + (typeof parents[1]) + "'and '" + (typeof parents[2]) + "'." + 548 "\nPossible parent types: [circle|line,circle|line,point]"); 549 } 550 551 el1 = board.select(parents[0]); 552 el2 = board.select(parents[1]); 553 other = board.select(parents[2]); 554 555 el = board.create('point', [function () { 556 var c = Geometry.meet(el1.stdform, el2.stdform, 0, el1.board); 557 558 if (Math.abs(other.X() - c.usrCoords[1]) > Mat.eps || 559 Math.abs(other.Y() - c.usrCoords[2]) > Mat.eps || 560 Math.abs(other.Z() - c.usrCoords[0]) > Mat.eps) { 561 return c; 562 } 563 564 return Geometry.meet(el1.stdform, el2.stdform, 1, el1.board); 565 }], attributes); 566 567 el.type = Const.OBJECT_TYPE_INTERSECTION; 568 el.elType = 'otherintersection'; 569 el.parents = [el1.id, el2.id, other]; 570 571 el1.addChild(el); 572 el2.addChild(el); 573 574 el.generatePolynomial = function () { 575 var poly1 = el1.generatePolynomial(el), 576 poly2 = el2.generatePolynomial(el); 577 578 if ((poly1.length === 0) || (poly2.length === 0)) { 579 return []; 580 } 581 582 return [poly1[0], poly2[0]]; 583 }; 584 585 return el; 586 }; 587 588 /** 589 * @class This element is used to provide a constructor for the pole point of a line with respect to a conic or a circle. 590 * @pseudo 591 * @description The pole point is the unique reciprocal relationship of a line with respect to a conic. 592 * The lines tangent to the intersections of a conic and a line intersect at the pole point of that line with respect to that conic. 593 * A line tangent to a conic has the pole point of that line with respect to that conic as the tangent point. 594 * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar. 595 * @name PolePoint 596 * @augments JXG.Point 597 * @constructor 598 * @type JXG.Point 599 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 600 * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or 601 * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the pole point of the line with respect to the conic or the circle. 602 * @example 603 * // Create the pole point of a line with respect to a conic 604 * var p1 = board.create('point', [-1, 2]); 605 * var p2 = board.create('point', [ 1, 4]); 606 * var p3 = board.create('point', [-1,-2]); 607 * var p4 = board.create('point', [ 0, 0]); 608 * var p5 = board.create('point', [ 4,-2]); 609 * var c1 = board.create('conic',[p1,p2,p3,p4,p5]); 610 * var p6 = board.create('point', [-1, 4]); 611 * var p7 = board.create('point', [2, -2]); 612 * var l1 = board.create('line', [p6, p7]); 613 * var p8 = board.create('polepoint', [c1, l1]); 614 * </pre><div id='7b7233a0-f363-47dd-9df5-8018d0d17a98' class='jxgbox' style='width:400px; height:400px;'></div> 615 * <script type='text/javascript'> 616 * var ppex1_board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-8018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false}); 617 * var ppex1_p1 = ppex1_board.create('point', [-1, 2]); 618 * var ppex1_p2 = ppex1_board.create('point', [ 1, 4]); 619 * var ppex1_p3 = ppex1_board.create('point', [-1,-2]); 620 * var ppex1_p4 = ppex1_board.create('point', [ 0, 0]); 621 * var ppex1_p5 = ppex1_board.create('point', [ 4,-2]); 622 * var ppex1_c1 = ppex1_board.create('conic',[ppex1_p1,ppex1_p2,ppex1_p3,ppex1_p4,ppex1_p5]); 623 * var ppex1_p6 = ppex1_board.create('point', [-1, 4]); 624 * var ppex1_p7 = ppex1_board.create('point', [2, -2]); 625 * var ppex1_l1 = ppex1_board.create('line', [ppex1_p6, ppex1_p7]); 626 * var ppex1_p8 = ppex1_board.create('polepoint', [ppex1_c1, ppex1_l1]); 627 * </script><pre> 628 * @example 629 * // Create the pole point of a line with respect to a circle 630 * var p1 = board.create('point', [1, 1]); 631 * var p2 = board.create('point', [2, 3]); 632 * var c1 = board.create('circle',[p1,p2]); 633 * var p3 = board.create('point', [-1, 4]); 634 * var p4 = board.create('point', [4, -1]); 635 * var l1 = board.create('line', [p3, p4]); 636 * var p5 = board.create('polepoint', [c1, l1]); 637 * </pre><div id='7b7233a0-f363-47dd-9df5-9018d0d17a98' class='jxgbox' style='width:400px; height:400px;'></div> 638 * <script type='text/javascript'> 639 * var ppex2_board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-9018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false}); 640 * var ppex2_p1 = ppex2_board.create('point', [1, 1]); 641 * var ppex2_p2 = ppex2_board.create('point', [2, 3]); 642 * var ppex2_c1 = ppex2_board.create('circle',[ppex2_p1,ppex2_p2]); 643 * var ppex2_p3 = ppex2_board.create('point', [-1, 4]); 644 * var ppex2_p4 = ppex2_board.create('point', [4, -1]); 645 * var ppex2_l1 = ppex2_board.create('line', [ppex2_p3, ppex2_p4]); 646 * var ppex2_p5 = ppex2_board.create('polepoint', [ppex2_c1, ppex2_l1]); 647 * </script><pre> 648 */ 649 JXG.createPolePoint = function (board, parents, attributes) { 650 var el, el1, el2, 651 firstParentIsConic, secondParentIsConic, 652 firstParentIsLine, secondParentIsLine; 653 654 if (parents.length > 1) { 655 firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC || 656 parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE); 657 secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC || 658 parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE); 659 660 firstParentIsLine = (parents[0].elementClass === Const.OBJECT_CLASS_LINE); 661 secondParentIsLine = (parents[1].elementClass === Const.OBJECT_CLASS_LINE); 662 } 663 664 /* if (parents.length !== 2 || !(( 665 parents[0].type === Const.OBJECT_TYPE_CONIC || 666 parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) && 667 parents[1].elementClass === Const.OBJECT_CLASS_LINE || 668 parents[0].elementClass === Const.OBJECT_CLASS_LINE && ( 669 parents[1].type === Const.OBJECT_TYPE_CONIC || 670 parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE))) {*/ 671 if (parents.length !== 2 || 672 !((firstParentIsConic && secondParentIsLine) || 673 (firstParentIsLine && secondParentIsConic))) { 674 // Failure 675 throw new Error("JSXGraph: Can't create 'pole point' with parent types '" + 676 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 677 "\nPossible parent type: [conic|circle,line], [line,conic|circle]"); 678 } 679 680 if (secondParentIsLine) { 681 el1 = board.select(parents[0]); 682 el2 = board.select(parents[1]); 683 } else { 684 el1 = board.select(parents[1]); 685 el2 = board.select(parents[0]); 686 } 687 688 el = board.create('point', 689 [function () { 690 var q = el1.quadraticform, 691 s = el2.stdform.slice(0, 3); 692 693 return [JXG.Math.Numerics.det([s, q[1], q[2]]), 694 JXG.Math.Numerics.det([q[0], s, q[2]]), 695 JXG.Math.Numerics.det([q[0], q[1], s])]; 696 }], attributes); 697 698 el.elType = 'polepoint'; 699 el.parents = [el1.id, el2.id]; 700 701 el1.addChild(el); 702 el2.addChild(el); 703 704 return el; 705 }; 706 707 JXG.registerElement('point', JXG.createPoint); 708 JXG.registerElement('glider', JXG.createGlider); 709 JXG.registerElement('intersection', JXG.createIntersectionPoint); 710 JXG.registerElement('otherintersection', JXG.createOtherIntersectionPoint); 711 JXG.registerElement('polepoint', JXG.createPolePoint); 712 713 return { 714 Point: JXG.Point, 715 createPoint: JXG.createPoint, 716 createGlider: JXG.createGlider, 717 createIntersection: JXG.createIntersectionPoint, 718 createOtherIntersection: JXG.createOtherIntersectionPoint, 719 createPolePoint: JXG.createPolePoint 720 }; 721 }); 722