let my={} function init(){let version='0.94' my.mode=getJSQueryVar('mode','bisect') if(my.mode=='seg')my.mode='line segment' my.lineTyps=['line','ray','line segment'] let canvasid='canvas'+my.mode my.dragging=false let w=540 let h=360 let s='' s+='
' s+='' if(my.lineTyps.indexOf(my.mode)!=-1){s+='
' for(let i=0;i' s+='
'} s+=''} s+='
' s+='' s+='
' s+='
' s+='' s+='' s+='
' s+=wrap({cls:'copyrt',pos:'abs',style:'left:5px; bottom:3px'},`© 2022 Rod Pierce v${version}`) s+='
' docInsert(s) my.can=new Can(canvasid,w,h,2) my.coords=new Coords(0,0,w,h,-2,-1.9,15,11,true) my.graph=new Graph(my.can.g,my.coords) my.dragNo=0 my.coordsQ=false my.shapes=[] switch(my.mode){case 'equi':break case 'bisect':break case 'reflect':break case 'pts':break default:setType()} makeShapes() let el=my.can.el el.addEventListener('mousedown',mouseDownListener,false) el.addEventListener('touchstart',ontouchstart,false) el.addEventListener('mousemove',domousemove,false) doType()} function reflect(){let g=my.can.g let ln=new Ln(my.shapes[0],my.shapes[1]) let wall=new Ln(my.shapes[2],my.shapes[3]) wall.setLen(1200) g.strokeStyle='hsla(0,100%,60%,1)' g.lineWidth=3 wall.draw(g) let iPt=ln.getIntersection(wall,false) console.log('iPt',iPt) let ln3=new Ln(my.shapes[0],iPt) g.strokeStyle='hsla(240,100%,75%,1)' g.lineWidth=2 ln3.draw(g) let ln4=ln.reflect(wall) ln4.setLen(1200,false) g.strokeStyle='hsla(240,100%,85%,1)' g.lineWidth=2 ln4.draw(g) return} function winnewSvg(){let s='' s+='' s+='' s+='' s+='' s+='' s+='' return s} function winNew(){if(my.mode=='line segment')my.mode='seg' window.open(toLoc('../appeb7b.html?folder=geometry&file=geom-line&p='+my.mode))} function toLoc(s){if(window.location.href.indexOf('localhost')>0)s='/mathsisfun'+s return s} function getType(){let typeStr='' if(my.lineTyps.indexOf(my.mode)!=-1){let buttons=document.getElementsByName('typ') for(let i=0;ihighestIndex){my.dragHoldX=pt.x-my.shapes[i].x my.dragHoldY=pt.y-my.shapes[i].y highestIndex=i my.dragNo=i}}} if(my.dragging){if(ev.touchQ){window.addEventListener('touchmove',ontouchmove,false)}else{window.addEventListener('mousemove',mouseMoveListener,false)} doType()} let el=my.can.el if(ev.touchQ){el.removeEventListener('touchstart',ontouchstart,false) window.addEventListener('touchend',ontouchend,false)}else{el.removeEventListener('mousedown',mouseDownListener,false) window.addEventListener('mouseup',mouseUpListener,false)} if(ev.preventDefault){ev.preventDefault()} else if(ev.returnValue){ev.returnValue=false} return false} function mouseUpListener(){let el=my.can.el el.addEventListener('mousedown',mouseDownListener,false) window.removeEventListener('mouseup',mouseUpListener,false) if(my.dragging){my.dragging=false window.removeEventListener('mousemove',mouseMoveListener,false)}} function mouseMoveListener(ev){let posX let posY let el=my.can.el let shapeRad=my.shapes[my.dragNo].rad let minX=shapeRad let maxX=el.width-shapeRad let minY=shapeRad let maxY=el.height-shapeRad let pt=my.can.mousePos(ev) posX=pt.x-my.dragHoldX posX=posXmaxX?maxX:posX posY=pt.y-my.dragHoldY posY=posYmaxY?maxY:posY my.shapes[my.dragNo].x=posX my.shapes[my.dragNo].y=posY doType()} function hitTest(shape,mx,my){let dx let dy dx=mx-shape.x dy=my-shape.y return dx*dx+dy*dymaxDist){maxDist=d maxPtNo=i}} ln=new Ln(drag,my.shapes[maxPtNo]) for(i=0;imaxNo){currNo=minNo+((currNo-minNo)%range)} return currNo} function constrain(min,val,max){return Math.min(Math.max(min,val),max)} function Coords(left,top,width,height,xStt,yStt,xEnd,yEnd,uniScaleQ){this.left=left this.top=top this.width=width this.height=height this.xStt=xStt this.yStt=yStt this.xEnd=xEnd this.yEnd=yEnd this.uniScaleQ=uniScaleQ this.xLogQ=false this.yLogQ=false this.skewQ=false this.xScale this.xLogScale this.yScale this.calcScale()} Coords.prototype.calcScale=function(){if(this.xLogQ){if(this.xStt<=0)this.xStt=1 if(this.xEnd<=0)this.xEnd=1} if(this.yLogQ){if(this.yStt<=0)this.yStt=1 if(this.yEnd<=0)this.yEnd=1} let temp if(this.xStt>this.xEnd){temp=this.xStt this.xStt=this.xEnd this.xEnd=temp} if(this.yStt>this.yEnd){temp=this.yStt this.yStt=this.yEnd this.yEnd=temp} let xSpan=this.xEnd-this.xStt if(xSpan<=0)xSpan=0.1 this.xScale=xSpan/this.width this.xLogScale=(Math.log(this.xEnd)-Math.log(this.xStt))/this.width let ySpan=this.yEnd-this.yStt if(ySpan<=0)ySpan=0.1 this.yScale=ySpan/this.height this.yLogScale=(Math.log(this.yEnd)-Math.log(this.yStt))/this.height if(this.uniScaleQ&&!this.xLogQ&&!this.yLogQ){let newScale=Math.max(this.xScale,this.yScale) this.xScale=newScale xSpan=this.xScale*this.width let xMid=(this.xStt+this.xEnd)/2 this.xStt=xMid-xSpan/2 this.xEnd=xMid+xSpan/2 this.yScale=newScale ySpan=this.yScale*this.height let yMid=(this.yStt+this.yEnd)/2 this.yStt=yMid-ySpan/2 this.yEnd=yMid+ySpan/2}} Coords.prototype.getXScale=function(){return this.xScale} Coords.prototype.getYScale=function(){return this.yScale} Coords.prototype.toXPix=function(val){if(this.xLogQ){return this.left+(Math.log(val)-Math.log(this.xStt))/this.xLogScale}else{return this.left+(val-this.xStt)/this.xScale}} Coords.prototype.toYPix=function(val){if(this.yLogQ){return this.top+(Math.log(this.yEnd)-Math.log(val))/this.yLogScale}else{return this.top+(this.yEnd-val)/this.yScale}} Coords.prototype.toPtVal=function(pt,useCornerQ){return new Pt(this.toXVal(pt.x,useCornerQ),this.toYVal(pt.y,useCornerQ))} Coords.prototype.toXVal=function(pix,useCornerQ){if(useCornerQ){return this.xStt+(pix-this.left)*this.xScale}else{return this.xStt+pix*this.xScale}} Coords.prototype.toYVal=function(pix,useCornerQ){if(useCornerQ){return this.yEnd-(pix-this.top)*this.yScale}else{return this.yEnd-pix*this.yScale}} Coords.prototype.getTicks=function(stt,span){let ticks=[] let inter=this.tickInterval(span/5,false) let tickStt=Math.ceil(stt/inter)*inter let i=0 let tick do{tick=i*inter tick=Number(tick.toPrecision(5)) ticks.push([tickStt+tick,1]) i++}while(tick=5){if(majorQ){return 5*pow10}else{return 2*pow10}} if(mantissa>=2){if(majorQ){return 2*pow10}else{return 1*pow10}} if(mantissa>=1){if(majorQ){return 1*pow10}else{return 0.2*pow10}} if(majorQ){return 1*pow10}else{return 0.2*pow10}} Coords.prototype.xTickInterval=function(tickDensity,majorQ){return this.tickInterval((this.xEnd-this.xStt)/tickDensity,majorQ)} Coords.prototype.yTickInterval=function(tickDensity,majorQ){return this.tickInterval((this.yEnd-this.yStt)/tickDensity,majorQ)} function Graph(g,coords){this.g=g this.coords=coords this.xLinesQ=true this.yLinesQ=true this.xValsQ=true this.yValsQ=true this.skewQ=false} Graph.prototype.drawGraph=function(){this.hzAxisY=this.coords.toYPix(0) if(this.hzAxisY<0)this.hzAxisY=0 if(this.hzAxisY>this.coords.height)this.hzAxisY=this.coords.height this.hzNumsY=this.hzAxisY+14 if(this.hzAxisY>this.coords.height-10)this.hzNumsY=this.coords.height-3 this.vtAxisX=this.coords.toXPix(0) if(this.vtAxisX<0)this.vtAxisX=0 if(this.vtAxisX>this.coords.width)this.vtAxisX=this.coords.width this.vtNumsX=this.vtAxisX-5 if(this.vtAxisX<10)this.vtNumsX=20 if(this.coords.xLogQ){this.drawLinesLogX()}else{if(this.xLinesQ){this.drawHzLines()}} if(this.coords.yLogQ){this.drawLinesLogY()}else{if(this.yLinesQ){this.drawVtLines()}}} Graph.prototype.drawVtLines=function(){let g=this.g g.lineWidth=1 let ticks=this.coords.getTicks(this.coords.xStt,this.coords.xEnd-this.coords.xStt) for(let i=0;ir1.lt+r1.wd)return false if(r2.lt+r2.wdr1.tp+r1.ht)return false if(r2.tp+r2.htMath.pow(aPt.x-bPt.x,2)+Math.pow(aPt.y-bPt.y,2))return null if(Math.pow(ip.x-aPt.x,2)+Math.pow(ip.y-aPt.y,2)>Math.pow(aPt.x-bPt.x,2)+Math.pow(aPt.y-bPt.y,2))return null if(Math.pow(ip.x-fPt.x,2)+Math.pow(ip.y-fPt.y,2)>Math.pow(ePt.x-fPt.x,2)+Math.pow(ePt.y-fPt.y,2))return null if(Math.pow(ip.x-ePt.x,2)+Math.pow(ip.y-ePt.y,2)>Math.pow(ePt.x-fPt.x,2)+Math.pow(ePt.y-fPt.y,2))return null} return ip} line_intersect(x1,y1,x2,y2,x3,y3,x4,y4){var ua,ub,denom=(y4-y3)*(x2-x1)-(x4-x3)*(y2-y1) if(denom==0){return null} ua=((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/denom ub=((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/denom return{x:x1+ua*(x2-x1),y:y1+ua*(y2-y1),seg1:ua>=0&&ua<=1,seg2:ub>=0&&ub<=1,}} getAngle(){return Math.atan2(this.b.y-this.a.y,this.b.x-this.a.x)} isPerp(vsLine,toler){if(true){let degDiff=this.getAngle()-vsLine.getAngle() degDiff=Math.abs(degDiff) if(degDiff>Math.PI)degDiff-=Math.PI if(isNear(degDiff,Math.PI/2,toler)){return true} return false}else{}}} function fmt(num,digits){digits=14 if(num==Number.POSITIVE_INFINITY)return 'undefined' if(num==Number.NEGATIVE_INFINITY)return 'undefined' num=num.toPrecision(digits) num=num.replace(/0+$/,'') if(num.charAt(num.length-1)=='.')num=num.substr(0,num.length-1) if(Math.abs(num)<1e-15)num=0 return num} function isNear(checkVal,centralVal,limitVal){if(checkValcentralVal+limitVal)return false return true} CanvasRenderingContext2D.prototype.drawArrow=function(x0,y0,totLen,shaftHt,headLen,headHt,angle,sweep,invertQ){let g=this let pts=[[0,0],[-headLen,-headHt/2],[-headLen+sweep,-shaftHt/2],[-totLen,-shaftHt/2],[-totLen,shaftHt/2],[-headLen+sweep,shaftHt/2],[-headLen,headHt/2],[0,0],] if(invertQ){pts.push([0,-headHt/2],[-totLen,-headHt/2],[-totLen,headHt/2],[0,headHt/2])} for(let i=0;i0?' onclick="'+fn+'" ':''),cls:'btn',fin:'>'+txt+''},can:{stt:''},div:{stt:'
0?' onclick="'+fn+'" ':''),cls:'',fin:' >'+txt+'
'},edit:{stt:''},inp:{stt:'0?' oninput="'+fn+'" onchange="'+fn+'"':''),cls:'input',fin:'>'+(lbl.length>0?'':'')},out:{stt:''+txt+''+(lbl.length>0?'':'')},radio:{stt:'
\n'},sel:{stt:'0?'':'0')},} let type=tags[tag] if(lbl.length>0)s+='
'} if(tag=='sel'){for(let i=0;i'+opt.descr+'\n'} s+='' if(lbl.length>0)s+=''} s+='\n' return s.trim()} init()