The Big Bad G'MIC Thread of Silly Questions

The fill expression equivalent would be just +f bool(i).

Even more confusing. +f !!i

I was far from all that… I was going for fill "i>0" but didn’t know what to put next, like how to tell it to fill with this or that color. I should re- read all the tutorial.

EDIT : so in the end i have these two solutions :
Flood with alpha 0:

+blend alpha,1 to_a. 
flood. 0,100%,0,255,0,1,255,255,255,0 
blend[-1,-2] alpha,1

label_fg (I still had to flood it because fill would make the background white):

[0],[0],1,3,255 mv. 1 +blend[-1,-2] alpha,1 
+label_fg. 20,0,0 fill. !!i 
flood. 0,100%,0,0,0,1,0,0,0 n. 0,255 d a[0] [-1],c keep[0,2]

There is a difference though:
Flood ( there is still some kind of color outline):

Label+fill (no color outline left yay!).


But using deform on the source image before label+fill changes the output. Some regions are not filled):

Changed the design a bit, so it’s a bit more stretched and rounder on the top:


Still have to fix the middle part, which is just a “fixed” spline.

1 Like

Seems like you have moved up your game.

Well, in the end it’s still just a bunch of splines in a repeat loop. I’m trying to put things together until i get what i’m looking for. I think i’m more lucky than anything else :slight_smile:
And i was tired of circles hahaha…

Not wasted for me. I’m a writer. I explain stuff — just for the sheer jollies. And — who knows? — I might trigger one of your famously light-hearted and insouciant animations that brings such songs to my heart.

What kind of songs — ? Um. Let’s not go there…

