1 /* 2 Copyright 2008-2023 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 <https://www.gnu.org/licenses/> 29 and <https://opensource.org/licenses/MIT/>. 30 */ 31 32 /*global JXG: true, define: true*/ 33 /*jslint nomen: true, plusplus: true*/ 34 35 /** 36 * @fileoverview The JSXGraph object Turtle is defined. It acts like 37 * "turtle graphics". 38 * @author A.W. 39 */ 40 41 import JXG from "../jxg"; 42 import Const from "./constants"; 43 import Mat from "../math/math"; 44 import GeometryElement from "./element"; 45 import Type from "../utils/type"; 46 47 /** 48 * Constructs a new Turtle object. 49 * @class This is the Turtle class. 50 * It is derived from {@link JXG.GeometryElement}. 51 * It stores all properties required 52 * to move a turtle. 53 * @constructor 54 * @param {JXG.Board} board The board the new turtle is drawn on. 55 * @param {Array} parents Start position and start direction of the turtle. Possible values are 56 * [x, y, angle] 57 * [[x, y], angle] 58 * [x, y] 59 * [[x, y]] 60 * @param {Object} attributes Attributes to change the visual properties of the turtle object 61 * All angles are in degrees. 62 * 63 * @example 64 * 65 * //creates a figure 8 animation 66 * var board = JXG.JSXGraph.initBoard('jxgbox',{boundingbox: [-250, 250, 250, -250]}); 67 * var t = board.create('turtle',[0, 0], {strokeOpacity:0.5}); 68 * t.setPenSize(3); 69 * t.right(90); 70 * var alpha = 0; 71 * 72 * var run = function() { 73 * t.forward(2); 74 * if (Math.floor(alpha / 360) % 2 === 0) { 75 * t.left(1); // turn left by 1 degree 76 * } else { 77 * t.right(1); // turn right by 1 degree 78 * } 79 * alpha += 1; 80 * 81 * if (alpha < 1440) { // stop after two rounds 82 * setTimeout(run, 20); 83 * } 84 * } 85 * 86 *run(); 87 * 88 * </pre><div class="jxgbox" id="JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> 89 * <script type="text/javascript"> 90 * (function() { 91 * var brd = JXG.JSXGraph.initBoard('JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723', 92 * {boundingbox: [-250, 250, 250, -250], axis: true, showcopyright: false, shownavigation: false}); 93 * var t = brd.create('turtle',[0, 0], {strokeOpacity:0.5}); 94 * t.setPenSize(3); 95 * t.right(90); 96 * var alpha = 0; 97 * 98 * var run = function() { 99 * t.forward(2); 100 * if (Math.floor(alpha / 360) % 2 === 0) { 101 * t.left(1); // turn left by 1 degree 102 * } else { 103 * t.right(1); // turn right by 1 degree 104 * } 105 * alpha += 1; 106 * 107 * if (alpha < 1440) { // stop after two rounds 108 * setTimeout(run, 20); 109 * } 110 * } 111 * 112 * run(); 113 * 114 * })(); 115 * 116 * </script><pre> 117 */ 118 JXG.Turtle = function (board, parents, attributes) { 119 var x, y, dir; 120 121 this.constructor(board, attributes, Const.OBJECT_TYPE_TURTLE, Const.OBJECT_CLASS_OTHER); 122 123 this.turtleIsHidden = false; 124 this.board = board; 125 this.visProp.curveType = "plot"; 126 127 // Save visProp in this._attributes. 128 // this._attributes is overwritten by setPenSize, setPenColor... 129 // Setting the color or size affects the turtle from the time of 130 // calling the method, 131 // whereas Turtle.setAttribute affects all turtle curves. 132 this._attributes = Type.copyAttributes(this.visProp, board.options, "turtle"); 133 delete this._attributes.id; 134 135 x = 0; 136 y = 0; 137 dir = 90; 138 139 if (parents.length !== 0) { 140 // [x,y,dir] 141 if (parents.length === 3) { 142 // Only numbers are accepted at the moment 143 x = parents[0]; 144 y = parents[1]; 145 dir = parents[2]; 146 } else if (parents.length === 2) { 147 // [[x,y],dir] 148 if (Type.isArray(parents[0])) { 149 x = parents[0][0]; 150 y = parents[0][1]; 151 dir = parents[1]; 152 // [x,y] 153 } else { 154 x = parents[0]; 155 y = parents[1]; 156 } 157 // [[x,y]] 158 } else { 159 x = parents[0][0]; 160 y = parents[0][1]; 161 } 162 } 163 164 this.init(x, y, dir); 165 166 this.methodMap = Type.deepCopy(this.methodMap, { 167 forward: 'forward', 168 fd: 'forward', 169 back: 'back', 170 bk: 'back', 171 right: 'right', 172 rt: 'right', 173 left: 'left', 174 lt: 'left', 175 penUp: 'penUp', 176 pu: 'penUp', 177 penDown: 'penDown', 178 pd: 'penDown', 179 clearScreen: 'clearScreen', 180 cs: 'clearScreen', 181 clean: 'clean', 182 setPos: 'setPos', 183 home: 'home', 184 hideTurtle: 'hideTurtle', 185 ht: 'hideTurtle', 186 showTurtle: 'showTurtle', 187 st: 'showTurtle', 188 penSize: 'setPenSize', 189 penColor: 'setPenColor', 190 getPenColor: 'getPenColor', 191 getHighlightPenColor: 'getHighlightPenColor', 192 getPenSize: 'getPenSize', 193 pushTurtle: 'pushTurtle', 194 push: 'pushTurtle', 195 popTurtle: 'popTurtle', 196 pop: 'popTurtle', 197 lookTo: 'lookTo', 198 pos: 'pos', 199 moveTo: 'moveTo', 200 X: 'X', 201 Y: 'Y' 202 }); 203 204 return this; 205 }; 206 207 JXG.Turtle.prototype = new GeometryElement(); 208 209 JXG.extend( 210 JXG.Turtle.prototype, 211 /** @lends JXG.Turtle.prototype */ { 212 /** 213 * Initialize a new turtle or reinitialize a turtle after {@link JXG.Turtle#clearScreen}. 214 * @private 215 */ 216 init: function (x, y, dir) { 217 var hiddenPointAttr = { 218 fixed: true, 219 name: "", 220 visible: false, 221 withLabel: false 222 }; 223 224 this.arrowLen = 225 20 / Mat.hypot(this.board.unitX, this.board.unitY); 226 227 this.pos = [x, y]; 228 this.isPenDown = true; 229 this.dir = 90; 230 this.stack = []; 231 this.objects = []; 232 this.curve = this.board.create( 233 "curve", 234 [[this.pos[0]], [this.pos[1]]], 235 this._attributes 236 ); 237 this.objects.push(this.curve); 238 239 this.turtle = this.board.create("point", this.pos, hiddenPointAttr); 240 this.objects.push(this.turtle); 241 242 this.turtle2 = this.board.create( 243 "point", 244 [this.pos[0], this.pos[1] + this.arrowLen], 245 hiddenPointAttr 246 ); 247 this.objects.push(this.turtle2); 248 249 this.visProp.arrow.lastArrow = true; 250 this.visProp.arrow.straightFirst = false; 251 this.visProp.arrow.straightLast = false; 252 this.arrow = this.board.create( 253 "line", 254 [this.turtle, this.turtle2], 255 this.visProp.arrow 256 ); 257 this.objects.push(this.arrow); 258 259 this.subs = { 260 arrow: this.arrow 261 }; 262 this.inherits.push(this.arrow); 263 264 this.right(90 - dir); 265 this.board.update(); 266 }, 267 268 /** 269 * Move the turtle forward. 270 * @param {Number} len of forward move in user coordinates 271 * @returns {JXG.Turtle} pointer to the turtle object 272 */ 273 forward: function (len) { 274 if (len === 0) { 275 return this; 276 } 277 278 var t, 279 dx = len * Math.cos((this.dir * Math.PI) / 180), 280 dy = len * Math.sin((this.dir * Math.PI) / 180); 281 282 if (!this.turtleIsHidden) { 283 t = this.board.create("transform", [dx, dy], { type: "translate" }); 284 285 t.applyOnce(this.turtle); 286 t.applyOnce(this.turtle2); 287 } 288 289 if (this.isPenDown) { 290 // IE workaround 291 if (this.curve.dataX.length >= 8192) { 292 this.curve = this.board.create( 293 "curve", 294 [[this.pos[0]], [this.pos[1]]], 295 this._attributes 296 ); 297 this.objects.push(this.curve); 298 } 299 } 300 301 this.pos[0] += dx; 302 this.pos[1] += dy; 303 304 if (this.isPenDown) { 305 this.curve.dataX.push(this.pos[0]); 306 this.curve.dataY.push(this.pos[1]); 307 } 308 309 this.board.update(); 310 return this; 311 }, 312 313 /** 314 * Move the turtle backwards. 315 * @param {Number} len of backwards move in user coordinates 316 * @returns {JXG.Turtle} pointer to the turtle object 317 */ 318 back: function (len) { 319 return this.forward(-len); 320 }, 321 322 /** 323 * Rotate the turtle direction to the right 324 * @param {Number} angle of the rotation in degrees 325 * @returns {JXG.Turtle} pointer to the turtle object 326 */ 327 right: function (angle) { 328 this.dir -= angle; 329 this.dir %= 360; 330 331 if (!this.turtleIsHidden) { 332 var t = this.board.create( 333 "transform", 334 [(-angle * Math.PI) / 180, this.turtle], 335 { type: "rotate" } 336 ); 337 t.applyOnce(this.turtle2); 338 } 339 340 this.board.update(); 341 return this; 342 }, 343 344 /** 345 * Rotate the turtle direction to the right. 346 * @param {Number} angle of the rotation in degrees 347 * @returns {JXG.Turtle} pointer to the turtle object 348 */ 349 left: function (angle) { 350 return this.right(-angle); 351 }, 352 353 /** 354 * Pen up, stops visible drawing 355 * @returns {JXG.Turtle} pointer to the turtle object 356 */ 357 penUp: function () { 358 this.isPenDown = false; 359 return this; 360 }, 361 362 /** 363 * Pen down, continues visible drawing 364 * @returns {JXG.Turtle} pointer to the turtle object 365 */ 366 penDown: function () { 367 this.isPenDown = true; 368 this.curve = this.board.create( 369 "curve", 370 [[this.pos[0]], [this.pos[1]]], 371 this._attributes 372 ); 373 this.objects.push(this.curve); 374 375 return this; 376 }, 377 378 /** 379 * Removes the turtle curve from the board. The turtle stays in its position. 380 * @returns {JXG.Turtle} pointer to the turtle object 381 */ 382 clean: function () { 383 var i, el; 384 385 for (i = 0; i < this.objects.length; i++) { 386 el = this.objects[i]; 387 if (el.type === Const.OBJECT_TYPE_CURVE) { 388 this.board.removeObject(el); 389 this.objects.splice(i, 1); 390 } 391 } 392 393 this.curve = this.board.create( 394 "curve", 395 [[this.pos[0]], [this.pos[1]]], 396 this._attributes 397 ); 398 this.objects.push(this.curve); 399 this.board.update(); 400 401 return this; 402 }, 403 404 /** 405 * Removes the turtle completely and resets it to its initial position and direction. 406 * @returns {JXG.Turtle} pointer to the turtle object 407 */ 408 clearScreen: function () { 409 var i, 410 el, 411 len = this.objects.length; 412 413 for (i = 0; i < len; i++) { 414 el = this.objects[i]; 415 this.board.removeObject(el); 416 } 417 418 this.init(0, 0, 90); 419 return this; 420 }, 421 422 /** 423 * Moves the turtle without drawing to a new position 424 * @param {Number} x new x- coordinate 425 * @param {Number} y new y- coordinate 426 * @returns {JXG.Turtle} pointer to the turtle object 427 */ 428 setPos: function (x, y) { 429 var t; 430 431 if (Type.isArray(x)) { 432 this.pos = x; 433 } else { 434 this.pos = [x, y]; 435 } 436 437 if (!this.turtleIsHidden) { 438 this.turtle.setPositionDirectly(Const.COORDS_BY_USER, [x, y]); 439 this.turtle2.setPositionDirectly(Const.COORDS_BY_USER, [x, y + this.arrowLen]); 440 t = this.board.create( 441 "transform", 442 [(-(this.dir - 90) * Math.PI) / 180, this.turtle], 443 { type: "rotate" } 444 ); 445 t.applyOnce(this.turtle2); 446 } 447 448 this.curve = this.board.create( 449 "curve", 450 [[this.pos[0]], [this.pos[1]]], 451 this._attributes 452 ); 453 this.objects.push(this.curve); 454 this.board.update(); 455 456 return this; 457 }, 458 459 /** 460 * Sets the pen size. Equivalent to setAttribute({strokeWidth:size}) 461 * but affects only the future turtle. 462 * @param {Number} size 463 * @returns {JXG.Turtle} pointer to the turtle object 464 */ 465 setPenSize: function (size) { 466 //this.visProp.strokewidth = size; 467 this.curve = this.board.create( 468 "curve", 469 [[this.pos[0]], [this.pos[1]]], 470 this.copyAttr("strokeWidth", size) 471 ); 472 this.objects.push(this.curve); 473 return this; 474 }, 475 476 /** 477 * Sets the pen color. Equivalent to setAttribute({strokeColor:color}) 478 * but affects only the future turtle. 479 * @param {String} color 480 * @returns {JXG.Turtle} pointer to the turtle object 481 */ 482 setPenColor: function (color) { 483 this.curve = this.board.create( 484 "curve", 485 [[this.pos[0]], [this.pos[1]]], 486 this.copyAttr("strokeColor", color) 487 ); 488 this.objects.push(this.curve); 489 490 return this; 491 }, 492 493 /** 494 * Get attribute of the last turtle curve object. 495 * 496 * @param {String} key 497 * @returns attribute value 498 * @private 499 */ 500 getPenAttribute: function(key) { 501 var pos, le = this.objects.length; 502 if (le === 4) { 503 // No new turtle objects have been created 504 pos = 0; 505 } else { 506 pos = le - 1; 507 } 508 return Type.evaluate(this.objects[pos].visProp[key]); 509 }, 510 511 /** 512 * Get most recently set turtle size (in pixel). 513 * @returns Number Size of the last turtle segment in pixel. 514 */ 515 getPenSize: function() { 516 return this.getPenAttribute('strokewidth'); 517 }, 518 519 /** 520 * Get most recently set turtle color. 521 * @returns String RGB color value of the last turtle segment. 522 */ 523 getPenColor: function() { 524 return this.getPenAttribute('strokecolor'); 525 }, 526 527 /** 528 * Get most recently set turtle color. 529 * @returns String RGB highlight color value of the last turtle segment. 530 */ 531 getHighlightPenColor: function() { 532 return this.getPenAttribute('highlightstrokecolor'); 533 }, 534 535 /** 536 * Sets the highlight pen color. Equivalent to setAttribute({highlightStrokeColor:color}) 537 * but affects only the future turtle. 538 * @param {String} color 539 * @returns {JXG.Turtle} pointer to the turtle object 540 */ 541 setHighlightPenColor: function (color) { 542 //this.visProp.highlightstrokecolor = colStr; 543 this.curve = this.board.create( 544 "curve", 545 [[this.pos[0]], [this.pos[1]]], 546 this.copyAttr("highlightStrokeColor", color) 547 ); 548 this.objects.push(this.curve); 549 return this; 550 }, 551 552 /** 553 * Sets properties of the turtle, see also {@link JXG.GeometryElement#setAttribute}. 554 * Sets the property for all curves of the turtle in the past and in the future. 555 * @param {Object} attributes key:value pairs 556 * @returns {JXG.Turtle} pointer to the turtle object 557 */ 558 setAttribute: function (attributes) { 559 var i, 560 el, 561 tmp, 562 len = this.objects.length; 563 564 for (i = 0; i < len; i++) { 565 el = this.objects[i]; 566 if (el.type === Const.OBJECT_TYPE_CURVE) { 567 el.setAttribute(attributes); 568 } 569 } 570 571 // Set visProp of turtle 572 tmp = this.visProp.id; 573 this.visProp = Type.deepCopy(this.curve.visProp); 574 this.visProp.id = tmp; 575 this._attributes = Type.deepCopy(this.visProp); 576 delete this._attributes.id; 577 578 return this; 579 }, 580 581 /** 582 * Set a future attribute of the turtle. 583 * @private 584 * @param {String} key 585 * @param {Number|String} val 586 * @returns {Object} pointer to the attributes object 587 */ 588 copyAttr: function (key, val) { 589 this._attributes[key.toLowerCase()] = val; 590 return this._attributes; 591 }, 592 593 /** 594 * Sets the visibility of the turtle head to true, 595 * @returns {JXG.Turtle} pointer to the turtle object 596 */ 597 showTurtle: function () { 598 this.turtleIsHidden = false; 599 this.arrow.setAttribute({ visible: true }); 600 this.visProp.arrow.visible = false; 601 this.setPos(this.pos[0], this.pos[1]); 602 this.board.update(); 603 604 return this; 605 }, 606 607 /** 608 * Sets the visibility of the turtle head to false, 609 * @returns {JXG.Turtle} pointer to the turtle object 610 */ 611 hideTurtle: function () { 612 this.turtleIsHidden = true; 613 this.arrow.setAttribute({ visible: false }); 614 this.visProp.arrow.visible = false; 615 this.board.update(); 616 617 return this; 618 }, 619 620 /** 621 * Moves the turtle to position [0,0]. 622 * @returns {JXG.Turtle} pointer to the turtle object 623 */ 624 home: function () { 625 this.pos = [0, 0]; 626 this.setPos(this.pos[0], this.pos[1]); 627 628 return this; 629 }, 630 631 /** 632 * Pushes the position of the turtle on the stack. 633 * @returns {JXG.Turtle} pointer to the turtle object 634 */ 635 pushTurtle: function () { 636 this.stack.push([this.pos[0], this.pos[1], this.dir]); 637 638 return this; 639 }, 640 641 /** 642 * Gets the last position of the turtle on the stack, sets the turtle to this position and removes this 643 * position from the stack. 644 * @returns {JXG.Turtle} pointer to the turtle object 645 */ 646 popTurtle: function () { 647 var status = this.stack.pop(); 648 this.pos[0] = status[0]; 649 this.pos[1] = status[1]; 650 this.dir = status[2]; 651 this.setPos(this.pos[0], this.pos[1]); 652 653 return this; 654 }, 655 656 /** 657 * Rotates the turtle into a new direction. 658 * There are two possibilities: 659 * @param {Number|Array} target If a number is given, it is interpreted as the new direction to look to; If an array 660 * consisting of two Numbers is given targeted is used as a pair coordinates. 661 * @returns {JXG.Turtle} pointer to the turtle object 662 */ 663 lookTo: function (target) { 664 var ax, ay, bx, by, beta; 665 666 if (Type.isArray(target)) { 667 ax = this.pos[0]; 668 ay = this.pos[1]; 669 bx = target[0]; 670 by = target[1]; 671 672 // Rotate by the slope of the line [this.pos, target] 673 beta = Math.atan2(by - ay, bx - ax); 674 this.right(this.dir - (beta * 180) / Math.PI); 675 } else if (Type.isNumber(target)) { 676 this.right(this.dir - target); 677 } 678 return this; 679 }, 680 681 /** 682 * Moves the turtle to a given coordinate pair. 683 * The direction is not changed. 684 * @param {Array} target Coordinates of the point where the turtle looks to. 685 * @returns {JXG.Turtle} pointer to the turtle object 686 */ 687 moveTo: function (target) { 688 var dx, dy, t; 689 690 if (Type.isArray(target)) { 691 dx = target[0] - this.pos[0]; 692 dy = target[1] - this.pos[1]; 693 694 if (!this.turtleIsHidden) { 695 t = this.board.create("transform", [dx, dy], { type: "translate" }); 696 t.applyOnce(this.turtle); 697 t.applyOnce(this.turtle2); 698 } 699 700 if (this.isPenDown) { 701 // IE workaround 702 if (this.curve.dataX.length >= 8192) { 703 this.curve = this.board.create( 704 "curve", 705 [[this.pos[0]], [this.pos[1]]], 706 this._attributes 707 ); 708 this.objects.push(this.curve); 709 } 710 } 711 712 this.pos[0] = target[0]; 713 this.pos[1] = target[1]; 714 715 if (this.isPenDown) { 716 this.curve.dataX.push(this.pos[0]); 717 this.curve.dataY.push(this.pos[1]); 718 } 719 this.board.update(); 720 } 721 722 return this; 723 }, 724 725 /** 726 * Alias for {@link JXG.Turtle#forward} 727 */ 728 fd: function (len) { 729 return this.forward(len); 730 }, 731 /** 732 * Alias for {@link JXG.Turtle#back} 733 */ 734 bk: function (len) { 735 return this.back(len); 736 }, 737 /** 738 * Alias for {@link JXG.Turtle#left} 739 */ 740 lt: function (angle) { 741 return this.left(angle); 742 }, 743 /** 744 * Alias for {@link JXG.Turtle#right} 745 */ 746 rt: function (angle) { 747 return this.right(angle); 748 }, 749 /** 750 * Alias for {@link JXG.Turtle#penUp} 751 */ 752 pu: function () { 753 return this.penUp(); 754 }, 755 /** 756 * Alias for {@link JXG.Turtle#penDown} 757 */ 758 pd: function () { 759 return this.penDown(); 760 }, 761 /** 762 * Alias for {@link JXG.Turtle#hideTurtle} 763 */ 764 ht: function () { 765 return this.hideTurtle(); 766 }, 767 /** 768 * Alias for {@link JXG.Turtle#showTurtle} 769 */ 770 st: function () { 771 return this.showTurtle(); 772 }, 773 /** 774 * Alias for {@link JXG.Turtle#clearScreen} 775 */ 776 cs: function () { 777 return this.clearScreen(); 778 }, 779 /** 780 * Alias for {@link JXG.Turtle#pushTurtle} 781 */ 782 push: function () { 783 return this.pushTurtle(); 784 }, 785 /** 786 * Alias for {@link JXG.Turtle#popTurtle} 787 */ 788 pop: function () { 789 return this.popTurtle(); 790 }, 791 792 /** 793 * The "co"-coordinate of the turtle curve at position t is returned. 794 * 795 * @param {Number} t parameter 796 * @param {String} co. Either 'X' or 'Y'. 797 * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t 798 */ 799 evalAt: function (t, co) { 800 var i, 801 j, 802 el, 803 tc, 804 len = this.objects.length; 805 806 for (i = 0, j = 0; i < len; i++) { 807 el = this.objects[i]; 808 809 if (el.elementClass === Const.OBJECT_CLASS_CURVE) { 810 if (j <= t && t < j + el.numberPoints) { 811 tc = t - j; 812 return el[co](tc); 813 } 814 j += el.numberPoints; 815 } 816 } 817 818 return this[co](); 819 }, 820 821 /** 822 * if t is not supplied the x-coordinate of the turtle is returned. Otherwise 823 * the x-coordinate of the turtle curve at position t is returned. 824 * @param {Number} t parameter 825 * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t 826 */ 827 X: function (t) { 828 if (!Type.exists(t)) { 829 return this.pos[0]; 830 } 831 832 return this.evalAt(t, "X"); 833 }, 834 835 /** 836 * if t is not supplied the y-coordinate of the turtle is returned. Otherwise 837 * the y-coordinate of the turtle curve at position t is returned. 838 * @param {Number} t parameter 839 * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t 840 */ 841 Y: function (t) { 842 if (!Type.exists(t)) { 843 return this.pos[1]; 844 } 845 return this.evalAt(t, "Y"); 846 }, 847 848 /** 849 * @returns {Number} z-coordinate of the turtle position 850 */ 851 Z: function (t) { 852 return 1.0; 853 }, 854 855 /** 856 * Gives the lower bound of the parameter if the turtle is treated as parametric curve. 857 */ 858 minX: function () { 859 return 0; 860 }, 861 862 /** 863 * Gives the upper bound of the parameter if the turtle is treated as parametric curve. 864 * May be overwritten in @see generateTerm. 865 */ 866 maxX: function () { 867 var i, 868 el, 869 len = this.objects.length, 870 np = 0; 871 872 for (i = 0; i < len; i++) { 873 el = this.objects[i]; 874 if (el.elementClass === Const.OBJECT_CLASS_CURVE) { 875 np += this.objects[i].numberPoints; 876 } 877 } 878 return np; 879 }, 880 881 /** 882 * Checks whether (x,y) is near the curve. 883 * @param {Number} x Coordinate in x direction, screen coordinates. 884 * @param {Number} y Coordinate in y direction, screen coordinates. 885 * @returns {Boolean} True if (x,y) is near the curve, False otherwise. 886 */ 887 hasPoint: function (x, y) { 888 var i, el; 889 890 // run through all curves of this turtle 891 for (i = 0; i < this.objects.length; i++) { 892 el = this.objects[i]; 893 894 if (el.type === Const.OBJECT_TYPE_CURVE) { 895 if (el.hasPoint(x, y)) { 896 // So what??? All other curves have to be notified now (for highlighting) 897 return true; 898 // This has to be done, yet. 899 } 900 } 901 } 902 return false; 903 } 904 } 905 ); 906 907 /** 908 * @class This element is used to provide a constructor for a turtle. 909 * @pseudo 910 * @description Creates a new turtle 911 * @name Turtle 912 * @augments JXG.Turtle 913 * @constructor 914 * @type JXG.Turtle 915 * 916 * @param {JXG.Board} board The board the turtle is put on. 917 * @param {Array} parents 918 * @param {Object} attributes Object containing properties for the element such as stroke-color and visibility. See {@link JXG.GeometryElement#setAttribute} 919 * @returns {JXG.Turtle} Reference to the created turtle object. 920 */ 921 JXG.createTurtle = function (board, parents, attributes) { 922 var attr; 923 parents = parents || []; 924 925 attr = Type.copyAttributes(attributes, board.options, "turtle"); 926 return new JXG.Turtle(board, parents, attr); 927 }; 928 929 JXG.registerElement("turtle", JXG.createTurtle); 930 931 export default JXG.Turtle; 932 // export default { 933 // Turtle: JXG.Turtle, 934 // createTurtle: JXG.createTurtle 935 // }; 936