File: SVArtworkImpl.mesa
Author: Eric Bier in November, 1982
Last edited by Bier on January 13, 1985 10:44:12 pm PST
Contents: Procedures for mapping from simple surfaces to arbitrary surfaces and back again
Last Edited by: Spreitzer, July 19, 1984 12:11:00 pm PDT
DIRECTORY
AIS,
FS,
Graphics,
GraphicsColor,
GraphicsOps,
PadGraphics,
Real,
Rope,
SV2d,
SV3d,
SVArtwork,
SVCoordSys2d,
SVDraw,
SVFiles,
SVImage,
SVMappings,
SVMatrix2d,
SVModelTypes,
SVVector2d;
SVArtworkImpl:
PROGRAM
IMPORTS AIS, FS, GraphicsColor, Graphics, GraphicsOps, PadGraphics, Real, Rope, SVCoordSys2d, SVDraw, SVFiles, SVImage, SVMappings, SVMatrix2d, SVVector2d
EXPORTS SVArtwork =
BEGIN
Color: TYPE = GraphicsColor.Color;
Artwork: TYPE = REF ArtworkObj;
ArtworkObj: TYPE = SVModelTypes.ArtworkObj;
CoordSystem2d: TYPE = SVModelTypes.CoordSystem2d;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
ImageRef: TYPE = GraphicsOps.ImageRef;
Matrix3by3: TYPE = SV2d.Matrix3by3;
OMap: TYPE = SVModelTypes.OMap;
SMap: TYPE = SVModelTypes.SMap;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
Polygon: TYPE = SV2d.Polygon;
Vector: TYPE = SV3d.Vector;
Material: TYPE = SVModelTypes.Material;
Box: TYPE = SVModelTypes.Box;
Tube: TYPE = SVModelTypes.Tube;
SpaceFunction: TYPE = SVModelTypes.SpaceFunction;
CreateFileArtwork:
PUBLIC
PROC [coordSys: CoordSystem, material: Material, surface:
REF
ANY, oMap: OMap, sMap: SMap, filename: Rope.
ROPE, isColor:
BOOL, background: Color, resolution:
REAL ← 72.0, mat: Matrix3by3 ← SVMatrix2d.Identity[]]
RETURNS [artwork: Artwork] = {
fileName must be a full path name.
centerWRTLowerLeft: Point2d;
artWRTPad: CoordSystem2d;
imageXmin, imageYmin, imageXmax, imageYmax: REAL;
halfWidth, halfHeight: REAL;
halfWidthDots, halfHeightDots: REAL;
image: ImageRef;
fileFound: BOOL ← TRUE;
IF isColor
THEN
Open just one separation to gauge its size.
image ← GraphicsOps.NewAisImage[Rope.Concat[SVFiles.FilenameMinusExtension[filename], "-red.ais"]
!FS.Error => {IF error.group = user THEN {fileFound ← FALSE; CONTINUE} ELSE REJECT}]
ELSE image ← GraphicsOps.NewAisImage[filename
!FS.Error => {IF error.group = user THEN {fileFound ← FALSE; CONTINUE} ELSE REJECT}];
IF NOT fileFound THEN ERROR FileNotFound;
[imageXmin, imageYmin, imageXmax, imageYmax] ← GraphicsOps.ImageBox[image];
halfWidthDots ← (imageXmax-imageXmin)/2.0; -- in dots
halfWidth ← halfWidthDots/resolution;-- convert to inches
halfHeightDots ← (imageYmax-imageYmin)/2.0; -- in dots
halfHeight ← halfHeightDots/resolution;-- convert to inches
centerWRTLowerLeft ← [halfWidth*72.0, halfHeight*72.0]; -- in screen dots
artWRTPad ← SVCoordSys2d.CreateCoordSys[mat, NIL];
artwork ← NEW[ArtworkObj ← [class: simpleSurface, coordSys: coordSys, material: material, surface: surface, oMap: oMap, sMap: sMap, source: filename, color: background, isColorFile: isColor, resolution: resolution, halfWidth: halfWidth, halfHeight: halfHeight, halfWidthDots: halfWidthDots, halfHeightDots: halfHeightDots, centerWRTLowerLeft: centerWRTLowerLeft, artWRTPad: artWRTPad, redfile: NIL, greenfile: NIL, bluefile: NIL, blackfile: NIL, redWindow: NIL, greenWindow: NIL, blueWindow: NIL, blackWindow: NIL, open: FALSE]];
};
FileNotFound: PUBLIC ERROR = CODE;
Create3DArtwork:
PUBLIC
PROC [coordSys: CoordSystem, material: Material, data:
REF
ANY]
RETURNS [artwork: Artwork] = {
centerWRTLowerLeft: Point2d;
artWRTPad: CoordSystem2d;
color: Color ← GraphicsColor.white;
centerWRTLowerLeft ← [0,0];
artWRTPad ← SVCoordSys2d.CreateCoordSys[SVMatrix2d.Identity[], NIL];
artwork ← NEW[ArtworkObj ← [class: spaceFunction, coordSys: coordSys, material: material, surface: data, oMap: orthogonal, sMap: unfoldedBox, source: NIL, color: color, isColorFile: FALSE, resolution: 0.0, halfWidth: 0.0, halfHeight: 0.0, halfWidthDots: 0, halfHeightDots: 0, centerWRTLowerLeft: centerWRTLowerLeft, artWRTPad: artWRTPad, redfile: NIL, greenfile: NIL, bluefile: NIL, blackfile: NIL, redWindow: NIL, greenWindow: NIL, blueWindow: NIL, blackWindow: NIL, open: FALSE]];
};
CreateColorArtwork:
PUBLIC
PROC [color: Color, material: Material]
RETURNS [artwork: Artwork] = {
centerWRTLowerLeft: Point2d;
artWRTPad: CoordSystem2d;
centerWRTLowerLeft ← [0,0];
artWRTPad ← SVCoordSys2d.CreateCoordSys[SVMatrix2d.Identity[], NIL];
artwork ← NEW[ArtworkObj ← [class: justColor, coordSys: NIL, material: material, surface: NIL, oMap: orthogonal, sMap: unfoldedBox, source: NIL, color: color, isColorFile: FALSE, resolution: 0.0, halfWidth: 0.0, halfHeight: 0.0, halfWidthDots: 0, halfHeightDots: 0, centerWRTLowerLeft: centerWRTLowerLeft, artWRTPad: artWRTPad, redfile: NIL, greenfile: NIL, bluefile: NIL, blackfile: NIL, redWindow: NIL, greenWindow: NIL, blueWindow: NIL, blackWindow: NIL, open: FALSE]];
};
Copy:
PUBLIC
PROC [artwork: Artwork]
RETURNS [copy: Artwork] = {
copy ← NEW[ArtworkObj];
copy.class ← artwork.class;
copy.coordSys ← artwork.coordSys;
copy.material ← artwork.material;
copy.surface ← artwork.surface;
copy.source ← artwork.source;
copy.color ← artwork.color;
copy.isColorFile ← artwork.isColorFile;
copy.resolution ← artwork.resolution;
copy.halfWidth ← artwork.halfWidth;
copy.halfWidthDots ← artwork.halfWidthDots;
copy.centerWRTLowerLeft ← artwork.centerWRTLowerLeft;
copy.artWRTPad ← artwork.artWRTPad;
copy.redfile ← artwork.redfile;
copy.greenfile ← artwork.greenfile;
copy.bluefile ← artwork.bluefile;
copy.blackfile ← artwork.blackfile;
copy.redWindow ← artwork.redWindow;
copy.greenWindow ← artwork.greenWindow;
copy.blueWindow ← artwork.blueWindow;
copy.blackWindow ← artwork.blackWindow;
copy.open ← artwork.open;
};
OpenArtwork:
PUBLIC
PROC [artwork: Artwork] = {
IF artwork = NIL THEN RETURN;
IF artwork.source = NIL THEN RETURN;
IF artwork.isColorFile
THEN {-- open the three separations
redRope: Rope.ROPE ← Rope.Concat[SVFiles.FilenameMinusExtension[artwork.source], "-red.ais"];
greenRope: Rope.ROPE ← Rope.Concat[SVFiles.FilenameMinusExtension[artwork.source], "-grn.ais"];
blueRope: Rope.ROPE ← Rope.Concat[SVFiles.FilenameMinusExtension[artwork.source], "-blu.ais"];
artwork.open ← TRUE;
artwork.redfile ← AIS.OpenFile[redRope, FALSE];
artwork.greenfile ← AIS.OpenFile[greenRope, FALSE];
artwork.bluefile ← AIS.OpenFile[blueRope, FALSE];
artwork.redWindow ← AIS.OpenWindow[artwork.redfile];
artwork.greenWindow ← AIS.OpenWindow[artwork.greenfile];
artwork.blueWindow ← AIS.OpenWindow[artwork.bluefile];
}
ELSE { -- open the single grey-level ais file
artwork.open ← TRUE;
artwork.blackfile ← AIS.OpenFile[artwork.source, FALSE];
artwork.blackWindow ← AIS.OpenWindow[artwork.blackfile];
};
};
CloseArtwork:
PUBLIC
PROC [artwork: Artwork] = {
artwork.open ← FALSE;
IF artwork.isColorFile
THEN {-- close the three separations
AIS.CloseWindow[artwork.redWindow];
AIS.CloseFile[artwork.redfile];
artwork.redWindow ← NIL;
artwork.redfile ← NIL;
AIS.CloseWindow[artwork.greenWindow];
AIS.CloseFile[artwork.greenfile];
artwork.greenWindow ← NIL;
artwork.greenfile ← NIL;
AIS.CloseWindow[artwork.blueWindow];
AIS.CloseFile[artwork.bluefile];
artwork.blueWindow ← NIL;
artwork.bluefile ← NIL;
}
ELSE { -- close the single black and white file
artwork.blackWindow ← NIL;
artwork.blackfile ← NIL;
};
};
FindImageColorAtPoint:
PUBLIC
PROC [artwork: Artwork, imagePoint: Point2d]
RETURNS [color: Color] = {
Assume for now that artwork.file is an 8 bit-per-pixel ais file with rd scanning with origin in its lower left corner.
imagePoint is in screen dots.
Find the bounding box of the AIS file.
artworkPoint: Point2d;
IF artwork.source = NIL THEN RETURN[artwork.color];
BEGIN
uAIS, vAIS: REAL; -- u and v in AIS dots at this ais file's resolution
uInch, vInch: REAL; -- u and v in inches
artworkPoint ← SVMatrix2d.Update[artwork.artWRTPad.padWRTLocal, imagePoint]; -- in screen dots
uInch ← artworkPoint[1]/72.0; vInch ← artworkPoint[2]/72.0;
uAIS ← uInch*artwork.resolution; vAIS ← vInch*artwork.resolution;
IF artwork.isColorFile
THEN {
redValue, greenValue, blueValue: CARDINAL;
realRedValue, realGreenValue, realBlueValue: REAL;
If [u,v] is outside the AIS image, just use the background color.
IF uInch <= - artwork.halfWidth OR uInch >= artwork.halfWidth
OR vInch <= -artwork.halfHeight OR vInch >= artwork.halfHeight THEN RETURN[artwork.color];
redValue ← AIS.ReadSample[artwork.redWindow, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]];
realRedValue ← redValue;
realRedValue ← realRedValue/255.0; -- scale to the 0..1 range
greenValue ← AIS.ReadSample[artwork.greenWindow, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]];
realGreenValue ← greenValue;
realGreenValue ← realGreenValue/255.0; -- scale to the 0..1 range
blueValue ← AIS.ReadSample[artwork.blueWindow, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]];
realBlueValue ← blueValue;
realBlueValue ← realBlueValue/255.0; -- scale to the 0..1 range
color ← GraphicsColor.RGBToColor[realRedValue, realGreenValue, realBlueValue];
}
ELSE {-- artwork is a black and white file
blackValue: CARDINAL;
realBlackValue: REAL;
IF uInch <= - artwork.halfWidth OR uInch >= artwork.halfWidth
OR vInch <= -artwork.halfHeight OR vInch >= artwork.halfHeight
THEN RETURN[artwork.color];
blackValue ← AIS.ReadSample[artwork.blackWindow, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]];
realBlackValue ← blackValue;
realBlackValue ← realBlackValue/255.0; -- scale to the 0..1 range
color ← GraphicsColor.IntensityToColor[realBlackValue];
};
END;
}; -- end of FindImageColorAtPoint
FindColorAtSurfacePoint:
PUBLIC
PROC [artwork: Artwork, point3d: Point3d, normal: Vector]
RETURNS [color: Color] = {
normal and point3d in Master Object coordinates
first map surface point to tube point.
Next map tube point to image point.
Finally, find color at image point.
surfacePoint, imagePoint: Point2d;
IF artwork.surface = NIL THEN RETURN[artwork.color];
WITH artwork.surface
SELECT
FROM
tube: Tube => {
onTube: BOOL;
surfacePoint ← SVMappings.Point3dToTubePoint[point3d];
[imagePoint, onTube] ← SVMappings.TubeToImage[surfacePoint, tube];
};
box: Box =>{
onBox: BOOL;
SELECT artwork.oMap
FROM
orthogonal => [surfacePoint, onBox] ← SVMappings.BoxOrthogonalOInverse[point3d, normal, box];
radial => [surfacePoint, onBox] ← SVMappings.BoxRadialOInverse[point3d, normal, box];
ENDCASE => ERROR;
IF NOT onBox THEN RETURN[artwork.color];
[imagePoint, onBox] ← SVMappings.BoxToImage[surfacePoint, box];
IF NOT onBox THEN RETURN[artwork.color];
};
ENDCASE => ERROR;
color ← FindImageColorAtPoint[artwork, imagePoint];
}; -- end of FindColorAtSurfacePoint
FindColorAtSpacePoint:
PUBLIC
PROC [artwork: Artwork, point3d: Point3d, normal: Vector]
RETURNS [color: Color] = {
For now, use the rgb cube of side 2 with origin at [-1, -1, -1]. Ignore "normal".
redFraction, greenFraction, blueFraction: REAL;
halfSide: REAL = 1.0;
spaceFunction: SpaceFunction;
spaceFunction ← NARROW[artwork.surface];
redFraction ← (point3d[1]+spaceFunction.scalars[1]/2.0)/spaceFunction.scalars[1];
greenFraction ← (point3d[2]+spaceFunction.scalars[2]/2.0)/spaceFunction.scalars[2];
blueFraction ← (point3d[3]+spaceFunction.scalars[3]/2.0)/spaceFunction.scalars[3];
IF redFraction < 0 THEN redFraction ← 0.0;
IF greenFraction < 0 THEN greenFraction ← 0.0;
IF blueFraction < 0 THEN blueFraction ← 0.0;
IF redFraction > 1.0 THEN redFraction ← 1.0;
IF greenFraction > 1.0 THEN greenFraction ← 1.0;
IF blueFraction > 1.0 THEN blueFraction ← 1.0;
color ← GraphicsColor.RGBToColor[redFraction, greenFraction, blueFraction];
};
DrawArtwork:
PUBLIC
PROC [dc: Graphics.Context, artwork: Artwork, origin: Point2d, scalar:
REAL] = {
Draw a colored box.
tubePoly, padPoly: Polygon;
degrees: REAL;
mark: Graphics.Mark;
lowerLeftWRTCenter, lowerLeftInScreen: Point2d;
mark ← Graphics.Save[dc];
Graphics.SetColor[dc, artwork.color];
Graphics.DrawBox[dc, Graphics.GetBounds[dc]];
IF artwork.source = NIL THEN {Graphics.Restore[dc, mark]; RETURN}
ELSE {
lowerLeftInPad: Point2d;
Draw the image so that its declared center is placed at its declared displacement from the center of the artwork pad.
Find out where its lower left corner should be in pad coordinates.
Then find out where its lower left corner should be in viewer coordinates. Draw.
SVImage will draw the ais file centered on the current dc origin. Move this origin as needed.
lowerLeftWRTCenter ← SVVector2d.Scale[artwork.centerWRTLowerLeft, -1]; -- in artwork coordinates, units = screen dots
lowerLeftInPad ← SVMatrix2d.Update[artwork.artWRTPad.localWRTPad, lowerLeftWRTCenter]; -- in pad coordinates
lowerLeftInScreen ← PadGraphics.PadToScreen[lowerLeftInPad, origin, scalar];
degrees ← SVMatrix2d.RotationOfMatrix[artwork.artWRTPad.localWRTPad];
Graphics.Translate[dc, lowerLeftInScreen[1], lowerLeftInScreen[2]];
Graphics.Rotate[dc, degrees];
Graphics.Scale[dc, scalar, scalar];
IF artwork.isColorFile THEN SVImage.DrawColorImage[dc, artwork.source, NIL, artwork.resolution]
ELSE SVImage.DrawBlackAndWhiteImage[dc, artwork.source, NIL, artwork.resolution, FALSE];-- "FALSE" means "not raw". Interpret the values appropriately for the color map
Graphics.Restore[dc, mark];
Now draw the boundaries of the current simple surface
WITH artwork.surface
SELECT
FROM
tube: Tube => {
tubePoly ← tube.tubePoly;-- a poly of [theta, h] pairs
padPoly ← SVMappings.SurfacePolyToImagePoly[tubePoly,
SVMappings.TubeToImage, tube];
Graphics.SetColor[dc, GraphicsColor.black];
SVDraw.DrawPolygon[dc, padPoly, origin, scalar];
};
box: Box => {
Graphics.SetColor[dc, GraphicsColor.black];
FOR i:
NAT
IN [1..6]
DO
padPoly ← SVMappings.SurfacePolyToImagePoly[box.faces[i],
SVMappings.BoxToImage, box];
SVDraw.DrawPolygon[dc, padPoly, origin, scalar];
ENDLOOP;
};
ENDCASE => ERROR;
};
};
MaterialToRope:
PUBLIC
PROC [material: Material]
RETURNS [materialName: Rope.
ROPE] = {
ie returns "plastic" given plastic, "chalk" given chalk
SELECT material FROM
plastic => materialName ← "plastic";
chalk => materialName ← "chalk";
ENDCASE => ERROR UpdateThisCode;
};
UpdateThisCode: PUBLIC ERROR = CODE;
RopeToMaterial:
PUBLIC
PROC [materialName: Rope.
ROPE]
RETURNS [material: Material, success:
BOOL] = {
Does the inverse of MaterialToRope.
success ← TRUE;
SELECT TRUE FROM
Rope.Equal[materialName, "plastic", FALSE] => material ← plastic;
Rope.Equal[materialName, "chalk", FALSE] => material ← chalk;
ENDCASE => success ← FALSE;
};
OMapToRope:
PUBLIC
PROC [oMap: OMap]
RETURNS [mapName: Rope.
ROPE] = {
SELECT oMap
FROM
orthogonal => mapName ← "orthogonal";
radial => mapName ← "radial";
tubeO => mapName ← "tubeO";
ENDCASE => ERROR UpdateThisCode;
};
RopeToOMap: PUBLIC PROC [mapName: Rope.ROPE] RETURNS [oMap: OMap, success: BOOL] = {
success ←
TRUE;
SELECT
TRUE
FROM
Rope.Equal[mapName, "orthogonal", FALSE] => oMap ← orthogonal;
Rope.Equal[mapName, "radial", FALSE] => oMap ← radial;
Rope.Equal[mapName, "tubeO", FALSE] => oMap ← tubeO;
ENDCASE => success ← FALSE;
};
SMapToRope:
PUBLIC
PROC [sMap: SMap]
RETURNS [mapName: Rope.
ROPE] = {
SELECT sMap
FROM
unfoldedBox => mapName ← "unfoldedBox";
tubeS => mapName ← "tubeS";
ENDCASE => ERROR UpdateThisCode;
};
RopeToSMap:
PUBLIC
PROC [mapName: Rope.
ROPE]
RETURNS [sMap: SMap, success:
BOOL] = {
success ←
TRUE;
SELECT
TRUE
FROM
Rope.Equal[mapName, "unfoldedBox", FALSE] => sMap ← unfoldedBox;
Rope.Equal[mapName, "tubeS", FALSE] => sMap ← tubeS;
ENDCASE => success ← FALSE;
};
END.