Ah! So, the typewriter game. Hit a key. The face of the typebar strikes the paper, impressing some glyph upon it. Then the carriage translates at a set displacement, as is the wont for monspaced fonts. At the right margin, a carriage return removes all those displacements, translating back to the start point, then translates to the next row by the same set displacement, but vertical. So goes the catalogue of translations, cyclically applied, uniform: perhaps left-left-left-left-4-times-right-and-down, then again, and again, and again `til arms are bloody stumps, perhaps.
Game pieces:

  1. An image, rectangular, with arbitrary dimensions w and h.
    a. Within its confines, we step-and-repeat, these with constant-magnitude displacements. We’d rather not go off edges. Sizing exercises for steps and margins are in the offing: See 2. of Game play.
  2. A glyph, an image bound to the head of a typebar. This typewriter has one typebar — one glyph. We got the typewriter on the cheap, but it’s not very versatile.
    a. Glyphs consist of (maybe very long) position sequences of (x,y) pairs. They mark out circles, ellipses, squares, letter forms — maybe even fancy filigrees.
    b. These plots occupy the confines of an origin-centered, ±unit square, a bounding box, two units on a side. The values of these x, y coordinates all fall within the closed interval [-1,…,1].
  3. Two-channel path images store such glyphs. These occupy G’MIC’s stacks as would any other image. x coordinates occupy channel 0; y coordinates occupy channel 1; a pixel encapsulates the coordinates of one plot.
    a. G’MIC’s curve command consumes glyphs and plays a connect-the-dots game with these plots, drawing the glyph.

Game play:

  1. Plot glyphs so many times across the image (the sx step count) and and so many times down (the sy step count). sx and sy counts are integers and may or may not be equal.
  2. Sizing: To reconcile typebar faces and sx × sy step counts with image dimensions w and h, we (1) divide the image height h by sy, (2) the image width w by sx and (3) take the smaller of ratios w/sx or h/sy.
    a. That minimum establishes the stride of carriage translations; the stride also establishes the side lengths of the bounding boxes encompassing glyphs. It ensures that cumulative measures of the larger step counts fit within corresponding image dimensions.
    b. There is a contention between these sx × sy step counts, the image dimensions w and h and the stride. The image rectangle, perhaps, can be very much wider than it is high — or vice versa. Nonetheless, there are stride specifications where sy >> sx or sx >> sy. Sigh. Oh. Woe and Sorrow. To fit big step counts in correspondingly small image dimensions, the calamaty gives rise to tiny strides and little bounding boxes and unseemingly huge margins. Not pretty, but people can be silly.

Implementation:

A custom command, stampit in steprepeat.gmic carries out the game play. For example, here is a 5 × 3 stamping of a glyph rotated at 11° on a 979 × 1104 image.

gmic -m steprepeat.gmic {979*2},{1103*2+1},1,4 stampit. 5,3,11 r2dx. 50%,5 o. stampit_5-3-11.png
Output image [0] as png file 'stampit_5-3-11.png' (1 image 979x1104x1x4).

The smallest stride arises along the horizontal dimension, so there are large top-and-bottom margins.

A custom command, steprepeat, implemented below, performs the step-and-repeat pattern. It harnesses a fixed path image — the glyph — here rendered orange and generated by a gtutor_mkspectral/gtutor_specplot command pair. These ABN Filigree extracts fabricate paths from spinner chains (aka “wheelies”). How they come about is a story full of prodigious interest and indelible charm, but it is not the story here. The story here is playing the typewriter game with glyphs: the step-wise transit of these from place to place and how one might do that without bloodying oneself at a keyboard.

steprepeat.gmic
stampit: check  isint(${1=1})"        && "\
                ${1}>0"               && "\
                isint(${2=1})"        && "\
                ${2}>0"               && "\
                isnum(${3=0})
   stpx,stpy,rot=${1-3} # stepx, stepy and rotation in degrees.
   foreach {
      -name. canvas
      
      # mkspectral + specplot: Plots the path made by the tip of the last
      #                        spinner on a chain of spinners.
      # Path is in an origin-centered, ±unit square and is 2 units
      # on a side, each straddling the x or y axes. Arguments: 250
      # plots: path computed from three linked spinners each ≈1/3 in
      # length, all with 0° orientation and each spinning at 1, 3 and -13
      # Hertz, respectively.
      -gtutor_mkspectral 250,{0.95/3},0,1,{0.95/3},0,3,{0.95/3},0,-13 # filigree
   #  -gtutor_mkspectral 120,{0.95/2},0,1,{0.95/2},0,3                # 3-petal rose
   #  -gtutor_mkspectral 60,{0.95/3},0,1,{0.95/3},0,2,{0.95/3},0,-4   # bowtie
   #  -gtutor_mkspectral 20,{0.95},0,1                                # circle
      -gtutor_specplot. # Spectral ⇒ temporal conversion. Selected now a path.
      -name. plots
      -steprepeat[canvas] [plots],$stpx,$stpy,$rot
      -remove[plots]
   }

steprepeat : check ${"is_image_arg $1"}" && "\
                   isint(${2=1})"        && "\
                   ${2}>=0"              && "\
                   isint(${3=1})"        && "\
                   ${3}>=0"              && "\
                   isint(${3=1})"        && "\
                   ${4}>=0
   sx,sy,srot=${2-4} # Horizontal, vertical step counts and rotation angle, degrees.
   e[^-1] "Step and repeat given path $1 on image$? $2 times across and $3 times down."
   pass$1
   foreach {
      nm={n}
      -name. canvas
      w,h:=w#$canvas,h#$canvas # canvas dimensions: pels
      dx:=round($w/$sx,1,-1)   # across step length in pels, nearest lower whole pel.
      dy:=round($h/$sy,1,-1)   # down step length in pels, nearest lower whole pel.
      s:=min($dx,$dy)          # minimum across or down step lengths. s: stride. s × s: bounding box.
      mx:=($w-$s*$sx)/2        # across margin: (img. width – ( step length × horiz.step count.))/2
      my:=($h-$s*$sy)/2        # down margin: (img. height – ( step length × vert. step count.))/2
      pass.                    # path plotted in the origin-centered ±unit square
      -name. plots

      # Plots for a box that is just a slight smidgen smaller than
      # the bounding box. Visualization aid. Rotate, scale, shear,
      # translate along with any other path.
      -input (-0.99,-0.99^-0.99,0.99^0.99,0.99^0.99,-0.99^-0.99,-0.99)
      -name. box
      -permute[box] cyzx # swap x,y pairs from width-wise to spectral- (channel-) wise.

      # Set up initial transform from ± unit square to bounding box
      -moveglyph[plots,box] {$s/2},{-$s/2},{$mx+$s/2},{$my+$s/2},$srot
      -repeat {$sy} {
         -repeat {$sx} {
            -curve[canvas] [plots],4,0,0,1,1,255,200,0,255
            -curve[canvas]   [box],4,0,0,1,1,0,200,255,64
            -moveglyph[plots,box] 1,1,$s,0  # Step plots, box, once, +horizonal
         }
         -moveglyph[plots,box] 1,1,{-$sx*$s},$s # Step plots, box, -horizontal by one row,
                                                # then step +vertical, once.
      }
      -keep[canvas]
      -name[canvas] $nm
   }
   remove.

# Compose an affine transformation matrix and apply same
# to a path.
moveglyph : skip ${1=1},${2=1},${3=0},${4=0},${5=0}
   sx,sy,tx,ty,r=${1-5}
   foreach {
      nm={n}
      -name. plots
      -fill[plots] ">
                   begin(
                          M=eye(3);
                          M[0]=$sx;
                          M[2]=$tx;
                          M[4]=$sy;
                          M[5]=$ty;
                          $r>0?M=mul(M,rot([0,0,1],$r°),3)
                        );
                   (M*[I(x,y),1])[0,2]
                   "
      -name[plots] $nm
   }

camtrak:
   foreach {
      name. canvas
      bbs:=min(w#$canvas,h#$canvas)
      steps=200

      # Make glyph
      -gtutor_mkspectral {$steps},0.7,0,1,0.3,0,-4
      -name. glyph
      -gtutor_specplot[glyph]

      # Make path
      -gtutor_mkspectral {0.375*$steps},0.9,0,1,0.1,0,-3
      -name. track
      -gtutor_specplot[track]

      # Scale and translate glyph and track into position
      -moveglyph[track] {0.4*$bbs},{-0.4*$bbs},{0.4375*w#$canvas},{0.4375*h#$canvas}
      -moveglyph[glyph] {0.1*$bbs},{-0.1*$bbs},{I(#$track,0,0)}

      # Make (Δx,Δy) displacements to step glyph along track
      +shift[track] -1,0,0,0,2
      -sub[-1] [-2]
      -crop. 1,100%
      -name. tangents

      # Step and repeat
      -repeat {w#$tangents} {
         -curve[canvas] [glyph],5,30,50%,0,1,255,64,200
	 dx,dy:=I(#$tangents,$>+1,0)
         -moveglyph[glyph] 1,1,$dx,$dy
      }
   } 

Here’s a key bit. Applying affine transforms to path images can translate them from place to place. Or rotate them around a center point. Or scale them outward or toward critical points. Or shear them vertically or horizontally along center lines. Or do, as an indivisible action, any combination of these affine transformations. Here, the verb “apply”, stands for the action of rewriting the x and y coordinates taken from an initial path image and altering these, in place, to reflect the desired motion. Plotting the revised path image follows, perhaps using curve or some such.

Here’s another key bit. By the agency of revising x and y coordinates, path images retain “memory” of all applied transforms, these back to the initially created tabula rasa. path image. This gives step-and-repeat tasks like the typewriter game a straight forward play:

  1. Get glyph A (made by hand, like box, or, like plots, obtained wholesale from a
    gtutor_mkspectral/gtutor_specplot or similar glyph-generating toolset).

  2. Scale and translate glyph A from the origin-centered, ±unit square to the bounding box
    interior. By virtue of their rewriting, the path image coordinates retain these
    scalings and translations.

  3. repeat for vertical_steps:
    a. repeat for horizontal_steps:
    i. plot glyph A
    ii. translate glyph A horizontally 1 × stride
    Done
    b. translate glyph A –(horizontal_steps × stride)
    c. translate glyph A vertically 1 × stride
    Done

The custom command that does the ‘Apply affine transform’ operation is moveglyph. It is a wrapper that hides the mechanics of manipulating affine matrices. Give it a scaling, translation or a rotation (or all three). moveglyph sets up the appropriate affine transform matrix and applies the encoded transforms to the selected image, which is expected to be a path. Plot the path. apply another transform, plot the revised path. Apply another transform. ⇒ ∞. In a sense, the path retains the cumulative effect of the entire sequence of applied transforms.

Affine transforms descend from the garden variety 2×2 rotational/scaling matrices which David illustrated in Post 178 and Post 179 but are “augmented” in the sense that they are denizens of three dimensions and nominally operate on 3D points: (x, y, z) . The outcome of such augmented machinery are projections of 3D points onto 2D surfaces. The extra mechanics permit the inclusion of translation to the pantheon of rotational and scaling transforms, so that affine matrices can, in a uniform way, encode sequences of all three transforms, engendering shapes or motion of a subline character. But users of moveglyph need not worry about this back story; just provide a path image and ask for some transformation flavor and build up composite transforms in their path images.

Such augmentation opens up new possibilities for ABN Filigrees. In future incantations, that filter will furnish filigreed borders of the ilk shown in Squaring the Circle, except that the border need not be square, nor the filigree element a circle, and the whole enterprise can operate in resolution-independent vector graphics, a way of working that is opening up in G’MIC. The logistics of having a shape follow another shape as a guiding path is not difficult to achieve in this scheme of stepping path images with sequences of affine transforms, as the following toy, camtrak illustrates (see steprepeat.gmic, above, for the implementation):

gmic -m steprepeat.gmic 2048,2048,1,3 camtrak. r2dx[0] 50%,5 o. filigree.jpg

Paths:


Glyph and Track

EDIT: Originally posted with wrong glyph-and-track graphic.

2 Likes

Hi, thanks for the help.
I’m just testing your solution but it seems i’ll have to buy a NASA computer to run it.

On my mac m1:


gmic -m gmic_scripts/steprepeat.gmic run 'tic {979*2},{1103*2+1},1,4 stampit. 6,3,0 r2dx. 50%,5 toc d'

[gmic]./ Start G'MIC interpreter (v.3.3.4).
[gmic]./ Import commands from file 'gmic_scripts/steprepeat.gmic', with debug info (4 new, total: 4740).
[gmic]./run/__run/ Initialize timer.
[gmic]./run/__run/ Input black image at position 0 (1 image 1958x2207x1x4).
[gmic]./run/__run/ Resize 2D image [0] to 50% pixels along the x-axis, while preserving 2D ratio.
[gmic]./run/__run/ Elapsed time: 48.558 s.
[gmic]./run/__run/ Display image [0] = 'canvas'.

Could you test this command? I switched to spectral “circle” BTW:
gmic -m gmic_scripts/steprepeat.gmic run 'tic {979*2},{1103*2+1},1,4 stampit. 5,7,0 r2dx. 50%,5 toc d'

It’s been running for more than 10 minutes i think, and i’m still waiting for it to finish lol.

1 Like

You’re right. Even with a simple glyph:

   #  -gtutor_mkspectral 250,{0.95/3},0,1,{0.95/3},0,3,{0.95/3},0,-13 # filigree
   #  -gtutor_mkspectral 120,{0.95/2},0,1,{0.95/2},0,3                # 3-petal rose
      -gtutor_mkspectral 60,{0.95/3},0,1,{0.95/3},0,2,{0.95/3},0,-4   # bowtie
   #  -gtutor_mkspectral 20,{0.95},0,1                                # circle

And bracketing with tic/toc here:

         -repeat {$sx} {
	    -tic
            -curve[canvas] [plots],4,0,0,1,1,255,200,0,255
	    -toc
            -curve[canvas]   [box],4,0,0,1,1,0,200,255,64
            -moveglyph[plots,box] 1,1,$s,0  # Step plots, box, once, +horizonal

I get these elapse times:

gosgood@lydia ~ $ gmic run '-m steprepeat.gmic {979*2},{1103*2+1},1,4 stampit. 6,3,0 r2dx. 50%,5'
[gmic]./ Start G'MIC interpreter (v.3.3.5).
[gmic]./run/__run/ Import commands from file 'steprepeat.gmic', with debug info (4 new, total: 4750).
[gmic]./run/__run/ Input black image at position 0 (1 image 1958x2207x1x4).
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.002 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.001 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.002 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.003 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.005 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.015 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.022 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.037 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.075 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.152 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.321 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 0.694 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 1.913 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 5.137 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 24.351 s.
[gmic]./run/__run/stampit/*foreach#7/steprepeat/*foreach#37/*repeat#58/*repeat#59/ Elapsed time: 81.997 s.
[gmic]./run/__run/ Resize 2D image [0] to 50% pixels along the x-axis, while preserving 2D ratio.
[gmic]./ Display image [0] = 'canvas'.

where the time required by curve grows exponentially in the final iterations.
`tis an odd one, that. Eventually, I do get this image:

