turtle-class.js

total 0
used 0
limit 0
/* title: Turtle Graphics Drawing categories: basic dragging files: head point pointlist stage mouse dragging stroke ../point_src/constrain-distance.js ../point_src/functions/range.js ../point_src/split.js ../point_src/relative-xy.js ../point_src/relative.js ../point_src/random.js --- > A great little turtle. In this version we clean up the journey and walk methods, ensuring the _turtle_ can walk a path until it meets the initial point. Using a few simple commands, it's possible to draw very complex shapes. */ addControl('steps', { field: 'range' , stage: this , min: 1 , max: 200 // , value: 1 , onchange(ev, unit) { /*slider changed. */ let sval = ev.currentTarget.value unit.value = sval stage.stepCount = Number(sval) } }) addButton('toe', { onclick(ev) { stage.turtle.toe(stage.stepCount) } }) addButton('cut', { onclick(ev) { stage.turtle.cut() } }) addButton('clear', { onclick(ev) { stage.turtle.lines = [] } }) addButton('walk', { onclick(ev) { stage.turtle.walk() } }) addButton('once', { onclick(ev) { stage.turtle.once() } }) addButton('journey', { onclick(ev) { stage.turtle.journey() } }) class Turtle extends Point { stepTick = 0 turtleSteps() { return this.steps } created() { this.lines = [ // (new PointList([20, 20], [3, 40])).cast() ] this.start_action(); } toe(prepare=true, liveLine=true) { if(prepare && !this.isDown) { // this.down_Action() this.start_action() } if(prepare && liveLine) { this.lines.push(this.line) } this.performStep(this.stepTick++, 1) } feet(count=this.steps.length, initPoint){ for (var i = 0; i < range(count).length; i++) { // range(count)[i] let line = (this.lines.length > 0)? this.lines[0]: this.line let home = line[0] if(line.length > 1 && line[0] && this.distanceTo(home) < 2) { this._flagStop = true this.printSize() return } this.performStep(this.stepTick++, 1) } } journey() { // A journey is a walk, with start and end steps. this.start_action(); this.walk() return this.cut() } once() { /* walk the journey once, no repeat*/ this.start_action(); let stepCount = this.steps.length for (var i = 0; i < range(stepCount).length; i++) { // range(count)[i] console.log('tick', i, this.stepTick) this.performStep(this.stepTick++, 1) } return this.cut() } walk(startPoint, i=0, pointLimit=300, stepLimit=3000) { if(startPoint == undefined) { startPoint = this.copy(); } this.performStep(this.stepTick++, 1) // let line = (this.lines.length > 0)? this.lines[0]: this.line let home = startPoint // line[0] // let line = (this.lines.length > 0)? this.lines[0]: this.line // let home = line[0] let _distance = home? this.distanceTo(home): undefined; if(i > 1 && home && _distance < 1) { console.log('Stop.') this.printSize() return } if(i > stepLimit) { console.warn('Runaway stop at', stepLimit, 'steps') this.printSize() return this.line } if(this.line && this.line.length > pointLimit) { console.warn('Runaway stop at', pointLimit, 'points') this.printSize() return this.line } return this.walk(startPoint, ++i, pointLimit, stepLimit) } cut(){ // let item = this let l = this.line this.lines.push(l) this.line = new PointList() return l } printSize(){ let line = (this.lines.length > 0)? this.lines[0]: this.line console.log(`size: ${this.lines.length}x${line.length}`) } performStep(tick, stepCount=1) { let items = this.turtleSteps() let item = items[Math.floor(tick % items.length)] range(stepCount).forEach(()=>{ this.performAction(item) }) } performAction(item) { let func = `${item[0]}_Action` let args = item.slice(1,) // console.log('Running Action', func, args) return this[func].apply(this, args) } forward_Action(distance) { let item = this item.relative.forward(item.radius * 2 * distance) this.line.push(this.copy()) } down_Action() { this.isDown = true /* pen down actuate drawing on step.*/ this.line = new PointList(this.copy()) } start_action(liveLine=false){ this.down_Action() this.line.push(this.copy()) if(liveLine) { this.lines.push(this.line) } } up_Action() { /* stash line */ // let item = this this.isDown = false this.lines.push(this.line) this.line = new PointList() } rotate_Action(v) { let item = this item.rotation += v } } class Trundle extends Turtle { /* A Trundle provides mildly cheaper commands, for turning and walking in a direction, by combing the steps into one rotation and forward. By default 90degree rotations ['forward', 10] , ['rotate', 90] , ['forward', 10] , ['rotate', -90] , ['forward', 1] after: ['forward', 10] , ['left', 10] , ['right', 1] */ left_Action(distance=1, relDel=90) { /* Rotate 90degree left and walk forward to distance. */ this.rotate_Action(relDel) this.forward_Action(distance) } right_Action(distance=1, relDel=90) { /* Rotate 90degree right and walk forward to distance. */ this.rotate_Action(relDel * -1) this.forward_Action(distance) } } class MainStage extends Stage { // canvas = document.getElementById('playspace'); canvas = 'playspace' steps() { return this.layout() } layout() { let items = [ ['forward', 10], ['rotate', 90], ['forward', 10], ['rotate', 90], ['forward', 10], ['rotate', 90], ['forward', 10], ] return items } layoutFour() { let items = [ // Assume the point is facing _left_, as 0degree. ['forward', 10], // Front wall. 10, -1, -10, 5, 3, -1, -3, 20, 20, 20, 9, -1, -15, -1, -4, 20, 15, 20, 5, -1, -7, -21, 10, 50, 8, 4, ] let clock = (...vs) => { return vs.map((v)=>{ if(v < 0) { return ['right', Math.abs(v)] } return ['left', v] }) } let clean = function() { let r = [] for (var i = 0; i < items.length; i++) { let v = items[i] if (v == undefined) { continue } if(typeof(v) == 'number') { r = r.concat(clock(v)) } else { r.push(v) } } return r } return clean(items) } layoutThree() { let clock = (...vs) => { return vs.map((v)=>{ return ['left', v] }) } let anti = (...vs) => { return vs.map((v)=>{ return ['right', v] }) } return [ // Assume the point is facing _left_, as 0degree. ['forward', 10] // Front wall. , ...clock(10) // right wall (B) , ...anti(1, 10) // doorway out, left side. // left (B) // , ...clock(5, 30, 5, 14) // front door // corridor right , ...clock(5) // , ['forward', 30] // Front wall. , ...clock(3) , ...anti(1, 3) , ...clock(20, 20, 20, 9) , ...anti(1, 15, 1, 4) , ...clock(20, 15, 20, 5) , ...anti(1, 7, 21) , ...clock(10, 50, 8, 4) // , ...clock(5, 14) // front door // corridor right // , ...anti(1, 14) // , ...clock(5) // , ...anti(1, 5) // , ...clock(10, 4) // , ...anti(4) // , ...clock(30, 14, 20) // , ...anti(1, 20) // , ...clock(30, 24) ] } layoutTwo() { let clock = (v=1) => ['left', v]; let anti = (v=1) => ['right', v]; return [ // Assume the point is facing _left_, as 0degree. ['forward', 10] // Front wall. , clock(10) // right wall (B) , anti(1) // doorway out, left side. , anti(10) // left (B) , clock(5) // front door , clock(30) // corridor right , clock(5) , clock(14) , anti(1) , anti(14) , clock(5) , anti(1) , anti(5) , clock(10) , clock(4) , anti(4) , clock(30) , clock(14) , clock(20) , anti(1) , anti(20) , clock(30) , clock(24) ] } layoutOne() { return [ ['forward', 10] , ['rotate', 90] , ['forward', 10] , ['rotate', -90] , ['forward', 1] , ['rotate', -90] , ['forward', 10] , ['rotate', 90] , ['forward', 5] , ['rotate', 90] , ['forward', 20] , ['rotate', 90] , ['forward',16] , ['rotate', 90] , ['forward', 20] ] } snowflake() { return [ ['forward', 10] , ['rotate', 45] , ['forward', .5] , ['rotate', 90] , ['forward', 10] , ['rotate', -90] , ['forward', .5] , ['rotate', -90] ] } mounted(){ this.line = new PointList() this.stepCount = this.steps().length this.turtle = new Trundle(200, 100); this.turtle.steps = this.steps() this.dragging.add(this.turtle) this.turtle.radius = 5 this.turtle.once() } draw(ctx){ this.clear(ctx) this.turtle.pen.indicator(ctx, 'red') // this.line.pen.line(ctx, {color: 'pink'}) this.turtle.lines.forEach(line=>{ line.draw.line(ctx, {color: '#333'}) ctx.fill() // line.pen.quadCurve(ctx, {color: 'red'}) // line.pen.indicators(ctx, {color: '#880000'}) line.pen.line(ctx, {color: 'red'}) }) } } stage = MainStage.go(/*{ loop: true }*/)
Run
Meta Data
title Turtle Graphics Drawing
imports ()
files ('head', 'point', 'pointlist', 'stage', 'mouse', 'dragging', 'stroke', '../point_src/constrain-distance.js', '../point_src/functions/range.js', '../point_src/split.js', '../point_src/relative-xy.js', '../point_src/relative.js', '../point_src/random.js')
unused_keys ()
unknown_keys ('categories',)
categories ['basic', 'dragging']
filepath_exists True
path turtle-class.js
filepath turtle-class.js
clean_files ('../point_src/core/head.js', '../point_src/pointpen.js', '../point_src/compass.js', '../point_src/center.js', '../point_src/point-content.js', '../point_src/pointdraw.js', '../point_src/relative-xy.js', '../point_src/pointcast.js', '../point_src/point.js', '../point_src/pointlistdraw.js', '../point_src/pointlistgradient.js', '../point_src/pointlistshape.js', '../point_src/pointlistgenerator.js', '../point_src/unpack.js', '../point_src/pointlist.js', '../point_src/pointlistpen.js', '../point_src/stage-hooks.js', '../point_src/stage-resize.js', '../point_src/functions/resolve.js', '../point_src/stage.js', '../point_src/events.js', '../point_src/automouse.js', '../point_src/functions/clamp.js', '../point_src/distances.js', '../point_src/protractor.js', '../point_src/text/beta.js', '../point_src/dragging.js', '../point_src/setunset.js', '../point_src/stroke.js', '../point_src/constrain-distance.js', '../point_src/functions/range.js', '../point_src/split.js', '../point_src/relative.js', '../point_src/random.js')
markdown {'html': "<blockquote>\n<p>A great little turtle.</p>\n</blockquote>\n<p>In this version we clean up the journey and walk methods, ensuring the <em>turtle</em>\ncan walk a path until it meets the initial point.</p>\n<p>Using a few simple commands, it's possible to draw very complex shapes.</p>", 'content': "title: Turtle Graphics Drawing\ncategories: basic\n dragging\nfiles:\n head\n point\n pointlist\n stage\n mouse\n dragging\n stroke\n ../point_src/constrain-distance.js\n ../point_src/functions/range.js\n ../point_src/split.js\n ../point_src/relative-xy.js\n ../point_src/relative.js\n ../point_src/random.js\n---\n\n> A great little turtle.\n\nIn this version we clean up the journey and walk methods, ensuring the _turtle_\ncan walk a path until it meets the initial point.\n\nUsing a few simple commands, it's possible to draw very complex shapes."}