Macro to Create Windows [Double Glazed]

Now these are much more sophisticated and I wrote these some years ago when designing our house.  I wanted to not only see what the double glazing was going to look like on the house plans but also to use as a visual cross-check for the manufacturers as part of their spec.

 
They enable you to depict dimensionally correct windows and doors to fit any (reasonably!) sized opening.
 
As you will see from the top of each macro, you can set the dimensions of the individual profiles for both the window and door parts (they are currently set to "Profile 22" which is used by Europlas amongst others).
 
All you have to have to start are two opposing corners of the outer dimension and it doesn't matter if they are 90, 180 or 270 deg out as the macro can automatically rotate the resultant frame (it asks where the real bottom of the frame is).
 
You can specify how many window panes or doors there are across each set.  It can draw either a diamond pattern, a gothic arch or just plain glass.  You can have fanlights (windows) or midrails (doors).  If the frame is so split then what glass pattern(s) (if any) are in the top and in the bottom sections.  Do they have cills?  Do the doors (with midrails) have letterboxes?
 
The diamond pattern is centred in each glass pane but, on some size frames, it can look better to move the pattern up by "half a diamond" so there's a facility to do that if required.
 
To try it out, draw a box 2.4m high and 1.8m wide which we'll pretend is going to be a window on an elevation.
Call the Windows macro and enter the following values:
4 (panes)
Y (special reqs)
y (transom req'd)
d (diamond in fanlight)
g (gothic in rest)
y (cill req'd)
b (base is at the bottom of the rectangle)
Now click on any two opposing corners - why not make it unusual by right-clicking the top-right and bottom left corners?
 
Then stand back!
 
You'll notice that the pattern is in a faint grey but the "current colour" is unchanged and the whole window frame is grouped together.
 
Now try the Doors one using a rectangle about 0.9m by 2.0m for a single door . . .
 
Andrew Sanderson

File to Download: 

Windows.bsc

' Windows.bsc
' written by Andrew Sanderson
' revised 28 December 1998

' This module draws windows with (or without) "brilliant cut" patterns.
' It uses sub-routines - such as "diamond" and "arch" - to fill the glass panes with
' the chosen patterns before putting the whole window or door into a separate Group.

' The static sizes of the frame elements are all included in the first block below
' for ease of maintenance.

' The user specifies the number of window panes, whether there is a transom and the
' location of the opposite corners of the window to be drawn.

' =====================
' SET SIZES OF ELEMENTS
' =====================

' All measurements below are quoted in METRES

FrameT = 0.025 ' The visible portion of the main window frame surrounding the panes at the TOP
FrameB = 0.025 ' The visible portion of the main window frame surrounding the panes at the BOTTOM
FrameS = 0.025 ' The visible portion of the main window frame surrounding the panes at the SIDES
FrameP = 0.070 ' The width of the frame of each pane around the glass
CillH = 0.030 ' The height of the cill (its width is that of the overall window frame)
GapW = 0.013 ' The horizontal gap between multiple panes
GapH = 0.013 ' The vertical gap between the transom and the main pane
TrnsomH = 0.400 ' The height of the transom (from the top of its frame to the top of the main window frame)
DMajAng = 110 ' The major angle of each diamond
DGap = 0.100 ' The gap between the parallel sides of each diamond
MinW = 0.500 ' The minimum width allowed for a window
MinHwT = 0.800 ' The minimum height allowed for a window WITH a transom
MinHwoT = 0.500 ' The minimum height allowed for a window WITHOUT a transom
StripW = 0.006 ' The width of the cut forming the diamonds
Seal = 0.000 ' The seal between the frame and the brickwork (typically 5-15mm)

' ==================
' COLLECT USER INPUT
' ==================
if sys(34) > 0 then
message "De-select everything before proceeding"
end
endif

retryP:
input "Enter number of panes (1 - 5)", NumP
if NumP <1 or NumP >5 then goto retryP

retryS:
input "Are there any special requirements? (Y/N)", S$

if S$ = "Y" or S$ = "y" then
retryT:
input "Is a transom required? (Y/N)", T$
if T$ = "Y" or T$ = "y" then
Transom = 1
retryPT:
input "D(iamond)or N(o) pattern in the FANLIGHT?", PattT$
if PattT$ = "D" or PattT$ = "d" then
PattT$ = "Diamonds"
else
If PattT$ = "N" or PattT$ = "n" then
PattT$ = "None"
else
goto retryPT
endif
endif
else
If T$ = "N" or T$ = "n" then
Transom = 0
else
goto retryT
endif
endif

retryPM:
input "D(iamond), G(othic Arch) or N(o) pattern?", PattM$
if PattM$ = "D" or PattM$ = "d" then
PattM$ = "Diamonds"
retryAD: 
input "Adjust diamond pattern? (Y/N)", AdjD$
if AdjD$ = "Y" or AdjD$ = "y" then
AdjD = 1
else
if AdjD$ = "N" or AdjD$ = "n" or len(AdjD$) = 0 then
AdjD = 0
else
goto retryAD
endif
endif
else
If PattM$ = "G" or PattM$ = "g" then
PattM$ = "Gothic Arch"
else
If PattM$ = "N" or PattM$ = "n" then
PattM$ = "None"
else
goto retryPM
endif
endif
endif

retryC:
input "Do you want a cill? (Y/N)", C$
if C$ = "Y" or C$ = "y" then
Cill = 1
else
If C$ = "N" or C$ = "n" then
Cill = 0
else
goto retryC
endif
endif

else
if S$ = "N" or S$ = "n" or len(S$) = 0 then
Transom = 0 ' default to no transom
PattM$ = "Diamonds" ' default to diamonds in main window/door
Cill = 1 ' default to cill required
else
goto retryS
endif
endif

orient:
input "Which direction is the base? (T/B/L/R)", orient$
if Orient$ = "T" or Orient$ = "t" then
Orient$ = "Top"
else
If Orient$ = "B" or Orient$ = "b" or len(Orient$) = 0 then
' ie assume Bottom is required if no character input
Orient$ = "Bottom"
else
If Orient$ = "L" or Orient$ = "l" then
Orient$ = "Left"
else
If Orient$ = "R" or Orient$ = "r" then
Orient$ = "Right"
else
goto orient
endif
endif
endif
endif

where:
Setpoint "Set opposite corners of the overall window" 2
if sys(1) < 2 then
message "Set TWO points!"
goto where
endif

Pointval FirstX FirstY FirstZ 1
Pointval SecondX SecondY SecondZ 2

' First check that the user is operating in 2D mode by ensuring
' that the Z values of both points are identical:

If FirstZ = SecondZ then
StartZ = FirstZ
else
message "Points must be drawn on same Z plane. Start again."
end
endif

' We need to sort out the entered points so that "StartX,StartY,StartZ"
' represents the bottom lefthand corner of the final window frame
' NB The unit is drawn vertically but is then rotated as the final
' action so that it ends up in the correct position.
' At the same time,we can also work out the overall unit's width and height.

If Orient$ = "Top" then
If FirstX > SecondX then
StartX = FirstX
UnitW = ABS(FirstX - SecondX)
else
StartX = SecondX
UnitW = ABS(SecondX - FirstX)
endif
If FirstY > SecondY then
StartY = FirstY
UnitH = ABS(FirstY - SecondY)
else
StartY = SecondY
UnitH = ABS(SecondY - FirstY)
endif
else
If Orient$ = "Bottom" then
If FirstX > SecondX then
StartX = SecondX
UnitW = ABS(FirstX - SecondX)
else
StartX = FirstX
UnitW = ABS(SecondX - FirstX)
endif
If FirstY > SecondY then
StartY = SecondY
UnitH = ABS(FirstY - SecondY)
else
StartY = FirstY
UnitH = ABS(SecondY - FirstY)
endif
else
If Orient$ = "Left" then
If FirstX > SecondX then
StartX = SecondX
UnitH = ABS(FirstX - SecondX)
else
StartX = FirstX
UnitH = ABS(SecondX - FirstX)
endif
If FirstY > SecondY then
StartY = FirstY
UnitW = ABS(FirstY - SecondY)
else
StartY = SecondY
UnitW = ABS(SecondY - FirstY)
endif
else
If Orient$ = "Right" then
If FirstX > SecondX then
StartX = FirstX
UnitH = ABS(FirstX - SecondX)
else
StartX = SecondX
UnitH = ABS(SecondX - FirstX)
endif
If FirstY > SecondY then
StartY = SecondY
UnitW = ABS(FirstY - SecondY)
else
StartY = FirstY
UnitW = ABS(SecondY - FirstY)
endif
else
message "Incorrect value of Orient$: ", Orient$
goto group
endif
endif
endif
endif

' Check that the resultant window is not unacceptably small

if UnitW < MinW then
message "Window too narrow; reset window position. Press any key to continue."
goto where
end if

if Transom = 1 then
MinH = MinHwT
else
MinH = MinHwoT
endif

if UnitH < MinH then
message "Window too short; reset window position. Press any key to continue."
goto where
end if

' ==============================
' DERIVE OTHER WORKING CONSTANTS
' ==============================

' Calculate the size of each main window pane

' First derive the combined width of the pane(s)
PanesW = UnitW - ((2 * Seal) + (2 * FrameS) + ((NumP - 1) * GapW))
' Now divide by the number of panes ensuring that the width of each pane
' is a whole number of millimetres
PaneW = Int(1000 * PanesW / NumP) / 1000
GlassW = PaneW - (2 * FrameP)

' Now consider the height of the main window/door pane (ie not a fanlight)
MPaneH = UnitH - ((2 * Seal) + (FrameT + FrameB) + (Cill * CillH) + (Transom * TrnsomH))
MGlassH = MPaneH - (2 * FrameP)

If Transom = 1 then
TPaneH = TrnsomH - GapH
TGlassH = TPaneH - (2 * FrameP)
endif

' Using the following variables, calculate the key dimensions of the
' diamond pattern
' DMinAng the minor angle of each diamond
' DSideL the length of each side of the diamonds
' DHalfW the half-width of each diamond
' DHalfH the half-height of each diamond

DMinAng = 180 - DMajAng

' Knowing the gap between the lines (DGap) we can derive the length of a side:
DSideL = DGap/sin(DMinAng)

' and from this the half-width of each diamond:
DHalfW = DSideL * cos(0.5 * DMajAng)

' and from this the half-height of each diamond:
DHalfH = DHalfW / tan(0.5 * DMinAng)

' ========================
' DRAW MAIN FRAME AND CILL
' ========================

' Before drawing anything, determine the entity number of the first entity that
' this routine will draw so that all the window entities can be grouped
' together at the end

EntNum1 = sys(9) + 1

' First draw the overall outline of the window
>2Dbox
{
<pointxyz [StartX , StartY , StartZ]
<pointrel [UnitW, UnitH, 0]
}

' Next, draw the cill if required
if Cill = 1 then
>2Dbox
{
<pointxyz [StartX , StartY, StartZ]
<pointrel [UnitW, CillH + Seal, 0]
}
endif

' =================
' DRAW WINDOW PANES
' =================

' For each pane, draw an outer and an inner frame
' and call the diamond sub-routine having set the following variables
' to the co-ordinates of the corners of the glass pane
' GTLX the glass pane's top left corner x co-ordinate
' GTLY the glass pane's top left corner y co-ordinate
' GTRX the glass pane's top right corner x co-ordinate
' GTRY the glass pane's top right corner y co-ordinate
' GBLX the glass pane's bottom left corner x co-ordinate
' GBLY the glass pane's bottom left corner y co-ordinate
' GBRX the glass pane's bottom right corner x co-ordinate
' GBRY the glass pane's bottom right corner y co-ordinate

X = StartX + Seal + FrameS
Y = StartY + Seal + (Cill * CillH) + FrameB

CountP = 1 ' Initialise counter of Panes

do while CountP <= NumP

' Draw main outer frame
>2Dbox
{
<pointxyz [X , Y , StartZ]
<pointrel [PaneW, MPaneH, 0]
}

' Draw main inner frame
>2Dbox
{
<pointxyz [X + FrameP, Y + FrameP, StartZ]
<pointrel [GlassW, MGlassH, 0]
}

' See if a diamond pattern is required in the main window/door
If PattM$ = "Diamonds" then
' Set the corner co-ordinates and call the diamond sub-routine
GBLX = X + FrameP
GBLY = Y + FrameP
GTRX = GBLX + GlassW
GTRY = GBLY + MGlassH
GTLX = GBLX
GTLY = GTRY
GBRX = GTRX
GBRY = GBLY
gosub diamond 
else
' See if a gothic arch is required in the main window/door
If PattM$ = "Gothic Arch" then
' Set the co-ordinates of the top of the pane and call the arch sub-routine
GBLX = X + FrameP
GBLY = Y + FrameP
GTRX = GBLX + GlassW
GTRY = GBLY + MGlassH
GTLX = GBLX
GTLY = GTRY
GBRX = GTRX
GBRY = GBLY
gosub arch
else
If PattM$ <> "None" then
message "Incorrect value of PattM$ of ",PattM$
endif
endif 
endif

' Draw transom frame
if Transom = 1 then
' Draw outer frame
>2Dbox
{
<pointxyz [X , Y + MPaneH + GapH, StartZ]
<pointrel [PaneW, TPaneH, 0]
}
' Draw inner frame
>2Dbox
{
<pointxyz [X + FrameP, Y + MPaneH + GapH + FrameP, StartZ]
<pointrel [GlassW, TGlassH, 0]
}
' See if a diamond pattern is required in the fanlight window
If PattT$ = "Diamonds" then
' Set the corner co-ordinates and call the diamond sub-routine
GBLX = X + FrameP
GBLY = Y + MPaneH + GapW + FrameP
GTRX = GBLX + GlassW
GTRY = GBLY + TGlassH
GTLX = GBLX
GTLY = GTRY
GBRX = GTRX
GBRY = GBLY
gosub diamond
else
If PattT$ <> "None" then
message "Incorrect value of PattT$ of ",PattT$
endif
endif
endif

CountP = CountP + 1
X = X + PaneW + GapW
loop

' =============
' FINISHING OFF
' =============

' Before drawing anything, we put the entity number of our first entity in EntNum1.
' Now we ascertain the entity number of the last entity we drew

EntNum2 = sys(9)

' To put all these in a Group, they need to be selected first
for i = EntNum1 to EntNum2
getattr i, type, select
putattr i, type, 1
next i

' ===================
' ROTATE IF NECESSARY
' ===================

If Orient$ = "Bottom" then
goto group
else
If Orient$ = "Top" then
RotAng = 180
else
If Orient$ = "Left" then
RotAng = 270
else
If Orient$ = "Right" then
RotAng = 90
else
message "Incorrect value of Orient$: ", Orient$
goto group
endif
endif
endif

>Rotate
{
<PointXYZ [StartX, StartY, StartZ]
<Axis 2
<Angle [RotAng]
}
endif

group:
>GroupDefine
{
}

end

diamond:
' This routine is called with the co-ordinates of the four corners of a window pane
' contained within the following variables:
' GTLX the glass pane's top left corner x co-ordinate
' GTLY the glass pane's top left corner y co-ordinate
' GTRX the glass pane's top right corner x co-ordinate
' GTRY the glass pane's top right corner y co-ordinate
' GBLX the glass pane's bottom left corner x co-ordinate
' GBLY the glass pane's bottom left corner y co-ordinate
' GBRX the glass pane's bottom right corner x co-ordinate
' GBRY the glass pane's bottom right corner y co-ordinate

' In addition to the above, the following variables are used by this module:
' GMidX the glass pane's centre x co-ordinate
' GMidY the glass pane's centre y co-ordinate
' WestX the centre diamond's western point x co-ordinate
' WestY the centre diamond's western point y co-ordinate
' LRPX the left hand reference point x co-ordinate
' LRPY the left hand reference point y co-ordinate
' RRPX the right hand reference point x co-ordinate
' RRPY the right hand reference point y co-ordinate
' NSPX the normal start point of the line x co-ordinate
' NSPY the normal start point of the line y co-ordinate
' NEPX the normal end point of the line x co-ordinate
' NEPY the normal end point of the line y co-ordinate
' ASPX the actual start point of the line x co-ordinate
' ASPY the actual start point of the line y co-ordinate
' AEPX the actual end point of the line x co-ordinate
' AEPY the actual end point of the line y co-ordinate
' TempY a temporary vertical distance
' TempX a temporary horizontal distance 

' =========================
' STORE CURRENT ENVIRONMENT
' =========================

' Store the existing Colour and Linestyle settings as we force these values for
' the drawing of the diamond effect
XScale = sys(5)
XWidth = sys(6)
XRed = sys(300)
XGreen = sys(301)
XBlue = sys(302)

' ======================
' DETERMINE START POINTS
' ======================

' The method is based on the midpoint of a complete diamond being also the midpoint
' of the glass pane. The initial reference points for the parallel lines to be
' drawn - at an angle of one half of DMajAng, across the pane at intervals of DGap - are
' determined as being one half diamond height above the mid point of the left and
' right hand edges of the glass pane.

' First calculate the midpoint of the glass pane
GMiDX = ((GTRX - GBLX)/2)+ GBLX
GMidY = ((GTRY - GBLY)/2)+ GBLY

' Now, on the basis that that is also the midpoint of the centre diamond,
' calculate the point at which the line that joins the apex and the western
' point of the centre diamond intersects the left hand side of the pane.
' This will become the left hand reference point.

' The co-ordinates of the western point are:
WestX = GMidX - DHalfW
WestY = GMidY

TempY = ABS(WestX - GBLX) / tan(0.5 * DMinAng)

' therefore, the co-ordinates of the left hand reference point are:
LRPX = GBLX

if Adjd = 0 then
LRPY = GMidY - TempY
else
if AdjD = 1 then
LRPY = GMidY - TempY + (0.5 * DHalfH)
else
message "Incorrect value of AdjD: ", AdjD
goto retryP
endif
endif

' From this point we determine the highest intersection on the left hand side:
do while LRPY + (2 * DHalfH) <= GTLY
LRPY = LRPY + (2 * DHalfH)
loop

' Since the right hand reference point is a mirror image of the left:
RRPX = GBRX
RRPY = LRPY

' Now we have the first intersection, we can calculate the first line, draw it, and 
' move down the left hand side until we reach the point where the other end of its line
' would be below the bottom of the RIGHT hand side of the pane.

' For each starting point we calculate the end point of that line by considering the triangle
' whose hypoteneuse is the line we want to draw and where the right angle is the top left
' hand corner of the glass pane. We know the angle to the vertical (half of the minor
' angle) and we know the length of the vertical side. We just need to calculate the
' length of the horizontal - call it TempX.

' Once we have determined the normal end point, we then stop to consider whether:
' a) this is beyond the right hand side of the pane and, if it is, we calculate the point
' at which it intersects the right end side and use that as the actual end point instead;
' b) if the starting point itself is below the bottom of the pane and, if it is, calculate the 
' point at which it intersects the bottom of the pane and use that as the actual starting point.

' Our first line starts at the first (modified) reference point, so:
NSPX = LRPX
NSPY = LRPY

' then loop until the "exit do" statement is reached
OK = 1

do while OK = 1

' Calculate the normal end point as detailed above:
TempY = ABS(GTLY - NSPY)
TempX = TempY * tan(0.5 * DMinAng)
NEPX = NSPX + TempX
NEPY = GTLY

' now check to see if this is beyond the right hand edge of the pane
if NEPX > GTRX then
' use the usual basis for determing the intersection 
TempX = ABS(NEPX - GTRX)
TempY = TempX * tan(90 - (0.5 * DMinAng))
AEPX = GTRX
AEPY = GTRY - TempY

' also check to see if this point is below the bottom of the pane. If it is, exit
if AEPY < GBRY then exit do
else
AEPX = NEPX
AEPY = NEPY
endif

' now check to see if the starting point is below the bottom of the pane
if NSPY < GBLY then
' use the usual basis for determing the intersection 
TempY = ABS(GBLY - NSPY)
TempX = TempY * tan(0.5 * DMinAng)
ASPX = GBLX + TempX
ASPY = GBLY
else
ASPX = NSPX
ASPY = NSPY
endif

' and now draw the line:

gosub DrawD

' Move down the left hand side by the height of a diamond and start again:
NSPY = NSPY - (2* DHalFH) 
loop

' Now that we have gone down the left hand side, we need to do the same down the right hand side:
' Our first line starts at the first (modified) reference point, so:
NSPX = RRPX
NSPY = RRPY

' and we loop until the "exit do" statement is reached
OK = 1

do while OK = 1

' Calculate the normal end point as detailed above:
TempY = ABS(GTRY - NSPY)
TempX = TempY * tan(0.5 * DMinAng)
NEPX = NSPX - TempX
NEPY = GTRY

' now check to see if this is beyond the left edge of the pane
if NEPX < GTLX then
TempX = ABS(GTLX - NEPX)
TempY = TempX * tan(90 - (0.5 * DMinAng))
AEPX = GTLX
AEPY = GTLY - TempY

' also check to see if this point is below the bottom of the pane. If it is, exit
if AEPY < GBLY then exit do
else
AEPX = NEPX
AEPY = NEPY
endif

' now check to see if the starting point is below the bottom of the pane
if NSPY < GBRY then
' use the usual basis for determing the intersection 
TempY = ABS(GBRY - NSPY)
TempX = TempY * tan(0.5 * DMinAng)
ASPX = GBRX - TempX
ASPY = GBRY
else
ASPX = NSPX
ASPY = NSPY
endif

' and now draw the line:

gosub DrawD

' Move down the right hand side by the height of a diamond and start again:
NSPY = NSPY - (2* DHalfH) 
loop

' ===========================
' RESTORE CURRENT ENVIRONMENT
' ===========================

' Reset the Colour and Linestyle settings as we changed them in drawing the diamond effect
sys(5) = XScale
sys(6) = XWidth
sys(300) = XRed
sys(301) = XGreen
sys(302) = XBlue

return

DrawD:
' This is the sub-routine that actually draws the diamond-effect lines
>Line
{
<Color 161,161,161
<LineStyle 0,1.0000,0.0060
<PointXYZ [ASPX,ASPY,StartZ]
<PointXYZ [AEPX,AEPY,StartZ]
}
return

Arch:
' This is the sub-routine which draws the gothic arches

' =========================
' STORE CURRENT ENVIRONMENT
' =========================

' Store the existing Colour and Linestyle settings as we force these values for
' the drawing of the diamond effect
XScale = sys(5)
XWidth = sys(6)
XRed = sys(300)
XGreen = sys(301)
XBlue = sys(302)

' The method used is to draw an arc whose radius is 1.5 times the width of the glass pane
' between a point that is the width of the pane down the right hand side to the mid point
' of the top and one from the midpoint of the top to a point on the left hand side that is
' also the width of the pane down

CentreX = (GTLX + GTRX) / 2
CentreY = GTLY
WidthP = ABS(GTRX - GTLX)
LeftX = GTLX
LeftY = GTLY - WidthP
RightX = GTRX
RightY = GTRY - WidthP
RadGA = 1.5 * WidthP

>Arc2
{
<Color 161,161,161
<LineStyle 0,1.0000,0.0060
<PointXYZ [RightX,RightY,StartZ]
<PointXYZ [CentreX,CentreY,StartZ]
<Type [0]
<Radius [RadGA]
}

>Arc2
{
<Color 161,161,161
<LineStyle 0,1.0000,0.0060
<PointXYZ [CentreX,CentreY,StartZ]
<PointXYZ [LeftX,LeftY,StartZ]
<Type [0]
<Radius [RadGA]
}

' ===========================
' RESTORE CURRENT ENVIRONMENT
' ===========================

' Reset the Colour and Linestyle settings as we changed them in drawing the diamond effect
sys(5) = XScale
sys(6) = XWidth
sys(300) = XRed
sys(301) = XGreen
sys(302) = XBlue

return

File to Download:

Windows.bsc