Lydia is my knockabout laptop. 16 GB i5-8250 Mobile running at 1.6 gHz, but I bet my workstation won’t fare better. That `hocky-stick time profile is strange indeed…

Time to walk little Vinnie (the dog). Maybe can investigate during morning coffee and a bagel (with cream cheese).

1 Like

Enjoy the walk & breakfast :wink: It’s lunch time here.

I didn’t expect such a slowdown though by just adding a glyph on the line.

1 Like

Good catch, @prawnsushi. The plot [th/s]ickens! (As always, I much appreciate you breaking my toys — because then the bug hunt is on!)

Here’s the curious bit. If I append together all my plotting images into one looong! image, then call curve with ten thousand plots, then tic/toc returns about 0.008 seconds.

Big glyph:

    -gtutor_mkspectral 500,{0.95/3},0,1,{0.95/3},0,3,{0.95/3},0,-13 # filigree

Hacked steprepeat

steprepeat : check ${"is_image_arg $1"}" && "\
                   isint(${2=1})"        && "\
                   ${2}>=0"              && "\
                   isint(${3=1})"        && "\
                   ${3}>=0"              && "\
                   isint(${3=1})"        && "\
                   ${4}>=0
   sx,sy,srot=${2-4} # Horizontal, vertical step counts and rotation angle, degrees.
   e[^-1] "Step and repeat given path $1 on image$? $2 times across and $3 times down."
   pass$1
   foreach {
      nm={n}
      -name. canvas
      w,h:=w#$canvas,h#$canvas # canvas dimensions: pels
      dx:=round($w/$sx,1,-1)   # across step length in pels, nearest lower whole pel.
      dy:=round($h/$sy,1,-1)   # down step length in pels, nearest lower whole pel.
      s:=min($dx,$dy)          # minimum across or down step lengths. s: stride. s × s: bounding box.
      mx:=($w-$s*$sx)/2        # across margin: (img. width – ( step length × horiz.step count.))/2
      my:=($h-$s*$sy)/2        # down margin: (img. height – ( step length × vert. step count.))/2
      pass.                    # path plotted in the origin-centered ±unit square
      -name. glyphplot

      # Plots for a box that is just a slight smidgen smaller than
      # the bounding box. Visualization aid. Rotate, scale, shear,
      # translate along with any other path.
      -input (-0.99,-0.99^-0.99,0.99^0.99,0.99^0.99,-0.99^-0.99,-0.99)
      -name. boxplot
      -permute[boxplot] cyzx # swap x,y pairs from width-wise to spectral- (channel-) wise.

      # Set up initial transform from ± unit square to bounding box
      -moveglyph[glyphplot,boxplot] {$s/2},{-$s/2},{$mx+$s/2},{$my+$s/2},$srot
      -repeat {$sy} {
         -repeat {$sx} {
#            -tic
#            -curve[canvas] [plots],4,0,0,1,1,255,200,0,255
#            -toc
#            -curve[canvas]   [box],4,0,0,1,1,0,200,255,64
             +moveglyph.. 1,1,$s,0   # Step plots once +horizonal
             -name. glyphplot
             +moveglyph.. 1,1,$s,0   # Step box once +horizonal
             -name. boxplot
	     -echo "sx: "$>
          }
	 -if $><($sy-1)
            +moveglyph.. 1,1,{-$sx*$s},$s # Step glyphplot -sx*horizontal,
            -name. glyphplot              # then step glyphplot +sy*vertical.
            +moveglyph.. 1,1,{-$sx*$s},$s # Step boxplot -sx*horizontal,
            -name. boxplot                # then step boxplot +sy*vertical.
	    -echo "sy: "$>
	 -fi
      }
      -append[glyphplot] x
      -append[boxplot]   x     d ,
      -tic
      -curve[canvas] [glyphplot],4,0,0,1,1,255,200,0,255
      -curve[canvas]   [boxplot],4,0,0,1,1,0,200,255,64
      -toc
      -keep[canvas]
      -name[canvas] $nm
   }
   remove.

Produces:

The zig-zags happen because glomming together all of the plots gives no opportunity for a “pen lift” operation. Also, the image management/movement is a bit screwed up, I am printing one image twice.

Don’t know why, yet, why curve becomes bogged down when called repeatedly with the data set divided, but behaves well when called once with the same data appended together. Stay tuned.

1 Like


Breaking stuff is cool heheh
( Those who know the Beavis & Butthead CD will understand) ( and there’s a great Primus song on it too).

Oh btw, you said :

Blockquote
We’d rather not go off edges

But in my case I want to since the pattern should be seamless.

( Why is it so freaking hard to quote someone on a smartphone? Will fix later if I have to)

Pattern is seamless if you don’t try to extend the border to fit all circles. Unfortunately, so you have to make that option. Just the nature of raster graphics and their discrete units.

Well, what I actually needed to say was that the circles overlap.

What do you mean by that?

Just that the circles in my script are not just drawn side by side but over each other, with a step of 1 radius. In Gary’s example they are drawn side by side.

Because the plot [th/s]ickens every day
And the pieces of my puzzle keep crumblin’ away
But I know, there’s a picture beneath

FNM, Falling to Pieces

Could it be that curve is afraid of heights and doesn’t want to go down from the abscissa and descend into the abyss?
( Yeah I know, that didn’t help you at all :rofl:)

1 Like

Brightens my day, though. Improving the general aspects of a dreary late winter day in Brooklyn is worth some points.

FNM, Falling to Pieces FNM ⇒ Faith No More. Almost went over my head.

1 Like

Goodness, gracious! Night falls on the eastern shores of the Atlantic pond, and I haven’t given @prawnsushi anything new to break. Probably even now the poor, listless sod could be idly twirling the big dial of some vintage Sears Silvertone 10 transistor radio, looking for `80’s rock-and-roll that might be radiating out into the aether somewhere.

