CDVScale.mesa (a ChipNDale module)
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, July 15, 1983 11:16 am
complete redesigned by Christian Jacobi, August 28, 1984 8:44:31 am PDT
last edited by Christian Jacobi, January 27, 1986 5:05:07 pm PST
DIRECTORY
Basics USING [DoubleShiftRight],
CD USING [Number, Position, Rect];
CDVScale:
CEDAR
DEFINITIONS
IMPORTS Basics =
BEGIN
Non public ChipNDale interface to scaling of viewers.
-- Scaling must be real fast, therefore the crazyness.
-- Design -> Viewer is the most speed critical operation done, used for drawing every rectangle...
-- Viewer -> Design is speed critical for cursor tracking
-- This interface is thought as an implementation module and freely recompiled to improve the
-- inline procedures. Do never copy code from this module, because this module changes to
-- often, but if new need for scaling appears, include it here.
-- Analyzing compiler generated code showed that it is feasible to have a full record as
-- parameter, since the optimization will get rid of copying the record.
scaleNum: CARDINAL = 22;
ScaleRange:
TYPE = [0..scaleNum);
--A type describing scales; increasing a scale number means viewing a bigger part of the
--chip in a viewer; (more overview, less detail).
ScaleRec:
TYPE =
RECORD [
--data in this record must be gridded correctly, such that the origin of
--the viewer lies on a grid point; otherwise the gridding would
--require more complex and slower arithmetic.
off: CD.Position,
xx: PRIVATE INT,
useMultiply: PRIVATE BOOL,
sS: PRIVATE NAT,
sA, sB, sC, sD: PRIVATE CARDINAL,
designToViewerFactor: PRIVATE REAL,
grid: INTEGER, --in DesignCoordinates
nscale: INTEGER
];
ArithmeticShiftRight:
PROC [x:
INT, by:
NAT]
RETURNS [
INT] =
INLINE BEGIN
IF x>=0 THEN RETURN [LOOPHOLE[Basics.DoubleShiftRight[LOOPHOLE[x], by]]]
ELSE
RETURN [
LOOPHOLE[
LAST[LONG CARDINAL] -
LOOPHOLE[
Basics.DoubleShiftRight[
LOOPHOLE[ LAST[LONG CARDINAL] - LOOPHOLE[x, LONG CARDINAL] ],
by
],
LONG CARDINAL
]
]]
END;
DesignToViewerFactor:
PROC [scale: ScaleRec]
RETURNS [
REAL] ~
INLINE {
--without translation
RETURN [scale.designToViewerFactor]
};
DesignToViewerScalar:
PROC [scale: ScaleRec, n:
CD.Number]
RETURNS [CD.Number] ~ INLINE {
--without translation
RETURN [IF scale.useMultiply THEN n*scale.xx ELSE ArithmeticShiftRight[n, scale.sS]];
};
DesignToViewerPosition:
PROC[scale: ScaleRec, designPos:
CD.Position]
RETURNS [viewerPos: CD.Position] ~ INLINE {
--Including translation to viewer origin
--Caller must make sure that the designRect is only little outside the viewer clip rect
RETURN[
IF scale.useMultiply
THEN
CD.Position[
(designPos.x-scale.off.x)*scale.xx,
(designPos.y-scale.off.y)*scale.xx
]
ELSE
CD.Position[
ArithmeticShiftRight[designPos.x-scale.off.x, scale.sS],
ArithmeticShiftRight[designPos.y-scale.off.y, scale.sS]
]
]
};
DesignToViewerRect:
PROC[scale: ScaleRec, designRect:
CD.Rect]
RETURNS [CD.Rect] ~ INLINE {
--Including translation to viewer origin.
--Caller must make sure that the designRect is only little outside the viewer clip rect.
RETURN[
IF scale.useMultiply
THEN
CD.Rect[
x1: (designRect.x1-scale.off.x)*scale.xx,
y1: (designRect.y1-scale.off.y)*scale.xx,
x2: (designRect.x2-scale.off.x)*scale.xx,
y2: (designRect.y2-scale.off.y)*scale.xx
]
ELSE
CD.Rect[
x1: ArithmeticShiftRight[designRect.x1-scale.off.x, scale.sS],
y1: ArithmeticShiftRight[designRect.y1-scale.off.y, scale.sS],
x2: ArithmeticShiftRight[designRect.x2-scale.off.x, scale.sS],
y2: ArithmeticShiftRight[designRect.y2-scale.off.y, scale.sS]
]
]
};
UngriddedViewerToDesignScalar:
PROC [scale: ScaleRec, v:
LONG
CARDINAL]
RETURNS [
CD.Number] =
INLINE {
--without translation, without grid
IF scale.useMultiply
THEN
RETURN [LOOPHOLE[(v*scale.sA+scale.xx-1)/scale.xx, CD.Number]]
ELSE
RETURN [LOOPHOLE[(v*scale.sA), CD.Number]]
};
ViewerToDesignScalar:
PROC [scale: ScaleRec, v:
LONG
CARDINAL]
RETURNS [
CD.Number] =
INLINE {
--without translation, but gridded to the current grid
RETURN [LOOPHOLE[(v*scale.sA+scale.sB)/scale.sC*scale.sD, CD.Number]]
};
ViewerToDesignPosition:
PROC[scale: ScaleRec, viewerPos:
CD.Position]
RETURNS [designPos:
CD.Position] =
INLINE {
--with offset and grid
RETURN[
CD.Position[
ViewerToDesignScalar[scale, viewerPos.x]+scale.off.x,
ViewerToDesignScalar[scale, viewerPos.y]+scale.off.y]
]
};
MakeScale:
PROC [off:
CD.Position←[0, 0], nscale: ScaleRange𡤄, grid:
INTEGER←-1]
RETURNS [ScaleRec];
--given the grid, offset and nscale; makes a correctly gridded and initialized ScaleRec
GetClipRecord:
PROC [scale: ScaleRec, highX, highY:
CARDINAL]
RETURNS [
CD.Rect];
--given the index of the (high-most) pixel in the viewer, compute an outside clipping
--rectangle in design coordinates; (such that all outside the clipping area is invisible).
END.