<> <> <> <<>> DIRECTORY CADIO, CADTypes USING [CellRec, CellSequence, CompoundOperator, QuantifierFreeFormula, QuantifierFreeFormulaSequence, Scad, SimpleOperator, TriangleSequence, VariableRec, VertexSequence, VisibleMask], Convert, FormulaOperators, Formulas, FS USING [StreamOpen], Interminal USING [MousePosition], IO USING [BreakProc, Close, CR, GetTokenRope, IDProc, int, NUL, PutF, PutFR, real, rope, SP, STREAM], MultiPolynomial USING [EvaluationBindings, RefFromRope, RopeFromRef, TotallyEvaluate], AlgebraClasses, Ints, Polynomials, Vectors, Sequences, CoveringSets, Triangles, Cells, Cads, PopUpSelection, Reals, Rope USING [Compare, Concat, ROPE], Geometry3dVector USING [Triple]; CADIOImpl: CEDAR PROGRAM IMPORTS AlgebraClasses, Convert, FS, IO, MultiPolynomial, Polynomials, PopUpSelection, Triangles, Cads, Rope EXPORTS CADIO ~ BEGIN Error: PUBLIC ERROR[why: ATOM] = CODE; ReadVAXCadFiles: PUBLIC PROC [cadFile, csFile: Rope.ROPE] RETURNS [info: CADTypes.Scad] ~ BEGIN <> cadStream, csStream: IO.STREAM; qeCad: Cads.Cad; qeCadData: Cads.CadData; oldCellsData: Sequences.SequenceData; polySeqData: Sequences.SequenceData; cellData: Cells.CellData; pointData: Vectors.VectorData; inputPoly: Polynomials.Polynomial; cadStructure: AlgebraClasses.Object _ Cads.MakeCadStructure[]; readMethod: AlgebraClasses.Method _ AlgebraClasses.LookupMethodInStructure[$read, cadStructure]; surfaceRope: Rope.ROPE; oldCells: Sequences.Sequence; numberOfOldCells: NAT; newCells: REF CADTypes.CellSequence; newCellIndex: NAT; compressedNewCells: REF CADTypes.CellSequence; <> TranslateQFF: PROC [old: Formulas.Formula] RETURNS [new: CADTypes.QuantifierFreeFormula] ~ BEGIN oldData: Formulas.FormulaData _ NARROW[old.data]; mainOp: FormulaOperators.Op _ NARROW[oldData.mainOperator.data, FormulaOperators.OperatorData]^; <> IF oldData.atomicMatrix THEN BEGIN newOperator: CADTypes.SimpleOperator; SELECT mainOp FROM lt => newOperator _ isNegative; gt => newOperator _ isPositive; eq => newOperator _ isZero; le, ge, ne => ERROR Error[$UnimplementedOperator]; ENDCASE => ERROR Error[$BadOperator]; RETURN [[ isCompound: FALSE, compoundOperator: none, compoundArguments: NIL, simpleOperator: newOperator, simpleArgument: MultiPolynomial.RefFromRope[Polynomials.ToRope[oldData.polynomial]] ]]; END <> ELSE BEGIN newOperator: CADTypes.CompoundOperator; newOperands: REF CADTypes.QuantifierFreeFormulaSequence; oldOperands: LIST OF Formulas.Formula; nOperands: NAT; SELECT mainOp FROM and => newOperator _ and; or => newOperator _ or; not => ERROR Error[$UnimplementedOperator]; ENDCASE => ERROR Error[$BadOperator]; nOperands _ 0; oldOperands _ oldData.operands; UNTIL oldOperands = NIL DO nOperands _ nOperands + 1; oldOperands _ oldOperands.rest; ENDLOOP; newOperands _ NEW[CADTypes.QuantifierFreeFormulaSequence[nOperands]]; oldOperands _ oldData.operands; FOR i: NAT IN [0..nOperands) DO newOperands[i] _ TranslateQFF[oldOperands.first]; oldOperands _ oldOperands.rest; ENDLOOP; RETURN [[ isCompound: TRUE, compoundOperator: newOperator, compoundArguments: newOperands, simpleOperator: none, simpleArgument: NIL ]]; END; END; <> cadStream _ FS.StreamOpen[cadFile]; qeCad _ AlgebraClasses.ApplyReadMethod[readMethod, cadStream, cadStructure]; csStream _ FS.StreamOpen[csFile]; Cads.ReadCoveringSets[csStream, qeCad]; <<>> <> qeCadData _ NARROW[qeCad.data]; polySeqData _ NARROW[qeCadData.inputPolynomials.data]; inputPoly _ polySeqData[1]; <> surfaceRope _ Polynomials.ToRope[inputPoly]; <> oldCells _ qeCadData.cells; oldCellsData _ NARROW[oldCells.data]; numberOfOldCells _ oldCellsData.lengthPlus1 - 1; newCells _ NEW[CADTypes.CellSequence[numberOfOldCells]]; newCellIndex _ 0; <> FOR oldCellIndex: NAT IN [1..numberOfOldCells] DO <> cellData _ NARROW[oldCellsData[oldCellIndex].data]; pointData _ NARROW[cellData.index.data]; IF NARROW[pointData[3].data, Ints.IntData]^ MOD 2 = 0 THEN BEGIN <<>> <> <<9/11/86 Do the cell if it has dimension less than 3; clearly wrong; the intent here was just to pick up nasty vertical lines.>> <<>> <> <> newCells[newCellIndex].indexX _ NARROW[pointData[1].data, Ints.IntData]^; newCells[newCellIndex].indexY _ NARROW[pointData[2].data, Ints.IntData]^; newCells[newCellIndex].indexZ _ NARROW[pointData[3].data, Ints.IntData]^; newCells[newCellIndex].dimension _ cellData.dimension; <> <> <<(NARROW[oldCells[oldCellIndex].index.data, Vectors.VectorData][1] MOD 2) +>> <<(NARROW[oldCells[oldCellIndex].index.data, Vectors.VectorData][2] MOD 2) + >> <<(NARROW[oldCells[oldCellIndex].index.data, Vectors.VectorData][3] MOD 2);>> <<>> <> newCells[newCellIndex].definingFormula _ TranslateQFF[cellData.definingFormula]; <> SELECT newCells[newCellIndex].dimension FROM 0 => BEGIN xReal, yReal, zReal: REAL; coveringSetData: CoveringSets.CoveringSetData _ NARROW[cellData.coveringSet.data]; setData: Sequences.SequenceData _ NARROW[coveringSetData.dataPoints.data]; columnData: Sequences.SequenceData _ NARROW[setData[1].data]; pointData: Vectors.VectorData _ NARROW[columnData[1].data ]; newCells[newCellIndex].vertices _ NEW[CADTypes.VertexSequence[1]]; xReal _ NARROW[pointData[1].data, Reals.RealData]^; yReal _ NARROW[pointData[2].data, Reals.RealData]^; zReal _ NARROW[pointData[3].data, Reals.RealData]^; newCells[newCellIndex].vertices[0] _ [ x: xReal, y: yReal, z: zReal ]; newCells[newCellIndex].polygons _ NEW[CADTypes.TriangleSequence[0]]; END; 1 => BEGIN coveringSetData: CoveringSets.CoveringSetData _ NARROW[cellData.coveringSet.data]; setData: Sequences.SequenceData _ NARROW[coveringSetData.dataPoints.data]; columnData: Sequences.SequenceData _ NARROW[setData[1].data]; numberOfPoints: NAT _ columnData.lengthPlus1 - 1; newCells[newCellIndex].vertices _ NEW[CADTypes.VertexSequence[numberOfPoints]]; FOR j: NAT IN [0..numberOfPoints) DO xReal, yReal, zReal: REAL; pointData: Vectors.VectorData _ NARROW[columnData[j + 1].data ]; xReal _ NARROW[pointData[1].data, Reals.RealData]^; yReal _ NARROW[pointData[2].data, Reals.RealData]^; zReal _ NARROW[pointData[3].data, Reals.RealData]^; newCells[newCellIndex].vertices[j] _ [ x: xReal, y: yReal, z: zReal ]; ENDLOOP; newCells[newCellIndex].polygons _ NEW[CADTypes.TriangleSequence[0]]; END; 2 => BEGIN numberOfPoints, pointIndex: NAT; triangulation: Triangles.TriangleSeq; coveringSetData: CoveringSets.CoveringSetData _ NARROW[cellData.coveringSet.data]; setData: Sequences.SequenceData _ NARROW[coveringSetData.dataPoints.data]; <> numberOfPoints _ 0; <> FOR i: NAT IN [1..setData.lengthPlus1) DO columnData: Sequences.SequenceData _ NARROW[setData[i].data]; numberOfPoints _ numberOfPoints + columnData.lengthPlus1 - 1; ENDLOOP; newCells[newCellIndex].vertices _ NEW[CADTypes.VertexSequence[numberOfPoints]]; <> <> pointIndex _ 0; FOR i: NAT IN [1..setData.lengthPlus1) DO columnData: Sequences.SequenceData _ NARROW[setData[i].data]; FOR j: NAT IN [1..columnData.lengthPlus1) DO xReal, yReal, zReal: REAL; pointData: Vectors.VectorData _ NARROW[columnData[j].data ]; xReal _ NARROW[pointData[1].data, Reals.RealData]^; yReal _ NARROW[pointData[2].data, Reals.RealData]^; zReal _ NARROW[pointData[3].data, Reals.RealData]^; newCells[newCellIndex].vertices[pointIndex] _ [ x: xReal, y: yReal, z: zReal ]; pointIndex _ pointIndex + 1; ENDLOOP; ENDLOOP; <> triangulation _ Triangles.GenerateTriangles[cellData.coveringSet]; <> IF triangulation = NIL THEN newCells[newCellIndex].polygons _ NEW[CADTypes.TriangleSequence[0]] ELSE { newCells[newCellIndex].polygons _ NEW[CADTypes.TriangleSequence [triangulation.trianglesPlusOne - 1]]; FOR i: NAT IN [1..triangulation.trianglesPlusOne) DO newCells[newCellIndex].polygons[i - 1] _ [ firstVertex: triangulation[i].firstVertex, secondVertex: triangulation[i].secondVertex, thirdVertex: triangulation[i].thirdVertex ]; ENDLOOP; }; <> END; ENDCASE => BEGIN ERROR Error[$DegreeOutOfRange]; END; <> newCellIndex _ newCellIndex + 1; END; <> ENDLOOP; <> compressedNewCells _ NEW[CADTypes.CellSequence[newCellIndex]]; FOR i: NAT IN [0..newCellIndex) DO compressedNewCells[i] _ newCells[i]; ENDLOOP; <> info _ [ surface: MultiPolynomial.RefFromRope[surfaceRope], named: FALSE, name: "(none)", color: [1, 1, 1], cells: compressedNewCells]; END; ReadInfoFile: PUBLIC PROC [filename: Rope.ROPE] RETURNS [info: CADTypes.Scad] ~ BEGIN <> <> infoStream: IO.STREAM _ FS.StreamOpen[filename]; token: Rope.ROPE _ ""; InfoFileError: ERROR = CODE; TestError: ERROR = CODE; Break: SIGNAL = CODE; BreakProc: IO.BreakProc ~ IO.IDProc; numberOfCells: NAT; <> TokenBreakProc: IO.BreakProc ~ BEGIN RETURN [SELECT char FROM IN [IO.NUL .. IO.SP], '$ => sepr, ENDCASE => other ]; END; <> PolynomialBreakProc: IO.BreakProc ~ BEGIN RETURN [SELECT char FROM '$, IO.CR => break, ENDCASE => other ]; END; <> NextToken: PROC [proc: IO.BreakProc _ TokenBreakProc] RETURNS [Rope.ROPE] ~ BEGIN token: Rope.ROPE; [token: token] _ IO.GetTokenRope[infoStream, proc]; RETURN [token]; END; <> GetDefiningFormula: PROC RETURNS [CADTypes.QuantifierFreeFormula] ~ BEGIN operatorRope: Rope.ROPE; simpleOperator: CADTypes.SimpleOperator; compoundOperator: CADTypes.CompoundOperator; isCompound: BOOLEAN; operatorRope _ NextToken[]; IF Rope.Compare[operatorRope, "IsPositive"] = equal THEN {simpleOperator _ isPositive; isCompound _ FALSE} ELSE IF Rope.Compare[operatorRope, "IsZero"] = equal THEN {simpleOperator _ isZero; isCompound _ FALSE} ELSE IF Rope.Compare[operatorRope, "IsNegative"] = equal THEN {simpleOperator _ isNegative; isCompound _ FALSE} ELSE IF Rope.Compare[operatorRope, "And"] = equal THEN {compoundOperator _ and; isCompound _ TRUE} ELSE IF Rope.Compare[operatorRope, "Or"] = equal THEN {compoundOperator _ or; isCompound _ TRUE} ELSE ERROR InfoFileError; IF ~isCompound THEN BEGIN polyRope: Rope.ROPE _ NextToken[PolynomialBreakProc]; RETURN [[ isCompound: FALSE, compoundOperator: none, compoundArguments: NIL, simpleOperator: simpleOperator, simpleArgument: MultiPolynomial.RefFromRope[polyRope] ]]; END ELSE BEGIN numberOfArguments: NAT _ Convert.IntFromRope[NextToken[]]; qff: CADTypes.QuantifierFreeFormula _ [ isCompound: TRUE, compoundOperator: compoundOperator, compoundArguments: NEW[CADTypes.QuantifierFreeFormulaSequence[numberOfArguments]], simpleOperator: none, simpleArgument: NIL]; FOR argument: NAT IN [0..numberOfArguments) DO qff.compoundArguments[argument] _ GetDefiningFormula[]; ENDLOOP; RETURN [qff]; END; END; <> UNTIL Rope.Compare[token, "BEGIN"] = equal DO token _ NextToken[]; ENDLOOP; <> IF Rope.Compare[NextToken[], "CAD"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "DESCRIPTION"] # equal THEN ERROR InfoFileError; <> IF Rope.Compare[NextToken[], "Surface"] # equal THEN ERROR InfoFileError; token _ NextToken[PolynomialBreakProc]; info.surface _ MultiPolynomial.RefFromRope[token]; <> IF Rope.Compare[NextToken[], "Name"] # equal THEN ERROR InfoFileError; token _ NextToken[]; IF Rope.Compare[token, "UNNAMED"] = equal THEN BEGIN info.named _ FALSE; info.name _ "(unnamed)"; END ELSE BEGIN info.named _ TRUE; info.name _ token; END; <<>> <> IF Rope.Compare[NextToken[], "Color"] # equal THEN ERROR InfoFileError; info.color.R _ Convert.RealFromRope[NextToken[]]; info.color.G _ Convert.RealFromRope[NextToken[]]; info.color.B _ Convert.RealFromRope[NextToken[]]; <<>> <> IF Rope.Compare[NextToken[], "Cells"] # equal THEN ERROR InfoFileError; numberOfCells _ Convert.IntFromRope[NextToken[]]; info.cells _ NEW[CADTypes.CellSequence[numberOfCells]]; <> IF Rope.Compare[NextToken[], "BEGIN"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "CELL"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "DEFINITIONS"] # equal THEN ERROR InfoFileError; <<>> <> FOR cell: NAT IN [0..numberOfCells) DO <> dimension: CARDINAL; <> IF Rope.Compare[NextToken[], "CellIndices"] # equal THEN ERROR InfoFileError; info.cells[cell].indexX _ Convert.IntFromRope[NextToken[]]; info.cells[cell].indexY _ Convert.IntFromRope[NextToken[]]; info.cells[cell].indexZ _ Convert.IntFromRope[NextToken[]]; <<>> <> IF Rope.Compare[NextToken[], "CellDegree"] # equal THEN ERROR InfoFileError; dimension _ Convert.CardFromRope[NextToken[]]; IF dimension > 2 THEN ERROR InfoFileError; info.cells[cell].dimension _ dimension; <> IF Rope.Compare[NextToken[], "DefiningFormula"] # equal THEN ERROR InfoFileError; info.cells[cell].definingFormula _ GetDefiningFormula[]; <> ENDLOOP; <> IF Rope.Compare[NextToken[], "END"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "CELL"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "DEFINITIONS"] # equal THEN ERROR InfoFileError; <> IF Rope.Compare[NextToken[], "BEGIN"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "CELL"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "DISPLAY"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "INFORMATION"] # equal THEN ERROR InfoFileError; <> FOR cell: NAT IN [0..numberOfCells) DO <> dimension: CARDINAL; nVertices, nTriangles: NAT; <> IF Rope.Compare[NextToken[], "Indices"] # equal THEN ERROR InfoFileError; IF Convert.IntFromRope[NextToken[]] # info.cells[cell].indexX THEN ERROR InfoFileError; IF Convert.IntFromRope[NextToken[]] # info.cells[cell].indexY THEN ERROR InfoFileError; IF Convert.IntFromRope[NextToken[]] # info.cells[cell].indexZ THEN ERROR InfoFileError; <<>> <> IF Rope.Compare[NextToken[], "Degree"] # equal THEN ERROR InfoFileError; dimension _ Convert.CardFromRope[NextToken[]]; IF dimension # info.cells[cell].dimension THEN ERROR InfoFileError; <> IF dimension = 0 THEN BEGIN IF Rope.Compare[NextToken[], "Position"] # equal THEN ERROR InfoFileError; info.cells[cell].vertices _ NEW[CADTypes.VertexSequence[1]]; info.cells[cell].vertices[0].x _ Convert.RealFromRope[NextToken[]]; info.cells[cell].vertices[0].y _ Convert.RealFromRope[NextToken[]]; info.cells[cell].vertices[0].z _ Convert.RealFromRope[NextToken[]]; END ELSE IF dimension = 1 OR dimension = 2 THEN BEGIN IF Rope.Compare[NextToken[], "Vertices"] # equal THEN ERROR InfoFileError; nVertices _ Convert.IntFromRope[NextToken[]]; info.cells[cell].vertices _ NEW[CADTypes.VertexSequence[nVertices]]; FOR i: NAT IN [0..nVertices) DO info.cells[cell].vertices[i].x _ Convert.RealFromRope[NextToken[]]; info.cells[cell].vertices[i].y _ Convert.RealFromRope[NextToken[]]; info.cells[cell].vertices[i].z _ Convert.RealFromRope[NextToken[]]; ENDLOOP; END ELSE ERROR InfoFileError; <> IF dimension = 2 THEN BEGIN IF Rope.Compare[NextToken[], "Triangles"] # equal THEN ERROR InfoFileError; nTriangles _ Convert.IntFromRope[NextToken[]]; info.cells[cell].polygons _ NEW[CADTypes.TriangleSequence[nTriangles]]; FOR i: NAT IN [0..nTriangles) DO info.cells[cell].polygons[i].firstVertex _ Convert.IntFromRope[NextToken[]]; info.cells[cell].polygons[i].secondVertex _ Convert.IntFromRope[NextToken[]]; info.cells[cell].polygons[i].thirdVertex _ Convert.IntFromRope[NextToken[]]; ENDLOOP; END ELSE BEGIN info.cells[cell].polygons _ NEW[CADTypes.TriangleSequence[0]]; END; <> ENDLOOP; <> IF Rope.Compare[NextToken[], "END"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "CELL"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "DISPLAY"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "INFORMATION"] # equal THEN ERROR InfoFileError; <> IF Rope.Compare[NextToken[], "END"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "CAD"] # equal THEN ERROR InfoFileError; IF Rope.Compare[NextToken[], "DESCRIPTION"] # equal THEN ERROR InfoFileError; END; WriteInfoFile: PUBLIC PROC [filename: Rope.ROPE, info: CADTypes.Scad] ~ BEGIN <> infoStream: IO.STREAM _ FS.StreamOpen[filename, $create]; InternalError: ERROR = CODE; <> WriteDefiningFormula: PROC[df: CADTypes.QuantifierFreeFormula, nesting: NAT _ 2] ~ BEGIN <> operatorRope: Rope.ROPE _ IF df.isCompound THEN SELECT df.compoundOperator FROM and => "And", or => "Or", ENDCASE => ERROR InternalError ELSE SELECT df.simpleOperator FROM isPositive => "IsPositive", isZero => "IsZero", isNegative => "IsNegative" ENDCASE => ERROR InternalError; <> IF nesting # 2 THEN FOR i: NAT IN [1..nesting] DO IO.PutF[infoStream, "\t"]; ENDLOOP; <> IF df.isCompound THEN BEGIN IO.PutF[ infoStream, "%g %g\n", IO.rope[operatorRope], IO.int[df.compoundArguments.length]]; FOR formula: NAT IN [0..df.compoundArguments.length) DO WriteDefiningFormula[df.compoundArguments[formula], nesting + 1]; ENDLOOP; END ELSE BEGIN IO.PutF[ infoStream, "%g %g\n", IO.rope[operatorRope], IO.rope[MultiPolynomial.RopeFromRef[df.simpleArgument]]]; END; END; <> IO.PutF[infoStream, "BEGIN CAD DESCRIPTION\n\n"]; IO.PutF[ infoStream, "\tSurface %g\n", IO.rope[MultiPolynomial.RopeFromRef[info.surface]]]; IF info.named THEN IO.PutF[infoStream, "\tName %g\n", IO.rope[info.name]] ELSE IO.PutF[infoStream, "\tName UNNAMED\n"]; IO.PutF[ infoStream, "\tColor %g %g %g\n", IO.real[info.color.R], IO.real[info.color.G], IO.real[info.color.B]]; IO.PutF[infoStream, "\tCells %g\n", IO.int[info.cells.nCells]]; IO.PutF[infoStream, "\n\tBEGIN CELL DEFINITIONS\n"]; <> FOR cell: NAT IN [0..info.cells.nCells) DO IO.PutF[ infoStream, "\n\t\tCellIndices %g %g %g\n", IO.int[info.cells[cell].indexX], IO.int[info.cells[cell].indexY], IO.int[info.cells[cell].indexZ]]; IO.PutF[infoStream, "\t\tCellDegree %g\n", IO.int[info.cells[cell].dimension]]; IO.PutF[infoStream, "\t\tDefiningFormula "]; WriteDefiningFormula[info.cells[cell].definingFormula, 2]; ENDLOOP; <<>> <> IO.PutF[infoStream, "\n\tEND CELL DEFINITIONS\n"]; IO.PutF[infoStream, "\n\tBEGIN CELL DISPLAY INFORMATION\n"]; <> FOR cell: NAT IN [0..info.cells.nCells) DO <> dimension: CARDINAL _ info.cells[cell].dimension; nVertices: NAT _ info.cells[cell].vertices.nVertices; nTriangles: NAT _ info.cells[cell].polygons.nTriangles; <<>> <> IO.PutF[ infoStream, "\n\t\tIndices %g %g %g\n", IO.int[info.cells[cell].indexX], IO.int[info.cells[cell].indexY], IO.int[info.cells[cell].indexZ]]; IO.PutF[infoStream, "\t\tDegree %g\n", IO.int[dimension]]; <> IF dimension = 0 THEN IO.PutF[ infoStream, "\t\tPosition %g %g %g\n", IO.real[info.cells[cell].vertices[0].x], IO.real[info.cells[cell].vertices[0].y], IO.real[info.cells[cell].vertices[0].z]] ELSE BEGIN IO.PutF[infoStream, "\t\tVertices %g\n", IO.int[nVertices]]; FOR i: NAT IN [0..nVertices) DO IO.PutF[ infoStream, "\t\t\t%g %g %g\n", IO.real[info.cells[cell].vertices[i].x], IO.real[info.cells[cell].vertices[i].y], IO.real[info.cells[cell].vertices[i].z]]; ENDLOOP; END; <> IF dimension = 2 THEN BEGIN IO.PutF[infoStream, "\t\tTriangles %g\n", IO.int[nTriangles]]; FOR i: NAT IN [0..nTriangles) DO IO.PutF[ infoStream, "\t\t\t%g %g %g\n", IO.int[info.cells[cell].polygons[i].firstVertex], IO.int[info.cells[cell].polygons[i].secondVertex], IO.int[info.cells[cell].polygons[i].thirdVertex]]; ENDLOOP; END; <> ENDLOOP; <<>> <> IO.PutF[infoStream, "\n\tEND CELL DISPLAY INFORMATION\n"]; IO.PutF[infoStream, "\nEND CAD DESCRIPTION\n"]; IO.Close[infoStream]; END; SelectCell: PUBLIC PROC [scad: CADTypes.Scad, mask: REF CADTypes.VisibleMask, title: Rope.ROPE] RETURNS [index: INT] ~ BEGIN <> menuRopes: LIST OF Rope.ROPE _ NIL; mousePosition: REF Interminal.MousePosition; selection: INT; <> IF scad.cells.nCells # mask.length THEN ERROR Error[$WrongNumberOfCells]; <> FOR i: INT IN [0..scad.cells.nCells) DO j: NAT _ scad.cells.nCells - i - 1; cell: CADTypes.CellRec _ scad.cells[j]; cellRope: Rope.ROPE _ IO.PutFR["(%g, %g, %g)", IO.int[cell.indexX], IO.int[cell.indexY], IO.int[cell.indexZ]]; IF mask[j] THEN cellRope _ Rope.Concat[cellRope, " V"]; menuRopes _ CONS[cellRope, menuRopes]; ENDLOOP; <> mousePosition _ NEW[Interminal.MousePosition _ [mouseX: 0, color: FALSE, mouseY: 0]]; selection _ PopUpSelection.Request[ header: title, choice: menuRopes]; <> <> <> <> <> <> <<>> <> IF (selection = 0) OR (selection = -1) THEN RETURN[-1] ELSE RETURN[selection - 1]; END; WhatCellIsItOn: PUBLIC PROC[point: Geometry3dVector.Triple, variables: CADTypes.VariableRec, scad: CADTypes.Scad] RETURNS [cell: NAT] ~ BEGIN FOR i: NAT IN [0..scad.cells.nCells) DO IF SatisfiesQFF[point, variables, scad.cells[i].definingFormula] THEN RETURN[i]; ENDLOOP; ERROR Error[$NotOnAnyCell]; END; <<>> SatisfiesQFF: PROC[point: Geometry3dVector.Triple, variables: CADTypes.VariableRec, qff: CADTypes.QuantifierFreeFormula] RETURNS [satisfiesQFF: BOOLEAN] ~ BEGIN <> <<>> whoops: ERROR = CODE; epsilon: REAL ~ 0.0001; <<>> IF qff.isCompound THEN SELECT qff.compoundOperator FROM and => BEGIN FOR i: NAT IN [0..qff.compoundArguments.length) DO IF ~SatisfiesQFF[point, variables, qff.compoundArguments[i]] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; END; or => BEGIN FOR i: NAT IN [0..qff.compoundArguments.length) DO IF SatisfiesQFF[point, variables, qff.compoundArguments[i]] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; ENDCASE => ERROR whoops ELSE BEGIN bindings: MultiPolynomial.EvaluationBindings _ LIST [ [variable: variables.x, value: point.x], [variable: variables.y, value: point.y], [variable: variables.z, value: point.z] ]; evaluatedPol: REAL _ MultiPolynomial.TotallyEvaluate[qff.simpleArgument, bindings]; SELECT qff.simpleOperator FROM isPositive => RETURN[evaluatedPol > 0]; isZero => RETURN[ABS[evaluatedPol] < epsilon]; isNegative => RETURN[evaluatedPol < 0]; ENDCASE => ERROR whoops; END; END; END.