And so it did. Ah — I wasn’t managing steprepeat’s foreach loop very well. Under supervised, it looped over the path image arguments as well as those intended to be drawn on. One unintended consequences of such entailed curve being called thirty, forty, maybe fifty times, always with path images containing hundreds of identical (x,y) point pairs. Since curve takes time to cull plots falling within a close proximity, things rather bogged down. Fixed now.

Post 241 is still pertinent. I decided that Commenting/Uncommenting code line to choose glyphs is too gauche even for demo toys, so spent Sunday Morning After Breakfast rigging ways of calling path images by name. So:

 gmic -run '-m steprepeat.gmic 512,256,1,3 4096,2048,1,3 stampit atomicage,256,13,17,63'

plasters 221 1950’s retro atoms, in seventeen rows and thirteen columns, on a couple of variable-sized images. Have fun…
knot3210

 gmic -run '-m steprepeat.gmic 1024,1024,1,3 stampit. knot3210,256,1,1,0 r2dx. 50%,5 o. knot3210.jpg,80'
steprepeat.gmic
#@cli stampit : [glyph] | "glyphname",stepx,stepy,rotation
#@cli : Fill selected image with a rectangular array of rotated glyphs.
stampit: skip   ${1='circle'}
         check  isint(${2=100})"      && "\ # pcnt => plot count: +integer.
                ${2}>0"               && "\ 
                isint(${3=1})"        && "\ # stpx => col count: +integer.
                ${3}>0"               && "\
                isint(${4=1})"        && "\ # stpy => row count: +integer.
                ${4}>0"               && "\
                isnum(${5=0})               # glyph rotation
   -if !$!
      -return
   -fi
   pcnt,stpx,stpy,rot=${2-5}
   foreach {
      nm={n}
      -name. canvas

      # First argument can be an path image,
      # name (string) or index (number)
      -if  ${"is_image_arg $1"}
         -pass$1 0
      -else # name or index
         gnames=${-_glyphnames}
         numargs:=narg($gnames)
         -local[] {
            -if isint("$1")
               glyphname=${"arg0 ($1%"$numargs"),"$gnames}
            -else
               glyphname=$1
            -fi
            -_glyph_$glyphname $pcnt
            -gtutor_specplot.
         -onfail
            glyphname=$1
	    error "Unknown\ glyph:\ "$glyphname
         }
      -fi
      e[^-1] "Draw glyph "$glyphname" with $2 plots in $3 columns & $4 rows with a $5° rotation."
      -name. glyphplot
      -crop[glyphplot] -1,{w#-1-1},1 # Close loop: duplicate first plot to last
      -shift[glyphplot] -1,0,0,0,2
      -steprepeat[canvas] [glyphplot],$stpx,$stpy,$rot
      -remove[glyphplot]
   }

# -----------------------------------------------------------------
# Spectral generators. Post: gtutor_specplot to convert to path
# image. Plots the path made by the tip of the last spinner on a
# chain given to gtutor_mkspectral as an argument. Path is in an
# origin-centered, ±unit square, 2 units on a side, each
# straddling the x or y axes.
_glyph_atomicage   : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{2/5},0,10,{1/5},0,-20
_glyph_bowtie      : -check isint($1) -gtutor_mkspectral $1,{1/4},0,1,{1/4},0,2,{1/4},0,-4
_glyph_circle      : -check isint($1) -gtutor_mkspectral $1,{2/3},0,1
_glyph_eightpetal  : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-8
_glyph_eightrose   : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,8
_glyph_ellipseh    : -check isint($1) -gtutor_mkspectral $1,{1/4},90,1,{1/2},180,-2
_glyph_ellipsev    : -check isint($1) -gtutor_mkspectral $1,{1/4},0,1,{1/2},180,-2
_glyph_filigree    : -check isint($1) -gtutor_mkspectral $1,{1/4},0,1,{1/4},0,3,{1/4},0,-13
_glyph_fivepetal   : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-5
_glyph_fiverose    : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,5
_glyph_fourpetal   : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-4
_glyph_fourrose    : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,4
_glyph_knot328     : -check isint($1) -gtutor_mkspectral $1,{1/4},0,1,{1/5},0,2,{1/4},0,-8
_glyph_knot3210    : -check isint($1) -gtutor_mkspectral $1,{1/4},0,1,{1/5},0,2,{1/4},0,-10
_glyph_ninepetal   : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-9
_glyph_ninerose    : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,9
_glyph_palmette    : -check isint($1) -gtutor_mkspectral $1,{1/4},90,1,{1/4},0,15,{1/4},0,1
_glyph_sevenpetal  : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-7
_glyph_sevenrose   : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,7
_glyph_sixpetal    : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-6
_glyph_sixrose     : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,6
_glyph_spiralrose  : -check isint($1) -gtutor_mkspectral $1,{1/4},0,1,{sqrt(2)/4},-135,-6,{sqrt(2)/4},-90,3
_glyph_tenpetal    : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-10
_glyph_tenrose     : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,10
_glyph_threepetal  : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,-3
_glyph_threerose   : -check isint($1) -gtutor_mkspectral $1,{1/3},0,1,{1/3},0,3
_glyph_trispiral   : -check isint($1) -gtutor_mkspectral $1,{1/4},0,1,{sqrt(2)/4},-135,-18,{sqrt(2)/4},-90,9

# -----------------------------------------------------------------
_glyphnames :
   -status atomicage,bowtie,circle,eightpetal,eightrose,ellipseh,ellipsev,filigree,fivepetal,fiverose,fourpetal,fourrose,knot328,ninepetal,ninerose,palmette,sevenpetal,sevenrose,sixpetal,sixrose,spiralrose,tenpetal,tenrose,threepetal,threerose,trispiral

# -----------------------------------------------------------------

steprepeat: check ${"is_image_arg $1"}" && "\
                isint(${2=1})"          && "\
                ${2}>=0"                && "\
                isint(${3=1})"          && "\
                ${3}>=0"                && "\
                isint(${3=1})"          && "\
                ${4}>=0
   sx,sy,srot=${2-4}
   e[^-1] "Step and repeat given path $1 on image$? $2 times across and $3 times down."
   -pass$1 0                   # path plots
   -foreach[^-1] {
      nm={n}
      -name. stepcanvas
      w,h:=w#$stepcanvas,h#$stepcanvas # stepcanvas dimensions
      dx:=round($w/$sx,1,-1)   # across step length in image pels, nearest lower whole pel.
      dy:=round($h/$sy,1,-1)   # down step length in image pels, nearest lower whole pel.
      s:=min($dx,$dy)          # minimum across or down step lengths. This: square's side.
      mx:=($w-$s*$sx)/2        # across margin
      my:=($h-$s*$sy)/2        # down margin
      pass. 0                  # path plotted in the origin-centered ±unit square
      -name. glyphplot
      -input (-0.99,-0.99^-0.99,0.99^0.99,0.99^0.99,-0.99^-0.99,-0.99)
      -name. boxplot
      -permute[boxplot] cyzx

      # Set up initial transform from ± unit square to bounding box
      -moveglyph[glyphplot,boxplot] {$s/2},{-$s/2},{$mx+$s/2},{$my+$s/2},$srot
      -repeat {$sy} {
         row=$>
         -repeat {$sx} {
            -curve[stepcanvas] [glyphplot],5,0,0,1,1,255,200,0,255
            -curve[stepcanvas]   [boxplot],5,0,0,1,1,0,200,255,64
            -moveglyph[glyphplot,boxplot] 1,1,$s,0
         }
         -if $row<$sy
            -moveglyph[glyphplot,boxplot] 1,1,{-$sx*$s},$s
         -fi
      }
      -keep[stepcanvas]
      -name[stepcanvas] $nm
   }
   remove.

# -----------------------------------------------------------------

#@cli moveglyph : _tsx,_tsy,_ttx,_tty,_rot
#@cli : Compose an affine transformation matrix & apply to 
#@cli : the selected path image. Defaults to an identity matrix.
moveglyph : skip ${1=1},${2=1},${3=0},${4=0},${5=0}
   e[^-1] "Transform of the day: Scale: $1,$2; Translate: $3,$4; Rotate: $5"
   sx,sy,tx,ty,r=${1-5}
   foreach {
      nm={n}
      -name. plots
      -fill[plots] ">
                   begin(
                          M=eye(3);
                          M[0]=$sx;
                          M[2]=$tx;
                          M[4]=$sy;
                          M[5]=$ty;
                          $r>0?M=mul(M,rot([0,0,1],$r°),3)
                        );
                   (M*[I(x,y),1])[0,2]
                   "
      -name[plots] $nm
   }

# -----------------------------------------------------------------

camtrak:
   foreach {
      name. canvas
      bbs:=min(w#$canvas,h#$canvas)
      steps=200

      # Make glyph
      -gtutor_mkspectral {$steps},0.7,0,1,0.3,0,-4
      -name. glyph
      -gtutor_specplot[glyph]

      # Make path
      -gtutor_mkspectral {0.375*$steps},0.9,0,1,0.1,0,-3
      -name. track
      -gtutor_specplot[track]

      # Scale and translate glyph and track into position
      -moveglyph[track] {0.4*$bbs},{-0.4*$bbs},{0.4375*w#$canvas},{0.4375*h#$canvas}
      -moveglyph[glyph] {0.1*$bbs},{-0.1*$bbs},{I(#$track,0,0)}

      # Make (Δx,Δy) displacements to step glyph along track
      +shift[track] -1,0,0,0,2
      -sub[-1] [-2]
      -crop. 1,100%
      -name. tangents

      # Step and repeat
      -repeat {w#$tangents} {
         -curve[canvas] [glyph],5,30,50%,0,1,255,64,200
         dx,dy:=I(#$tangents,$>+1,0)
         -moveglyph[glyph] 1,1,$dx,$dy
      }
   }

Well, i do enjoy the Garypedia articles and usually await them like the rich sods waitng in line for the new iphone. But even I have stuff to do every now and then :slight_smile:

Stuff so off topic i have to hide it

That FNM song isn’t even one i really like, it’s rather cheesy. Try this one instead :slight_smile:
Note that i never listen willingly to the radio. I’ve been buying cds for 33-34 years now, at this point i could start my own radio. But anyway i’m not against 80’s music, and it’s easy to find on the radio, i think half of what i hear (see? i didn’t say listen) in the car is quite old indeed.
But the math amputee that i am can sill solve this :
Good music + good recording + good production = Eternal enjoyment

I was learning tricks about 90° rotations and looking to adapt them to G’mic since i can’t use negative numbers without leaving the canvas:
gmic run '1000,1000,1,3,0 repeat 100 sx:=$> sy:=$>%($<+1) repeat 4 circle. $sx%,$sy%,.5%,1,255,0,0 tmpx,tmpy=$sx,$sy sx:=100-$sy sy=$tmpx line. $tmpx%,$tmpy%,$sx%,$sy%,1,255 done w. wait 50 done d'


Nothing neww for you.
Got some fun patterns that i immediately forgot about.

I see. So with plot points being added each pass it would take more and more time to process, hence the weird tic toc results.
Thanks for the update, i’ll go test break it now.

1 Like

Hello, I have a new question to get out of my head… For the sake of learning a bit of math parser syntax… I’ve been roaming the forum and tutorials but I only see syntax for fill.

How do I iterate over pixels in a (binary or grayscale containing just edges or an outlined shape) image to check their values ( i ) and get their positions? I know their are predefined vars like i, x ,y etc, but I can’t seem to figure out how to write what I want to do. I just want to draw a line going outward to image border were i>0. Just for fun.