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
/
isr2specifypixelmap.lisp
< prev
next >
Wrap
Lisp/Scheme
|
1995-04-11
|
12KB
|
277 lines
;;; -*- Mode:Common-Lisp; Package:ISR2; Base:10 -*-
;;;
;;; ISR2SPECIFYBITPLANE.LISP - make a bitplane from a specified geometric shape
;;; author: Bob Collins
;;; Copyright 1988 by University of Massachusetts
;;;
;;; Modifications
(in-package "ISR2")
(defvar *bits-table*
(make-array 256 :element-type '(unsigned-byte 4) :initial-contents
'( 0 1 1 2 1 2 2 3 1 2 2 3 2 3 3 4 ;/* 00 - 0F */
1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5 ;/* 10 - 1F */
1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5 ;/* 20 - 2F */
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 ;/* 30 - 3F */
1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5 ;/* 40 - 4F */
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 ;/* 50 - 5F */
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 ;/* 60 - 6F */
3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7 ;/* 70 - 7F */
1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5 ;/* 80 - 8F */
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 ;/* 90 - 9F */
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 ;/* A0 - AF */
3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7 ;/* B0 - BF */
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 ;/* C0 - CF */
3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7 ;/* D0 - DF */
3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7 ;/* E0 - EF */
4 5 5 6 5 6 6 7 5 6 6 7 6 7 7 8 ;/* F0 - FF */
))
"This is a lookup table which tells how many bits are set in the binary representation of a given byte."
)
(defun specify-pixelmap (&rest row-col-points)
(declare (optimize (speed 3) (safety 0)))
(let* ((col-row-point-list (mapcar #'(lambda (pair)
(list (cadr pair) (car pair)))
row-col-points))
(extents-and-bitplane (specify-bitplane col-row-point-list)))
(make-pixelmap :extents (car extents-and-bitplane) :bitplane (cadr extents-and-bitplane))))
(defun specify-bitplane (point-list)
" POINT-LIST is a list of vertex points defining a walk around the edges of
a polygon. Points are given in the form (col row) in the screen coordinate
system, that is, point (col=0,row=0) is in the upper left hand corner of the
image. A bitplane and extents structure are created to represent the given
geometric object. A list containing the extents structure and the bitplane array
is returned.
SPECIAL CASES: If only two points are given, a line is drawn. If just one point
is specified, a single pixel is turned on."
(unless point-list (error "null point-list argument passed to specify-bitplane"))
(multiple-value-bind (minx miny maxx maxy) (find-extents point-list)
(let* ((extents (make-extents 0 minx miny maxx maxy))
(bitplane (make-bitplane-array (* 8 (byte-width-of extents))
(1+ (- maxy miny -1)))))
(bitmap-polygon-w-extents bitplane 1 point-list minx miny maxx maxy
:x-offset (byte-bound-of extents) :y-offset miny)
(setf (extents-pixel-count extents)
(count-bitplane-pixels bitplane))
(list extents bitplane))))
#-(or :ALLEGRO :lispworks)
(defun count-bitplane-pixels (bitplane)
"Count the number of set pixels in the given bitplane."
;;turn the bit array into a one dimensional array of bytes then blow down
;;the array counting bits. This only works when the number of elements in
;;the bitplane array is an even multiple of 8. Since bitplane arrays are
;;currently forced to have a width of 32 bits, this is true.
(let* ((num-bytes (/ (reduce #'* (array-dimensions bitplane)) 8))
(byte-array (make-array num-bytes :element-type '(unsigned-byte 8)
:displaced-to bitplane))
(count 0))
(dotimes (i num-bytes count)
(incf count (aref *bits-table* (aref byte-array i))))))
#+(or :ALLEGRO :lispworks)
(defun count-bitplane-pixels (bitplane)
"Count the number of set pixels in the given bitplane."
(let* ((num-bits (reduce #'* (array-dimensions bitplane)))
(flat-array (make-array num-bits :element-type 'bit :displaced-to bitplane))
(count 0))
(dotimes (i num-bits count)
(incf count (aref flat-array i)))))
(defun find-extents (point-list)
"return 4 values, MINX, MINY, MAXX, and MAXY, in that order."
(multiple-value-bind (lowx lowy highx highy) (find-extrema point-list)
(let ((minx (floor lowx))
(miny (floor lowy)))
(values minx miny (max minx (1- (ceiling highx))) (max miny (1- (ceiling highy)))))))
(defun bitmap-polygon (array value vertex-list &key (x-offset 0)(y-offset 0))
" Puts VALUE into cells of ARRAY which correspond to the polygon
specified by VERTEX-LIST. VERTEX-LIST should be a list of vertex
points corresponding to a walk around the edges of the polygon.
Points are given in the screen coordinate system, that is, point (0,0)
of the screen is in the upper left hand corner. Element (0,0) of the
array corresponds to (X-OFFSET,Y-OFFSET) of the screen."
(multiple-value-bind (minx miny maxx maxy) (find-extents vertex-list)
(bitmap-polygon-w-extents array value vertex-list minx miny maxx maxy
:x-offset x-offset :y-offset y-offset)))
(defun bitmap-polygon-w-extents (array value vertex-list minx miny maxx maxy &key (x-offset 0)(y-offset 0))
" See documentation for BITMAP-POLYGON."
;; force vertex-list to specify a counterclockwise walk around the polygon
(unless (counterclockwise-p vertex-list)
(setf vertex-list (reverse vertex-list)))
(case (length vertex-list)
;; NOTHING AT ALL
(0 nil)
;; A SINGLE POINT
(1 (bitmap-line array value
(car (first vertex-list)) (cadr (first vertex-list))
(car (first vertex-list)) (cadr (first vertex-list))
:x-offset x-offset :y-offset y-offset))
;; A LINE
(2 (bitmap-line array value
(car (first vertex-list)) (cadr (first vertex-list))
(car (second vertex-list)) (cadr (second vertex-list))
:x-offset x-offset :y-offset y-offset))
;; A POLYGON
(t (progn
;; draw edges
(for-each-edge (vertex-list x1 y1 x2 y2)
(bitmap-line array value x1 y1 x2 y2 :x-offset x-offset :y-offset y-offset))
;; fill in the polygon
(fill-in-polygon array value vertex-list minx miny maxx maxy
:x-offset x-offset :y-offset y-offset))))
array)
#-:EXPLORER
(eval-when (load eval compile)
(defconstant 0%-gray (make-array '(1 32) :element-type 'bit :initial-element 0))
(defconstant 100%-gray (make-array '(1 32) :element-type 'bit :initial-element 1))
)
(defun fill-in-polygon (array value vertex-list minx miny maxx maxy &key (x-offset 0)(y-offset 0))
(let ((lag (construct-lag array value
(- miny y-offset) (- minx x-offset)
(- maxy y-offset) (- maxx x-offset)
:background t))
(fill-value (case value
(0 #+:EXPLORER w::0%-gray #-:EXPLORER 0%-gray)
(1 #+:EXPLORER w::100%-gray #-:EXPLORER 100%-gray)
(t (error "VALUE argument must be either 0 or 1")))))
(clear-lag-segment-marks lag)
(for-each-unmarked-lag-segment (lag ycoord segment)
(if (point-inside-polygon-p (+ (segment-entry-startx segment) x-offset 1/10)
(+ ycoord y-offset 1/10)
vertex-list)
(mark-each-connected-segment
segment ycoord
:function #'(lambda (segment y)
(bitblt #+:EXPLORER w::alu-seta #-:EXPLORER :set
(- (segment-entry-endx segment)
(segment-entry-startx segment) -1) 1
fill-value 0 0
array (segment-entry-startx segment) y)))
(mark-each-connected-segment segment ycoord)))))
;;(defun fill-array-row (array value row startcol endcol)
;; (do ((col startcol (1+ col)))
;; ((> col endcol) array)
;; (setf (aref array row col) value)))
(defun bitmap-line (array value x1 y1 x2 y2 &key (x-offset 0)(y-offset 0))
" Puts VALUE into cells of ARRAY which correspond to the directed line
starting at (SCREEN-X1,SCREEN-Y1) and ending at (SCREEN-X2,SCREEN-Y2).
Element (0,0) of the array corresponds to (X-OFFSET,Y-OFFSET) of the screen."
(declare (arglist array value screen-x1 screen-y1 screen-x2 screen-y2 &key (x-offset 0)(y-offset 0)))
(let ((xoff (round x-offset))
(yoff (round y-offset)))
(cond
((or (and (> x2 x1) (>= y2 y1)) ;FIRST-QUADRANT
(and (= x2 x1) (= y2 y1))) ;OR A SINGLE POINT
(bitmap-line-normalized
array x1 y1 x2 y2 value
(- (floor x1) xoff) (- (floor y1) yoff) 1))
((and (<= x2 x1) (> y2 y1)) ;SECOND-QUADRANT
(bitmap-line-normalized
array y1 (- x1) y2 (- x2) value
(max 0 (- (ceiling x1) 1 xoff))
(- (floor y1) yoff) 2))
((and (< x2 x1) (<= y2 y1)) ;THIRD-QUADRANT
(bitmap-line-normalized
array (- x1) (- y1) (- x2) (- y2) value
(max 0 (- (ceiling x1) 1 xoff)) (- (ceiling y1) 1 yoff) 3))
((and (>= x2 x1) (< y2 y1)) ;FOURTH-QUADRANT
(bitmap-line-normalized
array (- y1) x1 (- y2) x2 value
(- (floor x1) xoff) (- (ceiling y1) 1 yoff) 4))
(t (error "how did you ever get here?")))))
(defmacro FILL-RELATIVE (direction array basecol baserow relcol relrow fill-length fill-value quadrant)
`(case ,quadrant
(1 (let ((col (max 0 (+ ,basecol ,relcol)))
(row (max 0 (+ ,baserow ,relrow))))
(dotimes (i ,fill-length)
(setf (aref ,array row col) ,fill-value)
,(if (eq direction :row)
`(incf col)
`(incf row)))))
(2 (let ((col (max 0 (- ,basecol ,relrow)))
(row (max 0 (+ ,baserow ,relcol))))
(dotimes (i ,fill-length)
(setf (aref ,array row col) ,fill-value)
,(if (eq direction :row)
`(incf row)
`(decf col)))))
(3 (let ((col (max 0 (- ,basecol ,relcol)))
(row (max 0 (- ,baserow ,relrow))))
(dotimes (i ,fill-length)
(setf (aref ,array row col) ,fill-value)
,(if (eq direction :row)
`(decf col)
`(decf row)))))
(4 (let ((col (max 0 (+ ,basecol ,relrow)))
(row (max 0 (- ,baserow ,relcol))))
(dotimes (i ,fill-length)
(setf (aref ,array row col) ,fill-value)
,(if (eq direction :row)
`(decf row)
`(incf col)))))
(t (error "invalid quadrant number: ~d, must be 1 2 3 or 4." ,quadrant))))
(defun bitmap-line-normalized (array x1 y1 x2 y2 value basecol baserow quadrant-number)
" Endpoints X1, Y1, X2, Y2 describe a line in the first quadrant, starting near the origin,
that is, the condition (x2 > x1, y2 >= y1) holds. BASECOL and BASEROW specify the actual array
indices of the start of the line, and the actual quadrant of the line (1 2 3 or 4) is specified
by QUADRANT-NUMBER. Top level calls should be made to BITMAP-LINE rather than to this routine."
;;;;Note: BITMAP-LINE relies on this routine also working when both x1=x2 and y1=y2.
(setf basecol (max 0 basecol))
(setf baserow (max 0 baserow))
(let ((deltax (- x2 x1))
(deltay (- y2 y1))
(startcol (floor x1))
(startrow (floor y1)))
(if (>= deltax deltay)
;;FIRST OCTANT, STEP ALONG ROWS
(let ((slope (unless (zerop deltay) (/ deltax deltay)))
(endrow (max (1+ startrow) (ceiling y2))))
(do ((row (1+ startrow) (1+ row))
(oldcol startcol (floor x))
(x 0.0))
((> row endrow))
(setf x (if (= row endrow) x2 (+ x1 (* (- row y1) slope))))
(FILL-RELATIVE :row ;fill a row or a col
array basecol baserow ;array and its base indices
(- oldcol startcol) ;relative col
(- row startrow 1) ;relative row
(max 1 (- (ceiling x) oldcol)) ;length of fill
value ;fill value to use
quadrant-number))) ;quadrant 1,2,3,4
;;SECOND OCTANT, STEP ALONG COLUMNS
(let ((slope (unless (zerop deltax) (/ deltay deltax)))
(endcol (max (1+ startcol) (ceiling x2))))
(do ((col (1+ startcol) (1+ col))
(oldrow startrow (floor y))
(y 0.0))
((> col endcol))
(setf y (if (= col endcol) y2 (+ y1 (* (- col x1) slope))))
(FILL-RELATIVE :col ;fill a row or a col
array basecol baserow ;array and its base indices
(- col startcol 1) ;relative col
(- oldrow startrow) ;relative row
(max 1 (- (ceiling y) oldrow)) ;length of fill
value ;fill value to use
quadrant-number)) ;quadrant 1,2,3,4
array))))