<> <> <> DIRECTORY Cubic USING [Bezier], Complex USING [Vec, Sub, Abs, Mul, Add], Seq USING [ComplexSequence,NatSequence, NatSequenceRec, ComplexSequenceRec], FitBasic, FitStateUtils, FitState; FitStateImpl: CEDAR PROGRAM IMPORTS Complex, FitStateUtils EXPORTS FitState = BEGIN Handle: TYPE = FitBasic.Handle; <> <> <> <> <> <> <<];>> <<>> SampleHandle: TYPE = FitBasic.SampleHandle; SListHandle: TYPE = FitBasic.SListHandle; LinkHandle: TYPE = FitBasic.LinkHandle; TrajHandle: TYPE = FitBasic.TrajHandle; Contour: TYPE = FitBasic.Contour; DataType: TYPE = FitState.DataType; Vec: TYPE = Complex.Vec; <<>> Create: PUBLIC PROC RETURNS [handle: Handle] = { handle _ NEW[FitBasic.Rec _ [ traj: NEW[FitBasic.Traj], slist: NEW[FitBasic.SList _ NewSList[]], closed: FALSE, minDist: 0, otherContours: NIL, undo: NIL ]]; }; NewSList: PROC RETURNS [s: FitBasic.SList] = { s.header _ NEW[FitBasic.Sample]; s.selectedSample _ s.header.next _ s.header.prev _ s.header; s.first _ NIL; s.last _ NIL; }; UnlinkSamples: PROC[slist: SListHandle] = { IF slist#NIL AND slist.header#NIL THEN { s,t: SampleHandle; s _ slist.header.next; UNTIL s = slist.header DO t _ s.next; s.next _ s.prev _ NIL; s _ t; ENDLOOP; slist.header.next _ slist.header.prev _ NIL; }; }; UnlinkLinks: PROC[traj: TrajHandle] = { IF traj #NIL THEN { l,t: LinkHandle; l _ traj.links; UNTIL l=NIL DO t _ l.next; l.next _l.prev _ NIL; l _ t; ENDLOOP; }; }; Closed: PUBLIC PROC [handle: Handle, closed: BOOLEAN _ TRUE] RETURNS [was: BOOLEAN] = { was _ handle.closed; handle.closed _ closed; RETURN[was]; }; MinDist: PUBLIC PROC [handle: Handle, minDist: REAL _ 0] RETURNS [was: REAL] = { was _ handle.minDist; handle.minDist _ minDist; RETURN[was]; }; ResetData: PUBLIC PROC[handle: Handle, type: DataType, all: BOOLEAN _ FALSE] = { SELECT type FROM samples => { reset: FitStateUtils.SListProc = { UnlinkSamples[slist]; slist^ _ NewSList[]; }; [] _ reset[handle.slist]; IF all THEN FitStateUtils.ForAllOtherSLists[handle,reset]; }; links => { reset: FitStateUtils.TrajProc = { UnlinkLinks[traj]; traj.links _ NIL; traj.lastLink _ NIL; }; [] _ reset[handle.traj]; IF all THEN FitStateUtils.ForAllOtherTrajs[handle,reset]; }; nodes => { reset: FitStateUtils.SListProc = {FitStateUtils.ForAllSamples[handle.slist, ResetNode]}; [] _ reset[handle.slist]; IF all THEN FitStateUtils.ForAllOtherSLists[handle,reset]; }; cusps => { reset: FitStateUtils.SListProc = {FitStateUtils.ForAllSamples[handle.slist, ResetCusp]}; [] _ reset[handle.slist]; IF all THEN FitStateUtils.ForAllOtherSLists[handle,reset]; }; contour => { ResetData[handle, samples, all]; ResetData[handle, links, all]; IF all THEN handle.otherContours _ NIL; }; ENDCASE => ERROR; }; ScaleData: PUBLIC PROC[handle: Handle, scale: REAL, type: DataType, all: BOOLEAN _ FALSE] = { XFormData[handle: handle, scale: [scale,scale], type: type, all: all]; }; TranslateData: PUBLIC PROC[handle: Handle, trans: Vec, type: DataType, all: BOOLEAN _ FALSE] = { XFormData[handle: handle, trans: trans, type: type, all: all]; }; XFormData: PROC[handle: Handle, scale: Vec _ [1,1], trans: Vec _ [0,0], type: DataType, all: BOOLEAN _ FALSE] = { xformSample: FitStateUtils.SampleProc = { p: Vec _ s.xy; s.xy _ Complex.Mul[p,scale]; p _ s.tangent; s.tangent _ Complex.Mul[p,scale]; }; SELECT type FROM samples => { xform: FitStateUtils.SListProc = {FitStateUtils.ForAllSamples[handle.slist,xformSample]}; [] _ xform[handle.slist]; IF all THEN FitStateUtils.ForAllOtherSLists[handle,xform]; }; links => { xform: FitStateUtils.LinkProc = { cubic: Cubic.Bezier _ l.cubic; l.cubic.b0 _ Complex.Add[Complex.Mul[scale,cubic.b0], trans]; l.cubic.b1 _ Complex.Add[Complex.Mul[scale,cubic.b1], trans]; l.cubic.b2 _ Complex.Add[Complex.Mul[scale,cubic.b2], trans]; l.cubic.b3 _ Complex.Add[Complex.Mul[scale,cubic.b3], trans]; }; do: FitStateUtils.TrajProc = {FitStateUtils.ForAllLinks[handle.traj,xform]}; [] _ do[handle.traj]; IF all THEN FitStateUtils.ForAllOtherTrajs[handle,do]; }; nodes => { xform: FitStateUtils.SampleProc = {IF s.isNode THEN [] _ xformSample[s]}; do: FitStateUtils.SListProc = {FitStateUtils.ForAllSamples[handle.slist,xform]}; [] _ do[handle.slist]; IF all THEN FitStateUtils.ForAllOtherSLists[handle,do]; }; cusps => { xform: FitStateUtils.SampleProc = {IF s.isCusp THEN [] _ xformSample[s]}; do: FitStateUtils.SListProc = {FitStateUtils.ForAllSamples[handle.slist,xform]}; [] _ do[handle.slist]; IF all THEN FitStateUtils.ForAllOtherSLists[handle,do]; }; contour => { XFormData[handle, scale, trans, samples, all]; XFormData[handle, scale, trans, links, all]; }; ENDCASE => ERROR; }; AddSample: PUBLIC PROC[handle: Handle, x,y: REAL] = { IF Complex.Abs[Complex.Sub[[x,y],handle.slist.header.prev.xy]]>handle.minDist THEN { handle.slist.selectedSample _ handle.slist.header; InsertBeforeSample[handle, x,y]; }; }; RemoveSample: PUBLIC PROC[handle: Handle] = { IF handle.slist#NIL AND handle.slist.selectedSample # handle.slist.header THEN { sample: SampleHandle _ handle.slist.selectedSample; handle.slist.selectedSample _ sample.next; IF handle.slist.first=sample THEN handle.slist.first _ sample.next; IF handle.slist.last=sample THEN handle.slist.last _ sample.next; sample.prev.next _ sample.next; sample.next.prev _ sample.prev; sample.next _ sample.prev _ NIL; }; }; InsertBeforeSample: PUBLIC PROC[handle: Handle, x,y: REAL] = { IF handle.slist#NIL THEN { s: SampleHandle _ handle.slist.selectedSample; new: SampleHandle _ NEW[FitBasic.Sample]; new.xy _ [x,y]; new.prev _ s.prev; new.next _ s; s.prev _ new; new.prev.next _ new; handle.slist.selectedSample _ new; }; }; StartSamples: PUBLIC PROC[handle: Handle, x,y: REAL] = { ResetData[handle, samples]; InsertBeforeSample[handle, x,y]; }; AddLink: PUBLIC PROC[handle: Handle, b: Cubic.Bezier] = { new: LinkHandle _ NEW[FitBasic.Link]; new.cubic _ b; IF handle.traj.links=NIL THEN { handle.traj.links _ new; handle.traj.lastLink _ new; } ELSE { handle.traj.lastLink.next _ new; new.prev _ handle.traj.lastLink; handle.traj.lastLink _ new; }; }; AddNode: PUBLIC PROC[handle: Handle, index: NAT, tan: Vec _ [0,0]] = {OPEN handle^; i:NAT _ 0; FOR s: SampleHandle _ slist.header.next, s.next UNTIL s=slist.header DO IF i=index THEN {s.isNode _ TRUE; s.tangent _ tan; RETURN}; i_i+1; ENDLOOP; }; DeleteNode: PUBLIC PROC[handle: Handle, index: NAT] = {OPEN handle^; i:NAT _ 0; FOR s: SampleHandle _ slist.header.next, s.next UNTIL s=slist.header DO IF i=index THEN {[] _ ResetNode[s]; EXIT}; i_i+1; ENDLOOP; }; ResetNode: FitStateUtils.SampleProc = { s.isNode _ s.isCusp _ FALSE; s.tangent _ [0,0]; }; AddCusp: PUBLIC PROC[handle: Handle, index: NAT, tanIn,tanOut: Vec _ [0,0]] = {OPEN handle^; i:NAT _ 0; FOR s: SampleHandle _ slist.header.next, s.next UNTIL s=slist.header DO IF i=index THEN { s.isCusp _ s.isNode _ TRUE; s.tangent _ tanIn; s.tanOut _ tanOut; RETURN}; i_i+1; ENDLOOP; }; DeleteCusp: PUBLIC PROC[handle: Handle, index: NAT] = {OPEN handle^; i:NAT _ 0; FOR s: SampleHandle _ slist.header.next, s.next UNTIL s=slist.header DO IF i=index THEN {[] _ ResetCusp[s]; EXIT}; i_i+1; ENDLOOP; }; ResetCusp: FitStateUtils.SampleProc = { s.isCusp _ s.isNode _ FALSE; s.tangent _ s.tanOut _ [0,0]; }; NewContour: PUBLIC PROC[handle: Handle] = { IF handle.otherContours = NIL THEN handle.otherContours _ LIST[[handle.traj, handle.slist]] ELSE { p: LIST OF Contour _ handle.otherContours; UNTIL p.rest = NIL DO p _ p.rest ENDLOOP; p.rest _ LIST[[handle.traj, handle.slist]]; }; handle.slist _ NEW[FitBasic.SList _ NewSList[]]; handle.traj _ NEW[FitBasic.Traj]; }; NextContour: PUBLIC PROC[handle: Handle] = { IF handle.otherContours # NIL THEN { p: LIST OF Contour _ handle.otherContours; ts: Contour _ handle.otherContours.first; handle.otherContours.first _ [handle.traj, handle.slist]; [handle.traj, handle.slist] _ ts; UNTIL p.rest = NIL DO p _ p.rest ENDLOOP; p.rest _ handle.otherContours; -- make it circular for a few microseconds p _ p.rest; handle.otherContours _ p.rest; p.rest _ NIL; } }; CurrentNodes: PUBLIC PROC [handle: Handle] RETURNS[nodes: Seq.NatSequence, tangents: Seq.ComplexSequence] = { i,n:NAT _ 0; count: FitStateUtils.SampleProc = {IF s.isNode THEN n_n+1}; copy: FitStateUtils.SampleProc = { IF s.isNode THEN {nodes[n] _ i; tangents[n] _ s.tangent; n_n+1}; i_i+1; }; FitStateUtils.ForAllSamples[handle.slist,count]; nodes _ NEW[Seq.NatSequenceRec[n]]; tangents _ NEW[Seq.ComplexSequenceRec[n]]; i _ n _ 0; FitStateUtils.ForAllSamples[handle.slist,copy]; }; CurrentSamples: PUBLIC PROC[handle: Handle] RETURNS [z: Seq.ComplexSequence] = { i,n:NAT _ 0; count: FitStateUtils.SampleProc = {n_n+1}; copy: FitStateUtils.SampleProc = { z[i] _ s.xy; i_i+1; }; FitStateUtils.ForAllSamples[handle.slist,count]; z _ NEW[Seq.ComplexSequenceRec[n]]; i _ 0; FitStateUtils.ForAllSamples[handle.slist,copy]; }; CurrentCusps: PUBLIC PROC[handle: Handle] RETURNS[cusps: Seq.NatSequence, tangents: Seq.ComplexSequence] = {OPEN handle^; i,n:NAT _ 0; count: FitStateUtils.SampleProc = {IF s.isCusp THEN n_n+1}; copy: FitStateUtils.SampleProc = { IF s.isCusp THEN { cusps[n] _ i; tangents[2*n] _ s.tangent; tangents[2*n+1] _ s.tanOut; n_n+1; }; i_i+1; }; FitStateUtils.ForAllSamples[handle.slist,count]; cusps _ NEW[Seq.NatSequenceRec[n]]; tangents _ NEW[Seq.ComplexSequenceRec[2*n]]; i _ n _ 0; FitStateUtils.ForAllSamples[handle.slist,copy]; }; EnumerateLinks: PUBLIC PROC[handle: Handle, newContour: PROC[x,y: REAL], newCubic: PROC[c: Cubic.Bezier]] = { trajProc: FitStateUtils.TrajProc = { newContour[traj.links.cubic.b0.x, traj.links.cubic.b0.y]; FitStateUtils.ForAllLinks[traj,callCubic]; }; callCubic: FitStateUtils.LinkProc = {newCubic[l.cubic]}; --there's a defaulted return[false] FitStateUtils.ForAllTrajs[handle, trajProc]; }; EnumerateSamples: PUBLIC PROC[handle: Handle, newContour: PROC[x,y: REAL], newSample: PROC[x,y: REAL]] = { first: BOOLEAN _ TRUE; slistProc: FitStateUtils.SListProc = { first _ TRUE; FitStateUtils.ForAllSamples[slist,callNewSample]; }; callNewSample: FitStateUtils.SampleProc = { IF first THEN {newContour[s.xy.x, s.xy.y]; first _ FALSE} ELSE newSample[s.xy.x, s.xy.y]; }; FitStateUtils.ForAllSLists[handle, slistProc]; }; CountContours: PUBLIC PROC[handle: Handle] RETURNS [INT] = { i: INT _ 1; FOR p: LIST OF Contour _ handle.otherContours, p.rest UNTIL p=NIL DO i_i+1 ENDLOOP; RETURN[i] }; END.