DIRECTORY SV2d, SV3d, SVBoundBox, SVFaces, SVLines2d, SVModelTypes, SVVector2d, SVVector3d; SVFacesImpl: CEDAR PROGRAM IMPORTS SVBoundBox, SVLines2d, SVVector2d, SVVector3d EXPORTS SVFaces = BEGIN TrigLineSeg: TYPE = SV2d.TrigLineSeg; Vector3d: TYPE = SV3d.Vector3d; Vector2d: TYPE = SV2d.Vector2d; Cone: TYPE = REF ConeObj; ConeObj: TYPE = SVFaces.ConeObj; DiskRing: TYPE = REF DiskRingObj; DiskRingObj: TYPE = SVFaces.DiskRingObj; Cylinder: TYPE = REF CylinderObj; CylinderObj: TYPE = SVFaces.CylinderObj; EdgeOnRect: TYPE = REF EdgeOnRectObj; EdgeOnRectObj: TYPE = SVFaces.EdgeOnRectObj; Abs: PROC [r: REAL] RETURNS [REAL] = { RETURN[IF r >= 0 THEN r ELSE -r]; }; -- end of Abs ConeFromTrigLineSeg: PUBLIC PROC [seg: TrigLineSeg] RETURNS [cone: Cone] = { isParallel: BOOL; x, y: REAL; signHi, signLo: PosNeg; cone _ NEW[ConeObj]; [cone.h, isParallel] _ SVLines2d.TrigLineMeetsYAxis[seg.line]; IF isParallel THEN ERROR AttemptToCreateDegenerateCone; IF seg.pLo[2] = seg.pHi[2] THEN ERROR AttemptToCreateDegenerateCone; x _ IF Abs[seg.pLo[1]] > Abs[seg.pHi[1]] THEN Abs[seg.pLo[1]] ELSE Abs[seg.pHi[1]]; y _ (x*seg.line.s + seg.line.d)/seg.line.c; cone.M _ x/Abs[y - cone.h]; cone.yHi _ seg.pHi[2]; cone.yLo _ seg.pLo[2]; signHi _ Sign[cone.yHi - cone.h]; signLo _ Sign[cone.yLo - cone.h]; IF signHi # signLo AND signHi # zero AND signLo # zero THEN ERROR AttemptToCreateDegenerateCone; IF cone.yHi > cone.h THEN cone.noseIsUp _ FALSE ELSE cone.noseIsUp _ TRUE; IF seg.line.theta < 0 THEN cone.normalPointsOut _ TRUE ELSE cone.normalPointsOut _ FALSE; cone.boundHedron _ SVBoundBox.GeneralConeBoundHedron[seg.pHi[1], seg.pHi[2], seg.pLo[1], seg.pLo[2]]; }; -- end of ConeFromTrigLineSeg AttemptToCreateDegenerateCone: PUBLIC ERROR = CODE; PosNeg: TYPE = {pos, neg, zero}; Sign: PROC [r: REAL] RETURNS [sign: PosNeg] = { RETURN[IF r > 0 THEN pos ELSE IF r < 0 THEN neg ELSE zero]; }; DiskRingFromTrigLineSeg: PUBLIC PROC [seg: TrigLineSeg] RETURNS [diskRing: DiskRing] = { x1, x2: REAL; diskRing _ NEW[DiskRingObj]; IF seg.pLo[2] # seg.pHi[2] THEN ERROR AttemptToCreateDegenerateDiskRing; diskRing.yPlane _ seg.pLo[2]; IF seg.pLoIsFirst THEN { x1 _ seg.pLo[1]; x2 _ seg.pHi[1]} ELSE {x1 _ seg.pHi[1]; x2 _ seg.pLo[1]}; IF Sign[x1] # Sign[x2] AND Sign[x1] # zero AND Sign[x2] # zero THEN ERROR AttemptToCreateDegenerateDiskRing; x1 _ Abs[x1]; x2 _ Abs[x2]; IF x2 > x1 THEN { diskRing.normal _ [0,1,0]; diskRing.rInSquared _ x1*x1; diskRing.rOutSquared _ x2*x2; diskRing.boundHedron _ SVBoundBox.DiskBoundHedron[r: x2, h: seg.pLo[2]]} ELSE { diskRing.normal _ [0,-1,0]; diskRing.rInSquared _ x2*x2; diskRing.rOutSquared _ x1*x1; diskRing.boundHedron _ SVBoundBox.DiskBoundHedron[r: x1, h: seg.pLo[2]]}; }; -- end of DiskRingFromTrigLineSeg AttemptToCreateDegenerateDiskRing: PUBLIC ERROR = CODE; CylinderFromTrigLineSeg: PUBLIC PROC [seg: TrigLineSeg] RETURNS [cylinder: Cylinder] = { cylinder _ NEW[CylinderObj]; IF seg.pLo[1] # seg.pHi[1] THEN ERROR AttemptToCreateDegenerateCylinder; IF seg.line.theta < 0 THEN cylinder.normalPointsOut _ TRUE ELSE cylinder.normalPointsOut _ FALSE; cylinder.yHi _ seg.pHi[2]; cylinder.yLo _ seg.pLo[2]; cylinder.r _ seg.pLo[1]; cylinder.rSquared _ cylinder.r*cylinder.r; cylinder.boundHedron _ SVBoundBox.GeneralConeBoundHedron[seg.pLo[1], seg.pHi[2], seg.pLo[1], seg.pLo[2]]; }; AttemptToCreateDegenerateCylinder: PUBLIC ERROR = CODE; EdgeOnRectFromTrigLineSeg: PUBLIC PROC [seg: TrigLineSeg, frontZ, backZ: REAL] RETURNS [edgeOnRect: EdgeOnRect] = { normal2d: Vector2d; edgeOnRect _ NEW[EdgeOnRectObj]; edgeOnRect.frontZ _ frontZ; edgeOnRect.backZ _ backZ; edgeOnRect.A _ -seg.line.s; edgeOnRect.B _ seg.line.c; edgeOnRect.D _ -seg.line.d; normal2d _ SVVector2d.LeftNormalOfTrigLineSeg[seg]; edgeOnRect.normal _ SVVector3d.Vector2DAsXYVector[vXY: normal2d]; IF (45 <= seg.line.theta AND seg.line.theta <= 135) OR (-135 <= seg.line.theta AND seg.line.theta <= -45) THEN { edgeOnRect.valIsY _ TRUE; edgeOnRect.valLo _ seg.pLo[2]; edgeOnRect.valHi _ seg.pHi[2]; } ELSE { edgeOnRect.valIsY _ FALSE; edgeOnRect.valLo _ Min[seg.pLo[1], seg.pHi[1]]; edgeOnRect.valHi _ Max[seg.pLo[1], seg.pHi[1]]; }; }; -- end of EdgeOnRectFromTrigLineSeg AttemptToCreateDegenerateEdgeOnRect: PUBLIC ERROR = CODE; Max: PRIVATE PROC [a, b: REAL] RETURNS [REAL] = { RETURN [IF a>b THEN a ELSE b]; }; Min: PRIVATE PROC [a, b: REAL] RETURNS [REAL] = { RETURN [IF a= 0 AND rOut > rIn, and may have an upward or downward pointing normal. The cylinder described here is revolute around the y-axis. Otherwise it is very general. It may have its top and bottom in arbitrary horizontal planes (y = yHigh and y = yLow) subject to yHigh > yLow and may have an arbitrary radius r. The edge on rectangle has a surface normal parallel to the xy plane. That is, it is edge on when viewed from the z direction. Seg cannot be vertical. Seg cannot be horizontal To find the spread ratio r/|y-h|, we consider the intersection of the cone (meaning the two nose-to-nose "cones" meeting at the apex) with the z = 0 plane. This gives us two lines intersecting at (0,h). Consider the intersection of the line x = seg.pLo[1] or x = seg.pHi[1] (whichever is larger) (an arbitrary choice) with the negatively sloped line (corresponding to the nose-up cone at this point). The cone radius here is x. We can get the y of intersection from the line equation: y * cos(theta) - x*sin(theta) - d = 0; y = (x*sin(theta) + d)/cos(theta); Finally, M = 1/Abs[y - h] . Debugging. Find the distance from the cone to each of the points of seg: BEGIN coneSeg: TrigLineSeg _ SVLines2d.CreateTrigLineSeg[[x, y], [0, cone.h]]; d1: REAL _ SVLines2d.DistancePointToTrigLineSeg[seg.pLo, coneSeg]; d2: REAL _ SVLines2d.DistancePointToTrigLineSeg[seg.pHi, coneSeg]; d2 _ SVLines2d.DistancePointToTrigLineSeg[seg.pHi, coneSeg]; END; Make sure the y's are on the same side of the apex (or on the apex) IF seg goes down, normal should point out, else normal should point in. By down, I mean second point is below first point, or equivalently, theta is negative. IF y2 x1; If segment points out, normal points up, else normal points down. Seg must be vertical IF seg goes down normal should point out, else normal should point in. We wish to find the line equation in the from Ax + By + D = 0. Trig line segments have the form: y*cos(theta) - x*sin(theta) -d = 0; So A = -sin(theta), B = cos(theta), D = -d; To set valHi and valLo, we look at theta. If pi/4 <= theta < = 3pi/4 or -3pi/4 <=theta <= -pi/4 THEN use y else use x. Assume that the interior of the polygon is to the right of this line segment so that normals should point to the left. ΚΙ– "Mesa" style˜Iheadšœ™Iprocšœ7™7Lšœ‚™‚L˜šΟk ˜ LšœQ˜QL˜—šœ  ˜Lšœ.˜5Lšœ ˜—L˜Lš˜˜Lšœ œ˜%Lšœ œ˜Lšœ œ˜L˜Lšœ©™©Lšœœœ ˜Lšœ œ˜ L˜Lšœ—™—L˜Lšœ œœ ˜!Lšœ œ˜(L˜Lšœν™νL˜Lšœ œœ ˜!Lšœ œ˜(L˜Lšœ~™~L˜Lšœ œœ˜%Lšœœ˜,L˜—š Οnœœœœœ˜&Lšœœœœ˜!Lšœ˜—L˜šžœœœœ˜LLšœ œ˜Lšœœ˜ Lšœ˜Lšœœ ˜Lšœ>˜>šœ œœ˜7Lšœ™—šœœœ˜DLšœ™Lšœκ™κLšœ'™'Lšœ"™"Lšœ™—Lšœœ#œœ˜SLšœ+˜+šœœ˜LšœI™I—š™LšœH™HLšœœ:™BLšœœ:™BLšœ<™<—šœ™LšœC™C—Lšœ˜Lšœ˜Lšœ!˜!Lšœ!˜!Lš œœœœœ˜`š œœœœœ˜JLšœG™GLšœV™VLšœ)™)Lšœ"™"—Lš œœœœœ˜YLšœ#™#Lšœe˜eLšœ ˜ —Lšœœœœ˜3L˜Lšœœ˜ šžœœœœ˜/Lšœœœœœœœ˜;Lšœ˜—L˜šžœœœœ˜XLšœ|™|Lšœœ˜ šœ œ˜Lšœ#™#—Lšœœœ#˜HLšœ˜šœœ˜Lšœ"œ$˜JLšœΤ™Τ—Lš œœœœœ#˜lLšœ ˜ šœ ˜ LšœA™A—šœ œ˜Lšœ˜Lšœ˜Lšœ˜LšœH˜H—šœœ˜Lšœ˜Lšœ˜Lšœ˜LšœI˜I—Lšœ$˜$—Lšœ#œœœ˜7L˜šžœœœœ˜Xšœ œ˜Lšœ™—šœœœ#˜HLšœF™F—Lšœœ˜:Lšœœ˜&Lšœ˜Lšœ˜Lšœ˜Lšœ*˜*Lšœi˜iLšœ˜—Lšœ#œœœ˜7L˜š žœœœ#œœ˜sLšœ>™>LšœE™ELšœ+™+Lšœw™wLšœ˜Lšœ œ˜ Lšœ˜Lšœ˜Lšœ œ˜Lšœ œ˜šœ œ˜Lšœv™v—Lšœ3˜3LšœA˜Aš œœœœœ˜pLšœœ˜Lšœ˜Lšœ˜Lšœ˜—šœ˜Lšœœ˜Lšœ/˜/Lšœ/˜/Lšœ˜—Lšœ&˜&—šœ%œœœ˜9L˜—L˜š žœœœœœœ˜1Lšœœœœ˜Lšœ˜—š žœœœœœœ˜1Lšœœœœ˜Lšœ˜—L˜L˜Lšœ˜L˜—…—H%