<> <> <> <> DIRECTORY Graphics, RealFns, Rope, SV2d, SV3d, SVAngle, <> SVMappings, SVModelTypes, SVPolygon2d; SVMappingsImpl: PROGRAM IMPORTS RealFns, SVAngle, --SVDraw, --SVPolygon2d EXPORTS SVMappings = BEGIN Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; Polygon: TYPE = SV2d.Polygon; SpaceFunction: TYPE = REF SpaceFunctionObj; SpaceFunctionObj: TYPE = SVModelTypes.SpaceFunctionObj; Vector: TYPE = SV3d.Vector; Vector2d: TYPE = SV2d.Vector2d; Artwork: TYPE = SVModelTypes.Artwork; PDisk: TYPE = REF PDiskObj; PDiskObj: TYPE = SVModelTypes.PDiskObj; Tube: TYPE = REF TubeObj; TubeObj: TYPE = SVModelTypes.TubeObj; Box: TYPE = REF BoxObj; BoxObj: TYPE = SVModelTypes.BoxObj; Disk: TYPE = REF DiskObj; DiskObj: TYPE = SVModelTypes.DiskObj; Pi: REAL = 3.14159; PiUnder180: REAL = 180.0/Pi; PiOver180: REAL = Pi/180.0; CartesianToPolar: PUBLIC PROC [x, y: REAL] RETURNS [r, theta: REAL] = { r _ RealFns.SqRt[x*x + y*y]; theta _ SVAngle.ArcTan[y,x]; }; PolarToCartesian: PUBLIC PROC [r, theta: REAL] RETURNS [x, y: REAL] = { x _ r*RealFns.CosDeg[theta]; y _ r*RealFns.SinDeg[theta]; }; CreateFunction: PUBLIC PROC [scalars: Point3d] RETURNS [sf: SpaceFunction] = { sf _ NEW[SpaceFunctionObj _ [scalars]]; }; <> <> <<};>> <> <> <<};>> CreatePDisk: PUBLIC PROC [r: REAL, origin: Point2d] RETURNS [pdisk: PDisk] = { pdisk _ NEW[PDiskObj _ [r, origin]]; }; DrawPDisk: PUBLIC PROC [dc: Graphics.Context, pdisk: PDisk] = { <> }; CreateTube: PUBLIC PROC [R: REAL, H: REAL] RETURNS [tube: Tube] = { tubePoly: Polygon _ SVPolygon2d.CreatePoly[4]; -- a poly of [theta, h] pairs. tubePoly _ SVPolygon2d.AddPolyPoint[tubePoly, [-180, H/2]]; tubePoly _ SVPolygon2d.AddPolyPoint[tubePoly, [180, H/2]]; tubePoly _ SVPolygon2d.AddPolyPoint[tubePoly, [180, -H/2]]; tubePoly _ SVPolygon2d.AddPolyPoint[tubePoly, [-180, -H/2]]; tube _ NEW[TubeObj _ [R, H, tubePoly]]; }; CreateBox: PUBLIC PROC [x, y, z: REAL] RETURNS [box: Box] = { box _ NEW[BoxObj]; box.x _ x; box.halfX _ x/2; box.y _ y; box.halfY _ y/2; box.threeHalvesY _ 3*box.halfY; box.z _ z; box.halfZ _ z/2.0; FOR i: NAT IN [1..6] DO box.faces[i] _ SVPolygon2d.CreatePoly[4]; -- a poly of [x,y] pairs. ENDLOOP; <> box.faces[1] _ SVPolygon2d.AddPolyPoint[box.faces[1], [-(box.x+box.z), -box.halfY]]; box.faces[1] _ SVPolygon2d.AddPolyPoint[box.faces[1], [-(box.x+box.z), box.halfY]]; box.faces[1] _ SVPolygon2d.AddPolyPoint[box.faces[1], [-box.x, box.halfY]]; box.faces[1] _ SVPolygon2d.AddPolyPoint[box.faces[1], [-box.x, -box.halfY]]; box.faces[2] _ SVPolygon2d.AddPolyPoint[box.faces[2], [-box.x, -box.halfY]]; box.faces[2] _ SVPolygon2d.AddPolyPoint[box.faces[2], [-box.x, box.halfY]]; box.faces[2] _ SVPolygon2d.AddPolyPoint[box.faces[2], [0, box.halfY]]; box.faces[2] _ SVPolygon2d.AddPolyPoint[box.faces[2], [0, -box.halfY]]; box.faces[3] _ SVPolygon2d.AddPolyPoint[box.faces[3], [0, -box.halfY]]; box.faces[3] _ SVPolygon2d.AddPolyPoint[box.faces[3], [0, box.halfY]]; box.faces[3] _ SVPolygon2d.AddPolyPoint[box.faces[3], [box.z, box.halfY]]; box.faces[3] _ SVPolygon2d.AddPolyPoint[box.faces[3], [box.z, -box.halfY]]; box.faces[4] _ SVPolygon2d.AddPolyPoint[box.faces[4], [box.z, -box.halfY]]; box.faces[4] _ SVPolygon2d.AddPolyPoint[box.faces[4], [box.z, box.halfY]]; box.faces[4] _ SVPolygon2d.AddPolyPoint[box.faces[4], [(box.x+box.z), box.halfY]]; box.faces[4] _ SVPolygon2d.AddPolyPoint[box.faces[4], [(box.x+box.z), -box.halfY]]; box.faces[5] _ SVPolygon2d.AddPolyPoint[box.faces[5], [-box.x, box.halfY]]; box.faces[5] _ SVPolygon2d.AddPolyPoint[box.faces[5], [-box.x, box.halfY + box.z]]; box.faces[5] _ SVPolygon2d.AddPolyPoint[box.faces[5], [0, box.halfY + box.z]]; box.faces[5] _ SVPolygon2d.AddPolyPoint[box.faces[5], [0, box.halfY]]; box.faces[6] _ SVPolygon2d.AddPolyPoint[box.faces[6], [-box.x, -(box.halfY + box.z)]]; box.faces[6] _ SVPolygon2d.AddPolyPoint[box.faces[6], [-box.x, -box.halfY]]; box.faces[6] _ SVPolygon2d.AddPolyPoint[box.faces[6], [0, -box.halfY]]; box.faces[6] _ SVPolygon2d.AddPolyPoint[box.faces[6], [0, -(box.halfY + box.z)]]; }; Point3dToTubePoint: PUBLIC PROC [point3d: Point3d] RETURNS [tubePoint: Point2d] = { <> tubePoint[2] _ point3d[2]; tubePoint[1] _ SVAngle.ArcTan[-point3d[3], point3d[1]]; }; TubePointToPoint3d: PUBLIC PROC [tubePoint: Point2d, assembly: REF ANY] RETURNS [point3d: Point3d] = {}; <> ImageToTube: PUBLIC PROC [imagePoint: Point2d, data: REF ANY] RETURNS [surfacePoint: Point2d, onSurf: BOOL] = { <> <> <> tube: Tube _ NARROW[data]; surfacePoint[2] _ imagePoint[2]; surfacePoint[1] _ (imagePoint[1]/tube.R)*PiUnder180; onSurf _ TRUE; }; TubeToImage: PUBLIC PROC [surfacePoint: Point2d, data: REF ANY] RETURNS [imagePoint: Point2d, onSurf: BOOL] = { <> <> tube: Tube _ NARROW[data]; imagePoint[1] _ (tube.R*surfacePoint[1])*PiOver180; imagePoint[2] _ surfacePoint[2]; onSurf _ TRUE; }; ImageToTopDisk: PUBLIC PROC [u,v: REAL, disk: Disk] RETURNS [r, theta: REAL] = { <> [r, theta] _ CartesianToPolar[u,v-disk.R-disk.halfH]; }; TopDiskToImage: PUBLIC PROC [r, theta: REAL, disk: Disk] RETURNS [u,v: REAL] = { [u,v] _ PolarToCartesian[r, theta]; v _ v + disk.R + disk.halfH; }; ImageDiskToTopDiskBoundary: PUBLIC PROC [pdisk: PDisk, disk: Disk] RETURNS [R, halfH: REAL] = { R _ disk.R; halfH _ disk.halfH; }; TopDiskBoundaryToImageDisk: PUBLIC PROC [R, halfH: REAL, disk: Disk] RETURNS [pdisk: PDisk] = { pdisk _ NEW[PDiskObj _ [R, [0, halfH + R]]]; }; ImageToBottomDisk: PUBLIC PROC [u,v: REAL, disk: Disk] RETURNS [r, theta: REAL] = { <> [r, theta] _ CartesianToPolar[u,v+disk.R+disk.halfH]; }; BottomDiskToImage: PUBLIC PROC [r, theta: REAL, disk: Disk] RETURNS [u,v: REAL] = { [u,v] _ PolarToCartesian[r, theta]; v _ v - disk.R - disk.halfH; }; ImageDiskToBottomDiskBoundary: PUBLIC PROC [pdisk: PDisk, disk: Disk] RETURNS [R, halfH: REAL] = { R _ disk.R; halfH _ disk.halfH; }; BottomDiskBoundaryToImageDisk: PUBLIC PROC [R, halfH: REAL, disk: Disk] RETURNS [pdisk: PDisk] = { pdisk _ NEW[PDiskObj _ [R, [0, -halfH -R]]]; }; Point3dToDiskPoint: PUBLIC PROC [point3d: Point3d] RETURNS [r, theta: REAL] = { <> [r, theta] _ CartesianToPolar[point3d[1], point3d[2]]; }; DiskPointToPoint3d: PUBLIC PROC [r, theta: REAL, assembly: REF ANY] RETURNS [point3d: Point3d] = {}; <> <> <> <> <> <> <> <> <<-(sz+sx) <= x < -sx THEN Rectangle 1.>> <<-sx <= x <= 0 THEN Rectangle 2.>> <<0 < x <= sz THEN Rectangle 3.>> <> <> <> <> IndicesOfMax: PRIVATE PROC [v: Vector] RETURNS [indices: ARRAY[1..3] OF NAT, negArray: ARRAY[1..3] OF BOOL] = { <> temp: REAL; tempIndex: NAT; IF v[1] < 0 THEN {negArray[1] _ TRUE; v[1] _ -v[1]} ELSE negArray[1] _ FALSE; IF v[2] < 0 THEN {negArray[2] _ TRUE; v[2] _ -v[2]} ELSE negArray[2] _ FALSE; IF v[3] < 0 THEN {negArray[3] _ TRUE; v[3] _ -v[3]} ELSE negArray[3] _ FALSE; indices _ [1,2,3]; IF v[1] < v[2] THEN{ temp _ v[1]; v[1] _ v[2]; v[2] _ temp; tempIndex _ indices[1]; indices[1] _ indices[2]; indices[2] _ tempIndex}; IF v[2] < v[3] THEN { temp _ v[2]; v[2] _ v[3]; v[3] _ temp; tempIndex _ indices[2]; indices[2] _ indices[3]; indices[3] _ tempIndex}; IF v[1] < v[2] THEN { temp _ v[1]; v[1] _ v[2]; v[2] _ temp; tempIndex _ indices[1]; indices[1] _ indices[2]; indices[2] _ tempIndex}; }; BoxOrthogonalOInverse: PUBLIC PROC [point3d: Point3d, normal: Vector, box: Box] RETURNS [boxPoint: Point2d, hit: BOOL] = { <> indices: ARRAY[1..3] OF NAT; negArray: ARRAY[1..3] OF BOOL; [indices, negArray] _ IndicesOfMax[normal]; <> <> SELECT indices[1] FROM 1 => IF negArray[1] THEN {-- rectangle 1 of box = left side << y and z are of interest>> IF point3d[2] < -box.halfY OR point3d[2] > box.halfY OR point3d[3] < -box.halfZ OR point3d[3] > box.halfZ THEN RETURN [[0,0], FALSE]; boxPoint[2] _ point3d[2]; boxPoint[1] _ -(box.x+box.z) + point3d[3] + box.halfZ; } ELSE {-- rectangle 3 of box = right side <> IF point3d[2] < -box.halfY OR point3d[2] > box.halfY OR point3d[3] < -box.halfZ OR point3d[3] > box.halfZ THEN RETURN [[0,0], FALSE]; boxPoint[2] _ point3d[2]; boxPoint[1] _ -point3d[3] + box.halfZ; }; 2 => IF negArray[2] THEN {-- rectangle 6 of box = down side <> IF point3d[1] < -box.halfX OR point3d[1] > box.halfX OR point3d[3] < -box.halfZ OR point3d[3] > box.halfZ THEN RETURN [[0,0], FALSE]; boxPoint[1] _ point3d[1] + -box.halfX; boxPoint[2] _ point3d[3] -box.halfY -box.halfZ; } ELSE {-- rectangle 5 of box = up side IF point3d[1] < -box.halfX OR point3d[1] > box.halfX OR point3d[3] < -box.halfZ OR point3d[3] > box.halfZ THEN RETURN [[0,0], FALSE]; boxPoint[1] _ point3d[1] + -box.halfX; boxPoint[2] _ -point3d[3] + box.halfY + box.halfZ; }; 3 => IF negArray[3] THEN {-- rectangle 4 of box = back << x and y are of interest>> IF point3d[1] < -box.halfX OR point3d[1] > box.halfX OR point3d[2] < -box.halfY OR point3d[2] > box.halfY THEN RETURN [[0,0], FALSE]; boxPoint[2] _ point3d[2]; boxPoint[1] _ box.z - point3d[1] + box.halfX; } ELSE {-- rectangle 2 of box = front IF point3d[1] < -box.halfX OR point3d[1] > box.halfX OR point3d[2] < -box.halfY OR point3d[2] > box.halfY THEN RETURN [[0,0], FALSE]; boxPoint[2] _ point3d[2]; boxPoint[1] _ point3d[1] - box.halfX; }; ENDCASE => ERROR; hit _ TRUE; }; BoxPointToUnfoldedBoxPoint: PROC [boxPoint: Point3d, rect: NAT, pos: BOOL, box: Box] RETURNS [unfoldedBoxPoint: Point2d, hit: BOOL] = { SELECT rect FROM 1 => IF NOT pos THEN {-- rectangle 1 of box = left side <> IF boxPoint[2] < -box.halfY OR boxPoint[2] > box.halfY OR boxPoint[3] < -box.halfZ OR boxPoint[3] > box.halfZ THEN RETURN [[0,0], FALSE]; unfoldedBoxPoint[2] _ boxPoint[2]; unfoldedBoxPoint[1] _ -(box.x+box.z) + boxPoint[3] + box.halfZ; } ELSE {-- rectangle 3 of box = right side <> IF boxPoint[2] < -box.halfY OR boxPoint[2] > box.halfY OR boxPoint[3] < -box.halfZ OR boxPoint[3] > box.halfZ THEN RETURN [[0,0], FALSE]; unfoldedBoxPoint[2] _ boxPoint[2]; unfoldedBoxPoint[1] _ -boxPoint[3] + box.halfZ; }; 2 => IF NOT pos THEN {-- rectangle 6 of box = down side << x and z are of interest>> IF boxPoint[1] < -box.halfX OR boxPoint[1] > box.halfX OR boxPoint[3] < -box.halfZ OR boxPoint[3] > box.halfZ THEN RETURN [[0,0], FALSE]; unfoldedBoxPoint[1] _ boxPoint[1] + -box.halfX; unfoldedBoxPoint[2] _ boxPoint[3] -box.halfY -box.halfZ; } ELSE {-- rectangle 5 of box = up side IF boxPoint[1] < -box.halfX OR boxPoint[1] > box.halfX OR boxPoint[3] < -box.halfZ OR boxPoint[3] > box.halfZ THEN RETURN [[0,0], FALSE]; unfoldedBoxPoint[1] _ boxPoint[1] + -box.halfX; unfoldedBoxPoint[2] _ -boxPoint[3] + box.halfY + box.halfZ; }; 3 => IF NOT pos THEN {-- rectangle 4 of box = back <> IF boxPoint[1] < -box.halfX OR boxPoint[1] > box.halfX OR boxPoint[2] < -box.halfY OR boxPoint[2] > box.halfY THEN RETURN [[0,0], FALSE]; unfoldedBoxPoint[2] _ boxPoint[2]; unfoldedBoxPoint[1] _ box.z - boxPoint[1] + box.halfX; } ELSE {-- rectangle 2 of box = front IF boxPoint[1] < -box.halfX OR boxPoint[1] > box.halfX OR boxPoint[2] < -box.halfY OR boxPoint[2] > box.halfY THEN RETURN [[0,0], FALSE]; unfoldedBoxPoint[2] _ boxPoint[2]; unfoldedBoxPoint[1] _ boxPoint[1] - box.halfX; }; ENDCASE => ERROR; hit _ TRUE; }; VectorHitsSide: PROC [v: Vector2d, width, height: REAL] RETURNS [vertOrHoriz: NAT, positive: BOOL] = { <> yOverX: REAL; IF v[1] = 0 THEN {vertOrHoriz _ 2; positive _ v[2] > 0; RETURN}; yOverX _ v[2]/v[1]; IF v[1] < 0 THEN { IF v[2] > 0 THEN { IF -height/width <= yOverX AND yOverX <= 0 THEN RETURN[1, FALSE] ELSE RETURN[2, TRUE]; } ELSE { IF 0 <= yOverX AND yOverX <= height/width THEN RETURN[1, FALSE] ELSE RETURN[2, FALSE]; } } ELSE { IF v[2] > 0 THEN { IF 0 <= yOverX AND yOverX <= height/width THEN RETURN[1, TRUE] ELSE RETURN[2, TRUE]; } ELSE { IF -height/width <= yOverX AND yOverX <= 0 THEN RETURN[1, TRUE] ELSE RETURN[2, FALSE]; } }; }; -- end of VectorHitsSide RayHitsRect: PROC [v: Vector, rect: NAT, positive: BOOL, box: Box] RETURNS [point3d: Point3d] = { <> k, t: REAL; SELECT rect FROM 1 => { k _ box.halfX; IF NOT positive THEN k _ -k; IF v[1] = 0 THEN ERROR;-- this situation should be filtered out by VectorHitsSide. t _ k/v[1]; point3d _ [k, v[2]*t, v[3]*t]; }; 2 => { k _ box.halfY; IF NOT positive THEN k _ -k; IF v[2] = 0 THEN ERROR;-- this situation should be filtered out by VectorHitsSide. t _ k/v[2]; point3d _ [v[1]*t, k, v[3]*t]; }; 3 => { k _ box.halfZ; IF NOT positive THEN k _ -k; IF v[3] = 0 THEN ERROR;-- this situation should be filtered out by VectorHitsSide. t _ k/v[3]; point3d _ [v[1]*t, v[2]*t, k]; }; ENDCASE; }; BoxRadialOInverse: PUBLIC PROC [point3d: Point3d, normal: Vector, box: Box] RETURNS [boxPoint: Point2d, hit: BOOL] = { <> <> xyVert, zyVert, zxVert: NAT; xyPos, zyPos, zxPos: BOOL; boxPoint3d: Point3d; xScore, yScore, zScore: NAT; xScore _ yScore _ zScore _ 0; [xyVert, xyPos] _ VectorHitsSide[[point3d[1], point3d[2]], box.x, box.y]; IF xyVert = 1 THEN xScore _ xScore + 1 ELSE yScore _ yScore + 1; [zyVert, zyPos] _ VectorHitsSide[[point3d[3], point3d[2]], box.z, box.y]; IF zyVert = 1 THEN zScore _ zScore + 1 ELSE yScore _ yScore + 1; [zxVert, zxPos] _ VectorHitsSide[[point3d[3], point3d[1]], box.z, box.x]; IF zxVert = 1 THEN zScore _ zScore + 1 ELSE xScore _ xScore + 1; <> SELECT TRUE FROM xScore = 2 => { boxPoint3d _ RayHitsRect[point3d, 1, xyPos, box]; [boxPoint, hit] _ BoxPointToUnfoldedBoxPoint[boxPoint3d, 1, xyPos, box]; }; yScore = 2 => { boxPoint3d _ RayHitsRect[point3d, 2, xyPos, box]; [boxPoint, hit] _ BoxPointToUnfoldedBoxPoint[boxPoint3d, 2, xyPos, box]; }; zScore = 2 => { boxPoint3d _ RayHitsRect[point3d, 3, zxPos, box]; [boxPoint, hit] _ BoxPointToUnfoldedBoxPoint[boxPoint3d, 3, zxPos, box]; }; ENDCASE => ERROR; }; ImageToBox: PUBLIC PROC [imagePoint: Point2d, data: REF ANY] RETURNS [surfacePoint: Point2d, onSurf: BOOL] = { <> <> <> box: Box _ NARROW[data]; IF -box.halfY <= imagePoint[2] AND imagePoint[2] <= box.halfY AND -(box.x+box.z) <= imagePoint[1] AND imagePoint[1] <= (box.x+box.z) THEN onSurf _ TRUE ELSE IF -(box.halfY+box.z) <= imagePoint[2] AND imagePoint[2] <= -box.halfY THEN onSurf _ TRUE ELSE IF box.halfY <= imagePoint[2] AND imagePoint[2] <= box.halfY+box.z THEN onSurf _ TRUE ELSE onSurf _ FALSE; surfacePoint _ imagePoint; }; -- end of ImageToBox BoxToImage: PUBLIC PROC [surfacePoint: Point2d, data: REF ANY] RETURNS [imagePoint: Point2d, onSurf: BOOL] = { <> <> <> box: Box _ NARROW[data]; IF -box.halfY <= surfacePoint[2] AND surfacePoint[2] <= box.halfY AND -(box.x+box.z) <= surfacePoint[1] AND surfacePoint[1] <= (box.x+box.z) THEN onSurf _ TRUE ELSE IF -(box.halfY+box.z) <= surfacePoint[2] AND surfacePoint[2] <= -box.halfY THEN onSurf _ TRUE ELSE IF box.halfY <= surfacePoint[2] AND surfacePoint[2] <= box.halfY + box.z THEN onSurf _ TRUE ELSE onSurf _ FALSE; imagePoint _ surfacePoint; }; -- end of BoxToImage ImagePolyToSurfacePoly: PUBLIC PROC [imagePoly: Polygon, map: PROC [imagePoint: Point2d, data: REF ANY] RETURNS [surfacePoint: Point2d, onSurf: BOOL], data: REF ANY] RETURNS [surfacePoly: Polygon] = { surfacePoint: Point2d; onSurf: BOOL; < for some type of 3d surface.>> surfacePoly _ SVPolygon2d.CreatePoly[imagePoly.len]; FOR i: NAT IN [0..imagePoly.len) DO [surfacePoint, onSurf] _ map[imagePoly[i], data]; surfacePoly _ SVPolygon2d.AddPolyPoint[surfacePoly, surfacePoint]; ENDLOOP; }; SurfacePolyToImagePoly: PUBLIC PROC [surfacePoly: Polygon, map: PROC [surfacePoint: Point2d, data: REF ANY] RETURNS [imagePoint: Point2d, onSurf: BOOL], data: REF ANY] RETURNS [imagePoly: Polygon] = { imagePoint: Point2d; onSurf: BOOL; < for some type of 3d surface>> imagePoly _ SVPolygon2d.CreatePoly[surfacePoly.len]; FOR i: NAT IN [0..surfacePoly.len) DO [imagePoint, onSurf] _ map[surfacePoly[i], data]; imagePoly _ SVPolygon2d.AddPolyPoint[imagePoly, imagePoint]; ENDLOOP; }; END.