def O (0,0,0) def I [1,0,0] def J [0,1,0] def K [0,0,1] def cornerRad 0.1 def tireRad 0.5 def wheelWidth .4 def nArcSegs 3 def nTireSegs 20 def nAxleSegs 6 def axleRad .05 def robotWidth 1.5 def robotLength 2.5 def bodyWidth .5 def bodyHeight .4 def steeringGamma .2 def leftSteeringAngle atan2(2 * robotLength * steeringGamma, 2 - robotWidth * steeringGamma) def rightSteeringAngle atan2(2 * robotLength * steeringGamma, 2 + robotWidth * steeringGamma) def wheelRad tireRad - cornerRad def wheelXofs wheelWidth/2 - cornerRad def rightArc put { translate([ wheelXofs, wheelRad, 0]) } sweep { nArcSegs, rotate(90 / nArcSegs) } (cornerRad,0) def leftArc put { translate([-wheelXofs, wheelRad, 0]) } sweep { nArcSegs, rotate(90 / nArcSegs) } (0,cornerRad) def tread line(wheelXofs, tireRad)(-wheelXofs, tireRad) def hubPlate sweep[fillcolor=lightgray] { nTireSegs<>, rotate(-360 / nTireSegs, (O), [I]) } (0,wheelRad) def tire sweep[fillcolor=lightgray]{ nTireSegs, rotate(360 / nTireSegs, (O), -[I]) } { {leftArc} {rightArc} {tread} } def wheel { def leftHubPlate put { translate( [-wheelWidth/2, 0, 0] ) } {hubPlate} def rightHubPlate put { rotate(180, (O), [K]) } {leftHubPlate} {rightHubPlate} {leftHubPlate} {tire} } def axle sweep[fillcolor=darkgray]{ nAxleSegs, rotate(360 / nAxleSegs, (O), -[I]) } line (robotWidth/2, axleRad)(-robotWidth/2, axleRad) def leftSteerableWheel put { rotate(leftSteeringAngle, (O), [J]) then translate( [-robotWidth/2, 0, 0] ) } {wheel} def rightSteerableWheel put { rotate(rightSteeringAngle, (O), [J]) then translate( [robotWidth/2, 0, 0] ) } {wheel} def steerableAxleAssembly { {leftSteerableWheel} {rightSteerableWheel} {axle} } def fixedAxleAssembly { put { translate( [-robotWidth/2, 0, 0] ) } {wheel} put { translate( [ robotWidth/2, 0, 0] ) } {wheel} {axle} } def bodyopts [fillcolor=white] def bodyCorner # first octant "rounded corner" sweep [bodyopts]{ nArcSegs, rotate(90 / nArcSegs, (O), [I]) } sweep { nArcSegs, rotate(90 / nArcSegs, (O),-[K]) } (0,cornerRad) def zBodyEdge sweep [bodyopts] { 1, translate([K]) } sweep { nArcSegs, rotate(90 / nArcSegs, (O), -[K]) } (0,cornerRad,0) def xBodyEdge # positive y-z quadrant about x axis quarter-pipe of unit length sweep [bodyopts] { 1, translate([I]) } sweep { nArcSegs, rotate(90 / nArcSegs, (O), -[I]) } (0,0,cornerRad) def body { def xOfs bodyWidth/2 - cornerRad def yOfs bodyHeight/2 - cornerRad def zOfs robotLength/2 + cornerRad def posZend { # 4 corners put { translate([ xOfs, yOfs, zOfs]) } {bodyCorner} put { rotate(90, (O), [K]) then translate([-xOfs, yOfs, zOfs]) } {bodyCorner} put { rotate(180, (O), [K]) then translate([-xOfs, -yOfs, zOfs]) } {bodyCorner} put { rotate(270, (O), [K]) then translate([ xOfs, -yOfs, zOfs]) } {bodyCorner} # 4 edges put { scale([2*xOfs, 1, 1]) then translate([-xOfs, yOfs, zOfs]) } {xBodyEdge} put { scale([2*yOfs, 1, 1]) then rotate(90, (O), [K]) then translate([-xOfs,-yOfs, zOfs]) } {xBodyEdge} put { scale([2*xOfs, 1, 1]) then rotate(180, (O), [K]) then translate([ xOfs,-yOfs, zOfs]) } {xBodyEdge} put { scale([2*yOfs, 1, 1]) then rotate(270, (O), [K]) then translate([ xOfs, yOfs, zOfs]) } {xBodyEdge} def z zOfs + cornerRad polygon[bodyopts](xOfs,yOfs,z)(-xOfs,yOfs,z)(-xOfs,-yOfs,z)(xOfs,-yOfs,z) } def top { put { scale([1,1,2*zOfs]) then translate([xOfs, yOfs, -zOfs]) } {zBodyEdge} put { scale([1,1,2*zOfs]) then rotate(90) then translate([-xOfs, yOfs, -zOfs]) } {zBodyEdge} def y bodyHeight/2 polygon[bodyopts](xOfs,y,zOfs)(xOfs,y,-zOfs)(-xOfs,y,-zOfs)(-xOfs,y,zOfs) } def posXside { def x bodyWidth/2 polygon[bodyopts](x,yOfs,zOfs)(x,-yOfs,zOfs)(x,-yOfs,-zOfs)(x,yOfs,-zOfs) } # ends of the body {posZend} put { rotate(180, (O), [I]) } {posZend} {top} {posXside} # bottom and negative X side put { rotate(180) } { {top} {posXside} } } def robot { {fixedAxleAssembly} put { translate([0, 0, -robotLength]) } {steerableAxleAssembly} put { translate([0, 0, -robotLength/2]) } {body} } def centerXform translate(robotLength/2 * [K]) then rotate(90, (O), [J]) def winWidth 0.6 1.5 <> 1 def foreshorteningFactor .3 30 <> 1 # base def pai 8 def panAngle -pai -pai -pai pai 0 -pai pai pai pai <> 0 def panAxis [-1,-1,0] [-1,0,0] [-1,1,0] [0,1,0] [0,1,0] [0,1,0] [-1,1,0] [-1,0,0] [-1,-1,0] <> [0,1,0] def eyeAxis [10,7,10] def eyeI (O) + .5 * foreshorteningFactor * [eyeAxis] def dvI (O) - (eyeI) def upRot -20 20 <> 0 def up [0,1,0] then rotate(upRot, (O), -[eyeAxis]) def viewXformI view ((eyeI), [dvI], [up]) then rotate(-panAngle, (O), [panAxis]) then perspective(|[dvI]|) then scale(1.5/winWidth) then scale([1,1,1000]) <> view ((eyeI), [dvI], [up]) then rotate(-panAngle, (O), [panAxis]) then perspective(|[dvI]|) then scale(1.5/winWidth) def dashframe { line[linestyle=dashed](-1,-1, 1)( 1,-1, 1)(1,1, 1)(-1,1, 1)(-1,-1, 1) line[linestyle=dashed](-1,-1,-1)( 1,-1,-1)(1,1,-1)(-1,1,-1)(-1,-1,-1) line[linestyle=dashed](-1,-1, 1)(-1,-1,-1) line[linestyle=dashed]( 1,-1, 1)( 1,-1,-1) line[linestyle=dashed]( 1, 1, 1)( 1, 1,-1) line[linestyle=dashed](-1, 1, 1)(-1, 1,-1) } def floor_grid { def opts [linewidth=.2pt] def nX 7 def nZ 5 def dx (robotLength+tireRad*2) + 2 def dz (robotWidth+wheelWidth) + 2 def y -tireRad-.001 repeat { nX+1, translate([dx/nX,0,0]) } line[opts](-dx/2,y,-dz/2)(-dx/2,y,dz/2) repeat { nZ+1, translate([0,0,dz/nZ]) } line[opts](-dx/2,y,-dz/2)(dx/2,y,-dz/2) } put { [[viewXformI]] } { put { [[centerXform]] } {robot} {floor_grid} # put { scale([(robotLength+tireRad*2)/2, tireRad, (robotWidth+wheelWidth)/2]) } {dashframe} } #def frameOfs 2 #put { [[viewXformI]] then translate(-frameOfs * [I]) } {robot} #put { [[viewXformI]] then translate(frameOfs * [I]) } {robot} #put { [[simpleViewXform]] then translate(2*frameOfs * [I]) } {robot} global { set [linewidth=.3pt] % set up a bounding box def w 3 def ar 3/2.2 def cbp1 (-w,-w/ar,0) def cbp2 (w,w/ar,0) picturebox [.5] (cbp1)(cbp2) frame }