DIRECTORY Imager, RealFns, Rope, SV2d, SV3d, SVAngle, SVDraw, SVMappings, SVModelTypes, SVPolygon2d; SVMappingsImpl: CEDAR 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; Vector3d: TYPE = SV3d.Vector3d; 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: Imager.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] = {}; IndicesOfMax: PRIVATE PROC [v: Vector3d] 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: Vector3d, 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 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 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 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: Vector3d, 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: Vector3d, 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; 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; 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. LFile: SVMappingsImpl.mesa Last edited by Bier on May 31, 1984 5:51:33 pm PDT Author: Eric Bier on February 18, 1987 6:43:33 pm PST Contents: A set of bidirectional mappings between 3d surfaces and a 2d image plane Point3dToFunctionPoint: PUBLIC PROC [point3d: Point3d] RETURNS [sfPoint: Point3d] = { sfPoint _ point3d; }; FunctionPointToPoint3d: PUBLIC PROC [sfPoint: Point3d, assembly: REF ANY] RETURNS [point3d: Point3d] = { point3d _ sfPoint; }; SVDraw.Circle[dc, pdisk.origin[1], pdisk.origin[2], pdisk.r]; The eight vertex points are named mnemonically. luf = left, up, front, rdb = right, down, back, etc. Initialize these now. Given a point in assembly coordinates, we project it onto a vertical tube by dropping a perpendicular from the point to the y-axis. h = y and theta = ArcTan[-z/x] measuring angles in the xz plane as counter-clockwise (as seen from the positive y axis) from the positive x axis. Given a point on a tube, we find a point on an object by casting a ray directly at the y-axis and finding out where it hits the object. imagePoint[2] just maps to h imagePoint[1] maps to r*theta where r is the radius of the cylinder. ie theta _ u/r; theta is surfacePoint[1] u _ (tube.R*theta)*PiOver180; v _ h; Basically this is just a conversion to cartesian coordinates and a translation Basically this is just a conversion to cartesian coordinates Given a point in space, we project it onto a horizontal disk by dropping a perpendicular to the disk. This point of intersection differs from point3d in y value only. Hence, this mapping is just a conversion from Cartesian to polar coordinates. Box Mapping Imagine an unfolded box as follows: There are four rectangles numbered left to right as 1..4. Two more rectangles numbered 5 and 6 are above and below rectangle 2 respectively. Rectangle 2 maps to the front (pos z) side of the box. Square 6 maps to the bottom (neg y) side. All other rectangles map accordingly. An [x,y] pair maps to a surface point as follows: If a box has height sy, width sx, and depth sz then the correspondences are: IF -sy/2 <= y <= sy/2 AND -(sz+sx) <= x < -sx THEN Rectangle 1. -sx <= x <= 0 THEN Rectangle 2. 0 < x <= sz THEN Rectangle 3. sz < x <= sz + sx THEN Rectangle 4. IF -3sy/2 <= y < -sy/2 AND -sx <= x <= 0 THEN Rectangle 6. IF sy/2 < y <= 3sy/2 AND -sx <= x <= 0 THEN Rectangle 5. Otherwise, out of box. Bubble sort Given a point in space on some surface, we project it onto an aligned box by finding the aligned direction which the normal most closely follows and dropping a surface normal from the surface of the box which this normal points to, to the point. We then decode this point in three space to an unfolded box point (See the comment in SVMappings on boxes). indices is a permutation. 3,1,2 for instance means that normal is most closely aligned with the z axis, then the x axis, then the yaxis. negArray[indices[1]] tells whether it is most closely aligned with the positive or negative part of the axis. Together they define the 6 sides of a box as required. in each case, make sure that the calculated box point is within the expected rectangle. This will not be the case in general if the simple surface box is smaller than the object being painted. y and z are of interest y and z are of interest x and z are of interest x and y are of interest y and z are of interest y and z are of interest x and z are of interest x and y are of interest Given a two dimensional vector v whose tail is on the origin and a rectangle of dimensions width by height centered on the origin and aligned with the axes, which side of the rectangle does v point to? rect will be in [1..3]. Along with positive we describe a face of the box. For rect = 1, postive = FALSE for example, we describe the negative x face (face 1 in SVMappings). Its plane equation is x = -box.x. v, with its tail at the origin will forms a ray R(t) = t*v. R hits the plane when t*v[1] = -box.x. t = -box.x/v[1]. This is the point [-box.x, v[2]*(-box.x)/v[1], v[3]*(-box.x)/v[1]]. Similarly for other planes. A mapping from point3d to a box point along a ray passing from the origin of the box through point3d. We must figure out which face of the box is hit and then perform a ray-plane intersection. Project the vector from origin to point3d onto xy and zy planes. Find out which rectangle it is nearest in both cases and infer which face it points at. who wins 2 out of three? data will be a Box. It is a ref any so we can use this mapping in ImagePolyToSurfacePoly below surfacePoint is a [x, y] pair (See comment on Box Mapping above) since I use unfolded coordinates to refer to points on the surface of a box, this mapping is the identity. However, we can check for illegal values. data will be a Box. It is a ref any so we can use this mapping in SurfacePolyToImagePoly below surfacePoint is a [x, y] pair (See comment on Box Mapping above) since I use unfolded coordinates to refer to points on the surface of a box, this mapping is the identity. However, we can check for illegal values. data will probably be a REF for some type of 3d surface. data will probably be a REF for some type of 3d surface Κ”˜Iheadšœ™Jšœ2™2Jšœ5™5JšœR™RJ˜šΟk ˜ JšœZ˜Z—J˜Jšœ ˜Jšœ*˜1Jšœ ˜Jš˜˜Jšœ œ˜Jšœ œ˜Jšœ œ˜Jšœœœ˜+Jšœœ!˜7Jšœ œ˜Jšœ œ˜J˜Jšœ œ˜%J˜Jšœœœ ˜Jšœ œ˜'J˜Jšœœœ ˜Jšœ œ˜%J˜Jšœœœ˜Jšœœ˜#J˜Jšœœœ ˜Jšœ œ˜%J˜Jšœœ ˜Jšœ œ ˜Jšœ œ ˜J˜—š Οnœœœœœ œ˜GJšœ˜Jšœ˜Jšœ˜—š žœœœ œœœ˜GJšœ˜Jšœ˜Jšœ˜—J˜šžœ œœ˜NJšœœ˜'J˜—J˜šžœ œœ™UJšœ™J™—š žœ œœœœ™hJšœ™J™—š ž œœœœœ˜NJšœœ˜$Jšœ˜—šž œœœ'˜=Jšœ=™=Jšœ˜—šž œœœœœœœœ˜CJšœM˜MJšœ5œ˜;Jšœ4œ˜:Jšœ5œ˜;Jšœ6œ˜Jšœœœ˜Jšœ˜—šœ˜Jš œœ œœœ˜?Jšœœœ˜Jšœ˜—Jšœ˜—Jšœ˜—š ž œœœ œ ž˜cJšœ¬™¬Jšœœ˜ Jšœ˜šœ˜Jšœœœ œ˜,Jšœ œœ<˜RJšœ ˜ Jšœ˜Jšœ˜—šœ˜Jšœœœ œ˜,Jšœ œœ<˜RJšœ ˜ Jšœ˜Jšœ˜—šœ˜Jšœœœ œ˜,Jšœ œœ<˜RJšœ ˜ Jšœ˜Jšœ˜—Jšœ˜Jšœ˜—J˜š žœœœ0œœ˜xJšœΑ™ΑJšœ™™™Jšœœ˜Jšœœ˜Jšœ˜Jšœœ˜Jšœ˜JšœI˜IJšœ œœ˜@JšœI˜IJšœ œœ˜@JšœI˜IJšœ œœ˜@Jšœ™šœœ˜šœ˜Jšœ1˜1JšœH˜HJšœ˜—šœ˜Jšœ1˜1JšœH˜HJšœ˜—šœ˜Jšœ1˜1JšœH˜HJšœ˜—Jšœœ˜—Jšœ˜—J˜šž œœœœœœ!œ˜nJšœ_™_Jšœ@™@Jšœ•™•Jšœ œ˜Jšœœ˜=Jšœ!œ˜FJšœ œ˜Jšœœ%œ˜KJšœœ ˜Jšœœœœ!˜JJšœœ ˜Jšœœ œ˜Jšœ˜Jšœ˜—šž œœœœœœœ˜nJšœ_™_Jšœ@™@Jšœ”™”Jšœ œ˜Jšœœ˜AJšœ#œ!˜JJšœ œ˜Jšœœ'œ˜OJšœ ˜Jšœœœ%˜MJšœ ˜Jšœ œ˜Jšœ˜Jšœ˜—J˜šžœœœœœœœ!œ œœœ˜ΘJšœ˜Jšœœ˜ JšœB™BJšœ4˜4šœœœ˜#Jšœ1˜1JšœB˜B—Jšœ˜Jšœ˜—šžœœœœœœœœ œœœ˜ΘJšœ˜Jšœœ˜ JšœA™AJšœ4˜4šœœœ˜%Jšœ1˜1Jšœ<˜<—Jšœ˜Jšœ˜—J˜Jšœ˜J˜J˜—…—;~c^