From a5a1455737c948ee7edbae8f2afe55be0f8ea764 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 14 Jun 2013 07:24:12 -0400 Subject: [PATCH] figures/asy/Mechanics.asy: Add the mechanics library from my course project For drawing a Peltier. --- src/figures/asy/Mechanics-test.asy | 165 ++++++++ src/figures/asy/Mechanics.asy | 633 +++++++++++++++++++++++++++++ 2 files changed, 798 insertions(+) create mode 100644 src/figures/asy/Mechanics-test.asy create mode 100644 src/figures/asy/Mechanics.asy diff --git a/src/figures/asy/Mechanics-test.asy b/src/figures/asy/Mechanics-test.asy new file mode 100644 index 0000000..dcffda7 --- /dev/null +++ b/src/figures/asy/Mechanics-test.asy @@ -0,0 +1,165 @@ +/* Test suite for Mechanics.asy. + * + * Copyright (C) 2008-2009 W. Trevor King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +import three; +import Mechanics; + +currentprojection = TopView; + +real u = 1cm; + +LabeledCircle lc = LabeledCircle(center=(-2u, 1u)); +lc.draw(); +lc.label = "a"; +lc.center = (-2u, 0.5u); +lc.draw(); +lc.draw_label(Label("e", align=E)); +lc.center = (-2u, 0); +lc.label.align = W; +lc.draw(); +lc.draw_label("b"); +lc.draw_label(Label("c", align=E)); +lc.draw_label(rotate(90)*Label("e------I", align=S)); +lc.draw_label(rotate(45)*Label("e------I", align=S)); +lc.center = (-2u, -2u); +lc.radius = u/2; +lc.label.align = E; +lc.draw(); +lc.center = (-2u, -3u); +lc.label.align = E; +lc.draw(); + +Mass a = Mass(center=(0,0)); +Mass b = Mass(center=(2u,1u), Label("$m_b$", align=N)); +Mass c = Mass(center=(1u,-2u), Label("$m_c$", align=E)); +Mass ms[] = {a, b, c}; +Distance dab = Distance(a.center(), b.center(), scale=u, + L=Label("$r_{ab}$", align=N, embed=Shift)); +Distance dac = Distance(a.center(), c.center(), scale=u, + L=Label("$r_{ac}$", align=RightSide)); +Distance ds[] = {dab, dac}; +Angle bac1 = Angle( + b.center(), a.center(), c.center(), radius=.7u, fill=red, L="$\theta_T'$"); +Angle bac2 = Angle( + b.center(), a.center(), c.center(), radius=-.5u, L="$\theta_T$"); +Angle bac3 = Angle( + b.center(), a.center(), c.center(), radius=1.5u, + L=Label("$\theta_T''$", position=Relative(0.3))); +Angle as[] = {bac1, bac2, bac3}; + +Vector vs[]; + +draw_ijhat((-u, u)); + +vs.push(Vector(center=(-1u,-4u), phi=90, "Out")); +vs.push(Vector(center=(-1u,-5.5u), phi=-90, "In")); +vs.push(Vector(center=(0, -4u), mag=1.5u, dir=-90, phi=60, + Label("60dg OOP", position=EndPoint))); + +for (int i=0; i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +import geometry; +import three; + +// ----------------- Labeled circle -------------------- + +void label_path(picture pic=currentpicture, Label L, path g, real margin=0, + pair rdir=0) { + align a = L.align; + embed e = L.embed; + real m = labelmargin(L.p); + real scale = (m + margin)/m; + if (L.align.is3D) { + L.align.dir3 *= scale; + } else { + L.align.dir *= scale; + } + if (L.embed == Rotate) { + L.embed = Rotate(rdir); + } + label(pic=pic, L=L, g=g); + L.align = a; + L.embed = e; +} + +void label_path(picture pic=currentpicture, Label L, path3 g, real margin=0, + pair rdir=0) { + align a = L.align; + embed e = L.embed; + real m = labelmargin(L.p); + real scale = (m + margin)/m; + if (L.align.is3D) { + L.align.dir3 *= scale; + } else { + L.align.dir *= scale; + } + if (L.embed == Rotate) { + L.embed = Rotate(rdir); + } + label(pic=pic, L=L, g=g); + L.align = a; + L.embed = e; +} + +struct LabeledCircle { + pair center; + real radius; + pen outline; + pen fill; + Label label; + + void operator init(pair center=(0,0), real radius=2mm, + pen outline=currentpen, pen fill=grey, Label L="") { + this.center = center; + this.radius = radius; + this.outline = outline; + this.fill = fill; + this.label = L; + } + + void draw_label(picture pic=currentpicture, Label L=null) { + align a; + if (L == null) { + L = this.label; + } + a = L.align; + if (L.align != NoAlign && L.align != Align) { + real m = labelmargin(L.p); + real scale = (m + this.radius)/m; + if (L.align.is3D) { + L.align.dir3 *= scale; + } else { + L.align.dir *= scale; + } + } + label(pic=pic, L=L, position=this.center); + L.align = a; + } + + void draw(picture pic=currentpicture) { + path p = shift(this.center)*scale(this.radius)*unitcircle; + filldraw(pic, p, this.fill, this.outline); + this.draw_label(pic=pic); + } +} + +// ---------------------- Mass ------------------------- + +struct Mass { + LabeledCircle lc; + real m; + + void operator init(pair center=(0,0), real m=1, real radius=2mm, + pen outline=currentpen, pen fill=grey, Label L="") { + this.lc.operator init(center=center, radius=radius, outline=outline, + fill=fill, L=L); + this.m = m; + } + + pair center() { return this.lc.center; } + void set_center(pair center) { this.lc.center = center; } + void draw(picture pic=currentpicture) = this.lc.draw; +} + +struct Block { + pair center; + real m; + real width; + real height; + real direction; + pen outline; + pen fill; + Label L; + + void operator init(pair center=(0,0), real m=1, real width=5mm, real height=-1, real direction=0, pen outline=currentpen, pen fill=grey, Label L="") { + this.center = center; + this.m = m; + this.width = width; + if (height == -1) + this.height = width; + else + this.height = height; + this.direction = direction; + this.outline = outline; + this.fill = fill; + this.L = L; + } + + void draw(picture pic=currentpicture) { + picture picF; + path c = rotate(direction)*scale(width,height)*shift(-.5,-.5)*unitsquare; + filldraw(picF, c, fill, outline); + label(pic=picF, L=L, position=(0,0)); + add(pic, picF, center); + } +} + +// ---------------------- Vectors ------------------------- + +struct Vector { + pair center; + real mag; + real dir; // angle in the plane of the drawing. + real phi; // angle with the plane of the drawing, 90 is out of the page. + pen outline; + Label label; + real out_of_plane_radius; + real out_of_plane_tolerance; + + void operator init(pair center=(0,0), real mag=5mm, real dir=0, real phi=0, pen outline=currentpen, Label L="") { + this.center = center; + this.mag = mag; + this.dir = dir; + this.phi = phi; + this.outline = outline; + this.label = L; + this.out_of_plane_radius = 1mm; + this.out_of_plane_tolerance = 0.01; + } + + Vector copy() { + Vector v = Vector(center=this.center, mag=this.mag, dir=this.dir, + phi=this.phi, outline=this.outline, L=this.label); + v.out_of_plane_radius = this.out_of_plane_radius; + v.out_of_plane_tolerance = this.out_of_plane_tolerance; + return v; + } + + pair dTip() { // offset from center to tip + pair p = (0,0); + real phi_e = this.phi % 360; // effective phi + if (Tan(phi_e) == 0 || abs(1.0/Tan(phi_e)) > this.out_of_plane_tolerance) { + return this.mag*Cos(this.phi)*dir(this.dir); + } + return (0, 0); + } + + pair pTip() { + return this.dTip() + this.center; + } + + void draw(picture pic=currentpicture) { + pair p = this.dTip(); + path P; + real phi_e = this.phi % 360; // effective phi + if (this.mag < 0) (phi_e + 180) % 360; + if (Tan(phi_e) == 0 || abs(1.0/Tan(phi_e)) > this.out_of_plane_tolerance) { + // draw arrow in the plane of the drawing + // TODO: thickening for phi? + P = shift(this.center)*((0,0)--p); + draw(pic, P, this.outline, Arrow); + } else if (phi_e > 0 && phi_e < 180) { + // draw a circled dot for out-of-the-page + P = shift(this.center)*scale(this.out_of_plane_radius)*unitcircle; + draw(pic, P, outline); + dot(pic, this.center, this.outline); + } else { + // draw a circled cross for into-the-page + real a = 0.8*sqrt(2.0)/2.0; + P = shift(this.center)*scale(this.out_of_plane_radius)*unitcircle; + draw(pic, P, this.outline); + draw(pic, shift(this.center)*scale(this.out_of_plane_radius + )*((-a,-a)--(a,a)), this.outline); + draw(pic, shift(this.center)*scale(this.out_of_plane_radius + )*((-a,a)--(a,-a)), this.outline); + } + label_path(pic=pic, L=this.label, g=P); + } +} + +Vector operator +(Vector a, Vector b) { + Vector c = a.copy(); + pair p = a.mag*dir(a.dir) + b.mag*dir(b.dir); + c.mag = length(p); + c.dir = degrees(p); + return c; +} + +Vector operator -(Vector a, Vector b) { + Vector c = a.copy(); + pair p = a.mag*dir(a.dir) - b.mag*dir(b.dir); + c.mag = length(p); + c.dir = degrees(p); + return c; +} + +void vector_field(pair center=(0,0), real width=2cm, real height=2cm, + real dv=0.5cm, real buf=2pt, Vector v=null, + pen outline=invisible) { + /* There will be a buffer of at least buf on each side */ + if (v == null) { + v = Vector(); // unlikely to be what they want, but it will draw something + } + + pair ovcenter = v.center; + real ovmag = v.mag; + path bufsq = shift(center)*xscale(width-2*buf)*yscale(height-2*buf) + *shift((-.5,-.5))*unitsquare; // buffered bounding box + pair uv = dir(v.dir); // unit vector in the direction of v + pair d = dv * dir(v.dir+90); + real dx = d.x; + real dy = d.y; + int nx = 1; // x steps + int ny = 1; // y steps + bool diag = false; + + if (abs(fmod(v.phi, 180)) == 90) { // pure in/out, make a 2D grid + dx = dy = dv; // v.dir was meaninless, reset dx and dy + nx = abs((int)((width-2*buf) / dx)) + 1; + ny = abs((int)((height-2*buf) / dy)) + 1; + } else if (abs(fmod(v.dir, 180)) == 0) { // pure left/right, vert. border + ny = abs((int)((height-2*buf) / dy)) + 1; + dx = 0; + } else if (abs(fmod(v.dir, 180)) == 90) { // pure up/down, horiz. border + nx = abs((int)((width-2*buf) / dx)) + 1; + dy = 0; + } else { // diagonal, draw along a vertical an horizontal border + diag = true; + // this requires enough special handling that we break it out below + } + + if (!diag) { // square grid + real xx=buf, xy=buf; // buffer distace per side + if (dx != 0) + xx = (width-(nx-1)*fabs(dx))/2.0; // "extra" left over after division + if (dy != 0) + xy = (height-(ny-1)*fabs(dy))/2.0; + + real xstart = center.x - width/2 + xx; + real ystart = center.y - height/2 + xy; + if (dx < 0 || (dx == 0 && dot(uv, dir(0)) < 0)) + xstart += width - 2*xx; + if (dy < 0 || (dy == 0 && dot(uv, dir(90)) < 0)) + ystart += height - 2*xy; + + for (int i=0; i 0) + start = xs[1]; + v.center = start; + v.mag = length(xs[1]-xs[0]); + v.draw(); + } + } + + v.center = ovcenter; // restore original center + v.mag = ovmag; // restore original magnitude + + // draw bounding box + draw(shift(center)*xscale(width)*yscale(height)*shift((-.5,-.5))* + unitsquare, outline); +} + +Vector Velocity(pair center=(0,0), real mag=5mm, real dir=0, real phi=0, Label L="") +{ + Vector v = Vector(center=center, mag=mag, dir=dir, phi=phi, L=L, outline=rgb(1,0.1,0.2)); // red + return v; +} + +// ---------------------- Forces ------------------------- + +Vector Force(pair center=(0,0), real mag=5mm, real dir=0, real phi=0, Label L="") +{ + Vector v = Vector(center=center, mag=mag, dir=dir, phi=phi, L=L, outline=rgb(0.1,0.2,1)); // blue + return v; +} + +// ---------------------- Measures ------------------------- + +// Distance derived from CAD.MeasuredLine +struct Distance { + pair pFrom; + pair pTo; + real offset; + real scale; + pen outline; + Label label; + + void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), real offset=0, real scale=5mm, pen outline=currentpen, Label L="") { + this.pFrom = pFrom; + this.pTo = pTo; + this.offset = offset; + this.scale = scale; + this.outline = outline; + this.label = L; + } + + void draw(picture pic=currentpicture) { + pair o = this.offset*unit(rotate(-90)*(this.pTo - this.pFrom)); + path p = (this.pFrom+o) -- (this.pTo+o); + draw(pic, p, outline, Arrows); + label_path(pic=pic, L=this.label, g=p, rdir=this.pTo - this.pFrom); + } +} + +struct Angle { + pair B; + pair A; // center of angle + pair C; + real radius; // radius < 0 for exterior angles. + pen outline; + pen fill; + Label label; + + void operator init(pair B, pair A, pair C, real radius=5mm, pen outline=currentpen, pen fill=invisible, Label L="") { + this.B = B; + this.A = A; + this.C = C; + this.radius = radius; + this.outline = outline; + this.fill = fill; + this.label = L; + } + + void draw(picture pic=currentpicture) { + bool direction; + + real ccw_angle = degrees(C-A)-degrees(B-A); + bool direction = CCW; + if (ccw_angle < 0) ccw_angle += 360.0; + if (ccw_angle > 180) + direction = CW; + if (radius < 0) + direction = !direction; + path p = arc(this.A, fabs(radius), degrees(B-A), degrees(C-A), direction); + if (this.fill != invisible) { + path pcycle = this.A -- p -- cycle; + fill(pic, pcycle, this.fill); + } + draw(pic, p, this.outline); + if (direction == CW) { + p = reverse(p); + } + label_path(pic=pic, L=this.label, g=p); + } +} + +Vector hatVect (string name, pair center=(0,0), real dir=0, real phi=0) { + string s = replace("$\mathbf{\hat{X}}$", "X", name); + Label L = Label(s, position=EndPoint, align=RightSide); + Vector v = Vector( + center=center, mag=5mm, dir=dir, phi=phi, L=L, outline=rgb(0,0,0)); + return v; +} + +Vector ihat (pair center=(0,0), real dir=0, real phi=0) { + Vector v = hatVect(name="i", center=center, dir=dir, phi=phi); + return v; +} + +Vector jhat (pair center=(0,0), real dir=90, real phi=0) { + Vector v = hatVect(name="j", center=center, dir=dir, phi=phi); + return v; +} + +void draw_ijhat(pair center=(0,0), real idir=0) { + Vector ihat = ihat(center, idir); + Vector jhat = jhat(center, idir+90); + ihat.draw(); + jhat.draw(); +} + +// ---------------------- Shapes ------------------------- + +struct Wire { + pair pFrom; + pair pTo; + pen outline; + Label label; + + void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), pen outline=currentpen, Label L="") { + this.pFrom = pFrom; + this.pTo = pTo; + this.outline = outline; + this.label = L; + } + + void draw(picture pic=currentpicture) { + path p = this.pFrom--this.pTo; + draw(pic, p, outline); + label_path(pic=pic, L=this.label, g=p, rdir=this.pTo - this.pFrom); + } +} + +struct Surface { + pair pFrom; + pair pTo; + real thickness; + pen outline; + pen filla; + pen fillb; + Label label; + + void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), real thickness=5mm, pen outline=currentpen, pen filla=rgb(.5,.5,.5), pen fillb=rgb(.7,.7,.7), Label L="") { + this.pFrom = pFrom; + this.pTo = pTo; + this.thickness = thickness; + this.outline = outline; + this.filla = filla; + this.fillb = fillb; + this.label = L; + } + + void draw(picture pic=currentpicture) { + pair pDiff = pTo - pFrom; + pair pDepth = rotate(-90)*unit(pDiff)*thickness; + path p = (0, 0) -- pDiff -- (pDiff + pDepth) -- pDepth -- cycle; + p = shift(this.pFrom) * p; + axialshade( + pic=pic, g=p, pena=filla, a=this.pFrom, + penb=fillb, b=this.pFrom+pDepth); + draw(pic, p, outline); + label_path(pic=pic, L=this.label, + g=shift(pDepth/2)*(this.pFrom -- this.pTo), rdir=this.pTo - this.pFrom); + } +} + +struct Spring { + pair pFrom; + pair pTo; + real k; + real width; + real dLength; // length of a single loop (when unstretched) + real deadLength; // length before loops start on each end + real unstretchedLength; + int nLoops; + pen outline; + Label label; + + void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), real k=1, real width=3mm, real dLength=1mm, real deadLength=3mm, real unstretchedLength=12mm, pen outline=currentpen, Label L="") { + this.pFrom = pFrom; + this.pTo = pTo; + this.k = k; + this.width = width; + this.dLength = dLength; + this.unstretchedLength = unstretchedLength; + this.outline = outline; + this.label = L; + + this.nLoops = floor((unstretchedLength-2*deadLength)/dLength); + if (this.nLoops == 0) + this.nLoops = 1; + this.deadLength = (unstretchedLength-this.nLoops*dLength)/2; + } + + void draw(picture pic=currentpicture) { + pair pDiff = pTo - pFrom; + + real working_dLength = (length(pDiff) - 2*deadLength) / nLoops; + path p = (0,0)--(deadLength,0); + path loop = (0,0) + --(working_dLength/4, width/2) + --(working_dLength*3/4, -width/2) + --(working_dLength, 0); + pair loopStart; + for (int i=0; i