1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
|
(09:03:49) ACSpike: I tried to glean drawing a circle from conic-4 (I think) I'm either missing the drawing of the circle in the rest of the code, or it is just so short and simple that I don't get it
(09:08:03) ACSpike: heh, oh "Define here various primatives, such as line, line segment, circle, bezier path etc."
(09:18:29) njh: don't look at that
(09:18:37) njh: that's done in a hacky way
(09:19:09) njh: ok, lets plan what your program will do
(09:19:23) njh: I'm thinking an 'on canvas' editor for gears
(09:20:13) njh: the biggest problem is that you have lumpy parameters (for example number of teeth is a whole number)
(09:20:54) ACSpike: lets start smaller
(09:21:00) njh: ok
(09:21:09) njh: howabout just drawing a circle
(09:21:11) ACSpike: I need an entry point into the world of 2geom
(09:21:31) ACSpike: can I get an svg path for a circle?
(09:21:35) njh: well, what I was going to suggest was just making circles with handles
(09:21:44) ACSpike: ie, no gtk gui stuff
(09:21:47) njh: hehe, I still haven't done circles :)
(09:21:52) njh: but you can use cairo
(09:21:58) ACSpike: well
(09:22:02) njh: cairo_arc
(09:22:03) ACSpike: what can I get?
(09:22:27) njh: lets make a program that just draws a single circle
(09:23:00) ACSpike: ok. back in a bit
(09:31:15) njh: ok
(09:31:22) njh: I've committed a starting point for you
(09:31:23) ACSpike: ok, I get it. 2geom doesn't do svg
(09:31:29) ACSpike: it does beziers
(09:31:37) ACSpike: and draws them on a cairo surface
(09:32:27) njh: at this point, yeah
(09:32:38) njh: actually, it doesn't even draw them :)
(09:32:54) njh: that's done by path-cairo, which is demidetached :)
(09:33:22) njh: so gear.cpp is a starting point for you
(09:33:51) njh: one issue is that I haven't done elliptical arcs in Paths yet
(09:34:04) njh: so we're going to not even use paths at this point
(09:34:34) njh: just attempt to make a circle using sbasis rather than calling cairo_arc
(09:35:03) verbalshadow [verbalshadow@gristle.org/Laptop] entered the room.
(09:35:17) ACSpike: oy
(09:35:19) njh: so a circle is parameterised by <cos(t), sin(t)> with t going form 0 to 2*pi
(09:35:27) ACSpike: right
(09:35:41) njh: does gear compile and run on your computer?
(09:36:35) ACSpike: did you commit it?
(09:39:27) njh: I spose I should add before commiting
(09:39:37) njh: done
(09:39:57) njh: ok, your second step will be to add two handles
(09:48:04) njh: feel free to ask if you are stuck
(09:48:50) ACSpike: oh, boy
(09:49:04) ACSpike: so we have a handle for radius
(09:50:01) Botty: the most elegant way to do this convex stuff would be to have a circular iterator
(09:50:16) Botty: i suppose modulus works
(09:51:32) njh: it does
(09:51:55) njh: ACSpike: the longest journey starts with a single step
(09:52:11) ACSpike: or a single grep
(09:52:24) njh: I prefer emacs isearch
(09:52:35) njh: so, does it compile?
(09:52:39) ACSpike: ya
(09:52:41) ACSpike: and runs
(09:52:48) njh: and have yuo worked out how to add a handle
(09:52:59) ACSpike: pushback
(09:53:05) njh: yep
(09:53:11) njh: just increase the loop
(09:53:27) njh: generates random handles
(09:53:51) njh: anyway, have you got two extra handles?
(09:54:00) ACSpike: no
(09:54:01) njh: please tell me when you have something working
(09:54:16) ACSpike: I'm trying to grok the single handle
(09:54:33) njh: just assume that handles can be moved anyway
(09:54:40) njh: how they work is a bit fiddly
(09:54:49) ACSpike: and raise kids :-)
(09:54:51) njh: but all they are is a Geom::Point
(09:57:54) njh: no
(09:58:05) njh: how do I do that?
(10:01:44) ACSpike: yes
(10:05:04) ACSpike: norm ~ magnatude ~ distance?
(10:06:07) njh: norms are like distance, yes
(10:06:31) njh: but not just 'as the crow flies' distance
(10:06:51) njh: another norm would be how long it takes you to get between places
(10:07:17) njh: 2geom provides a few norms: L2 and Linfinity
(10:07:28) njh: L2 = eucliean, as the crow flies distance
(10:07:34) ACSpike: L1, L2 and infinity
(10:07:47) ACSpike: l1 equals as the taxi drives
(10:07:50) njh: Linfinity = maximum distance in x or y
(10:07:56) njh: yeah l1 is taxi
(10:08:07) Botty: (X+Y)
(10:08:11) ACSpike: linfinity is x or y?
(10:08:14) njh: no, |X| + |Y|
(10:08:23) Botty: good point...
(10:08:25) njh: Linfinity = max(|X|, |Y|)
(10:08:30) ACSpike: right
(10:08:34) ACSpike: interesting
(10:08:40) ACSpike: thanks
(12:02:59) ACSpike: what should I do with these two random handles?
(12:03:19) ACSpike: pressure angle and number of teeth is what's needed
(12:06:18) njh: lets start with a line
(12:06:49) ACSpike: like constrain the movement of the handles?
(12:06:52) njh: ok, SBasis functions map [0,1] to a value
(12:06:57) njh: no, just darwing a line segment
(12:07:20) ACSpike: each handle makes one endpoint?
(12:07:21) njh: so we want to construct a function that maps [0,1] onto a line from handle 1 to handle 2
(12:08:14) njh: do you have two new handles?
(12:09:35) ACSpike: yes
(12:09:59) njh: ok, so we're going to make a pair of sbasis functions, one for x, one for y
(12:10:10) njh: to do this we need a multidim_sbasis<2>
(12:10:18) njh: (one day I'll work out better names :)
(12:10:28) ACSpike: which means, a second degree sbasis?
(12:10:47) njh: multidim_sbasis<2> B;
(12:10:56) ACSpike: this is global?
(12:10:57) njh: it means a function which maps [0,1] onto a point
(12:11:03) njh: no, put it in expose
(12:11:07) njh: everything goes in expose
(12:20:09) njh: anyway, so you have a function that maps [0,1] onto a point
(12:20:08) ACSpike: I'm about to look for the definition of multidim_sbasis
(12:20:15) njh: don't
(12:20:23) njh: it's complicated and not necessary
(12:20:27) ACSpike: ok
(12:20:36) ACSpike: leaps with faith
(12:21:21) njh: so we need to define what the functions are for X and Y
(12:21:36) njh: just like a point, these are B[X] and B[Y]
(12:21:47) ACSpike: ah
(12:21:55) ACSpike: X and Y are defined somewhere?
(12:22:00) njh: yeah, in point I think
(12:22:06) njh: but I'm lazy and use 0 and 1
(12:22:12) ACSpike: ah, good
(12:23:33) njh: Now the simplest function maps [0,1] onto a constant value
(12:23:53) njh: we could do this with B[0] = handles[1][0];
(12:23:59) ACSpike: so all values between 0 and 1 are the same
(12:24:03) njh: and similarly B[1] = handles[1][1];
(12:24:07) njh: yep
(12:24:11) njh: that would define a point
(12:24:32) njh: (I'm not sure that would compile, due to missing code)
(12:24:48) njh: I usually do everything in parallel like this:
(12:24:55) njh: for(int im = 0; dim < 2; dim++)
(12:25:04) njh: B[dim] = handles[1][dim];
(12:25:25) njh: remember that handles[0] is the point on the gear we did already
(12:25:51) njh: we're going to draw a line somewhere
(12:25:57) njh: (you have to draw a line somewhere!)
(12:26:27) njh: to do this we want to map [0,1] to points between handles[1] and handles[2]
(12:27:06) njh: for technical(and not very good) reasons this means using BezOrds
(12:27:11) ACSpike: pause for reflection
(12:27:11) njh: like this:
(12:27:30) njh: B[dim] = BezOrd(handles[1][dim], handles[2][dim]);
(12:27:41) ACSpike: what are BezOrds?
(12:27:50) njh: so try adding that code into expose
(12:28:07) njh: BezOrd(a,b) maps 0,1 onto [a,b]
(12:29:48) njh: the reason for BezOrds is they are the fundamental unit for all the maths
(12:30:08) ACSpike: what does BezOrd mean though?
(12:30:10) njh: just like points are the fundamental units for graphics
(12:30:14) njh: Bezier Ordinal
(12:30:16) ACSpike: I need to attach the idea to the name
(12:30:27) njh: you can think of them as linear bezier segments
(12:30:46) njh: add another poit and you have a quadratic, another, cubic
(12:31:08) njh: a two point bezier is a line segment
(12:31:13) Botty: so its like a parametric thing?
(12:31:19) njh: Botty: correct
(12:31:30) njh: parametric here means maps from [0,1] to a point
(12:31:37) njh: <x(t), y(t)>
(12:31:38) ACSpike: sbasis is all parametric vector squishyness
(12:31:50) njh: yes, most computer graphics is parametric
(12:31:59) ACSpike: and squishy
(12:32:06) njh: sometimes
(12:32:11) njh: sometimes it is all angular
(12:39:28) ACSpike: do I need to draw the bezord out?
(12:39:39) njh: draw it out?
(12:39:41) njh: to the canvas?
(12:40:08) njh: no, here is some boilerplate to draw a md_sb to the canvas
(12:40:25) njh: void draw_cb(cairo_t *cr, multidim_sbasis<2> const &B) {
Geom::PathBuilder pb;
subpath_from_sbasis(pb, B, 0.1);
cairo_path(cr, pb.peek());
}
(12:40:37) njh: add that to gear
(12:41:02) njh: perhaps change the name to draw_md_sb or something
(12:41:11) njh: then to draw B, just use:
(12:41:19) njh: draw_md_sb(cr, B);
(12:41:26) njh: (cr is the cairo canvas)
(12:41:38) njh: so paste what you have so far
(12:41:50) njh: (I mean just your lines, not the whole file!)
(12:46:12) ACSpike: random points are in the same spot on every execution?
(12:46:31) njh: correct
(12:46:36) ACSpike: neat
(12:46:48) njh: that's just rand()
(12:47:11) ACSpike: wow, the line. it moves.
(12:47:16) njh: if you want different positions you start the random number generator in a different spot, using say the current time
(12:47:28) njh: can you commit your changes?
(12:49:09) ACSpike: yes
(12:49:11) ACSpike: done
(12:50:24) njh: ok, so we have a single line :)
(12:50:35) ACSpike: and a single circle
(12:50:46) njh: now the nice thing about lines in this form is we can perform arithmetic on them
(12:50:46) ACSpike: but I don't know why we have a line
(12:50:54) ACSpike: ok
(12:52:14) njh: ok, so now you have some experience with lines, we're going to try to make an arc
(12:52:30) njh: remember that a circle is just <cos, sin>
(12:52:35) ACSpike: why would I perform arithmetic on a line?
(12:52:51) njh: because all geometry is arithmetic
(12:53:31) njh: so we're going to use two built in functions, sin and cos to make an arc from 0 to 1 radian
(12:53:52) njh: SBasis sin(double a0, double a1, int k);
SBasis cos(double a0, double a1, int k)
(12:54:15) njh: these two functions take a range of angles (a0, a1) and a parameter k
(12:54:23) njh: k is the accuracy
(12:54:30) njh: for now lets just use k = 2
(12:55:23) njh: so lets make B[0] = BezOrd(centre[0]) + 100*cos(0,1,2);
(12:55:29) njh: and similarly Y
(12:55:44) ***njh has never tried this before, it might not work :)
(12:56:10) ACSpike: I realize you are taking really small really slow steps
(12:56:21) ACSpike: but I'm loosing a lot of it
(12:56:35) njh: that should make an arc centred at the centre with a radius 100
(12:56:55) njh: perhaps we could convert this conversation into a tutorial when we're finished
(12:57:01) ACSpike: do I replace the line?
(12:57:06) njh: yeah
(12:57:07) ACSpike: make a new arc?
(12:57:09) ACSpike: ok
(12:57:19) njh: just comment out the line if you like
(12:57:25) njh: or you can overwrite it
(12:58:02) ACSpike: compiling
(13:00:05) ACSpike: http://rafb.net/paste/results/ZXudDC19.html
(13:01:26) ACSpike: misplaced parens?
(13:02:00) njh: no, missing defn
(13:02:03) njh: try
(13:02:16) njh: SBasis(BezOrd(centre[0])) + 100*cos(0,1,2);
(13:02:40) njh: might be due to std::cos actually
(13:02:48) njh: sin and cos are slightly crap
(13:03:00) njh: ah, I've got an idea
(13:05:37) njh: yep, looks like it will work
(13:07:02) ACSpike: indeed it does
(13:07:08) ACSpike: now I can draw arcs
(13:07:29) ACSpike: ok
(13:07:48) ACSpike: at this point I'm gonna copy the backlogs and go to bed
(13:08:07) njh: ok!
(13:08:09) njh: worked it out
(13:08:21) ACSpike: worked what?
(13:08:26) njh: I know all this sounds pedestrian
(13:08:46) ACSpike: you mean this tutorial?
(13:09:03) njh: but perhaps what you aren't realising is that when you write cos(0,1,2) you aren't just computing cos at a single point
(13:09:10) ACSpike: right
(13:09:12) njh: you are computing cos everywhere at the same time
(13:09:16) ACSpike: it the whole sweep
(13:09:19) njh: yep
(13:09:23) ACSpike: I see that
(13:09:31) ACSpike: but I don't "get" it at all :-)
(13:09:38) njh: if you run conic-3 you'll see that it converts to beziers automagically
(13:09:52) njh: well, do you understand how std::cos(t) works?
(13:10:11) ACSpike: I don't even understand the question
(13:10:31) njh: well, you wrote cos(x) in your gear program
(13:10:36) njh: do you understand how it works?
(13:10:38) ACSpike: my math is really rusty
(13:10:46) njh: right, yet you managed to draw gears
(13:11:02) njh: my point is that understanding how something works isn't entirely necessary to use it
(13:11:05) ACSpike: I don't know the definition of the function, but I know the triangle soh cah toa thing
(13:11:11) njh: yep
(13:11:32) njh: I use floating point all the time. I know exactly how it works,because I once implemented my own version
(13:11:41) njh: but 99.9999% of programmers don't
(13:11:52) ACSpike: I read the spec once
(13:11:53) njh: the same should be true of this new stuff
(13:12:13) ACSpike: but I want to grok it because I want to help
(13:12:19) njh: you should be able to make an involute without any more than a rough idea of how it works
(13:12:29) Botty: I just remember that sin is Y (intuitively opposite), cos is X (intuitively adjacent), and tan is Y / X
(13:12:32) njh: I think you will grok it, once you've got the hang of playing withit
(13:12:49) njh: we'll get some nice circular arcs going
(13:13:01) njh: maybe you can try and come up with a nice interface for circulat arcs
(13:13:04) ACSpike: I think right now I could draw all the arcs from the gear
(13:13:14) njh: yep, I think so too
(13:13:26) njh: and you would get bezier curves at the end, rather than line segments
(13:13:36) njh: and I think it would be a lot faster as well
(13:13:40) ACSpike: right
(13:13:44) njh: (actually, in this case, I doubt it metters :)
(13:14:04) ACSpike: curveto or arcto?
(13:14:19) njh: curveto, I'm afraid
(13:14:31) njh: I would like to pick the best choice, but I haven't worked out how yet
(13:14:56) ACSpike: so if I want to draw the involute I need to map that function in there somehow
(13:15:04) njh: but you can't represent involutes with arcs anyway
(13:15:07) njh: yeah
(13:15:13) ACSpike: ah hah
(13:15:15) njh: that is basically all there is to it
(13:15:24) ACSpike: so this is crazy function plotting
(13:15:38) njh: you should theoretically be able to just change the type of your equation to SBasis and use the old code
(13:15:57) njh: the only reason you can't do that is because I haven't written all the operator*(,) type functions :)
(13:16:19) njh: even more cool is you can compute the derivatives in the same way. that is something you simply can't do with point plotting
(13:16:50) njh: for example, if you want the tangent to a bezier path, B, just write derivative(B)
(13:17:10) njh: something I played with last night was trying to find the points of maximum and minimum curvature on paths
(13:17:14) njh: ('corners')
(13:17:29) njh: so I computed the curvature, took the derivative and found where that = 0
(13:17:44) njh: SBasis curvature(multidim_sbasis<2> & B) {
multidim_sbasis<2> dB = derivative(B);
multidim_sbasis<2> ddB = derivative(dB);
SBasis n = multiply(dB[0], ddB[1]) - multiply(dB[1], ddB[0]);
SBasis den = multiply(dB[0], dB[0]) + multiply(dB[1], dB[1]);
den = multiply(den, den);
return divide(multiply(n, sqrt(den, 4)), den, 6);
}
(13:17:54) njh: that is pretty much the definition off wikipedia
(13:18:16) njh: std::vector<double> r = roots(derivative(curvature(B)));
(13:18:42) njh: gives r, a list of t values with maximum or minimum curvature
|