From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/3rdparty/2geom/doc/tutorial.txt | 291 ++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/3rdparty/2geom/doc/tutorial.txt (limited to 'src/3rdparty/2geom/doc/tutorial.txt') diff --git a/src/3rdparty/2geom/doc/tutorial.txt b/src/3rdparty/2geom/doc/tutorial.txt new file mode 100644 index 0000000..9d0c81e --- /dev/null +++ b/src/3rdparty/2geom/doc/tutorial.txt @@ -0,0 +1,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 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: +(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 +(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 r = roots(derivative(curvature(B))); +(13:18:42) njh: gives r, a list of t values with maximum or minimum curvature -- cgit v1.2.3