summaryrefslogtreecommitdiffstats
path: root/doc/tutorial.txt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
commit61f3ab8f23f4c924d455757bf3e65f8487521b5a (patch)
tree885599a36a308f422af98616bc733a0494fe149a /doc/tutorial.txt
parentInitial commit. (diff)
downloadlib2geom-upstream.tar.xz
lib2geom-upstream.zip
Adding upstream version 1.3.upstream/1.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/tutorial.txt')
-rw-r--r--doc/tutorial.txt291
1 files changed, 291 insertions, 0 deletions
diff --git a/doc/tutorial.txt b/doc/tutorial.txt
new file mode 100644
index 0000000..9d0c81e
--- /dev/null
+++ b/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 <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