From 2120572c51c27c79c76b3a298175c55ce91e65c8 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 18 Feb 2010 12:34:14 -0500 Subject: [PATCH] Moved AFM-drawing functions from unfolding.asy to base_afm.asy & made substrate motion controllable --- tex/src/figures/schematic/Makefile | 2 +- tex/src/figures/schematic/base_afm.asy | 169 +++++++++++++++++++++++ tex/src/figures/schematic/unfolding.asy | 171 +----------------------- 3 files changed, 175 insertions(+), 167 deletions(-) create mode 100644 tex/src/figures/schematic/base_afm.asy diff --git a/tex/src/figures/schematic/Makefile b/tex/src/figures/schematic/Makefile index c66dc39..2f440a6 100644 --- a/tex/src/figures/schematic/Makefile +++ b/tex/src/figures/schematic/Makefile @@ -3,5 +3,5 @@ all : unfolding.pdf clean : rm -f unfolding.pdf -unfolding.pdf : +unfolding.pdf : unfolding.asy base_afm.asy asy -f pdf unfolding.asy diff --git a/tex/src/figures/schematic/base_afm.asy b/tex/src/figures/schematic/base_afm.asy new file mode 100644 index 0000000..1859b86 --- /dev/null +++ b/tex/src/figures/schematic/base_afm.asy @@ -0,0 +1,169 @@ +// AFM drawing utilities. + +struct Cantilever { + // draw an AFM cantilever with the tip at TIP (x,y) position on page + // the cantilever arm is roughly parallel to DIR_TO_BASE (x,y) vector + // POINT_SCALE x gives the height of the tip. + pair tip; + pair tip_top; + pair base; + real arm_length; + real tip_height; + real rest_angle; // in degrees + real dx; + real theta; // in radians + real r_curve; + + void align_tip(pair tip) { + pair offset = tip - this.tip; + this.tip += offset; + this.tip_top += offset; + this.base += offset; + } + + real dx_error(real theta) { + /* Call the radius of curvature, r_curve=R + * arm_length=L lies along the perimiter, so + * R\theta = L + * The perpendicular deflection dx is then + * R(1-\cos\theta) = L(1-\cos\theta)/\theta = dx + * and the horizontal displacement L' from the base is + * R\sin\theta = L\sin\theta/\theta = L\sinc\theta= L' + */ + return this.arm_length * (1.0 - cos(theta)) / theta - this.dx; + } + + real dx_prime(real theta) { + /* d(dx)/d(\theta) = L/\theta * [(\cos\theta-1)/\theta + \sin\theta] */ + return this.arm_length/theta * ((cos(theta)-1)/theta + sin(theta)); + } + + void set_tip_for_dx(real dx) { + /* invert dx(theta) using bracketed Newton-Raphson bisection. + * First order theta from + * dx = L(1-\cos\theta)/\theta + * = L[1-(1-\theta^2/2!+...)]/\theta + * ~= L\theta/2 + * \theta != 2dx/L + */ + this.dx = dx; + real Lp; + if (dx == 0) { + this.theta = 0; + this.r_curve = -1; + Lp = this.arm_length; + } else { + real first_order_theta = 2.0*dx/this.arm_length; + this.theta = newton(this.dx_error, this.dx_prime, + 0.1 * first_order_theta, + min(3.0 * first_order_theta, pi/2.0)); + /* because we ignored tip_height when we calculated theta, cheat a + * bit and pretend the tip is directly under our caculated + * tip_top. Then adjust tip_top accordingly. This throws off the + * bend (and maybe the arm length) a bit, but ah well :p. + */ + this.r_curve = this.arm_length / this.theta; + Lp = this.r_curve * sin(this.theta); + } + pair uy = dir(this.rest_angle); + pair ux = dir(this.rest_angle+90); + pair utx = dir(this.rest_angle+90+degrees(this.theta)); + this.tip = this.base + Lp*uy + (dx+this.tip_height)*utx; + this.tip_top = this.tip - this.tip_height*utx; + } + + guide tip_guide() { + path p; + pair uty, tip_distal, tip_proximal; + pair uty = dir(this.rest_angle+degrees(this.theta)); + tip_distal = this.tip_top + this.tip_height/3.0*uty; + tip_proximal = this.tip_top - this.tip_height/3.0*uty; + p = this.tip -- tip_distal -- tip_proximal -- cycle; + return p; + } + + guide arm_guide() { + path p; + pair uy, uty, tip_distal, tip_proximal; + pair uy = dir(this.rest_angle); + pair ux = dir(this.rest_angle+90); + pair uty = dir(this.rest_angle+degrees(this.theta)); + tip_distal = this.tip_top + this.tip_height/3.0*uty; + tip_proximal = this.tip_top - this.tip_height/3.0*uty; + if (this.dx == 0) { + p = tip_distal -- tip_proximal -- this.base; // should be colinear + } else { + p = tip_distal -- tip_proximal{-uty} .. tension 0.75 .. {-uy}this.base; + /* real angle_tip_proximal, angle_base; + pair center = this.base + this.r_curve*dx; + angle_tip_proximal = angle(tip_proximal - center); + angle_base = angle(this.base - center); + p = tip_distal -- arc(center, this.r_curve, angle_tip_proximal, angle_base); + tip_proximal{-uty} .. tension 0.75 .. {uy}this.base; + */ + } + return p; + } + + void operator init (pair base=(0,0), real arm_length=2.5cm, real tip_height=0.5cm, real rest_angle=185, real dx=0) { + this.base = base; + this.arm_length = arm_length; + this.tip_height = tip_height; + this.rest_angle = rest_angle; + this.set_tip_for_dx(dx); + } +} + +struct Substrate { + pair prot_connect_point; + real substrate_width = 3cm; + real substrate_height = 10pt; + real piezo_width = 1.5cm; + real piezo_height = 0.75cm; + pen substrate_fill = grey; + + path box(pair top_center, real width, real height) { + real w = width/2; + pair ul = top_center+(-w,0); + pair ur = top_center+( w,0); + pair ll = top_center+(-w,-height); + pair lr = top_center+( w,-height); + path p = ul -- ur -- lr -- ll -- cycle; + return p; + } + + void draw(pair dir=(0,0)) { + pair piezo_top = this.prot_connect_point - (0,this.substrate_height); + pair piezo_bot = this.prot_connect_point - (0,this.substrate_height+this.piezo_height); + filldraw(this.box(this.prot_connect_point, this.substrate_width, this.substrate_height), + fillpen=this.substrate_fill); + label("Substrate", this.prot_connect_point - (0,this.substrate_height/2)); + draw(this.box(piezo_top, this.piezo_width, this.piezo_height)); + label("Piezo", piezo_top, S); + if (dir != (0,0)) { + real arrow_length = this.piezo_height/3; + pair arrow_center = piezo_bot + (0, arrow_length/2 + 2pt); + arrow(b=arrow_center + dir*arrow_length/2, dir=-dir, + length=this.piezo_height/3, Arrow(size=8pt), + margin=NoMargin); + } + } + + void operator init(pair prot_connect_point=(0,0)) { + this.prot_connect_point = prot_connect_point; + } +} + +void distance(Label L, pair start, pair end) { + pair center = (start+end)/2; + pair u = unit(end-start); + picture picL; + label(picL, L); + pair label_size = 1.2 * (max(picL)-min(picL)); + real arrow_length = length(end-start)/2 - label_size.y; + if (arrow_length > 4pt) { + arrow(b=start, dir=u, length=arrow_length, Arrow(size=4pt)); + arrow(b=end, dir=-u, length=arrow_length, Arrow(size=4pt)); + } + label(L, center); +} diff --git a/tex/src/figures/schematic/unfolding.asy b/tex/src/figures/schematic/unfolding.asy index 6b5d871..bc70205 100644 --- a/tex/src/figures/schematic/unfolding.asy +++ b/tex/src/figures/schematic/unfolding.asy @@ -2,7 +2,8 @@ //size(x=9cm,keepAspect=true); -import stats; // for Gaussrand() +import stats; // for unitrand +import base_afm; // for Cantilever, Substrate, ... struct Wiggle { // Generate a horizontal wiggly line, centered at CENTER (x,y) @@ -124,168 +125,6 @@ struct ProteinChain { } } -struct Cantilever { - // draw an AFM cantilever with the tip at TIP (x,y) position on page - // the cantilever arm is roughly parallel to DIR_TO_BASE (x,y) vector - // POINT_SCALE x gives the height of the tip. - pair tip; - pair tip_top; - pair base; - real arm_length; - real tip_height; - real rest_angle; // in degrees - real dx; - real theta; // in radians - real r_curve; - - void align_tip(pair tip) { - pair offset = tip - this.tip; - this.tip += offset; - this.tip_top += offset; - this.base += offset; - } - - real dx_error(real theta) { - /* Call the radius of curvature, r_curve=R - * arm_length=L lies along the perimiter, so - * R\theta = L - * The perpendicular deflection dx is then - * R(1-\cos\theta) = L(1-\cos\theta)/\theta = dx - * and the horizontal displacement L' from the base is - * R\sin\theta = L\sin\theta/\theta = L\sinc\theta= L' - */ - return this.arm_length * (1.0 - cos(theta)) / theta - this.dx; - } - - real dx_prime(real theta) { - /* d(dx)/d(\theta) = L/\theta * [(\cos\theta-1)/\theta + \sin\theta] */ - return this.arm_length/theta * ((cos(theta)-1)/theta + sin(theta)); - } - - void set_tip_for_dx(real dx) { - /* invert dx(theta) using bracketed Newton-Raphson bisection. - * First order theta from - * dx = L(1-\cos\theta)/\theta - * = L[1-(1-\theta^2/2!+...)]/\theta - * ~= L\theta/2 - * \theta != 2dx/L - */ - this.dx = dx; - real Lp; - if (dx == 0) { - this.theta = 0; - this.r_curve = -1; - Lp = this.arm_length; - } else { - real first_order_theta = 2.0*dx/this.arm_length; - this.theta = newton(this.dx_error, this.dx_prime, - 0.1 * first_order_theta, - min(3.0 * first_order_theta, pi/2.0)); - /* because we ignored tip_height when we calculated theta, cheat a - * bit and pretend the tip is directly under our caculated - * tip_top. Then adjust tip_top accordingly. This throws off the - * bend (and maybe the arm length) a bit, but ah well :p. - */ - this.r_curve = this.arm_length / this.theta; - Lp = this.r_curve * sin(this.theta); - } - pair uy = dir(this.rest_angle); - pair ux = dir(this.rest_angle+90); - pair utx = dir(this.rest_angle+90+degrees(this.theta)); - this.tip = this.base + Lp*uy + (dx+this.tip_height)*utx; - this.tip_top = this.tip - this.tip_height*utx; - } - - guide tip_guide() { - path p; - pair uty, tip_distal, tip_proximal; - pair uty = dir(this.rest_angle+degrees(this.theta)); - tip_distal = this.tip_top + this.tip_height/3.0*uty; - tip_proximal = this.tip_top - this.tip_height/3.0*uty; - p = this.tip -- tip_distal -- tip_proximal -- cycle; - return p; - } - - guide arm_guide() { - path p; - pair uy, uty, tip_distal, tip_proximal; - pair uy = dir(this.rest_angle); - pair ux = dir(this.rest_angle+90); - pair uty = dir(this.rest_angle+degrees(this.theta)); - tip_distal = this.tip_top + this.tip_height/3.0*uty; - tip_proximal = this.tip_top - this.tip_height/3.0*uty; - if (this.dx == 0) { - p = tip_distal -- tip_proximal -- this.base; // should be colinear - } else { - p = tip_distal -- tip_proximal{-uty} .. tension 0.75 .. {-uy}this.base; - /* real angle_tip_proximal, angle_base; - pair center = this.base + this.r_curve*dx; - angle_tip_proximal = angle(tip_proximal - center); - angle_base = angle(this.base - center); - p = tip_distal -- arc(center, this.r_curve, angle_tip_proximal, angle_base); - tip_proximal{-uty} .. tension 0.75 .. {uy}this.base; - */ - } - return p; - } - - void operator init (pair base=(0,0), real arm_length=2.5cm, real tip_height=0.5cm, real rest_angle=185, real dx=0) { - this.base = base; - this.arm_length = arm_length; - this.tip_height = tip_height; - this.rest_angle = rest_angle; - this.set_tip_for_dx(dx); - } -} - -struct Substrate { - pair prot_connect_point; - real substrate_width = 3cm; - real substrate_height = 10pt; - real piezo_width = 1.5cm; - real piezo_height = 0.75cm; - pen substrate_fill = grey; - - path box(pair top_center, real width, real height) { - real w = width/2; - pair ul = top_center+(-w,0); - pair ur = top_center+( w,0); - pair ll = top_center+(-w,-height); - pair lr = top_center+( w,-height); - path p = ul -- ur -- lr -- ll -- cycle; - return p; - } - - void draw() { - pair piezo_top = this.prot_connect_point - (0,this.substrate_height); - pair piezo_bot = this.prot_connect_point - (0,this.substrate_height+this.piezo_height); - filldraw(this.box(this.prot_connect_point, this.substrate_width, this.substrate_height), - fillpen=this.substrate_fill); - label("Substrate", this.prot_connect_point - (0,this.substrate_height/2)); - draw(this.box(piezo_top, this.piezo_width, this.piezo_height)); - label("Piezo", piezo_top, S); - arrow(b=piezo_bot, dir=N, length=this.piezo_height/3, Arrow(size=8pt)); - } - - void operator init(pair prot_connect_point=(0,0)) { - this.prot_connect_point = prot_connect_point; - } -} - -void distance(Label L, pair start, pair end) { - pair center = (start+end)/2; - pair u = unit(end-start); - picture picL; - label(picL, L); - pair label_size = 1.2 * (max(picL)-min(picL)); - real arrow_length = length(end-start)/2 - label_size.y; - if (arrow_length > 4pt) { - arrow(b=start, dir=u, length=arrow_length, Arrow(size=4pt)); - arrow(b=end, dir=-u, length=arrow_length, Arrow(size=4pt)); - } - label(L, center); -} - defaultpen(fontsize(size=10pt, lineskip=10pt)); bool folded[] = {true,true,false,true}; @@ -299,19 +138,19 @@ Cantilever c = Cantilever(); // position base so tip touches protein when bent c.set_tip_for_dx(12pt); c.align_tip(p.end); -// now unbend the tip and draw it in grey +// unbend the tip and draw it in grey c.set_tip_for_dx(0); pair unbent_tip = c.tip; filldraw(c.tip_guide(), fillpen=grey, grey); draw(c.arm_guide(), grey); -// now rebend the tip and draw it in black +// rebend the tip and draw it in black c.set_tip_for_dx(12pt); filldraw(c.tip_guide(), fillpen=black); draw(c.arm_guide(), black); label("Cantilever", c.base-(0,10pt), SW); Substrate s = Substrate(); -s.draw(); +s.draw(dir=S); real xt_x = -0.45*s.substrate_width; real xi_x = -0.27*s.substrate_width; -- 2.26.2