Quick
index
main
eev
eepitch
maths
angg
blogme
dednat6
littlelangs
PURO
(C2,C3,C4,
 λ,ES,
 GA,MD,
 Caepro,
 textos,
 Chapa 1)

emacs
lua
(la)tex
maxima
 qdraw
git
lean4
agda
forth
squeak
icon
tcl
tikz
fvwm
debian
irc
contact

Eev and (My)Qdraw

My main page on Maxima is here.
This page is about my extensions to Ted Woollett's Qdraw, a drawing package for Maxima.
I'm calling my extensions "MyQdraw". Its examples use eepitch blocks and test blocks.

0. Introduction
1. Maxima by Example
2. The "load"s
3. Emacs
4. The core of MyQdraw
4.1. Eight functions
4.2. The rest of the core
5. Generating PDFs
5.1. Animations


0. Introduction

The animations below were created with MyQdraw:

Creating animations with MyQdraw is not hard - see this section.
Using MyQdraw interactively is quite easy. Click on the screenshots below:

I also use MyQdraw to LaTeXify Maxima logs with images - but the interface for that is very weird. See here.


1. Maxima by Example

One of the best places for learning Maxima from examples is a (free) book whose name is - ta-daaa! - Maxima by Example. It is divided into chapters, and my script to download a local copy of it is here. Its chapter 13 is about Qdraw, that is a front-end to Maxima's draw2d command (see also the Maxima Workbook).

This page is about my current extensions to Qdraw. I'm calling my extensions "MyQdraw" - a bad name, chosen on purpose to indicate that this is not a mature package.


2. The "load"s

The examples in this page will suppose that you have downloaded myqdraw from its git repository, with something like this:

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
# (find-fline "/tmp/myqdraw/")
rm -Rv /tmp/myqdraw/
mkdir  /tmp/myqdraw/
cd     /tmp/myqdraw/
git clone https://github.com/edrx/myqdraw .

and that you have two lines like these ones in your init file:

load_qdraw  () := load("/tmp/myqdraw/qdraw.mac");
load_myqdraw() := load("/tmp/myqdraw/myqdraw3.mac");

I use the definitions below - see here:

load_qdraw  () := load("~/myqdraw/qdraw.mac");
load_myqdraw() := load("~/myqdraw/myqdraw3.mac");


3. Emacs

I will also suppose that you have eev installed - see this page - and that you have a `code-c-d' that makes `find-myqdraw' point to the right place, like this:

;; Test: (find-myqdrawfile "")
;;  See: http://anggtwu.net/eev-qdraw.html
(code-c-d "myqdraw" "~/myqdraw/" :anchor)

At this moment all the people who are testing MyQdraw have installed it using this:

(find-windows-beginner-intro)
(find-windows-beginner-intro "12. Install qdraw")


4. The core of MyQdraw

Initially "myqdraw" was just this one-liner:

