globals [ p1x p1y p2x p2y c1x c1y c2x c2y ep1 ep2 cp1 cp2 steps inc dragged ] undirected-link-breed [ pathlinks pathlink ] directed-link-breed [ cplinks cplink ] breed [ waypoints waypoint ] breed [ endpoints endpoint ] waypoints-own [ index t u t2u t3 u2t u3] endpoints-own [ newx newy next-move target ] to startup setup end to setup ca ask patches [ checkers ] set steps 10 set p1x random-xcor set p1y min-pycor + 3 set p2x random-xcor set p2y max-pycor - 3 set c1x random-xcor set c2x random-xcor set c1y random-ycor set c2y random-ycor create-endpoints 1 [ set ep1 self set label 0 setxy p1x p1y set color blue set shape "circle" __set-line-thickness .1 set size 2 set label-color black ] set inc 1 / steps let windex 1 let prevpoint ep1 create-waypoints steps - 1 [ set index windex set t (inc * index) set shape "circle" set color 3 + windex * 10 set u (1 - t) set u2t u * u * t set u3 u * u * u set t2u t * t * u set t3 t * t * t set-waypoint-xy set windex windex + 1 create-pathlink prevpoint set prevpoint self set hidden? hide-dots? ] create-endpoints 1 [ set ep2 self set label 3 setxy p2x p2y set color blue set shape "circle" __set-line-thickness .1 set size 2 create-pathlink prevpoint set label-color black ] create-endpoints 1 [ set cp1 self setxy c1x c1y set label 1 set size 2 set shape "circle" create-cplink-to ep1 [ set shape "cplink" set color green ] set label-color black ] create-endpoints 1 [ set cp2 self setxy c2x c2y set label 2 set shape "circle" set size 2 create-cplink-to ep2 [ set shape "cplink" set color green ] set label-color black ] ask endpoints [ set newx xcor set newy ycor set next-move int timer ] display end to create-pathlink [ agent ] create-pathlink-with agent [ set color (blue - 2) set thickness .5 ] end to go ifelse animate? [ ;; animate? = true, so move automatically ;; every few seconds, pick a new set of endpoints, ;; and cause the control point turtles to ;; gradually slide into the new control point positions ask endpoints [ ;; is the current location too far from the desired location? if abs (xcor - newx) > .1 or abs ( ycor - newy) > .1 [ ;; interpolate between the current location ;; and the desired location set xcor .99 * xcor + .01 * newx set ycor .99 * ycor + .01 * newy ] ;; is it time to pick a new location? if timer > next-move [ if is-patch? target [ ask target [ checkers ] ] set newx random-xcor set newy random-ycor set target patch (round newx) (round newy) ask target [ set pcolor red + 30 * [label] of myself] ;; next move time is 2 to 5 seconds from now set next-move int (timer + 2 + random 4) ] ] ] [ ;; animate? = false, so read mouse for user input ;; read mouse, allow dragging of endpoints with mouse if mouse-inside? [ ;; mouse is inside view ifelse mouse-down? [ ;; mouse button is down ;; record mouse pointer position let mx mouse-xcor let my mouse-ycor ;; if the variable dragged is a turtle, and an endpoint ;; then an endpoint is being dragged ;; move the endpoint to the mouse position ifelse is-turtle? dragged [ ask dragged [ if breed = endpoints [ ;;; ;; if endpoint is one of the line endpoints ;;; ;; then moving the endpoint moves the attached control point, too! ;;; if label = 3 or label = 0 ;;; [ let .my-cplink one-of __my-in-cplinks ;;; let new-end-x limitx (mx - value-from .my-cplink [ dx * size ]) ;;; let new-end-y limity (my - value-from .my-cplink [ dy * size ]) ;;; ask .my-cplink ;;; [ ask __other-end ;;; [ setxy new-end-x new-end-y ;;; ] ;;; ] ;;; ] ;; finally, move the endpoint setxy mx my ] ;if breed = cplinks ;[ let endx dx * size * .5 ; let endy dy * size * .5 ; ask end1 ; [ setxy limitx [ mx - endx ] of myself ; limity [ my - endy ] of myself ; ] ; ask end2 ; [ setxy limitx [ mx + endx ] of myself ; limity [ my + endy ] of myself ; ] ;] ] ] [ ;; dragged is not an endpoint or link, so maybe ;; there is an endpoint nearby? let draggable [ endpoints in-radius 1 ] of patch mx my ;if not any? draggable ;[ ;; no, no endpoint nearby, maybe a control point link? ; set draggable [ cplinks in-radius 1 ] of patch-at mx my ;] if any? draggable [ ;; there is an endpoint or link near the mouse click. ;; make that the dragged endpoint set dragged min-one-of draggable [ who ] ] ] ] [ ;; mouse is up, so end drag set dragged nobody ] ] ] let points [ "ep1" "ep2" "cp1" "cp2" ] let epx [ "p1x" "p2x" "c1x" "c2x" ] let epy [ "p1y" "p2y" "c1y" "c2y" ] (foreach points epx epy [ run (word "set " ?2 " [ xcor ] of " ?1 "\n" "set " ?3 " [ ycor ] of " ?1 "\n" ) ] ) ask waypoints [ set-waypoint-xy ] ;; update the display on a seperate schedule. ;; this makes using the speed slider to slow down the model ;; *also* appear to increase the resolution of the model ;; even though the only difference is that when the model ;; is moving quickly, fewer screen updates occur ;; this probably sort of simulates netlogo's own ;; screen-update scheduling every .02 [ ;; at this time, see if the value of the hide-dots? switch has changed if any? waypoints with [ hidden? != hide-dots? ] [ ask waypoints [ set hidden? hide-dots? ] ] if any? pathlinks with [ hidden? != hide-line? ] [ ask pathlinks [ set hidden? hide-line? ] ] ] tick end to set-waypoint-xy set xcor p1x * u3 + 3 * c1x * u2t + 3 * c2x * t2u + p2x * t3 set ycor p1y * u3 + 3 * c1y * u2t + 3 * c2y * t2u + p2y * t3 ; set xcor p1x * u + p2x * t ; set ycor p1y * u + p2y * t end to checkers set pcolor sky + 4.5 - .5 * ((pxcor + pycor ) mod 2) end to-report limitx [ xx ] report max (list min-pxcor min (list max-pxcor xx)) end to-report limity [ yy ] report max (list min-pycor min (list max-pycor yy)) end @#$#@#$#@ GRAPHICS-WINDOW 122 10 442 351 15 15 10.0 1 18 1 1 1 0 0 0 1 -15 15 -15 15 1 1 0 ticks CC-WINDOW 5 365 451 460 Command Center 0 BUTTON 9 10 64 43 NIL setup NIL 1 T OBSERVER NIL NIL NIL NIL BUTTON 10 46 65 79 NIL go T 1 T OBSERVER NIL NIL NIL NIL SWITCH 9 82 107 115 hide-dots? hide-dots? 1 1 -1000 SWITCH 8 156 113 189 animate? animate? 0 1 -1000 SWITCH 8 119 102 152 hide-line? hide-line? 1 1 -1000 TEXTBOX 9 199 114 340 To use: Press go. With \"animate?\" off, you can use the mouse to drag the endpoints, control points or connectors (at x), changing the shape of the spline. 11 0.0 0 @#$#@#$#@ == WHAT IS IT? == A model that produces and allows the manipulation of a Bézier Curve, a kind of Spline. == HOW IT WORKS == A spline is generated between endpoints ep1 and ep1, influenced by control points cp1 and cp2, and interpolated among "steps" waypoints. As U varies from 1 to 0, the spline is interpolated from ep1 to ep2. At each step n that is 1/steps of the way along the curve, a waypoint calculates the interpolated value of the bezier function for UsubN == EXTENDING THE MODEL == Encapsulate the spline generator for general purpose use Generate other kinds of splines, such as cubic Generate splines with more than 2 control points Generate smoothly connected multiple splines Enable dragging of the link between the control- and end- points to modify the spline. Use splines to define smooth paths for agents in a simulation == NETLOGO FEATURES == === Mouse Dragging === The mouse- primitives are used to enable dragging of the endpoints, control points, and connectors. Programming different drag behaviors is interesting. For endpoints, (and control points) just changing the coordinates automatically moves the connector (cplinks). But to drag the connector, we can't just setxy on it and be done, as the endpoints will not follow. So, we have to calculate the new position of the endpoints, and move them there, they will cause the link to move automatically. As a technical note: since we are moving both endpoints, that causes TWO automatic moves of the link, and thus two view refreshes. The netlogo LINKS features are used to generate the automatically updating lines between the endpoints every is used to speed up graphics rendering timer is used to time the changes of location the technique of iterated interpolation is used to shift the spline from the current location to the new location == CREDITS AND REFERENCES == Inspired, long ago, by an old Byte magazine that I can't find anymore that talked about bezier curves (or was it Compute!'s Gazzette, or Scientific American?) Additional resources and information about Bezier Curves and Splines http://mathworld.wolfram.com/BezierCurve.html http://mathworld.wolfram.com/Spline.html http://en.wikipedia.org/wiki/Spline_(mathematics) Going 'round the bend with splines Copyright © 2005,2009 James P. Steiner @#$#@#$#@ default true 0 Polygon -7500403 true true 150 5 40 250 150 205 260 250 circle false 6 Circle -13840069 false true 15 15 268 dot false 0 Circle -7500403 true true 90 90 120 ex false 6 Line -13840069 true 0 0 300 300 Line -13840069 true 0 300 300 0 @#$#@#$#@ NetLogo 4.0.4 @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ default 0.0 -0.2 0 0.0 1.0 0.0 1 1.0 0.0 0.2 0 0.0 1.0 link direction true 0 Line -7500403 true 150 150 90 180 Line -7500403 true 150 150 210 180 cplink 0.0 -0.2 0 0.0 1.0 0.0 1 4.0 4.0 0.2 0 0.0 1.0 link direction true 0 Line -7500403 true 150 150 90 180 Line -7500403 true 150 150 210 180 @#$#@#$#@