summaryrefslogtreecommitdiff
path: root/ipl/gpacks/weaving/heddle.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/gpacks/weaving/heddle.icn')
-rw-r--r--ipl/gpacks/weaving/heddle.icn426
1 files changed, 426 insertions, 0 deletions
diff --git a/ipl/gpacks/weaving/heddle.icn b/ipl/gpacks/weaving/heddle.icn
new file mode 100644
index 0000000..087a69c
--- /dev/null
+++ b/ipl/gpacks/weaving/heddle.icn
@@ -0,0 +1,426 @@
+############################################################################
+#
+# File: heddle.icn
+#
+# Subject: Program to find thread colors for weaving
+#
+# Author: Will Evans
+#
+# Date: April 19, 1999
+#
+############################################################################
+#
+# Contributor: Gregg Townsend
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# Heddle solves a coloring problem inspired by weaving. Given a
+# multicolored rectangular pattern, assign colors to warp and weft
+# threads that will allow the pattern to be woven on a loom.
+# We ignore questions of structural integrity and insist only
+# that each cell's color be matched by either the corresponding
+# warp thread (column color) or weft thread (row color).
+#
+############################################################################
+#
+# Usage: heddle filename
+#
+# Input is an image file (GIF, XBM) to be mapped to the c1 palette,
+# or an image string acceptable to readims(). The maximum size is
+# 256 x 256.
+#
+#
+############################################################################
+#
+# Requires: Version 9 graphics
+#
+############################################################################
+#
+# Links: graphics, imscolor, imsutils
+#
+############################################################################
+
+
+link graphics
+link imscolor
+link imsutils
+
+global opts # command options
+global fname # input file name
+global imstring # image string from input file
+global nrows # number of rows in input image
+global ncols # number of columns in input image
+global palette # palette type (e.g. "c1")
+global data # image data
+
+############################## MAIN ##############################
+
+procedure main(args)
+ local g
+
+ *args >= 1 | stop("usage: ", &progname, " imsfile <imsfile>*")
+
+ every (fname := !args) do {
+ if not readWeaving(fname) then {
+ write(&errout,fname," : Can't load file")
+ } else {
+ g := implicationGraph()
+# writeGraph(g)
+
+ scc(g)
+# writes("finishOrder ")
+# writeList(finishOrder)
+# writes("visited ")
+# writeForest(visited)
+
+ if not assignColors() then {
+ write(&errout,fname," : Can't assign colors")
+# writeForest(visited)
+ } else {
+ dpygrid(fname)
+ }
+ }
+ }
+ return
+end
+
+
+
+############################## INPUT ##############################
+
+# readWeaving(fname) -- load image from file, convert to imstring
+# if necessary
+
+procedure readWeaving(fname)
+ local f, s
+
+ if f := WOpen("canvas=hidden", "image=" || fname) then {
+ if WAttrib(f, "width" | "height") > 256 then
+ write("image exceeds 256 x 256") & fail
+ imstring := Capture(f, "c1") |
+ (write("can't init captured image") & fail)
+ WClose(f)
+ } else {
+ f := open(fname) | fail
+ imstring := readims(f) | fail
+ close(f)
+ }
+ ncols := imswidth(imstring) | fail
+ nrows := imsheight(imstring) | fail
+ palette := imspalette(imstring) | fail
+ data := (imstring ? 3(tab(upto(',')+1), tab(upto(',')+1), tab(0))) | fail
+ if *data ~= nrows * ncols then
+ write("malformed image string: wrong data length") & fail
+ if nrows > 256 || ncols > 256 then
+ write("pattern exceeds 256 x 256") & fail
+ return
+end
+
+
+
+######################### Graph Structure ###########################
+#
+# Consists of a table of lists of strings.
+# The strings are vertex names.
+# The table is indexed by vertex names.
+# T["x1==c"] is a list of neighbors of vertex "x1==c"
+# The naming convention of vertices used in loom is:
+#
+# <x|y><==|~=><color character>
+#
+# "x1==c" is a vertex that says "the first warp thread is color c"
+# "y3~=c" means the third weft thread is NOT color c"
+#
+#######################################################################
+
+
+######################### Depth First Search ########################
+
+global visited # keep track of visited vtcs
+global finishOrder # vertex list: rev. finish order
+global treeNumber # DFS tree number
+
+$define RECURSIVE_DFS
+$ifdef RECURSIVE_DFS
+
+procedure dfs(g,visitOrder)
+ local v
+
+ finishOrder := [] # vertex list: rev. finish order
+ visited := table() # table of visited vtcs (holds their
+ treeNumber := 1 # DFS tree number)
+
+ if /visitOrder then {
+ visitOrder := []
+ every put(visitOrder,key(g))
+ }
+ every /visited[v := !visitOrder] do { # loop over unvisited vertices
+ dfsFrom(g,v)
+ treeNumber +:= 1
+ }
+ return
+end
+
+procedure dfsFrom(g,v)
+ local w
+
+ visited[v] := treeNumber # mark vertex with its DFStree number
+ every /visited[w := !g[v]] do { # loop over unvisited nbrs
+ dfsFrom(g,w) # push dfs from nbr onto tree
+ }
+ push(finishOrder,v) # store as finished
+ return
+end
+
+$else
+
+procedure dfs(g,visitOrder)
+ local v, w, stack
+
+ stack := [] # stack for DFS
+ finishOrder := [] # vertex list: rev. finish order
+ visited := table() # table of visited vtcs (holds their
+ treeNumber := 0 # DFS tree number)
+
+ if /visitOrder then { # arbitrary visitOrder if not given
+ visitOrder := []
+ every put(visitOrder,key(g))
+ }
+ every /visited[v := !visitOrder] do { # loop over unvisited vertices
+ treeNumber +:= 1
+ visited[v] := treeNumber # assign treeNumber
+ put(g[v],"*") # add mark to end of adj list
+ push(stack,v) # push vertex onto stack
+ while (v := stack[1]) do {
+ w := get(g[v]) # get next nbr of v
+ if w == "*" then { # exhausted nbrs so pop v
+ push(finishOrder,pop(stack))
+ } else {
+ put(g[v],w) # put nbr at end of v's adj list
+ if /visited[w] then { # if w not visited then visit...
+ visited[w] := treeNumber
+ put(g[w],"*")
+ push(stack,w) # ...and stack
+ }
+ }
+ }
+ }
+end
+
+$endif
+
+######################### Strongly Connected Components #############
+# Sets "visited" to be SCC number of vertices in g:
+# If visited[v] = visited[w] then v and w in same SCC.
+# Sets "finishOrder" to be SCC-topoorder of vertices:
+# If (v,w) \in g then v and w in same SCC or v after w
+# in "finishOrder".
+
+procedure scc(g)
+ dfs(g)
+ dfs(transpose(g),copy(finishOrder))
+ return
+end
+
+
+######################### Transpose #################################
+
+procedure transpose(g)
+ local h, v, w
+
+ h := table() # table of lists
+ every v := key(g) do {
+ /h[v] := [] # create empty adj list if needed
+ every w := !g[v] do {
+ /h[w] := []
+ put(h[w],v)
+ }
+ }
+ return h
+end
+
+
+######################### Graph from Image ##########################
+
+procedure implicationGraph()
+ local colors, i, j, c, d, g, x, y, notx, noty
+
+ colors := set() # set of colors in image
+
+# Form an implication graph from the given data
+ g := table() # graph = table of lists
+
+# Put in edges caused by the color matrix
+ data ? {
+ every j := 1 to nrows do {
+ every i := 1 to ncols do {
+ c := move(1)
+ notx := "x"||i||"~="||c
+ noty := "y"||j||"~="||c
+ x := "x"||i||"=="||c
+ y := "y"||j||"=="||c
+ /g[notx] := [] # create empty adj lists if needed
+ /g[noty] := []
+ /g[x] := []
+ /g[y] := []
+ put(g[notx],y) # xi~=c --> yj==c
+ put(g[noty],x) # yj~=c --> xi==c
+ insert(colors,c) # add color to set of seen colors
+ }
+ }
+ }
+
+# Put in edges that say color for a thread must be unique
+ every c := !colors do {
+ every i := 1 to ncols do {
+ every d := (c ~== !colors) do {
+ x := "x"||i||"=="||c
+ notx := "x"||i||"~="||d
+ /g[x] := [] # create empty adj lists if needed
+ /g[notx] := []
+ put(g[x],notx) # xi==c --> xi~=d
+ }
+ }
+ every i := 1 to nrows do {
+ every d := (c ~== !colors) do {
+ y := "y"||i||"=="||c
+ noty := "y"||i||"~="||d
+ /g[y] := [] # create empty adj lists if needed
+ /g[noty] := []
+ put(g[y],noty) # yi==c --> yi~=d
+ }
+ }
+ }
+ return g
+end
+
+######################### Assign Colors #############################
+# If "xi==c" and "xi~=c" (or "yj==c" and "yj~=c") both occur in the same
+# strongly connected component, for some character c and 1<=i<=nrows
+# (1<=j<=nrows), then there is no solution.
+#
+# If "xi==c" is first occurrence of "xi==*" (or "yi==c" is first of "yi==*")
+# in SCC-topoorder then the warp thread i (weft thread i) can be colored c.
+
+global colColor
+global rowColor
+
+procedure assignColors()
+ local v, xy, i, op, c
+
+ colColor := list(ncols)
+ rowColor := list(nrows)
+ every v := !finishOrder do {
+ v ? { # parse vertex name
+ xy := move(1)
+ i := tab(many(&digits))
+ op := move(2)
+ c := move(1)
+ }
+ if (op == "==") then {
+ if (xy == "x") & (/colColor[i]) then {
+ if (visited[v] == visited[xy||i||"~="||c]) then fail
+ colColor[i] := c
+ } else if (xy == "y") & (/rowColor[i]) then {
+ if (visited[v] == visited[xy||i||"~="||c]) then fail
+ rowColor[i] := c
+ }
+ }
+ }
+ return
+end
+
+
+######################### OUTPUT #############################
+
+# dpygrid(label) -- display grid in window
+
+$define BACKGROUND "pale-weak-yellow"
+$define PREFSZ 800 # preferred size after scaling
+$define MAXMAG 10 # maximum magnification
+
+$define STRIPE 6 # space for thread color(s)
+$define GAP 1 # margin around image
+
+procedure dpygrid(label)
+ local s, x, y, c
+ static w, h, z, p, v
+
+ p := imspalette(imstring)
+ w := STRIPE + GAP + ncols + GAP + STRIPE
+ h := STRIPE + GAP + nrows + GAP + STRIPE
+ z := PREFSZ / w
+ z >:= PREFSZ / h
+ z <:= 1
+ z >:= MAXMAG
+ WOpen("width=" || (z * w), "height=" || (z * h), "bg=" || BACKGROUND) |
+ (write("can't open window") & fail)
+
+ EraseArea()
+ DrawImage(STRIPE + GAP, STRIPE + GAP, imstring)
+ y := 0
+ every c := !rowColor do {
+ Fg(PaletteColor(palette,c))
+ DrawPoint(STRIPE - 1, STRIPE + GAP + y)
+ DrawPoint(w - STRIPE, STRIPE + GAP + y)
+ y +:= 1
+ }
+ x := 0
+ every c := !colColor do {
+ Fg(PaletteColor(palette,c))
+ DrawPoint(STRIPE + GAP + x, STRIPE - 1)
+ DrawPoint(STRIPE + GAP + x, h - STRIPE)
+ x +:= 1
+ }
+
+ Zoom(0, 0, w, h, 0, 0, z * w, z * h)
+
+ if nrows <= z * STRIPE & ncols <= z * STRIPE then
+ every DrawImage(1 | z * w - ncols - 1, 1 | z * h - nrows - 1, imstring)
+
+ WAttrib("label=" || fname || ": " || label)
+ until Event() === QuitEvents()
+ WClose()
+ return
+end
+
+############################## DEBUG #############################
+
+procedure writeGraph(g)
+ local v
+ every v := key(g) do {
+ writes(v,":")
+ writeList(g[v])
+ }
+ return
+end
+
+procedure writeList(L)
+ writes("[")
+ every writes(!L,",")
+ write("]")
+ return
+end
+
+procedure writeForest(F)
+ local pair, index
+
+ index := 0
+ every pair := !sort(F,2) do {
+ if (index ~== pair[2]) then {
+ write()
+ writes(index +:= 1,": ")
+ }
+ writes(pair[1]," ")
+ }
+ write()
+ return
+end
+
+
+
+