myqdraw([drargs]) := apply('qdraw, flatten([drargs]));

Here's why. The program below produces these two images:

Its call to `qdraw' produces the image at the left and its call to `myqdraw' produces the image at the right. Here is the code:

* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load_qdraw();

P  : [cos(t), sin(2*t)];
ts : [0, %pi/4, %pi/2];

define(P(t),   P);
define(Pt(t),  diff(P,t));
define(Ptt(t), diff(P,t,2));

qdraw(xr(-4,4),yr(-4,4),
      para(P[1],P[2], t,0,2*%pi, lc(orange)),
      vector(P(0),    Pt(0),      hl(0.1),lc(red)),
      vector(P(%pi/4),Pt(%pi/4),  hl(0.1),lc(red)),
      vector(P(0),    Ptt(0),     hl(0.1),lc(forest_green)),
      vector(P(%pi/4),Ptt(%pi/4), hl(0.1),lc(forest_green))
     );

myqdraw([drargs]) := apply('qdraw, flatten([drargs]));
myqdraw(xr(-4,4),yr(-4,4),
        para(P[1],P[2], t,0,2*%pi, lc(orange)),
        makelist(vector(P(t),Pt (t), hl(0.1),lc(red)), t, ts),
        makelist(vector(P(t),Ptt(t), hl(0.1),lc(forest_green)), t, ts)
     );

The `qdraw' in it is called - and it needs to be called - with all its drawing commands "at the same level", but `myqdraw' flattens its list of drawing commands and then passes the flattened version to qdraw. The qdraw and the myqdraw above are called like this:

qdraw(xr(_),
      yr(_),
      para(_),
      vector(_),
      vector(_),
      vector(_),
      vector(_));
myqdraw(xr(_),
        yr(_),
        para(_),
        [vector(_),
         vector(_),
         vector(_)],
        [vector(_),
         vector(_),
         vector(_)]);

For complex drawings I found `myqdraw' much easier to use.

After a while I saw that it would be good karma to also include some debugging functions. `qdraw' is a kind of preprocessor - first it calls `qdraw1' to transform its drawing commands into a list of drawing commands in the syntax of `draw2d', and then it calls `draw2d'. In this program

* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load_myqdraw();
a_circle : para(cos(t), sin(t), t,0,2*%pi);
qdraw  (a_circle);
qdraw1 (a_circle);
qdraw1v(a_circle);

the `qdraw' just draws a circle, and the `qdraw1' doesn't draw anything, it just returns this list of drawing commands for `draw2d':

[ip_grid_in = [10, 10], grid = true, nticks = 100, key = "", 
line_width = 3, transparent = true, point_size = 3, point_type = 7, 
label_alignment = left, head_type = nofilled, head_angle = 30, 
head_length = 0.5, parametric(cos(t), sin(t), t, 0, 2 %pi), xaxis = true, 
xaxis_width = 2, yaxis = true, yaxis_width = 2]

and the `qdraw1v' - a function that I defined - returns that list of drawing commands for `draw2d' "formatted vertically", like this:

ip_grid_in = [10,10]
grid = true
nticks = 100
key = ""
line_width = 3
transparent = true
point_size = 3
point_type = 7
label_alignment = left
head_type = nofilled
head_angle = 30
head_length = 0.5
parametric(cos(t),sin(t),t,0,2*%pi)
xaxis = true
xaxis_width = 2
yaxis = true
yaxis_width = 2


4.1. Eight functions

So, qdraw.mac defines these two main functions:

  • `qdraw1', that just translates the qdraw commands to draw2d commands, and
  • `qdraw', that does that translation and calls draw2d to draw the result.

Let me invent some new verbs:

  • `qdraw1' "qtranslates"
  • `qdraw' qtranslates and draws the result - or, in short: "qdraws".

This part of myqdraw-core.mac complement those two functions with six new ones to build this cube,

qdraw ------ myqdraw
   | \         |   \
   | qdraw1    |  myqdraw1
   |   |       |      |
qdrawv |---- myqdrawv |
     \ |          \   |
     qdraw1v ---- myqdraw1v

where:

  • `qdraw' qdraws,
  • `qdraw1' qtranslates,
  • `qdrawv' formats vertically,
  • `qdraw1v' qtranslates and formats vertically,
  • `myqdraw' flattens and then qdraws,
  • `myqdraw1' flattens and qtranslates,
  • `myqdrawv' flattens and formats vertically,
  • `myqdraw1v' flattens, qtranslates and formats vertically.


4.2. The rest of the core


5. Generating PDFs

This module

(find-myqdraw "topdf1.mac")

defines a variant of `myqdraw' called `myqdrawp', that can be configured to work in three modes. The command

myqdrawp_to_screen();

makes `myqdrawp' be equivalent to `myqdraw'; the command

myqdrawp_to_single_pdf();

is not very interesting, so I won't explain it now, and

myqdrawp_to_new_pdf();

makes each call to `myqdrawp' draw into a new PDF instead of drawing on the screen. This mode is to generate animations, as explained in the next section, and by my variant of emaxima.sty - see here.


5.1. Animations

In all the (few!) cases in which I wanted to produce animations with Maxima my animations were always just teasers for something else... for example, this animation

is a teaser for this flipbook. I needed a way to make all frames of my animations accessible in high resolution, and I needed to let people move back and forth easily between the frames with an adjustable speed - and the easiest way to do that was by generating flipbooks in PDF. The animation loads immediately, and jumps in your face; accessing the PDF takes some clicks, some seconds, and some patience.

Maxima comes with several ways to create animated gifs. We can use:

  • draw with "terminal=animated_gif" to produce animated gifs directly, or
  • draw or with "terminal=multipage_pdf", and then convert the multipage PDF to an animated gif,
  • or we can use WxMaxima, that comes with with_slider_draw and friends...

...but it was easy to adapt MyQdraw to make it produce a series of frames and then glue them into a flipbook, so I did that.

One of the files that myqdraw3.mac loads is topdf1.mac, and topdf1.mac ends with a test block called "quick-demo", that has a part that starts with

* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)

that produces the frames, and a part that starts with

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)

that produces the flipbook and the animated gif. Here's what we see after running the first part:

Note this part of the log:

(%i3) myqdrawp_to_screen ();
(%o3)                      Will draw to the screen.
(%i4) myqdrawp_to_new_pdf();    "Skip this line to draw to the screen"$
(%o4)                   Will always draw to a new PDF.
(%i6) 

If we just press a series of <f8>s the "myqdrawp_to_new_pdf()" overrides the "myqdrawp_to_screen()", and each one of these `myqdrawp's

myqdrawp(drawing(0));
myqdrawp(drawing(0.5));
myqdrawp(drawing(1.0));
myqdrawp(drawing(1.5));

saves a new PDF to disk; but if we had skipped the "myqdrawp_to_new_pdf()" by typing a <down> on its line instead of an <f8>, then each one of the `myqdrawp's above would draw to the screen - instead of creating a PDF.

The second part, whose core is:

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
./mkanim1.sh ECHO=and_run makeboth /tmp/frames.gif /tmp/frames.pdf /tmp/frame_*
**
** Inspect frames.pdf and frames.git with:
** (find-fline "/tmp/" "frames.pdf")
** (find-pdf-page "/tmp/frames.pdf")
**          file:///tmp/frames.gif
**           (brg "/tmp/frames.gif")

is explained here. Lines that start with "**" are treated by <f8> as comments; some of them contain ways to inspect the flipbook or the animated git, but to execute them we need `M-e' or `M-x brg'.