home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
vis-ftp.cs.umass.edu
/
vis-ftp.cs.umass.edu.tar
/
vis-ftp.cs.umass.edu
/
pub
/
Software
/
ASCENDER
/
ascendMar8.tar
/
UMass
/
ISR
/
isr2lag.lisp
< prev
next >
Wrap
Lisp/Scheme
|
1995-07-06
|
7KB
|
190 lines
;;; -*- Mode:Common-Lisp; Package:ISR2; Base:10 -*-
(in-package "ISR2")
;;;; Part of building Pixel Maps involves LAGs - see below - therefore, here
;;;; it is, part of the ISR2.
;;;;
;;;; 6/19/91 Bob Collins
;;;; A Line Adjacency Graph (LAG) is a graph where horizontal line segments
;;;; are represented as nodes, and above/below adjacency of the line segments
;;;; is explicitly represented by pointers.
;; Line Adjacency Graph (LAG)
(defstruct (lag (:constructor make-lag-struct))
(array nil) ;each full horizontal line has a slot in the lag-array.
;the slot contains a list of segment-entries, one for
;each line segment within the full horizontal line.
(starty 0)) ;lag-array element 0 corresponds to screen-array line starty.
(defun make-lag (starty height)
(make-lag-struct
;;one slot for each horizontal line
:array (make-array height :initial-element nil)
:starty starty))
;; a horizontal line segment in the line adjacency graph
(defstruct segment-entry
(startx 0) ;starting x coord of this segment block
(endx 0) ;ending x coord of this segment block
(above-list nil) ;list of segment entries adjacent to and above this one
(below-list nil) ;list of segment entries adjacent to and below this one
(marked nil)) ;a boolean flag
(defmacro for-each-lag-segment ((lag y segment) &body body)
" Perform the body once for each segment in the LAG, with the
variables Y and SEGMENT bound to the y coord of the segment,
and the segment entry itself, respectively."
(let ((numrows (gensym))
(thelag (gensym))
(index (gensym)))
`(let ((,thelag ,lag))
(do ((,numrows (length (lag-array ,thelag)) (1- ,numrows))
(,y (lag-starty ,thelag) (1+ ,y))
(,index 0 (1+ ,index)))
((zerop ,numrows) ,thelag)
(dolist (,segment (aref (lag-array ,thelag) ,index))
,@body)))))
(defmacro for-each-unmarked-lag-segment ((lag y segment) &body body)
" Performs body once for each unmarked segment in the LAG, with
variables Y and SEGMENT bound to the y coord of the segment,
and the segment entry itself, respectively."
`(for-each-lag-segment (,lag ,y ,segment)
(unless (segment-entry-marked ,segment)
,@body)))
(defun mark-each-connected-segment (initial-segment initial-y &key (function nil))
" Marks each segment connected to the INITIAL-SEGMENT which resides at y-coordinate
INITIAL-Y. If a FUNCTION is specified, it is applied to the segment and all connected
segments before they are marked. The function must take two arguments, the first
will be the current segment structure, the second will be the y coordinate of the segment.
Note: if the initial-segment is already marked, nothing will be done."
(unless (segment-entry-marked initial-segment)
(when function
(funcall function initial-segment initial-y))
(setf (segment-entry-marked initial-segment) t)
(dolist (above (segment-entry-above-list initial-segment))
(mark-each-connected-segment above (1- initial-y) :function function))
(dolist (below (segment-entry-below-list initial-segment))
(mark-each-connected-segment below (1+ initial-y) :function function))))
(defun clear-lag-segment-marks (lag)
"Unmark all lag segment flags."
(for-each-lag-segment (lag y segment)
(setf (segment-entry-marked segment) nil)))
(defun print-lag (lag)
(let ((y (lag-starty lag))
(numrows (length (lag-array lag))))
(dotimes (i numrows nil)
(format t "~% row ~d:" (+ i y))
(dolist (segment (aref (lag-array lag) i))
(format t " (~d,~d)" (segment-entry-startx segment) (segment-entry-endx segment))))))
(defun enter-4-connected-segment-into-lag (lag y startx endx)
"returns segment structure constructed."
(let ((current (make-segment-entry :startx startx :endx endx))
(index (- y (lag-starty lag))))
(setf (aref (lag-array lag) index) (nconc (aref (lag-array lag) index)
(list current)))
(when (> index 0)
(dolist (above (aref (lag-array lag) (1- index)))
(unless (or (> (segment-entry-startx above) endx)
(< (segment-entry-endx above) startx))
(push current (segment-entry-below-list above))
(push above (segment-entry-above-list current)))))))
(defun enter-8-connected-segment-into-lag (lag y startx endx)
"returns segment structure constructed."
(let ((current (make-segment-entry :startx startx :endx endx))
(index (- y (lag-starty lag))))
(setf (aref (lag-array lag) index) (nconc (aref (lag-array lag) index)
(list current)))
(when (> index 0)
(dolist (above (aref (lag-array lag) (1- index)))
(unless (or (> (segment-entry-startx above) (1+ endx))
(< (segment-entry-endx above) (1- startx)))
(push current (segment-entry-below-list above))
(push above (segment-entry-above-list current)))))))
(defun construct-lag (array value startrow startcol endrow endcol &key (background nil))
" Given a specification of a rectangular portion of an array, create a
line adjacency graph (LAG) for that array area. VALUE is the value which
corresponds to the foreground object in the array. If BACKGROUND is t,
then a lag of the background will be produced, by default the foreground
lag is constructed. Foreground pixels are considered to have 8-connected
neighborhoods while background pixels are only 4-connected."
(if background
(construct-background-lag array value startrow startcol endrow endcol)
(construct-foreground-lag array value startrow startcol endrow endcol)))
(defun construct-foreground-lag (array value startrow startcol endrow endcol)
"See CONSTRUCT-LAG."
;;foreground is 8 connected.
(let ((lag (make-lag startrow (- endrow startrow -1))))
(do ((y startrow (1+ y)))
((> y endrow) nil)
(do ((x startcol (1+ x))
(in-segment nil)
(segment-start))
((> x endcol)
(when in-segment
(enter-8-connected-segment-into-lag
lag y
segment-start
endcol)))
(cond
((and in-segment (not (= (aref array y x) value)))
(enter-8-connected-segment-into-lag lag y segment-start (1- x))
(setf in-segment nil))
((and (not in-segment) (= (aref array y x) value))
(setf segment-start x)
(setf in-segment t))
(t nil))))
lag))
(defun construct-background-lag (array value startrow startcol endrow endcol)
"See CONSTRUCT-LAG."
;;background is 4 connected.
;;the lag artificially includes a one pixel buffer all the way around the
;;specified rectangle so that the rectangle boundaries do not cause the
;;background to be broken up into unconnected patches.
(let ((lag (make-lag (1- startrow) (- endrow startrow -3))))
(enter-4-connected-segment-into-lag lag (1- startrow) (1- startcol) (1+ endcol))
(do ((y startrow (1+ y)))
((> y endrow) nil)
(do ((x startcol (1+ x))
(in-segment t)
(segment-start (1- startcol)))
((> x endcol)
(enter-4-connected-segment-into-lag
lag y
(if in-segment segment-start (1+ endcol))
(1+ endcol)))
(cond
((and in-segment (= (aref array y x) value))
(enter-4-connected-segment-into-lag lag y segment-start (1- x))
(setf in-segment nil))
((and (not in-segment) (not (= (aref array y x) value)))
(setf segment-start x)
(setf in-segment t))
(t nil))))
(enter-4-connected-segment-into-lag lag (1+ endrow) (1- startcol) (1+ endcol))
lag))