GGModelTypes.mesa
Last edited by: Eric Bier on September 19, 1985 5:46:11 pm PDT
Copyright © 1985 by Xerox Corporation. All rights reserved.
Stone, August 5, 1985 2:13:37 pm PDT
DIRECTORY
Imager,
ImagerPath,
ImagerTransformation,
Rope,
Rosary;
GGModelTypes: CEDAR DEFINITIONS =
BEGIN
The joint size
jointSize: REAL = 6;
The maximum number of segments which are guaranteed to work.
MaxSegments: NAT = 100;
Very Basic Types
Angle: TYPE = REAL;
Point: TYPE = ARRAY[1..2] OF REAL;
Matrix3by3: TYPE = ARRAY [1..3] OF ARRAY [1..3] OF REAL;
Vector: TYPE = ARRAY[1..2] OF REAL;
Edge: TYPE = REF EdgeObj;
EdgeObj: TYPE = RECORD [
line: Line, -- the line which passes through the endpoints of this edge
startIsFirst: BOOL,
start, end: Point];
Line: TYPE = REF LineObj;
LineObj: TYPE = RECORD [
Line equation of the form: y*cos(theta) - x*sin(theta) -d = 0,
where theta is the angle which the line makes with the x axis and d is the distance from the line to the origin.
theta: REAL, -- angle in (-pi..pi]
d: REAL, -- distance from line to origin
c: REAL, -- cos(theta). Cached for convenience.
s: REAL, -- sin(theta). Cached for convenience.
slope: REAL,
yInt: REAL -- for historical (Solidviews) reasons
];
Circle: TYPE = REF CircleObj;
CircleObj: TYPE = RECORD [
origin: Point,
radius: REAL
];
Arc: TYPE = REF ArcObj;
ArcObj: TYPE = RECORD [
circle: Circle,
startIsFirst: BOOL,
start, end: Point];
Ray: TYPE = REF RayObj;
RayObj: TYPE = RECORD [
p: Point,
d: Vector];
Screen coordinates have the origin in the lower left hand corner of the viewer. The camera is always centered on the viewer. Hence, cameraScreen is the position of the center of the viewer. It changes whenever the viewer is resized. cameraWorld is the position of the camera in Gargoyle coordinates. I assume for now that Gargoyle coordinates have screen dots for units. If this is not true, then cameraWorld must include a scaling as well as a translation.
Camera: TYPE = REF CameraObj;
CameraObj: TYPE = RECORD [
cameraWorld: Vector,
scalar: REAL,
cameraScreen: Vector
];
Scene: TYPE = REF SceneObj;
SceneObj: TYPE = RECORD [
entities: LIST OF REF ANYNIL -- a list of clusters and outlines
];
SelectedObjectData: TYPE = RECORD [
normal: BOOLFALSE,
copy: BOOLFALSE,
hot: BOOLFALSE,
active: BOOLFALSE
];
Cluster: TYPE = REF ClusterObj;
ClusterObj: TYPE = RECORD [
children: LIST OF REF ANY, -- a list of clusters or outlines
parent: Cluster,
selected: SelectedObjectData,
boundBox: BoundBox ← NIL
];
Outline: TYPE = REF OutlineObj;
OutlineObj: TYPE = RECORD [
fillColor: Imager.Color,
lineEnds: Imager.StrokeEnd,
children: LIST OF Traj,
parent: Cluster,
boundBox: BoundBox,
onOverlay: BOOLFALSE,
whyOnOverlay: REF ANY, -- the selected piece of the outline
selected: SelectedObjectData
];
Traj: TYPE = REF TrajObj;
TrajObj: TYPE = RECORD [
role: FenceHoleOpen,
segCount: NAT,    -- the number of segments currently in this trajectory
segments: Rosary.ROSARY, -- the segments themselves
Segments refer to joints (and other control points), and have drawing styles.
joints: Rosary.ROSARY,  -- the segCount+1 joints at which the segments meet
Joints have a position and a continuity constraint
extraPoints: LIST OF Point,
outline: Outline,    -- the parent outline of this trajectory,
boundBox: BoundBox,
visibleJoints: BOOLTRUE,
strokeJoint: Imager.StrokeJoint ← round,
selected: SelectedObjectData
];
BoundBox: TYPE = REF BoundBoxObj;
BoundBoxObj: TYPE = RECORD [loX, loY, hiX, hiY: REAL];
FenceHoleOpen: TYPE = {fence, hole, open};
TrajEnd: TYPE = {lo, hi};
Joint: TYPE = REF JointObj;
JointObj: TYPE = RECORD [
point: Point,
selected: SelectedObjectData,
touchItem: TouchItem
];
JointPair: TYPE = RECORD [
start, end: NAT
];
Sequence: TYPE = REF SequenceObj;
SequenceObj: TYPE = RECORD [
traj: Traj,
all: BOOLFALSE, -- does this sequence represent the whole trajectory? If so parts = LIST[0, 0] and all = TRUE
parts: LIST OF JointPair,
selected: SelectedObjectData,
boundBox: BoundBox
];
The basic unit of a Trajectory is the Segment. We will experiment with "object style" segments to put allow the maximum flexibility for constructing pieces of trajectories.
Segment: TYPE = REF SegmentObj;
SegmentObj: TYPE = RECORD [
class: SegmentClass,
looks: Rope.ROPE, -- may be used later for the style machinery
strokeWidth: REAL ← 1.0, -- for now
color: Imager.Color, -- for now
lo, hi: Point,
hiTan, loTan: Point ← [0,0], --[0,0] is the undefined value for the tangents.
selected: SelectedObjectData,
boundBox: BoundBox,
touchItemList: LIST OF TouchItem,
data: REF ANY
];
SegmentClass: TYPE = REF SegmentClassObj;
SegmentClassObj: TYPE = RECORD [
type: ATOM,
copyData: CopyDataProc,
reverse: ReverseProc,
transform: TransformProc,
endpointMoved: EndPointMovedProc,
maskStroke: MaskStrokeProc,
maskStrokeTransform: MaskStrokeTransformProc,
buildPath: BuildPathProc,
buildPathTransform: BuildPathTransformProc,
closestPoint: ClosestPointProc,
closestPointAndTangent: ClosestPointAndTangentProc,
boundBox: BoundBoxProc
];
CopyDataProc: TYPE = PROC [seg: Segment] RETURNS [data: REF ANY];
Copies the data in the "data" field of seg. This data is class-dependent.
ReverseProc: TYPE = PROC [seg: Segment];
The "lo" end and "hi" end have switched roles. Update data structures as necessary.
TransformProc: TYPE = PROC [transform: ImagerTransformation.Transformation, seg: Segment];
Apply the given transformation to all internal data of the segment. It is now in a new position, orientation, scaling, or skewing.
EndPointMovedProc: TYPE = PROC [seg: Segment, lo: BOOL, newPoint: Point];
MaskStrokeProc: TYPE = PROC [dc: Imager.Context, seg: Segment];
Draw yourself into dc as a stroke. Assume that strokeWidth, and color are already set.
MaskStrokeTransformProc: TYPE = PROC [dc: Imager.Context, seg: Segment, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL];
Draw yourself into dc as a stroke. However, apply transform to your lower joint if lo = TRUE (and entire is FALSE), and apply transform to your higher joint if hi = TRUE (and entire is FALSE). Apply the transform to the entire trajectory if entire = TRUE. This is for rubberbanding.
BuildPathProc: TYPE = PROC [seg: Segment, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc];
Assume that the Imager's current point is at your lower joint. Call the procedures given to draw yourself (moveTo is left out -- you shouldn't need it).
BuildPathTransformProc: TYPE = PROC [seg: Segment, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL];
BuildPathTransformProc is to BuildPathProc what MaskStrokeTransformProc is to MaskStrokeProc. This is for rubberbanding filled areas.
ClosestPointProc: TYPE = PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, success: BOOL];
Used for hit testing. Find the nearest point on seg to testPoint. If the nearest point is farther away than tolerance units, this procedure may opt to return success = FALSE. If a valid point is returned, then success = TRUE.
ClosestPointAndTangentProc: TYPE = PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, tangent: Vector, success: BOOL];
Used for hit testing. Find the nearest point on seg to testPoint and the tangent vector (towards hi end of segment) at that point. If the nearest point is farther away than tolerance units, this procedure may opt to return success = FALSE. If a valid point and tangent are returned, then success = TRUE.
BoundBoxProc: TYPE = PROC [seg: Segment];
Updates the geometric bounds for this segment (does not include control point size or stroke width).
Generators
EntityGenerator: TYPE = REF EntityGeneratorObj;
EntityGeneratorObj: TYPE = RECORD [
list: LIST OF REF ANY
];
TrajGenerator: TYPE = REF TrajGeneratorObj;
TrajGeneratorObj: TYPE = RECORD [
list: LIST OF Traj
];
SequenceGenerator: TYPE = REF SequenceGeneratorObj;
SequenceGeneratorObj: TYPE = RECORD [
list: LIST OF Sequence
];
SegmentGenerator: TYPE = REF SegmentGeneratorObj;
SegmentGeneratorObj: TYPE = RECORD [
traj: Traj,
toGo: NAT,
index: NAT ← 0,
nextParts: LIST OF JointPair
];
JointGenerator: TYPE = REF JointGeneratorObj;
JointGeneratorObj: TYPE = RECORD [
traj: Traj,
toGo: NAT,
index: NAT,
nextParts: LIST OF JointPair
];
BoundBoxGenerator: TYPE = REF BoundBoxGeneratorObj;
BoundBoxGeneratorObj: TYPE = RECORD [
list: LIST OF BoundBox
];
Touching:
TouchGroup: TYPE = REF TouchGroupObj;
TouchGroupObj: TYPE = RECORD [
list: LIST OF TouchItem,
point: Point,
updated: BOOLFALSE
];
TouchingPartType: TYPE = {joint, segment};
TouchItem: TYPE = REF TouchItemObj;
TouchItemObj: TYPE = RECORD [
group: TouchGroup,
traj: Traj,
touchingPartType: TouchingPartType,
joint: Joint,
seg: Segment,
segPoint: Point
];
END.