GGSegmentTypes.mesa
Copyright c 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on May 28, 1986 4:34:19 pm PDT
Contents: Segments are parts of Trajectories, which are part of Outlines. Outline is a class of Slice. Segments include straight line segments, arcs, Bezier splines, conics, and so on. Each class of segment must know how to draw itself, how to change shape when its control points are moved, and how to compute its nearest point to a given test point.
DIRECTORY
GGBasicTypes, Imager, ImagerPath, ImagerTransformation, IO, Rope;
GGSegmentTypes: CEDAR DEFINITIONS = BEGIN
StrokeEnd: TYPE = Imager.StrokeEnd; -- TYPE = {square, butt, round}
StrokeJoint: TYPE = Imager.StrokeJoint; -- TYPE = {miter, bevel, round}
BitVector: TYPE = GGBasicTypes.BitVector;
BoundBox: TYPE = GGBasicTypes.BoundBox;
Circle: TYPE = GGBasicTypes.Circle;
Line: TYPE = GGBasicTypes.Line;
Point: TYPE = GGBasicTypes.Point;
SequenceOfReal: TYPE = GGBasicTypes.SequenceOfReal;
Vector: TYPE = GGBasicTypes.Vector;
Joint: TYPE = REF JointObj;
JointObj: TYPE = RECORD [
point: Point,
TselectedInFull: SelectedObjectData, -- T is for "temporary"
touchItem: TouchItem
];
Segment: TYPE = REF SegmentObj;
SegmentObj: TYPE = RECORD [
class: SegmentClass,
looks: Rope.ROPE, -- may be used later for the style machinery
strokeWidth: REAL ← 1.0,
strokeEnd: StrokeEnd ← round,
dashed: BOOLFALSE, pattern: SequenceOfReal ← NIL, offset: REAL ← 0.0, length: REAL ← -1.0, -- dashed stroke properties
color: Imager.Color,
lo, hi: Point,
hiTan, loTan: Point ← [0,0], --[0,0] is the undefined value for the tangents.
TselectedInFull: SelectedObjectData, -- T is for "temporary"
bBox: BoundBox,
touchItemList: LIST OF TouchItem,
data: REF ANY,
props: LIST OF REF ANY
];
SegmentClass: TYPE = REF SegmentClassObj;
SegmentClassObj: TYPE = RECORD [
type: ATOM,
Fundamentals
boundBox: BoundBoxProc,
tightBox: TightBoxProc,
copyData: CopyDataProc,
reverse: ReverseProc, -- peculiar to segments
Drawing
buildPath: BuildPathProc,
buildPathTransform: BuildPathTransformProc,
Transforming
transform: TransformProc,
endPointMoved: EndPointMovedProc, -- peculiar to segments
controlPointMoved: ControlPointMovedProc, -- peculiar to segments
Textual Description
describe: DescribeProc,
fileOut: FileOutProc,
fileIn: FileInProc,
Parts
controlPointFieldSet: ControlPointFieldSetProc,
controlPointFieldGet: ControlPointFieldGetProc,
Part Generators
controlPointGet: ControlPointGetProc,
controlPointCount: ControlPointCountProc,
Hit Testing
closestPoint: ClosestPointProc,
closestControlPoint: ClosestControlPointProc,
closestPointAndTangent: ClosestPointAndTangentProc,
lineIntersection: LineIntersectionProc,
circleIntersection: CircleIntersectionProc,
asSimpleCurve: AsSimpleCurveProc,
Editing
addJoint: AddJointProc,
setStrokeWidth: SetStrokeWidthProc -- needed for bounding box updates
don't need class specific Set/Get of strokeEnd, strokeJoint, dashes, or colors
];
Fundamentals
BoundBoxProc: TYPE = PROC [seg: Segment] RETURNS [bBox: BoundBox];
Returns the geometric bounds for this segment. Allows extra space for control points, for control point size, for joint size and for stroke width.
TightBoxProc: TYPE = PROC [seg: Segment] RETURNS [bBox: BoundBox];
Returns the geometric bounds for this segment. Does NOT allow extra space for control points, for control point size, for joint size and for stroke width.
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.
Drawing
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, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL, controlPoints: BitVector, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc];
BuildPathTransformProc is to BuildPathProc what MaskStrokeTransformProc is to MaskStrokeProc. This is for rubberbanding filled areas.
Transforming
TransformProc: TYPE = PROC [seg: Segment, transform: ImagerTransformation.Transformation];
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];
ControlPointMovedProc: TYPE = PROC [seg: Segment, transform: ImagerTransformation.Transformation, controlPointNum: NAT];
Textual Description
FileOutProc: TYPE = PROC [seg: Segment, f: IO.STREAM];
Describe yourself onto f.
FileInProc: TYPE = PROC [f: IO.STREAM, loPoint, hiPoint: Point, version: REAL] RETURNS [seg: Segment];
Make a new segment of this class. The segments endpoints are loPoint and hiPoint.
DescribeProc: TYPE = PROC [seg: Segment, self, lo, hi: BOOL, cps: BitVector] RETURNS [rope: Rope.ROPE];
Parts
ControlPointFieldSetProc: TYPE = PROC [seg: Segment, controlPointNum: NAT, selected: BOOL, selectClass: SelectionClass];
ControlPointFieldGetProc: TYPE = PROC [seg: Segment, controlPointNum: NAT, selectClass: SelectionClass] RETURNS [selected: BOOL];
Part Generators
ControlPointGetProc: TYPE = PROC [seg: Segment, controlPointNum: NAT] RETURNS [point: Point];
Returns position of designated control point
ControlPointCountProc: TYPE = PROC [seg: Segment] RETURNS [controlPointCount: NAT];
Returns total number of control points in segment
Hit Testing
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.
ClosestControlPointProc: TYPE = PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, controlPointNum: NAT, success: BOOL];
Used for hit testing. Find the nearest control point of 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. If there are no control points, success = FALSE.
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.
LineIntersectionProc: TYPE = PROC [seg: Segment, line: Line] RETURNS [points: LIST OF Point, pointCount: NAT];
CircleIntersectionProc: TYPE = PROC [seg: Segment, circle: Circle] RETURNS [points: LIST OF Point, pointCount: NAT];
AsSimpleCurveProc: TYPE = PROC [seg: Segment, point: Point] RETURNS [simpleCurve: REF ANY];
If you can be expressed easily as a straight Edge, a circular Arc, a Conic, or a Bezier piece, then return an Edge, Arc, Conic, or Bezier. Otherwise, return NIL. If you are made of several such pieces, return the one nearest to point.
Editing
AddJointProc: TYPE = PROC [seg: Segment, pos: Point] RETURNS [seg1, seg2: Segment];
Returns a new run which represents the old segment with a new joint edited in
SetStrokeWidthProc: TYPE = PROC [seg: Segment, strokeWidth: REAL];
Changes the stroke width of the segment (and updates its bounding box).
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: REF ANY,
touchingPartType: TouchingPartType,
joint: Joint,
seg: Segment,
segPoint: Point
];
SelectionClass: TYPE = {normal, hot, active};
SelectedObjectData: TYPE = RECORD [
normal: BOOLFALSE,
hot: BOOLFALSE,
active: BOOLFALSE
];
END.