<<>> <> <> <> DIRECTORY G3dBasic, G3dDraw, G3dFunction, G3dMatrix, G3dSpline, G3dTube, G3dVector, Imager, ImplicitDefs, ImplicitTube, RealFns, ImplicitSurface; ImplicitTubeImpl: CEDAR MONITOR IMPORTS G3dDraw, G3dFunction, G3dSpline, G3dTube, G3dVector, RealFns, ImplicitSurface EXPORTS ImplicitTube ~ BEGIN Pair: TYPE ~ G3dBasic.Pair; Triple: TYPE ~ G3dBasic.Triple; Matrix: TYPE ~ G3dMatrix.Matrix; Tube: TYPE ~ G3dTube.Tube; TubeProc: TYPE ~ G3dTube.TubeProc; XSection: TYPE ~ G3dTube.XSection; NearSegment: TYPE ~ G3dVector.NearSegment; Context: TYPE ~ Imager.Context; Sample: TYPE ~ ImplicitDefs.Sample; DistanceMode: TYPE ~ ImplicitDefs.DistanceMode; ValueProc: TYPE ~ ImplicitDefs.ValueProc; PI: REAL ~ 3.1415926535; PrepareTube: PUBLIC PROC [tube: Tube, distanceMode: DistanceMode, measureMode: ATOM] ~ { IF NOT tube.xSectionsValid THEN G3dTube.MakeXSections[tube, FALSE, TRUE]; IF NOT tube.lengthsValid THEN G3dTube.SetLengths[tube]; IF NOT tube.planeValid THEN G3dTube.SetPlanes[tube]; SELECT measureMode FROM $Sum => G3dTube.SetDescendantRadii[tube, IF distanceMode=inverse THEN linear ELSE square]; ENDCASE; }; StartPoint: PUBLIC PROC [ tube: Tube, valueProc: ValueProc, threshold: REAL ¬ 1.0, measureMode: ATOM ¬ $Unspecified, spread: REAL ¬ 0.75, clientData: REF ANY ¬ NIL] RETURNS [tt: Triple] ~ { t: REAL ~ 0.5; pIn, pOut, v: Triple; factor: REAL; factor ¬ SELECT measureMode FROM $Segment => 2.0/spread, --($Sum)-- ENDCASE => 1.5; -- 1.5 instead of 1.0, for some fudge pIn ¬ G3dSpline.Position[tube.spline, t]; v ¬ G3dSpline.Velocity[tube.spline, t]; v ¬ G3dVector.Unit[G3dVector.Ortho[v]]; pOut ¬ G3dVector.ScaleRay[[pIn, v], factor*G3dTube.Radius[tube, t]]; tt ¬ ImplicitSurface.SurfacePoint[pIn, pOut, valueProc, threshold, clientData]; }; SampleTube: PUBLIC PROC [ q: Triple, tube: Tube, measureMode: ATOM, distanceMode: DistanceMode, tolerance, spread: REAL] RETURNS [sample: Sample] ~ { s: Sample ¬ sample ¬ SampleTubeBranch[q, tube, measureMode, distanceMode, tolerance, spread]; nearest: Tube ¬ G3dTube.NearestTube[q, tube].tube; IF nearest.nearSpline.distance # 0.0 THEN { -- useful sample information: v: Triple ~ G3dVector.Sub[q, nearest.nearSpline.point]; radius: REAL ~ G3dTube.Radius[nearest, nearest.nearSpline.t]; d: REAL ~ nearest.nearSpline.distance; sample.near ¬ G3dVector.ScaleRay[[nearest.nearSpline.point, v], radius/d]; } ELSE sample.near ¬ nearest.nearSpline.point; }; SampleTubeBranch: PUBLIC PROC [ q: Triple, tube: Tube, measureMode: ATOM, distanceMode: DistanceMode, tolerance, spread: REAL] RETURNS [Sample] ~ { segment: Sample ¬ SampleTubeSegment[q, tube, measureMode, distanceMode, tolerance, spread]; branches: Sample ¬ SampleTubeBranches[q, tube, measureMode, distanceMode, tolerance, spread]; <> RETURN[IF branches.value > segment.value THEN branches ELSE segment]; }; <> <> <> <> <> <<~ {>> <> <> <<};>> <<>> SampleTubeBranches: PUBLIC PROC [ q: Triple, tube: Tube, measureMode: ATOM, distanceMode: DistanceMode, tolerance, spread: REAL] RETURNS [sample: Sample] ~ { tubeProc: TubeProc ~ { s: Sample ¬ SampleTubeBranch[q, tube, measureMode, distanceMode, tolerance, spread]; IF s.value > sample.value THEN sample ¬ s; samples[nBranches] ¬ s; nBranches ¬ nBranches+1; }; nBranches: NAT ¬ 0; samples: ARRAY [0..50) OF Sample; G3dTube.ApplyToBranches[tube, tubeProc]; sample.value ¬ 0.0; SELECT measureMode FROM $Segment => { FOR n: NAT IN [0..nBranches) DO s: Sample ¬ samples[n]; FOR nn: NAT IN (n..nBranches) DO ss: Sample ¬ samples[nn]; IF s.near = ss.near THEN sample.value ¬ sample.value+s.value ELSE { aveRadius: REAL ¬ 0.5*(s.radius+ss.radius); aveDistance: REAL ¬ 0.5*(s.distance+ss.distance); aveRatio: REAL ¬ Ratio[aveDistance, aveRadius, spread]; SELECT aveRatio FROM < 2.0 => { near: NearSegment ¬ G3dVector.NearestToSegment[s.near, ss.near, q]; lineDistance: REAL ¬ SELECT near.w0 FROM 0.0 => ss.distance, 1.0 => s.distance, ENDCASE => G3dVector.Distance[near.point, q]; lineValue: REAL ¬ G3dFunction.Wyvill[Ratio[lineDistance, aveRadius, spread]]; IF aveRatio < 1.0 THEN sample.value ¬ sample.value+lineValue ELSE { f: REAL ¬ 2.0-aveRatio; sample.value ¬ sample.value+f*lineValue+(1.-f)*(s.value+ss.value); }; }; ENDCASE => sample.value ¬ sample.value+s.value+ss.value; }; ENDLOOP; ENDLOOP; IF nBranches > 2 THEN sample.value ¬ 2.0*sample.value/(nBranches*(nBranches-1)); }; --($Sum)-- ENDCASE => FOR n: NAT IN [0..nBranches) DO sample.value ¬ sample.value+samples[n].value; ENDLOOP; }; SampleTubeSegment: PUBLIC PROC [ q: Triple, tube: Tube, measureMode: ATOM, distanceMode: DistanceMode, tolerance, spread: REAL] RETURNS [sample: Sample] ~ { SetBasics: PROC ~ { tube.nearSpline ¬ G3dSpline.NearestPoint[q, tube.spline, 0.0, 1.0, tolerance]; sample.near ¬ tube.nearSpline.point; sample.vector ¬ G3dVector.Sub[sample.near, q]; sample.radius ¬ G3dTube.Radius[tube, tube.nearSpline.t]; sample.squareDistance ¬ G3dVector.Square[sample.vector]; }; SetDistance: PROC ~ { sample.distance ¬ RealFns.SqRt[sample.squareDistance]; sample.distanceSet ¬ TRUE; }; sample.refAny ¬ tube; SELECT measureMode FROM $Segment => { SetBasics[]; SetDistance[]; sample.ratio ¬ Ratio[sample.distance, sample.radius, spread]; sample.value ¬ G3dFunction.Wyvill[sample.ratio]; }; --($Sum)-- ENDCASE => { SetBasics[]; IF distanceMode = inverse THEN SetDistance[]; sample.value ¬ IF distanceMode = inverse THEN sample.radius/MAX[0.0001, sample.distance] ELSE sample.radius*sample.radius/MAX[0.0001, sample.squareDistance]; }; }; Ratio: PROC [distance, radius, spread: REAL] RETURNS [REAL] ~ { RETURN[IF radius = 0.0 THEN 2.0 ELSE spread*(distance-radius)/radius]; }; TextureOfTube: PUBLIC PROC [q: Triple, tube: Tube] RETURNS [texture: Pair] ~ { nearest: Tube ¬ G3dTube.NearestTube[q, tube, FALSE].tube; xSection: XSection ¬ G3dTube.GetXSection[nearest, nearest.nearSpline.t]; vector: Triple ¬ G3dVector.Sub[q, xSection.frame.position]; xProj: Triple ¬ G3dVector.Project[vector, xSection.frame.triad.n]; yProj: Triple ¬ G3dVector.Project[vector, xSection.frame.triad.b]; proj: Triple ¬ G3dVector.Unit[G3dVector.Add[xProj, yProj]]; texture.x ¬ G3dVector.AngleBetween[proj, xSection.frame.triad.n, FALSE]/PI; texture.y ¬ SELECT nearest.nearSpline.t FROM 0.0 => tube.length0- G3dVector.Length[G3dVector.Project[vector, xSection.frame.triad.v]], 1.0 => tube.length1+ G3dVector.Length[G3dVector.Project[vector, xSection.frame.triad.v]], ENDCASE => nearest.length0+xSection.length; }; DiagramTube: PUBLIC PROC [ context: Context, view: Matrix, viewport: G3dMatrix.Viewport, q: Triple, tube: Tube, measureMode: ATOM, distanceMode: DistanceMode, tolerance, spread: REAL] ~ { Info: TYPE ~ RECORD [tube: Tube, branches: BOOL, sample: Sample]; InfoTubeBranch: PROC [q: Triple, tube: Tube] RETURNS [Info] ~ { segment: Info ¬ InfoTubeSegment[q, tube]; branches: Info ¬ InfoTubeBranches[q, tube]; RETURN[IF branches.sample.value > segment.sample.value THEN branches ELSE segment]; }; InfoTubeBranches: PROC [q: Triple, tube: Tube] RETURNS [info: Info] ~ { s: Sample ¬SampleTubeSegment[q, tube, measureMode, distanceMode, tolerance, spread]; RETURN[[tube, TRUE, s]]; }; InfoTubeSegment: PROC [q: Triple, tube: Tube] RETURNS [Info] ~ { s: Sample ¬SampleTubeSegment[q, tube, measureMode, distanceMode, tolerance, spread]; RETURN[[tube, FALSE, s]]; }; IF tube # NIL THEN SELECT measureMode FROM $Segment => { info: Info ¬ InfoTubeBranch[q, tube]; IF info.branches THEN { nBranches: NAT ¬ G3dTube.NBranches[info.tube]+1; FOR n: NAT IN [0..nBranches) DO b0: Tube ¬ G3dTube.GetBranch[info.tube, n]; p0: Triple ¬ G3dSpline.NearestPoint[q, b0.spline, 0.0, 1.0, tolerance].point; FOR nn: NAT IN (n..nBranches) DO b1: Tube ¬ G3dTube.GetBranch[info.tube, nn]; p1: Triple ¬ G3dSpline.NearestPoint[q, b1.spline, 0.0, 1.0, tolerance].point; x: Triple ¬ G3dVector.NearestToSegment[p0, p1, q].point; G3dDraw.Segment[context, p0, p1, view, viewport, solid]; G3dDraw.Segment[context, q, x, view, viewport, solid]; G3dDraw.Segment[context, q, p0, view, viewport, dotted]; G3dDraw.Segment[context, q, p1, view, viewport, dotted]; ENDLOOP; ENDLOOP; } ELSE { x: Triple ¬ G3dTube.NearestTube[q, info.tube].tube.nearSpline.point; G3dDraw.Segment[context, q, x, view, viewport, solid]; }; }; ENDCASE; }; END. .. TextureOfTube: PUBLIC PROC [q: Triple, tube: Tube] RETURNS [texture: Pair] ~ { Info: TYPE ~ RECORD [inverseDistance: REAL, texture: Pair]; tubeProc: TubeProc ~ { xSection: XSection ¬ G3dTube.GetXSection[tube, tube.nearSpline.t]; vector: Triple ¬ G3dVector.Sub[q, frame.position]; xProj: Triple ¬ G3dVector.Project[vector, xSection.frame.triad.n]; yProj: Triple ¬ G3dVector.Project[vector, xSection.frame.triad.b]; proj: Triple ¬ G3dVector.Unit[G3dVector.Add[xProj, yProj]]; tx: REAL ¬ G3dVector.AngleBetween[proj, xSection.frame.triad.n, FALSE]/PI; ty: REAL ¬ SELECT tube.nearSpline.t FROM 0.0 => tube.length0- G3dVector.Length[G3dVector.Project[vector, xSection.frame.triad.v]], 1.0 => tube.length1+ G3dVector.Length[G3dVector.Project[vector, xSection.frame.triad.v]], ENDCASE => tube.length0+frame.length; info[nBranches] ¬ [1.0/tube.nearSpline.distance, [tx, ty]]; nBranches ¬ nBranches+1; }; nBranches: NAT ¬ 0; info: ARRAY [0..50) OF Info; nearest: Tube ¬ G3dTube.NearestTube[q, tube, FALSE]; G3dTube.ApplyToSiblings[nearest, tubeProc]; IF nBranches = 1 THEN RETURN[info[0].texture] ELSE { inverseDistanceSum: REAL ¬ 0.0; texture ¬ [0.0, 0.0]; FOR n: NAT IN [0..nBranches) DO inverseDistanceSum ¬ inverseDistanceSum+info[n].inverseDistance; ENDLOOP; FOR n: NAT IN [0..nBranches) DO texture ¬ Vector2.Add[texture, Vector2.Mul[info[n].texture, info[n].inverseDistance]]; ENDLOOP; texture ¬ Vector2.Div[texture, inverseDistanceSum]; }; }; ValueOfTubeBranches: PUBLIC PROC [ q: Triple, tube: Tube, distanceMode: DistanceMode, tolerance: REAL ¬ 0.0] RETURNS [sample: Sample] ~ { nBranches: NAT ¬ 0; vSum: Triple ¬ [0.0, 0.0, 0.0]; maxValue: REAL ¬ -100000.0; vectors: ARRAY [0..50) OF Triple; samples: ARRAY [0..50) OF Sample; weight: BOOL ¬ distanceMode = wtInverse OR distanceMode = wtInvSq; tubeProc: G3dTube.TubeProc ~ { IF tube # NIL THEN { s: Sample ¬ ValueOfTubeBranch[q, tube, distanceMode, tolerance]; IF s.value > maxValue THEN {maxValue ¬ s.value; sample ¬ s}; IF (distanceMode=wtInverse OR distanceMode=wtInvSq) AND NOT s.distanceSet THEN { s.distance ¬ Real.SqRt[s.squareDistance]; s.distanceSet ¬ TRUE; }; samples[nBranches] ¬ s; nBranches ¬ nBranches+1; }; }; G3dTube.ApplyToBranches[tube, tubeProc]; SELECT distanceMode FROM wtInverse, wtInvSq => { <> FOR n: NAT IN [0..nBranches) DO v: Triple ¬ G3dVector.Sub[samples[n].nearest, q]; vectors[n] ¬ G3dVector.Div[v, samples[n].distance]; vSum ¬ G3dVector.Add[vSum, vectors[n]]; ENDLOOP; vSum ¬ G3dVector.Unit[vSum]; FOR n: NAT IN [0..nBranches) DO f: REAL ~ 0.5*(1.0-G3dVector.Dot[vSum, vectors[n]]); sample.value ¬ sample.value+f*samples[n].value; ENDLOOP; }; ENDCASE => { FOR n: NAT IN [0..nBranches) DO sample.value ¬ sample.value+samples[n].value; ENDLOOP; }; }; ValueOfTubeSegment: PUBLIC PROC [ q: Triple, tube: Tube, distanceMode: DistanceMode, tolerance: REAL ¬ 0.0] RETURNS [s: Sample] ~ { radius: REAL ~ G3dTube.Radius[tube, tube.nearSpline.t]; s ¬ ImplicitValue.ValueOfPoint[q, tube.nearSpline.point, radius, distanceMode, threshold]; }; mode: SampleMode.integral => { IF tube.length = 0.0 THEN G3dTube.SetSectionLengths[tube]; { Val: PROC RETURNS [REAL] ~ { distance: REAL ¬ G3dVector.Length[[diff[0][0], diff[0][1], diff[0][2]]]; RETURN[Strength[Ratio[distance, radius, mode.spread]]]; }; radius: REAL ¬ tube.r0; diff: Matrix ¬ G3dMatrix.ObtainMatrix[]; nSteps: NAT ¬ Real.Round[tube.length/mode.stepSize]; dRadius: REAL ¬ (tube.r1-tube.r0)/REAL[MAX[1, nSteps]]; diff^ ¬ tube.spline^; diff[3] ¬ [diff[3][0]-q.x, diff[3][1]-q.y, diff[3][2]-q.z, 0.0]; diff ¬ G3dSpline.ForwardDifference[diff, nSteps]; sample.value ¬ Val[]; FOR n: NAT IN [0..nSteps) DO radius ¬ radius+dRadius; FOR j: NAT IN [0..3) DO diff[0][j] ¬ diff[0][j]+diff[1][j]; diff[1][j] ¬ diff[1][j]+diff[2][j]; diff[2][j] ¬ diff[2][j]+diff[3][j]; ENDLOOP; sample.value ¬ sample.value+Val[]; ENDLOOP; G3dMatrix.ReleaseMatrix[diff]; }; };