A Simulation Tool for the Estimation and Optimization of Electrical Lighting Energy by Matthew A Lehar B.S., Mechanical Engineering (1999) Stanford University Submitted to the Department of Mechanical Engineering in Partial Fulfillment of the Requirements for the Degree of Master of Science in Mechanical Engineering at the MASSACHUSE S INSTITUTE OF TEC HOLOGY Massachusetts Institute of Technology February 2003 JUL 0 8RE LIBRARIES ©2003 Massachusetts Institute of Technology All rights reserved AY r ...... .............. Department of Mechanical Engineering March 13, 2003 Signature of Author...................... C ertified by............................................. 1Ieon R. Glicksman Professor of Mechanical Engineering Thesis Supervisor 0a Accepted by..........................-l.................. Ain A. Sonin Chairman, Department Committee on Graduate Students BARKER Room 14-0551 MITLibraries Document Services 77 Massachusetts Avenue Cambridge, MA 02139 Ph: 617.253.2800 Email: docs@mit.edu http://libraries.mit.edu/docs DISCLAIMER OF QUALITY Due to the condition of the original material, there are unavoidable flaws in this reproduction. We have made every effort possible to provide you with the best copy available. If you are dissatisfied with this product and find it unusable, please contact Document Services as soon as possible. Thank you. The images contained in this document are of the best quality available. A Simulation Tool for the Estimation and Optimization of Electrical Lighting Energy by MATTHEW A. LEHAR Submitted to the Department of Mechanical Engineering on January 17, 2003, in Partial Fulfillment of the Requirements for the Degree of Masters of Science in Engineering ABSTRACT The subject of this thesis is a daylighting simulation tool, designed to predict the distribution of daylight in an office room using a rapid calculation procedure. Results from this simulation are compared to the output from a professional rendering program, and are found to agree within 10% normalized error. A method for finding average light levels in an office room is described, and these calculations are used to infer a minimum required energy cost to supplement daylighting with artificial lighting. Thesis Supervisor: Leon R. Glicksman Title: Professor of Mechanical Engineering Table of Contents 1. Introduction 9 a. The need for a "Design Advisor" web tool 9 b. The daylighting tool 11 c. Simulation setup 11 2. Method Overview 14 a. Initialization 14 b. Iteration 18 c. Composing the room model 19 d. Displaying regions of light and shade 20 e. Predictions of long-term energy use 24 3. Theory of the Diffuse Reflections Method 28 a. Reflections and smoothing 35 b. Blind reflections 37 c. Daylighting results 40 d. Lighting energy estimation results 47 4. Detailed Method 57 a. Basic room objects 57 b. Initialization routines 59 c. Reflections 63 d. Smoothing 64 Bibliography 67 Appendix: Program Code for the Lighting Module 69 Acknowledgments I am grateful to Professor Glicksman for introducing me to this work, and for showing me a how to think like an engineer. I am also indebted to him for laying the groundwork for the approach presented here, for raising the alarm when we had bad data, and for the invaluable weekly discussions. Jim Gouldstone, who wrote the visual interface for my code, also helped me to understand Java through many informal tutorials. The implementation of my model is significantly due to him. His great ability as a teacher is matched only by the generosity with which he gave out his time. Permasteelisa Corporation provided the funding for my research. I am extremely grateful to their directors, as well as to the staff scientists who provided technical advice. Thanks to my dad for reviewing the thesis and offering advice and encouragement. CHAPTER 1: INTRODUCTION * THE NEED FOR A "DESIGN ADVISOR" WEB TOOL The Daylighting model described in this thesis has been designed as part of a suite of design tools currently available to the public through an MIT web service, called "Design Advisor'." The purpose of the site is to provide preliminary advice to architects and building engineers about the viability of their building designs. At present, the site consists of three modules, each intended to give the user easily comprehensible feedback about the tradeoff between energy efficiency and comfort in the proposed building. The first, an "Energy" module 2 , estimates the energy consumption of a building design based on simple user inputs. The second, called "Comfort," shows the effect of infrared radiation from the window surface on occupants standing at various positions in a room. "Daylighting" is the latest addition to the site, and provides a mixture of visual and quantitative results demonstrating how a typical room in the user's building will respond to natural daylight. The Daylighting module is the subject of this thesis. More sophisticated software has long been available for both building energy calculations (EnergyPlus 3 ) and daylighting simulations (Radiance 4). However, these tools are invariably difficult to learn, and they require both a detailed knowledge of the final design geometry and a large investment of time to configure and run. Consequently, they are seldom practical to use in a design project until a single concept has been finalized and all its dimensions fully determined - in other words, until there is no longer any possibility of changing the design in response to the results of the simulation. By contrast, the Design Advisor is designed to be useful at 9 the conceptual stage of a building project, when the general characteristics of a building are still being chosen. To this end, the modules in the Design Advisor package emphasize three priorities: 1. The interface must be simple and require no special training for the user to enter the minimal input parameters for a building 2. Each simulation must run to completion in seconds, returning results to the user essentially in real time, so that many design options can be explored in a single sitting 3. The simulation must return results that are visual and intuitive, and which are easily comprehended without engineering knowledge In exchange for these virtues, the Design Advisor sacrifices some degree of accuracy, but all modules have been designed to return results with, at most, a 15% margin of error. For simplicity of use, the main console of the tool provides only basic input options. However, the interface also offers "advanced" controls that are not visible on the startup screen. Many input fields have adjacent buttons that can be pressed to bring up palettes of advanced options for users with specialized knowledge (Fig. 1-1). AlI FS 4*m~ A ........ .. .. ... 7I Figure 1-1. The Design Advisor interface, with advanced options shown in a pop-up window 10 e THE DAYLIGHTING TOOL The daylighting module of the Design Advisor is the main subject of this thesis. Its scope has been somewhat limited by requirements that apply to the Design Advisor as a whole, namely that it be simple to use, have a rapid operation, and present results that are easy to interpret. To reduce computation time in the daylighting module, we have focused on modeling the effect of sunlight in a basic rectangular office room with a single window. To avoid the further computational demands of calculating the paths of individual rays of light (a procedure known as "ray tracing"), we assume all interior surfaces to be diffuse reflectors. This is a reasonable approximation for most interior surfaces, and we can check our implementation by comparing our results with a Radiance model. The purpose of a daylight-prediction tool is to give an accurate estimate of the amount of daylight entering an office room during work hours. Based on this information, the required investment of energy in artificial lighting can be predicted for any office room. Our aim has been to develop a daylighting model capable of delivering a tailored lighting-energy estimate to the user in a matter of seconds, and within a 10% margin of error. Like the other modules on the Design Advisor site, "Daylighting" uses data from location-specific weather files5 for its hourly lighting calculations. * SIMULATION SETUP The virtual "room" used in the simulation is a rectilinear space with a window opening in one wall. The wall containing the window, the two walls flanking the window, the floor, and the ceiling together make up the basic geometry of the room. The rear wall 11 is left out because it is the viewing plane in the user's visual display. The omission is acceptable from the standpoint of the simulation because reflections from the rear wall would contribute minimally to the daylighting on other surfaces. Other elements include an optional set of blinds positioned in the plane of the window and an transparent workplane with the same dimensions as the floor, but raised to the elevation of a desk or work surface (Fig. 1-2). The workplane is transparent in the sense that it does not cast shadows or reflect light onto the other surfaces. Its only purpose is to measure the amount of light that reaches the desk level. Blinds W~orkplane Figure 1-2. Layout of the basic room model Each of the room's panels, including the window and the workplane, is referred to as a "surface" in the simulation code. The current state of a surface is defined by a two- 12 dimensional array of brightness values representing the area of the surface. The value at each grid position represents the brightness, or radiosity of the surface at that location. The simulation proceeds by assigning initial radiosity values to each of these array elements, then calculating for each position how much reflected light it receives from all other positions in the room (Fig. 1-3). Wall I Floor Figure 1-3. The amount of light incident on element i is the sum of contributions from every other element in the room 13 CHAPTER 2: METHOD OVERVIEW Simulating daylighting inside an enclosed space consists of two basic operations. The first task, which we will refer to as initialization, is to model the penetration of the sun's direct rays into different parts of the room. The second, which we call iteration, is to carry out the reflection of this direct sunlight, as well as diffuse daylight, from one interior surface to another. e INITIALIZATION Before we can project sunlight through a window opening to illuminate the room interior, we must first devise a way to assign luminance values selectively to different parts of the room. We divide each of the room's interior surfaces into rectilinear grids of many small elements, as shown in Fig. 2-1. Each element is given a numerical value corresponding to the level of surface brightness at its position, measured as a radiosity. Certain elements can then be assigned higher radiosities than others, depending on where the sunlight falls. 14 Fine Coarse Radiouity Level Figure 2-1. A sunlight pattern can be digitized to a coarse or fine mesh, in which each element records a radiosity value at its location To determine which areas are directly illuminated by sunlight, and which are left in shadow, we make geometric calculations based on sun position and measurements of the window opening. The sun-brightened area of the floor, for example, is limited in the dimension parallel to the window by the right and left margins of the window area. In the other dimension (towards/away from the window plane), the limit is set by the window sill and head heights (Fig. 2-2). The shadows created by the sill and head are simplest to apply, because they run parallel to the sides of the floor. The following formula is used to convert sill and head heights into the positions of the shadow boundaries on the floor (measured from an origin at the window plane): 15 (2.1) tan(e) = a A where e is the elevation angle of the sun, a is the height of the sill or head above the floor, and A is the distance from the window plane of the corresponding shadow boundary (Fig. 2-3). The shadow boundary in the other dimension, the one encountered in moving from right to left across the floor, parallel to the window plane, is more difficult to impose because it generally runs diagonally. The angle of the diagonal shadow is determined only by the azimuthal angle of the sun, so for the purpose of simplifying our concept drawing, we will assume that the other angle parameter, the angle of elevation, is 30 degrees. If we use the floor as our coordinate system, with x running towards and away from the window plane and y running parallel to the window, and the origin at the intersection of floor, window and right wall, we can say that the position of the shadow boundary in y depends on our position in x. The following margin Region iliuminated Figure 2-2. Sunlight illuminating part of the floor of the room mode 16 Limit set by right margin right Equation: Y c + X* tAn (h) Margin ray of sunlight ---- w~inadow Sun Elevati~on, Sun Azimuth, h Figure 2-3. Measuring the extent of the sunlight projection formula gives the y-position of the shadow boundary on the floor caused by the right margin of the window: Ybo.nday = c + x tan(h) (2.2) where c is the y-position of the window's right margin, and h is the sun azimuthal angle, measured in degrees to the right of the outward-pointing normal to the window. The y-position of the edge of the shadow imposed by the left-hand margin obeys the same formula, slightly adjusted: Yboundary = c + w + x tan(h) (2.3) where w is the width of the window in the y-dimension. Using these simple formulas, we can entirely describe the boundaries of the shadows on each of the room's surfaces in Fig. 2-3. Boundaries on the walls and 17 floor that run parallel to the frame of the window each have a constant x-coordinate, and boundaries running longitudinally (away from the window) can be described by a linear formula giving the y- or z- coordinate in terms of x. The discrete elements that make up the virtual "surfaces" used in our simulation can each be set to a higher or lower value, depending on whether each element lies more in sunlight or shadow. The magnitude of the radiosity of a surface element in direct sunlight can be determined from the solar illuminance and the absorptivity of the surface. * ITERATION All surface elements in the room must be assigned brightnesses due to their being in or out of the path of direct sunlight from the window, before a simulation of reflected light, which we call an "iteration," can be carried out. Once the initial radiosity values have been set, reflections and re-reflections from the interior surfaces can be calculated. Any element lying completely outside the path of direct sunlight has its initial radiosity value set to 0. For simplicity, all surfaces in the room are assumed to reflect light diffusely. No information need be retained as to the original direction from which a ray of sunlight has struck a surface element, because there is no preferred direction in which it will be re-directed after striking the surface. If one surface element is reflecting sunlight, any other element that does not lie in the same plane will receive a certain fraction of the light reflected. That fraction is given by the view factor between the two elements (Fig. 2-4). All reflected light can be accounted for if view factors have been calculated for every possible permutation of two elements in the room. 18 Wall ji .. j2 3 3 i Floor ,=(1-a)((vF 1_,R, )+ (VF- R +(vF R )+...) (2.4) Figure 2-4. The brightness of element i rendered as a sum of the radiosities of all other surface elements, each multiplied by a view factor. a, represents the absorptivity of element i. The equation holds when all elements have the same area. A certain fraction of the light reflected from one surface element to another will again be reflected back into the room. To calculate the effect of this "second bounce," we simply repeat the operation used to obtain the first set of reflections. By repeating these "iterations," updating, at each step, the radiosities of each element, we eventually arrive at an equilibrium of surface radiosities, after which point there is no detectable change in the relative brightness of different parts of the room. * COMPOSING THE ROOM MODEL The time required to calculate each complete set of diffuse reflections (a complete set consists of one reflection for each surface element) rises geometrically with the resolution of the surface arrays. The total number of calculations goes as the 4th 19 power of the rank of the surface array, so that a room composed of surfaces with radiosity arrays measuring 10 elements on a side will take 16 times as long to compute as a room with arrays that are 5 on a side. Because of the time required to compute reflections, we use a low-resolution grid of elements to represent the room when running the reflection iterations. At the same time, a separate model of the room is stored at a much higher resolution, but is used only for representing the initial distribution of direct sunlight in the room. The high- and low-resolution surface maps are then combined into a single room model, which shows a crisp delineation between directly-lit regions and those that are initially in shadow, superimposed on a cruder plot showing the distribution of secondary light from reflections (Fig. 2-5). Since reflected radiation is spread diffusely about the room, one would expect it to have a smooth distribution, so that using a coarse grid to represent reflected light might introduce major errors if the grid were not then re-smoothed. To relieve the artificial "blockiness" of the reflected-light pattern, a blinear interpolation function is used to smooth the edges of the low-resolution cells. * DISPLAYING REGIONS OF LIGHT AND SHADE To display the room model as a realistic rendered image, we map radiosity levels from the surface grids to a perspective drawing of the walls, floor, and window. To complete this mapping, it will not be sufficient to do a linear transformation of the range of luminances in the room into shades of gray on a computer monitor. Even if we use walls with a high reflectivity (-0.7), the room image will look saturated with white in areas directly lit by the sun, and very dark elsewhere (Fig. 2-6a). In a real room, the eye does not perceive luminance values in proportion to their absolute magnitudes. Instead, the visual system increases contrast in certain bands of the 20 Reflections Smoothed Fine Grid, Plus Reflections Figure. 2-5. A coarse grid is used to determine reflections, the initial sunlight pattern is removed, the resulting pattern is smoothed, and a finer pattern of initial sunlight is added in the final frame luminance range, and decreases it in others, depending on the relative abundance of light at different levels of intensity. Contrast is increased for levels of luminance that are well-represented in the world-image, and reduced for under-represented levels. The method presented by Larson, Rushmeier, and Piatko6 imitates human perception by using a Cumulative Population Density function to map worldluminances to display-luminances. We have followed this algorithm in its basic approach. Once the simulation has run to completion, we record the radiosity value at each of the grid positions in the fine mesh representing the room. We divide the spectrum of radiosities, from least to greatest, into 100 equal partitions, and assign each radiosity value from the room to its corresponding bin. By keeping track of the number of gridpoint values assigned to each bin, we build up a population histogram for the room radiosity values (Fig. 2-7a). In fact, we do not use the actual radiosity values, but the logarithms of the values, to compress the spectrum and better approximate the human "subjective response" to brightness levels (Larson, 8). Using the histogram of radiosity values, we can easily construct a "cumulative distribution function" (Fig. 2-7b), which spans the same range of radiosities as the histogram, but shows the number of readings with values at or below a given radiosity range, rather than within that range. The CD function is defined in Larson in the following way: Zf(b,) P(b) = h (2.5) Zf(b,) where f(b,) is the number of radiosity samples to be found within the log-radiosity range b,, and P(b) is the value of the CD at a given brightness value. This new function can be used as a transfer function, showing the mapping from the log of radiosities recorded in the simulation to the log of levels of gray shown in the visual 22 a. Linear Transfer Function b. Histogram Transfer Function Figure 2-6. Display methods for the room model. In a.), radiosity values are linearly mapped to levels of grayscale. In b.), the transfer function is corrected to represent the image that the human eye would perceive when looking at a view of the real room 23 display. The transfer function can be further modified using methods presented in Larson, but for our relatively simple display purposes, the original CD function appears to be sufficient. The image resulting from the CD transfer function in Fig. 27b is shown in Fig. 2-6b. e PREDICTIONS OF LONG-TERM ENERGY USE So far, a method has been described with the object of creating a display image of the room model using a fixed sun position. A visual output showing the room at a certain time of day might be useful as an aesthetic design aid, but provides no quantitative feedback on the room design, and is of no help in planning for energy efficiency. The amount of energy consumed in electrical lighting fixtures is zero in a room that already receives enough natural sunlight through the windows to meet the lighting requirements of the occupant. But if, in the course of lighting a room, the sunlight also heats the interior space excessively, energy may have to be expended on air conditioners to control the temperature. Therefore, the total energy use will be minimized by an optimization of window size and position that accounts for the heating and cooling requirements of the building. To estimate the amount of electrical lighting energy used in a room during a given hour, we define a "desired light level" consistent with the kind of activity that will be taking place in the room, and pertaining to an invisible surface, some distance above the floor, called the "workplane" (Fig. 2-8). The workplane is a surface in its own right, like the walls, floor, and window. The initialization and iteration methods can be used to apply direct sunlight and reflections from other surfaces, and the resulting light pattern on the workplane could be displayed in a finished rendering. We can also use the 24 Population Histogram of Radiosity Values 0.16 , ~~1 014 I E 0.12 *t 0 0.1 0.08 C* 0.06 l I- 0.04 L* -A 0.02 0 a C2 Bin Number (Log Radiosity) a. Cumulative Distribution Function CD transfer function - - - -1.2 In linear transfer function -- 1 E a) 0.81 0 0.6 CL 0 o 0.4 0 LL 0.2 0 Bin Number (Log Radiosity) b. Figure 2-7. Radiosity values from each surface element in the room are organized into bins according to their magnitudes. a.) shows the population of each bin, and the running tally of values is shown in b.), rising to 100% of the total population at the right-hand side of the chart 25 - WMEN63im - - - -- - -. 1. illuminance values for each element of the workplane to compare the intensity of light due to daylight with the desired light level. In those regions of the workplane where natural daylight does not meet the lighting requirement, electrical lighting must make up the difference. The total electrical energy requirement for the hour can be expressed as follows: I., = Gii where Iar (2.6) - Gdaylgh , is the artificial light intensity requirement, light intensity for the workplane, and Gdalght direct sunlight and reflections. Rewriting Gin is the prescribed minimum is the local natural light intensity due to Gd,,igh, in terms of the radiosity R of the workplane element in question, R ar RGinin p R (2.7) (Gnin (- a) where p is the reflectivity of the workplane and a is the absorptivity. Warkp.Lane FeWorkfae e2 sDeuk) Gaded reflections Reflections + direct sunlighht overlay Figure 2-8. The "Workplane" surface within the simulated room model 26 I - -Ava This summation can now be compared with the cooling energy for the room during the same 1-hour period. By running the simulation once for each of the working hours in the day, and repeating this cycle at least once for each month of the year, we build a reliable history of electrical energy use. In our model, we assume that the electrical lighting can be continuously varied, and each fixture individually controlled, to achieve the desired lighting level. 27 CHAPTER 3: THEORY OF THE DIFFUSE REFLECTIONS METHOD We have made several key assumptions in constructing our computer model of daylighting. Firstly, we have simplified the surface properties of the walls and floor in our model so that they reflect only diffuse light. This step is reasonable as long as there are no highly polished surfaces present that would reflect light non-uniformly (i.e. create specular reflections). The diffuse approximation represents a vast simplification of the task posed by ray-tracing or other specular methods. Building on the assumption of diffuse reflections, we have further assumed that a discrete view factor formulation will be adequate to express the share of reflected light received from one surface by another. In general, the intensity of reflected light incident on a receiving surface A, is given by the following relation: Gi=(Ri A,) F- Fj G RA 1 A, 31 (3.1) where i and j denote the source and receiving surfaces, R, is the radiosity of the source surface, F,, is the view factor, and A is the area of a surface element. The view factor F is given in terms of the geometry of reflecting and receiving surfaces, their orientation in space, and the distance between them. As we have divided our surfaces into rectangular sections, each with a different radiosity, we would theoretically need to compute the full view factor between two rectangular surfaces each time we calculated a radiation exchange between surface elements in the room. The full view factor is found using the general form, 28 1 cosO, cosO i R (3.2) However, a discrete view factor with a much simpler formulation is applicable, provided each element's size is small in comparison with the distance between source and receiving elements. The view factor relation between two discrete elements i and j can be written: cosO, cosO " CosCR2C A. (3.3) The correspondence between the discrete and exact view factors is generally good, except where the discrete panels are very close or share a common edge. As shown in Fig. 3-1a, the error can suddenly increase when the panels are brought close together. Fig. 3-1b shows the amount by which the discrete formulation differs from the exact view factor for a range of distances separating the two panels. It is apparent from the graph that the separation between two grid elements from different surfaces should be at least three times larger than the average dimension of the elements themselves to ensure that large errors do not arise from the reflection calculations. Panels in separate surfaces that connect across a common edge can record measurements that are inaccurate by as much as 50% (Fig. 3-1a), so accurate readings of radiosity are not available from grid squares that lie on the perimeter of a surface. We can further simplify the view factor expression when we consider that the normal vectors of any two elements will either be parallel or perpendicular. The discrete view factor can then be re-written: 29 FA 4 T~7R [a,(x, -x, )+/,(y,-y )+ y,(z, -z 1 ) -. a(x, -x,)+,J(y-y,)+7y(zj-z) - (3.4) [a where R is the distance between source and receiver and x, y, and z are the coordinates of the center of the source and receiving elements. a has a value of 1 if the normal to the surface element points in the x -direction, and a value of 0 otherwise. 6 and y are similarly defined for the y - and z -directions. To initiate the process in which light is "reflected" between surfaces, a discrete view factor is computed for every possible permutation of two array elements in the room. With the directly illuminated regions of each surface having been identified in the initialization procedure, each surface of the room now contains a completely initialized radiosity array. The view factor relation is used to compute the amount of light that each element of one surface's array receives from each of the elements belonging to the other surfaces. This exchange of light between discrete surface elements approximates the diffuse reflection of daylight between surfaces. The reflected light that a surface element receives from all other surface elements is summed, and the total, multiplied the reflectivity (or 1 minus the absorptivity of the surface), is added to the radiosity value for that element, as described by equation 2.4. This proportion of the received light that is added to the radiosity value represents the part that will be reflected, hence the part that is visible to an observer. After each element in the room has been incremented in this way, the entire procedure is repeated, simulating the second, third, and fourth reflections of sunlight around the room, until an equilibrium is reached and there is no further change in light levels. 30 1xi panel 1xI panels 5 Discrete VF: 0.0127 Discrete VF: 0.3183 Exact VF: 0.0124 Exact VF: 0.2000 Fiqure 3.1 a. Comparison of discrete vs. exact view factors for two panel configurations % Error Using Discrete View Factor 100 90 80 70 60 0 50 wU 40 30 20 10 0 0.1 1.1 2.1 3.1 4.1 5.1 6.1 7.1 8.1 9.1 Separation Distance I Disk Diameter Figure 3.1 b. Discrete view factor error for two parallel disk-elements as a function of separation distance The method of iterating a series of element-by-element reflections was chosen over other techniques because of its speed. To achieve an exact result, the simulation would need to execute an infinite number of reflection-cycles, but experiments have shown that as few as 3 iterations are sufficient to bring surface radiosities to within 1 percent of their theoretical final values when the surface reflectivity is 0.7 or less (Fig. 3-2). Most of the time required for the reflection procedure is taken up with the 31 calculation of view factors between surface elements. View factors must be recalculated for each new set of room dimensions or surface resolutions, but once found for a particular room configuration, they are stored in memory so that subsequent reflection-iterations take relatively little time to run. The solution to a multi-surface radiation exchange can be found exactly using a system of linear equations relating a vector of radiosities to a vector of heat fluxes. However, comparing the number of algebraic operations required to find all the view factors in a room to the number of operations required for the solution of the system of linear equations, we find that the former method takes considerably less time to compute. Solar Intensity: 200 W/mA2 Radiosity vs. Number of Iterations Sun Altitude: 15 deg. 9.4 ...-.-. Sun Azimuth: 27 deg. E 9.2 Surface KMj!jWxty = 0.3 9 8.2 7.8 7.6 7.4 2 3 4 5 6 7 8 9 10 Iteration Figure 3.2. The brightness history of a single wall element, originally in shadow. It achieves most of its equilibrium brightness after the first iteration (bounce) We can determine how much brighter a surface will become after its initial brightness is reinforced by reflections. Consider the simple case, shown in Fig. 3-3, of two 32 infinite, parallel vertical surfaces with a mutual view factor of 1, and each surface starting the iteration cycle with the same uniformly applied distribution of sunlight, po. The intensity of light incident upon one surface (surface 1) from the other on the first reflection is given by: Infinite Flat Surface (directlylluminated) stBoun ce infinite Flat Surface (indirectly illuminated) Figure 3-3. The infinite parallel plates experiment G, = (1- a)po (3.5) where a is the absorptivity of the other surface. After the second reflection (n = 2), the light received at the other surface (surface 2) represents the sum of the first and second reflections, and is given by 33 G 2 = (1- a)(1+(1- a))po, or G2 =[(-a)+(1---a)2 Successive reflections add new terms to the summation until the value of G stabilizes completely as n goes to infinity in the geometric series, G = [(Q - a) +(1 _a)2 + (I - a)' +...+ (I - a)"]pO Following the Euler-Maclaurin Sum Formula, we render the summation as an "intensity factor," G (1- a)" -1 pO (1-a) -1 = [ - a(3.6) which is plotted in Fig. 3-4 for a range of values of a. As shown in the graph, a surface absorptivity of 0.3, typical for smooth wall surfaces painted white, will result in only a factor-of-two increase in the radiosity, or visible brightness, of the surface over the initialization value, (1- a)po. In the case of the full room model, the increase in brightness due to reflection is diminished by the view factor, the blinds, and the fact that only a small portion of any surface is directly illuminated by sunlight. 34 Surface Brightness at Equilibrium: Two Infinite Parallel Surfaces - -- - - -- - 4.5 - - - - - -- - - - - - - - - - ------ - - 4 3.5 o 3 u. 2.5 2 + 1.5 1 0.5 0 0.95 0.85 0.75 0.65 0.55 0.45 0.35 0.25 Surface Absorptivity Figure 3-4. Ratio of incident reflected light to initial sunlight intensity for the simplified case of two infinite parallel surfaces, plotted against surface absorptivity * REFLECTIONS AND SMOOTHING The time-intensive nature of the view factor calculations requires that we use a lowresolution grid of radiosities when calculating reflections. The new distribution of radiosity values that results from the reflections process can then be superimposed on a high-resolution model containing only the initial sunlight pattern. Because the incident daylight at any point is an integration of radiosities from all other points, it is expected that the resulting radiosity distribution over a surface approximates a smoothly varying, well-behaved function. To approach this smooth distribution in the program, the blocky, low-resolution grid on which reflections are calculated is smoothed before it is added to the high-resolution data. Fig. 2-5 shows the steps in this process. 35 For the smoothing procedure, we use a method of bilinear interpolation. This method can be explained by using the example of the crude, 2-by-2 radiosity grid in Fig. 3-5. The four points inside the square panels indicate locations on the surface where radiosity values have been recorded. Before smoothing, coordinates that lie between grid points are considered to have the same radiosity value as the nearest neighboring point. The smoothing procedure assigns intermediate values to these coordinates, so that when the grid data is transposed onto a grid with higher resolution, the surface radiosity will vary in a continuous manner between the positions where original data exists. To ensure that data points from the perimeter of the coarse grid appear in the smoothed version, the grid is augmented by a fringe of "dummy values" having the same value as their nearest neighbors on the perimeter. The radiosity values assigned to the intermediate coordinates (between grid points) can be expressed in terms of the radiosities at the surrounding points. If the rectangle defined by points a, b, c, and d in Fig. 3-5 has dimensions of Ax by Ay, and the point "d" has coordinates (xo,yo), the interpolated radiosity value J that is assigned to a point inside the rectangle having the coordinates (x,y) is given by J~~X-( =J, x-x, 36 y-y Ax A j~.X 3+J - 1 A Ax +Y )~YY (X Ay ") + - 1 xJ1 Ax Y -f~YoIK .o (3.7) Ay Added Fringe Points b a 0d C -A 0 c Interpolated Point d C * 0 e e 0 Boundary of 2x2 Sur face 0 Original Grid Point (radiosity value applies to area of surrounding square) Figure 3.5. Bilinear interpolation procedure * BLIND REFLECTIONS The daylighting program accounts for light reflecting off blind surfaces, but the distribution on the walls and ceiling of light emanating from the blinds is too detailed to be represented meaningfully at low resolutions. Therefore, these reflections are calculated prior to the iteration phase, so that light from the blinds is applied to the interior surfaces along with the initial sunlight distribution. The blinds are not involved in the radiosity equilibrium carried out during the iteration phase; the iterations involve only the 5 principal interior surfaces of the room. By adding blinds to the basic room model, we change only the initial distribution of sunlight in the room. Blinds span the window opening and can be tilted at any angle. 37 Light intercepted by the blinds is either reflected into the room, absorbed, or reflected to the exterior. To account for the light reflected into the room, we assume that each blind slat is a diffuse reflector of uniform emissivity. Although, in a real room, blinds would participate in a radiation exchange with the other surfaces, we account only for sunlight initially reflected from the blind slats, making this reflected light part of the initial sunlight distribution that prevails in the room before reflections between surfaces are calculated. A blind surface is considered to be illuminated by the sun if the line of sight between the sun and the center of the blind slat is not interrupted by the edge of the adjacent blind. A section of the ceiling (or wall) is illuminated in turn by light reflected from the blind slat if there is a line of sight between the center of the section and the center of the slat (Fig. 3-6). In calculating the view factor between the blind slat and sections of the inside surfaces, we use the discrete view factor developed above for the radiation exchange between surfaces (eq. 2.4). In this calculation, each blind slat is treated as a single element whose position is the geometric center of the slat. However, because this simplification causes areas of the ceiling directly over the blind slat centers to receive more light than those areas over the ends of the slat, the calculated view factors are averaged in the direction along the slat, and that average value used for the view factor between blinds and ceiling. 38 ~1 Maximum sun elevation to illuminate slat slat - Blind slat centerline sets: 1. Limit of sun's Illumination of slat 2. LImit of diffuse reflection to Interior surfaces Figure 3-6. Reflection field from a blind slat To account for the obstruction of direct sunlight by blinds in the window, we determine the position of the blind shadows. The extent of the shadow cast by each blind slat on the walls and floor is calculated using the same basic trigonometry from which the boundaries of sunlit regions were found in Chapter 2. The method for altering the radiosity grids so that they display blind shadows is explained in Chapter 4. 39 e DAYLIGHTING RESULTS The daylighting tool was originally designed to produce a visual output - a 3dimensional view of a room that would give a qualitative sense of the light distribution in a room lit only by natural light. This picture output from the program is based on numerical results for the radiosities at each data point inside the room, which are each associated with a region of the picture and prescribe the particular shade of gray to be displayed in that region. The data point values are also used in a second feature of the daylighting tool, in which the simulation cycles through many hours of daylight in a given room and records the amount by which the local radiosity falls short of some required minimum during each hour. By summing the shortfalls from all points on the grid, an hour-by-hour history of the total lighting "deficit" can be assembled, and a prediction made as to the amount of supplementary lighting required. The accuracy of the daylighting model can be judged by comparing the numerical output values from the simulation with the output from third-party rendering software. We used Lawrence Berkeley Labs' Radiance[3] on a Sony VAIO Pentium2 with 64 Mb RAM. Radiance is a general-purpose rendering program that can be programmed to illuminate any surface geometry and accommodate any degree of transparency or reflectivity in the surface materials, as well as handling light sources and color. The accuracy of our "initialization" routine, in which areas of the room that are lit directly by sunlight are identified, can be verified by a visual comparison with a Radiance model created using the same sun position. The accuracy of the diffuse reflection scheme used in our model is more difficult to verify. Ideally, we would like to isolate the reflected light from the direct sunlight in both room models (ours and 40 the Radiance model), and compare equilibrium radiosity values at corresponding positions in each room. We were able to run our model in parallel with a Radiance model in the absence of direct sunlight, by defining the window panel as an opaque surface that glows with the same intensity of diffuse light in both cases. Unfortunately, it is difficult to calibrate the overall brightness of our diffuse window surface with the window in the Radiance model, because of the restrictions that Radiance places on locations around the room where radiosities can be measured quantitatively by the user. It is not possible in Radiance to ascribe an initial diffuse brightness to the window surface, as we do in our own code. Instead, a diffuse light source must be established outside the window, and the light intensity set so as to produce the right level of brightness close to the inside window surface, where a measurement is made. This measurement can be made no closer than half an element-width from the window pane, and the agreement in absolute intensity between our model and the Radiance simulation is only approximate. We therefore tried to find a correspondence between the trends of light distribution in each of the models, rather than a strict agreement between the absolute magnitudes of the radiosities in each model. The comparison of models was carried out using a room with a floor area of 4m wide by 6m deep (in the direction away from the window plane), and 4m in height. The window sill is set at .6m above the floor, and the head of the window at .6m below the ceiling. All interior surfaces have 30% reflectance, and the grid of data points in both models measures 7 by 7 points on each surface. Blinds were not included in the comparison. Two sets of data from the Radiance model were available: the radiosity distribution after one reflection-iteration (bounce) and the slightly more 41 Floor Diffuse Brightness, Longitudinal 2.5 02 2 - - MIT Model 1.5 -ca 1 Radiance, 1 bounce Radiance, 2 bounces 0 0.5 0 1 2 3 4 5 6 7 Distance from Window Plane (Grid Row Number) Left Wall Diffuse Brightness, Longitudinal .2 3 2 -- MIT Model -N- Radiance, 1 bounce Radiance, 2 bounce 0 1 2 3 4 5 6 7 Distance from Window Plane (Grid Row Number) Figure 3-7. Comparison between MIT Design Advisor model results and a Radiance simulation in the longitudinal direction (towards and away from the window) 42 Floor Diffuse Brightness, Transverse 2.5 0 2 -+-MIT Model 1.5 -- Radiance, 1 bounce . ....... .U Radiance, 2 bounces 0. .2 0.5 0 1 2 3 4 5 6 7 Distance from Left Wall (Grid Row Number) a. Left Wall Diffuse Brightness, Transverse 4- .2 "0 3 -+-MIT Model -U-Radiance, 1 2_ bounce Radiance, 2 bounce .. ... .. "I, CL 0 1 2 3 4 5 6 7 Distance from Floor (Grid Row Number) b. Figure 3-8. Comparison between MIT Design Advisor model results and a Radiance simulation in the transverse direction (parallel to the window) 43 refined distribution after two. Since the window's sill and head both have the same thickness and since only diffuse light comes from the window, the lighting pattern on the floor is symmetrical with that on the ceiling, and the two walls have identical patterns also. To make a numerical comparison between our model and Radiance, we condense the 2-dimensional surface arrays into 2 data loci by averaging the surface radiosities in each of the two directions in turn. By comparing the loci on a 1dimensional basis, we observe that the correspondence between the two programs is generally stronger in the longitudinal direction, perpendicular to the plane of the window (Fig. 3-7). In the transverse direction, the floor and ceiling show good correspondence (Fig. 3-8a), but there is disagreement between the two representations of the walls (Fig. 3-8b). The values of radiosities in different parts of the room in relation to each other show almost identical trends in the two models. To produce the results shown in Figs. 3-7 through 3-9, we increased all of the radiosities in the MIT model by a constant factor to compare trends in the light distribution independent of overall brightness. To clarify some of the inconsistencies between the plots of Radiance surface brightness and the surface brightness recorded from our model, we ran a longer simulation using 20 grid points on each side instead of 7. The results are plotted in Fig. 3-9. Viewing the light distribution at a higher resolution helps to explain the diverging plots in Fig. 3-7a. The model's higher-than-expected value for grid 1 in Fig. 3-7a is apparently spurious, since the higher-resolution data drops off to a much lower value at the same distance from the window (Fig. 3-9a). This discovery does not resolve the discrepancy between the two models in Fig. 3-7a, but it does suggest that errors in the MIT model at positions close to the common edge of two surfaces 44 Floor Diffuse Brightness, Longitudinal 2.5 2 C 2 1.5 --- MIT Model 1 0 V M. (x 0.5 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1920 Distance from Window Plane (Grid Row Number) a. Left Wall Diffuse Brightness, Transverse 4 , .2 3 -+-4-MIT Model 2 ........... C1 0 .2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Distance from Floor (Grid Row Number) b. Figure 3-9. High-resolution results from the MIT model for both longitudinal and transverse directions 45 Figure. 3-10. Visual output from the MIT program, without blinds (top) and with (bottom). Comparable simulations in Radiance are pictured at right, along with the duration of the test might be artifacts of the discretization process. We also observe a discrepancy between the plots of wall brightness in the transverse direction; the Radiance plot indicates a fairly uniform radiosity distribution across the wall surface in the vertical direction, whereas the MIT model shows brighter values at the wall's midsection. The more highly resolved plot of the model's outputs (Fig. 3-9b) shows a previously unseen inflection in the radiosity curve, corresponding to the upper and lower edges of the window (the left and right ends of the plot). This expected signature is not found in the Radiance plot (Fig. 3-8b), which suggests that a finer mesh than 7-by-7 is required for Radiance to be used as a reliable control in this instance. The visual output from the program is similar to a Radiance image when the same scenarios are run in parallel. Regions of light and dark in the Radiance image are well preserved in the more rapid MIT simulation (Fig. 3-10). e LIGHTING ENERGY ESTIMATION RESULTS The radiosity values recorded for each grid element can be used to determine how effectively daylight will illuminate a room without the aid of electric lights. An architect designing an office space will be aware of the lighting requirement for the type of work that will go on in the office. This amount is usually given in lux (lumens per square meter) incident on the work surfaces in the room. We would like to be able to detect the light level across the workplane, fixed some distance above the floor at the height of a desk. By creating a new surface, giving it the coordinates of the workplane, and illuminating it with both direct sunlight and light reflected from the room's other interior surfaces, we can determine radiosity values at the workplane. If the sunlight that reaches the workplane does not meet the lighting requirement specified by the architect, the difference would be made up by electric lights, and the 47 ONE"," 9* - 8 8-9 7 ~6-7 5 5-6 5- .4-5 4 - 03-4 600- 02-3 2- *1-2 0 a. 9 8 5 7-1 6- 54- M8-9 07-8 M6-7 E) 5-6 04-5 133-4 02-3 M 1-2 3 2 001 Figure 3-11. Graphs of radiosity across a floor surface, represented as a "terrain." In b., setting the floor's minimum radiosity level is analogous to "pouring water" onto the terrain 48 yearly electricity requirement could be calculated from a knowledge of the sun position and intensity during each hour of the year. The sunlight distribution can be thought of as defining a topography over the workplane surface, with areas of high radiosity represented by hills and darker areas represented by valleys, as in Fig. 311 a. To this "landscape" we add light from electrical sources. The simplest way of modeling the light distribution from electric bulbs is to assume that a certain intensity of light can be commanded for each individual grid element of the workplane. If we assume that electric light can be delivered in this way, it can be added to the original sunlight illuminance until the lighting requirement for the workplane is satisfied for each element of the grid. In our topographic analogy, this is equivalent to pouring water onto the "landscape" defined by the sunlight distribution. The height of the free surface of the water and/or land represents the light intensity at any given position on the grid. We add water until the free surface reaches the height corresponding to the prescribed lighting requirement (Fig. 3-11b). When this point is reached, the electrical light will have met the lighting requirement using the most efficient distribution possible. The surface level is everywhere equal to the requirement, except in those places ("islands") where the intensity of sunlight alone is greater than the lighting requirement. Using the maximally efficient distribution of electric light, we can predict the amount of energy used by the lighting systems during a given hour. We use a quantity called the lighting "deficit" to represent the difference between the light provided by the sun and the total requirement for the office. The deficit is calculated every hour during a 49 Lighting Energy Deficit for Working Hours 70 - London - 400 Lux min. CI 60- light level - West-facing 50 -0 40 ----- 0 0I ... r~ 30 - -- .1 $2m depth -N-6m 1Om 15m 20m 20 10 0 1 2 3 4 5 6 7 8 9 10 11 12 Month (Jan = 1) a. Average Lighting Deficit 35 - London - 400 Lux min. level light level - West-facing 30 30 25 20 0 0 15 10 5 0 2m 6m lOn 15m 20m Depth of Room (m) b. ' Figure 3-12. Change in the lighting deficit with varying room depth 50 Average Lighting Deficit, Cairo (Working Hours) Room Depth = 16m 9 07 im05 5.F 4 - U) 0 2L --1%-0 north south east west Orientation a. Average Lighting Deficit, Anchorage (Working Hours) Room Depth = 16m 25 S 20 15 Uo 10 0 0 0 0 north south east west Orientation b. Figure 3-13. Change in the lighting deficit with varying building orientation 51 simulation run, using a sun position and solar direct and diffuse light intensities specific to each hour. In Fig. 3-12a, the lighting deficits, averaged by the month, are shown for an office room situated in London with a west-facing view from a single, wall-spanning window, a workplane 0.5m off the floor, 4m high and 6m wide, with 0.6-m margins above and below the window (height = 2.8m). The interior walls have an emissivity of 0.4. For a minimum lighting requirement at the workplane, we are using 400 lux, the European Union standard. This is also the maximum possible deficit - the amount of lighting that must be provided artificially when no light enters from outside (night conditions). The depth of the room is varied along the abscissa in Fig. 3-12b, showing an exponential increase in average electricity demand as the room becomes deeper in the dimension perpendicular to the window. Figure 13 shows the variation of required lighting energy by room orientation. A north-facing room (in the northern hemisphere) receives no direct sunlight, while a room with a southern prospect receives some direct light during every hour that the sun is visible. A west-facing building is exposed to direct rays for only half the day, but because of the low angle of incidence towards sunset, may receive more daylight overall than a south-facing window, as in the case of Cairo (Fig. 3-13a). As we would expect, at higher latitudes the incidence angle on the south face decreases, and the share of direct sunlight goes up relative to the west-facing window, as in Fig. 3-13b (Anchorage). Fig. 3-14 shows a range of average deficits for various cities ordered from north to south. In Cairo, the most southerly location, electrical lighting accounts for only 3.9% of the total lighting requirement for the working surfaces. 52 Lighting Energy Deficit for Working Hours Room Depth = 10m 70 - 60 50 - 40 - -- Anchorage -- 0 London Chicago Cairo 30 0 20 10 0 1 2 3 4 5 6 7 8 9 10 11 12 Month (Jan = 1) a. Average Lighting Deficit for Working Hours Room Depth = 10m 18 - x16 % 14 12 E o 0 b. 0 10 8 6 Fu 4 Chne 0 nte__hinectwihvryn___to 2 anchorage london chicago cairo Location b.- Figure 3-14. Change in the lighting deficit with varying location 53 Such results are useful for comparisons of energy cost between different scenarios, but to assess the real impact of a lighting configuration on the cost of building maintenance, we must find a way to equate electrical lighting energy costs with other expenses such as cooling and heating. One possible point at which to establish parity between these different energy quantities is at the power plant, where a chemical form of energy is converted into heat or electricity. We say there is a 1-to-1 conversion of chemical energy into heating energy, since fuel in the form of oil or natural gas is almost fully combusted within the building to produce heat for the rooms. Thus, E E H healers (Ieaters where E (3.8) is the chemical energy consumed at the building plant, and EHhactr is the amount of heating energy produced by the operation of the heaters. Electrical energy used for chillers and air conditioners inside the building represents perhaps one-third of the energy embodied in the chemical fuel consumed for its production. However, given an average coefficient of performance of 3 for the refrigeration of building air, the amount of energy removed from the air is about equal to the chemical energy converted to run the chillers: c hillers -"E - chillers electric E E( chE rS = 'clers E 1 ="eectric C 54 chillers E" cillers H Chillers (3.9) where EEchillers is the electrical energy used by the chillers and leec,,,c is the conversion efficiency (usually taken to be around 0.3). The amount of chemical energy effectively consumed for the sake of a given amount of lighting energy is as follows: 1 E ' lights 17 E E lights EElights electric = - E lighis 'lum 1 I E lIight 7 electric 7 Eght (3.10) , lum where E'tight. is equal to Iart (the illuminance by artificial light defined in eq. 2.5), multiplied by duration and area of coverage. The energy contained in the illumination of the workplane by electric lights is related to the electrical energy input to the lights This number can be anywhere from 0.019 for incandescent lights, to 0.14 by 77,,,. for fluorescents. By expressing the consumption of lighting energy as a cost at the power plant, we generally find that the cost of electric lighting is on the same order as the cost of heating and cooling. Unless the light fixtures are deliberately cooled, the electricity used reduces the heating load by the amount of electrical energy that is dissipated as heat in the fixture. Assuming that any electrical current is ultimately released into the room as heat, we can expand eq. 3.8 in the following way: E Cradiators =E H radiators EH gits = FE lights = L H load,healing - E - E H lights iights 11lum _ 55 radiators ::: E H lod heating -I ELlg (3.11) E' ii gis (3.12) similarly for the cooling load, E(' enil = Er load,cooling +[ L hun _ The Design Advisor website presents heating, cooling, and lighting energies in terms of the total required chemical energy, E" , based on simulation data for the values of E~load,eating , E 56 load,cooling , and ELuiglsj, for each hour of the test. CHAPTER 4: DETAILED METHOD o BASIC ROOM OBJECTS The simulation code for the program has been written in Java, an object-oriented language. The program is built of separate groupings of code called "classes," each of which contains the instructions for a certain "object," or component of the simulation, such as the blinds or the view factors. Once a new simulation has been ordered by the user, the first task of the software is to construct a room full of virtual objects in which to perform the daylighting calculations. The parameters specified by the user are used to create a "Map" object, of which each room is an instance, and which itself creates all other objects found in the room, including all the interior surfaces (see flowchart, Fig. 4-1). The "Surface" class is the basic element in the daylighting model. A room can contain several surfaces and a set of blinds. The Map class that defines each room in our program also contains various features that are permanently associated with any room, including routines that can be used to access information about the state of the room or its contents, storage space for the view factors between all possible permutations of surface elements, and software to allow one map to be added to another, producing a superposition of the two daylighting patterns. The surface object is the storage area where the simulation results are recorded in the form of radiosity values for each of the surface grid points. The surface file also retains information about the geometric dimensions of the surface and its grid point resolution. It is equipped with methods that allow a surface object to respond to 57 oto 00 -ft Process AN Figure. 4-1. Flowchart describing the operation of one siumulation cycle Object requests from the room object of which it is a part. The blinds are organized in a single package called a "BlindSet." The BlindSet object contains an array where it stores each of the blind slat objects. The BlindSet retains parameters referring to groupings of blind slats, such as the spacing between them, and handles all negotiations between the blind slats and the rest of the room. e INITIALIZATION ROUTINES To create a pattern on the inside surfaces where sunlight from the window would directly illuminate the interior, initialization routines must be adjusted for each particular kind of surface. One class, called "Surfacenitializer, "has been written as a universal template for applying a sunlight-pattern to interior surfaces. Different implementations of the template for floors and ceilings, windows, and walls, extend the generic methods in Surfacelnitializer to the case of a surface of one particular orientation. Using trigonometry, we find the distance from the window plane at which an observer at the level of the floor can just see the sun over the window sill. This is the minimum extent of the patch of sunlight on the floor, and the maximum extent, where the head of the window finally blocks the sun, can be calculated in the same way. To set the grid points on the floor to register a brightness due to the sunlit region, we find the rank of grid points in the floor's 2-D grid point array that most closely corresponds to the theoretical "minimum extent." Then, we begin assigning to this rank and all successive ranks up to the "maximum extent," the radiosity value that matches the brightness of reflected sunlight. 59 This procedure must be repeated in the direction parallel to the window surface, using a slightly different formula. The previous step left a band of illuminated grid points spanning the floor parallel to the window. However, the left and right boundaries of the window area will cast a diagonal shadow on the floor, for which the previous technique of simply blocking out ranks of the data grid is not adequate. Instead, each rank of grid points that is partly in shadow must have part of its rank blocked and part left illuminated. In other words, within the "for-loop" structure that advances away from the window at each increment to treat the next rank of grid points, there must be nested a second for-loop, which advances parallel to the window, point-by-point, to set boundaries on the illuminated part (Fig. 4-2). For-loop #1: Sets near and far extent of illumhuted region For-loop #2: Further constrains illumkirted region (Plae of Window) Figure 4-2. The sunlit region of a surface (the floor in this case) is first defined as a band of light between two lines parallel to the window. Then, a further limit on the region is imposed by moving rank-by-rank in the vertical direction and assigning individual limits in the horizontal direction for each rank The foregoing discussion has assumed that no blinds have been used in the window. For this simplified case, the walls and the floor and ceiling use almost identical methods to assign values to grid points in direct sunlight. However, when blinds are 60 used, the shadows cast on the floor look different from those on the walls. In the case of the floor, it is relatively simple to include blind shadows in the sunlight pattern: the blind slats cast rectangular shadows that run parallel to the window plane. To locate the blind shadows on the floor grid, we use the same procedure as we used to find the end of the sill shadow (the minimum extent of the sunlight) and the beginning of the head shadow (the maximum extent) in the case without blinds. We now apply the same technique to find the end of the shadow of one blind slat and the beginning of the shadow of the next. The blind shadows are not applied directly to the radiosity grid, but to a linear array representing the dimension running from the window to the back wall. The array consists of values of "1" and "0," and values of 1 are entered for cells corresponding to distances from the window at which a strip of sunlight penetrates through the blinds. Each rank of the grid containing the actual radiosities at each of the grid points is then multiplied by each successive element of the array of 1s and Os. Using this method, we can start with a sunlight pattern calculated without blinds, and then apply blind shadows to it, darkening the blindshadowed regions shaded by multiplying the corresponding grid points by the zeros in the array. Blind shadows cast on the walls have a diagonal pattern, so it is not possible simply to multiply each rank of the wall data grid by a linear array containing the shadow pattern. However, the blind shadows do run parallel to the edges of the original window-frame shadow, so a linear array can be used if it is applied starting with the lower edge of the diagonal sunlight pattern on the wall. A for-loop cycles through the ranks of wall grid points from the window surface to the rear wall, registering the blind shadow array with the beginning of the sunlight pattern for each new rank. By 61 multiplying each rank by a 1 or 0 from the blind shadow array, a diagonal blind shadow is superimposed on the original sunlight pattern. The pattern of light on the walls and ceiling includes light reflected from the blinds. To calculate this contribution to the initial sunlight distribution, we consider the blinds to be diffuse reflectors, and calculate view factors between the blind slats and each rectangular surface element represented by a grid point. To reduce the computation time, each blind slat is considered to be a single element, and the view factors taken in respect to the position of the center of the slat. We have remarked that one undesirable side effect of this simplification is that a much larger view factor is calculated for regions of the ceiling directly above the center of the slats, than for parts of the ceiling over the ends of the slats. If the problem were not corrected, a concentration of light would appear on the ceiling over the meridian of the window pane. Instead, we have calculated view factors between each blind slat and each surface element along each row from wall to wall across the ceiling. For each row, we find the average of all the view factors, and use that average as the new view factor for all surface elements in the row. Reflections from blind slats may be intercepted by other blinds. To account for this interference in a simple manner, we assume that: 1. A blind slat is fully illuminated by the sun if the line of sight from the center of the slat area to the sun is unobstructed, and otherwise the slat is illuminated not at all. 62 2. A surface element of the ceiling or wall is illuminated by reflections from the blind slat, using the view factor involving the entire area of the slat, if the line of sight with the slat center is unobstructed, and otherwise there is no reflection to the surface element. Both criteria are applied at the stage when the additional light due to the reflection from each blind is transferred to an interior surface element. Each criterion is represented by a test routine which returns a "0" if line-of-sight is broken, and a "1" if it is intact after the test. The amount of reflected light that stands to be applied to the surface element is then multiplied by each value returned, so that only if all tests are passed is there any contribution of reflected light from the slat in question. Each criterion can be tested by calculating the angle of elevation of the line drawn between the blind center and the surface element. This angle is compared with a maximumangle-for-unobstructed-sight, which is found as a function of the surface element's coordinates, the slat number and spacing, and the sun elevation. * REFLECTIONS The consideration that limits the resolution at which reflections can be calculated is the number of times that a view factor must be calculated between two surface elements in a room (the transmitting element and the receiving element). The number of these calculations is given by the square of the total number of elements, since for each element, we must be able to determine the light contribution from each other element according to a mutual view factor. Because the interior surfaces are flat, we assume that reflections are not exchanged between two elements of the same surface. The view factors between different elements need only be calculated once, just before the first round of reflections (the first "bounce") is performed. 63 Assuming that enough space can be reserved in memory, the view factor values may then be retained in memory and accessed quickly during successive bounces. A class called "Iterator" has been built to update radiosity values around the room with the contributions of reflected light. It manages the creation and referencing of view factors so that the time-consuming view factor calculation need only happen once. * SMOOTHING The daylighting simulation creates two separate versions of a room: the first is a high-resolution model in which direct sunlight has been applied to the interior surfaces but reflections have not been calculated. The second is a low-resolution model initialized in the same way, but in which the reflection procedure has proceeded to equilibrium. To combine the two models in the program's final output, we have written a set of routines to transfer the low-resolution data to a highresolution grid, then smooth the data and add it point-by-point to the existing highresolution model. Because grids cannot be added or subtracted unless they are of exactly the same dimensions, at least one of the grids involved in the operation must have its dimensions altered to accord with the dimensions of the other grid. To make it clear which set of dimensions are being used, we have made it the responsibility of each surface to create an algebraically compatible version of any other surface that is passed to it, so that it can then conduct the addition or subtraction at its own original resolution. 64 Methods for adding one set of grid data to another are embedded in the Surface class, where the grid data (the radiosity values) themselves are also stored. A surface object can pass grid data to a class called "Bilinear," which is the unit responsible for expanding or reducing the scale of a grid. To add low-resolution model data to a high-resolution model, the program employs a method called "Add RadiositiesFrom" in each of the "surface" objects of the high-resolution model. A reference to the low-res surface to be added is passed to the "AddRadiositiesFrom" method of the high-res surface. The high-res surface can then create a "Bilinear" object out of the grid from the low-res surface. The low-res surface grid, packaged in this new "Bilinear" object (see flowchart, Fig. 4-1), can be expanded and smoothed using methods in the Bilinear class, and the resulting grid added to the high-res surface's grid of radiosities. 65 66 Bibliography 1 [MIT 1999] 2 [Arons 2000] MIT Design Advisor website. http://18.80.2.250:8080/design Arons, Daniel M. M. Properties and Applications of Double-Skin Building Facades. Masters Thesis for the Department of Architecture, MIT. Cambridge, Massachusetts: 2000. and [Lehar 2001] Lehar, Matthew A. and Leon Glicksman. A Simulation Tool for Predicting the Energy Implications of Advanced Facades. MIT Building Technology Division. Cambridge, Massachusetts: 2002. 3 [DOE 2001] EnergyPlus building energy simulation program. Produced and distributed by the U.S. Department of Energy. Available at http://www.eren.doe.gov/buildings/energy tools/energyplus/ 4 [LBL ] Radiance rendering software. Produced and distributed by Lawrence Berkeley Labs. Available at http://radsite.lbl.gov/radiance/HOME.html 5 [MeteoTest 2000] MeteoNorm Global Meteorological Database for Solar Energy and Applied Climatology. CD-ROM by MeteoTest, Bern: 2000. 6 [Larson, 1997] Larson, Gregory Ward, Holly Rushmeier, and Christine Piatko. A Visibility Matching Tone Reproduction Operator for High Dynamic Range Scenes. Berkeley, California: 1997. 67 68 Appendix: Program Code for the Lighting Module The Java source code for the Illumination Module of the Design Advisor tool is presented in the following section. List of Classes Used in the Program.............................. 70 Program O rganization............................................... 71 Index of Method and Variable Names............................... 72 PROG RAM CODE..................................................... 91 69 1. List of Classes Used in the Program o 70 class java.lang.Object o class illumination.ArrayMaker o class illumination.Azimuth o class illumination.Bilinear o class illumination.BinSorter o class illumination.Blind o class illumination.BlindSet o class illumination.Box o class illumination.FileOut o class illumination.Fringer o class illumination.GrayScaleConverter o class illumination.Illumination o class illumination.Initializer o class illumination.Interpolator o class illumination.Iterator o class illumination.MaD o class illumination.PerspectiveView o class illumination.Point3D o class illumination.PVTest o class illumination.Ouadrant o class illumination.Resizer o class illumination.SettingSuite o class illumination.SolarlnfoCalculator o class illumination.SolarSuite o class illumination.Surface o class illumination.Facade o class illumination.Platform o class illumination.SideWall o class illumination.SurfaceInitializer o class illumination.Facadelnitializer o class illumination.Platformlnitializer o class illumination.FloorCeilin2lnitializer o class illumination.Workplanelnitializer o class illumination.SideWalllnitializer o class illumination.ViewFactorSuite o class illumination.ViewFactory o class illumination.Wall o class illumination.WeatherDataReader o class illumination.WindowSuite o class illumination.WorkplaneBay 2. Program Organization Program Classes I creates: JMNM _FMNIMW -am -low L 71 3. Index of Method and Variable Names A a - Variable in class illumination.Surface Resolution in the principal dimension of the surface. a - Variable in class illumination.Surfacelnitializer A - Variable in class illumination.Surface Array of differential areas of each element that makes up the surface. addRadiositiesFrom(Map, String!, Stringz) - Method in class illumination.Map Adds or subtracts the radiosity values of the input Map from the dereferenced Map. addRadiositiesFrom(Surface, String, String) - Method in class illumination.Surface alpha - Variable in class illumination.Surface "alpha," "beta," and "gamma" take values of either 1 or 0. angleOnSurface - Variable in class illumination.Surfacelnitializer applyPatchOfSunlight(String) - Method in class illumination.Facadelnitializer applyPatchOfSunlight(String) - Method in class illumination.FloorCeilinginitializer applyPatchOfSunlight(Strin2) - Method in class illumination. SideWalilnitializer applyPatchOfSunlight(String) - Method in class illumination.Surfacelnitializer applyPatchOfSunlight(Strin) - Method in class illumination.Workplanelnitializer ArrayMaker - class illumination.ArrayMaker. ArrayMakerO - Constructor for class illumination.ArrayMaker Azimuth - class illumination.Azimuth. Azimuth(double, String) - Constructor for class illumination.Azimuth Azimuth(double, String, double) - Constructor for class illumination.Azimuth B b - Variable in class illumination.Surface Resolution in the second dimension of the surface. b - Variable in class illumination.Surfacelnitializer 72 beta - Variable in class illumination.Surface "alpha," "beta," and "gamma" take values of either 1 or 0. Bilinear - class illumination.Bilinear. Bilinear(doublef][1, int, int) - Constructor for class illumination.Bilinear Reads in input array, creates output buffer, assigns dimensions to the output buffer, and puts a fringe on the output buffer bilinearlnterpolateO - Method in class illumination.B ilinear bilinearlnterpolate(doublel l[ 1) - Method in class illumination.Interpolator BinSorter - class illumination.BinSorter. BinSorter(double, double, double) - Constructor for class illumination.BinSorter Blind - class illumination.Blind. Blind(double, double) - Constructor for class illumination.Blind blinds - Variable in class illumination.Map BlindSet - class illumination.BlindSet. BlindSet(int, double, double, double, double, double) - Constructor for class illumination.BlindSet blindSpacing - Variable in class illumination.SettinaSuite blindSpacing - Variable in class illumination.Surfacelnitializer blindStartEndDistances - Variable in class illumination.Surfacelnitializer blindStartEndlndeces - Variable in class illumination. SurfaceInitializer blindViewFactorArray - Variable in class illumination.Map blindViewFactorSum - Variable in class illumination.Surfacelnitializer blindWidth - Variable in class illumination.Surfacelnitializer blocki - Variable in class illumination.Surfacelnitializer block2 - Variable in class illumination.Surfacelnitializer Box - class illumination.Box. Box(double, double, double, double, double, double) - Constructor for class illumination.Box 73 C calculate(int, int, double, double) - Method in class illumination.Azimuth calculateAn2leOflncidence(double, double) - Method in class illumination.Azimuth calculateAn2leOflncidence(double, double, double) - Method in class illumination.Azimuth calculateDeclination(double) - Method in class illumination.Azimuth calculateDiffuseSolarGain(double, double) - Method in class illumination.Azimuth calculateDirectSolarGain(double, double) - Method in class illumination.Azimuth calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.Facadelnitializer calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.Platformlnitializer Only one view factor is computed between each blind slat and each element of the platform (i.e. calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.SideWallInitializer calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.Surfacelnitializer calculateHourAngde(double) - Method in class illumination.Azimuth calculateSolarRadiationGain(double, double, double, double, double) - Method in class illumination.Azimuth calculateSurfaceSolarAzimuth(double, double) - Method in class illumination.Azimuth calculateWorkplaneLightLevels(SolarSuite, WindowSuite, double) - Method in class illumination.WorkplaneBay CALCULATEWORKPLANELIGHTLEVELSO centerInZ() - Method in class illumination.BlindSet cleanUpO - Method in class illumination.Map clearBilinearGridO - Method in class illumination.Surface columnTemplate - Variable in class illumination.Surfacelnitializer 74 computeViewFactor(double, double, double, double, double, double, double, double, double, double, double, double, double) - Method in class illumination.ViewFactory computeViewFactorWithBlinds(Surface, int, int, int, BlindSet, double) - Method in class illumination.ViewFactory constantCoordinate - Variable in class illumination.Surface Position of the surface in the dimension normal to the surface. constructSurface(String, int, int, double, double, double, double) - Method in class illumination. Surface Defines surface variables and allocates space for the surface's data arrays. convertRadiositvToGrayScale(double) - Method in class illumination.GrayScaleConverter convertRadiosityToGrayScale(double, double) - Method in class illumination.GrayScaleConverter createSurfaceFile(double[lff) - Static method in class illumination.FileOut createSurfaceFile(doublell HIi) - Static method in class illumination.FileOut createSurfaceFile(doubleH 11, Strins!) - Static method in class illumination.FileOut createSurfaceFile(Surface) - Static method in class illumination.FileOut createWorkplanes(double, int, int, int, int) - Method in class illumination.Map crossDistance - Variable in class illumination.Surface Magnitude of the distance across the surface in the direction of "b." crossDistance - Variable in class illumination.Surfacelnitializer cumulativeDistributionFunction(double) - Method in class illumination.BinSorter currentSurface - Variable in class illumination.Surfacelnitializer D degToRad(double) - Method in class illumination.Surfacelnitializer depthMagnitude - Variable in class illumination.SettingSuite depthResolution - Variable in class illumination.SettingSuite diffIntensity - Variable in class illumination.SolarSuite difflntensity - Variable in class illumination.Surfacelnitializer drawImage(int, int, int) - Method in class illumination.PerspectiveView 75 E emissivity - Variable in class illumination.SettingSuite emissivity - Variable in class illumination. Surface emissivity - Variable in class illumination.Surfacelnitializer F Facade - class illumination.Facade. Populates some of the basic arrays for the surface and invokes methods in the superclass to completely create the surface. Facade(String, int, int, double, double, double, double) - Constructor for class illumination.Facade FacadeInitializer - class illumination.Facadelnitializer. Facadelnitializer() - Constructor for class illumination.Facadelnitializer FileOut - class illumination.FileOut. FileOut() - Constructor for class illumination.FileOut findAngleOnSurface(double, double) - Method in class illumination.Facadelnitializer findAngleOnSurface(double, double) - Method in class illumination.Platformlnitializer findAngleOnSurface(double, double) - Method in class illumination.SideWalllnitializer findAngleOnSurface(double, double) - Method in class illumination.Surfacelnitializer findColumnIndexInRow(StringY, double, int, double, double, double) - Method in class illumination.Surfacelnitializer Returns an index corresponding to the near or far extent, in the surface's secondary direction, and within a particular row of elements specified by "presentlndex," of the patch of sunlight on a surface. findIlluminatedSide(double) - Method in class illumination.BlindSet findlndecesOfNearAndFarReach(double[, int, double) - Method in class illumination.Surfacelnitializer Returns a 2-element array containing the indeces of the elements on the surface grid corresponding to the near and far extent, in the surface's principal direction, of the projection of sunlight. 76 findNearAndFarDistances(double, double, double) - Method in class illumination.Surfacelnitializer Returns a 2-element array containing the near and far extent, in the surface's principal direction, of the patch of sunlight projected from the window upon the walls or floor. findObliquelntensityFraction(double) - Method in class illumination.Surfacelnitializer findRadiosityAtPoint(double, double, double, GrayScaleConverter) - Method in class illumination.Map Returns a value between 0 and 255 corresponding to the radiosity levels at the specified coordinates. The following conventions apply when using this method: "x" corresponds to the depth (in-out) dimension "y" corresponds to the height (up-down) dimension "z" corresponds to the width (left-right) dimension All coordinates are measured from an origin at the lower, right-hand corner of the window surface, assuming the window is viewed from inside the room. Surface numbers run as follows: 0: floor 1: sideWallI (right-hand side) 2: sideWall2 (left-hand side, looking toward window from inside) 3: ceiling 4: window findReciuiredLightingEnergy(String, String, double, double) - Method in class illumination.Illumination The following method is only for testing purposes: FINDREQUIREDLIGHTINGENERGY() Runs many daylighting calculations at different times of the day and during different months of the year. findStrike(double, double) - Method in class illumination.Box findStrike(double, double) - Method in class illumination.Quadrant FloorCeilinglnitializer - class illumination.FloorCeilin gInitializer. FloorCeilingInitializerO - Constructor for class illumination.FloorCeilingInitializer frinueArray(double[I W[D - Method in class illumination.Fringer Operates on an array consisting of two, 2-D arrays stacked one atop the other (a 3-D array with only two elements in the third dimension). Fringer - class illumination. Fringer. Fringer() - Constructor for class illumination.Fringer G 77 gamma - Variable in class illumination.Surface "alpha," "beta," and "gamma"take values of either 1 or 0. ietAltitudeO - Method in class illumination.Azimuth getAltitude() - Method in class illumination.SolarInfoCalculator ietArrayAndIndeces(double[ W) - Method in class illumination.Resizer getArrayAndIndeces(double[l[1, int, int) - Method in class illumination.Resizer Takes a pair of resolutions and returns a 2-D array of two layers (actually a 3-D array). getAzimuth() - Method in class illumination.Azimuth getAzimuth() - Method in class illumination.SolarlnfoCalculator getBlindSpacing() - Method in class illumination.BlindSet getBlindWidthO - Method in class illumination.BlindSet getCollectiveAngle() - Method in class illumination.BlindSet getCollectiveBlindAngle() - Method in class illumination.Illumination GETCOLLECTIVEBLINDANGLEO Returns current blind angle. getCollectiveBlindAngleo - Method in class illumination.Map getDepth() - Method in class illumination.Map Returns the in-out dimension of the room getDiffuseHorizonta1Radiation(int, int) - Method in class illumination. WeatherDataReader getDiffuseIntensityO - Method in class illumination.SolarInfoCalculator getDiffuseRadiationGaino - Method in class illumination.Azimuth getDirectIntensity() - Method in class illumination.SolarlnfoCalculator getDirectNormalRadiation(int, int) - Method in class illumination.WeatherDataReader getDirectRadiationGain() - Method in class illumination.Azimuth getDryBulbTemperature(int, int) - Method in class illumination.WeatherDataReader 2etEquivalentDistance(int, double, String) - Method in class illumination.BlindSet getFloorResolution ao - Method in class illumination.Map getFloorResolution bo - Method in class illumination.Map getHeightO - Method in class illumination.Map Returns the up-down dimension of the room getLatitudeO - Method in class illumination. WeatherDataReader 78 getMonthAveragedWorkplaneO - Method in class illumination.Illumination The following method is only for testing purposes: GETMONTHAVERAGEDWORKPLANE() getNumberCorrespondingToSurfaceName(String!) - Method in class illumination.Map getNumBlinds) - Method in class illumination.BlindSet getProiectedDistance(int, String) - Method in class illumination.BlindSet getRadiositv() - Method in class illumination.Blind getRadiosity(int) - Method in class illumination.BlindSet getResolutionOfExistingInputGrid a() - Method in class illumination.Bilinear getResolutionOfExistinglnputGrid bo - Method in class illumination.Bilinear getShade(double, double) - Method in class illumination.Wall 2etSolarRadiationGaino - Method in class illumination.Azimuth 2etSurfaceDimension(String) - Method in class illumination.Surface 2etSurfaceNameCorrespondingToNumber(int) - Method in class illumination.Map 2etSurfaceNewResolution(String, int, int, int) - Method in class illumination.Surface 2etSurfaceSolarAzimuthO - Method in class illumination.Azimuth getUnsmoothedArrayo - Method in class illumination.Bilinear uetUnsmoothedArray(doublefl ) - Method in class illumination.Bilinear 2etVerticalPositiono - Method in class illumination.Blind getVerticalPosition(int) - Method in class illumination.BlindSet getWidth(O - Method in class illumination.Map Returns the left-right dimension of the room GrayScaleConverter - class illumination.GrayScaleConverter. GrayScaleConverter(Map, int) - Constructor for class illumination.GrayScaleConverter GrayScaleConverter(Map, Map, int) - Constructor for class illumination.GrayScaleConverter 79 H H - Variable in class illumination.Surface "H" is the array of values of the intensity of light that is reflected from a surface. head - Variable in class illumination.Surfacelnitializer headHei2ht - Variable in class illumination.WindowSuite headIndex - Variable in class illumination.Surfacelnitializer heiihtMagnitude - Variable in class illumination.SettingSuite heightResolution - Variable in class illumination. SettingSuite hiResWorkplane - Variable in class illumination.Map horizontalAngle - Variable in class illumination.Surfacelnitializer I illuminateWithSunlight(String, double) - Method in class illumination.Surfacelnitializer Applies brightness to selected elements of the surface grid, according to a calculation of which parts of the surface would be reached by the sunlight. Illumination - class illumination.Illumination. Illumination(int, double, double, double, double, double, double, double, double, double) - Constructor for class illumination.Illumination "Pre-constructor" (2) for constructor No.1 - NO BLINDS. Illumination(int, double, double, double, double, double, double, double, double, double, int, double) - Constructor for class illumination.Illumination "Pre-constructor" (5) for constructor No.3 - INCLUDES BLINDS. Use this FOR TESTING ONLY if you want to specify the blind angle 11/20/02 Illumination(int, double, double, double, double, double, double, int, double, double, double) - Constructor for class illumination.Illumination "Pre-constructor" (3) for constructor No.1 - INCLUDES BLINDS. Illumination(int, double, double, double, int, RoomDescription) - Constructor for class illumination.Illumination Base constructor for Illumination class. Explanations of the input variables are as follows: nameOfJob only for your reference RESOLUTIONx low-res Map resolution RESOLUTIONFINE x high-res Map resolution sillHeight height, measured from floor, of bottom of transparent part of facade headHeight height, measured from floor, of top of transparent part of facade Illumination(RoomDescription) - Constructor for class illumination.Illumination "Pre-constructor" (4) for constructor No.1 - INCLUDES BLINDS. 80 imposeBlindSlatShadows(BlindSet) - Method in class illumination.Facadelnitializer imposeBlindSlatShadows(BlindSet) - Method in class illumination.FloorCeilinglnitializer imposeBlindSlatShadows(BlindSet) - Method in class illumination.SideWallInitializer imposeBlindSlatShadows(BlindSet) - Method in class illumination.Surfacelnitializer imposeBlindSlatShadows(BlindSet) - Method in class illumination.Workplanelnitializer indecesOfNearAndFarReach a - Variable in class illumination.SurfaceInitializer indecesOfNearAndFarReach b - Variable in class illumination. SurfaceInitializer initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite) - Method in class illumination.Facadelnitializer initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite) - Method in class illumination.FloorCeilingInitializer initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite) - Method in class illumination.SideWalllnitializer initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite) - Method in class illumination. SurfaceInitializer initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite) - Method in class illumination.WorkplaneInitializer All arguments to oneWorkplanelnitializer must be from the same room object, except for blindShadingScheme. initializeHiResWorkplane(Map, WindowSuite, String, double, SolarSuite) - Method in class illumination.Initializer initializeMasksO - Method in class illumination.Surfacelnitializer rowTemplate columnTemplate these arrays serve as masks: when pointwisemultiplied by the radiosity arrays of a surface, they introduce black (zero-valued) bands where the shadow of a blind slat crosses that surface. Initializer - class illumination.Initializer. InitializerO - Constructor for class illumination.Initializer initializeSurfaceVariables(Surface, BlindSet, WindowSuite, SolarSuite) - Method in class illumination.Surfacelnitializer Defines variables that are surface-specific, and therefore not covered by "constructSurfacelnitializerInAbstract." Also initializes surface radiosity arrays to zero. Interpolator - class illumination.Interpolator. Interpolator(doublel [1) - Constructor for class illumination.Interpolator 81 isFirstInitialization - Variable in class illumination.Map isFirstlteration - Variable in class illumination.Map isFirstWorkplanelnitialization - Variable in class illumination.Map isFirstWorkplanelteration - Variable in class illumination.Map iteratedRoom - Variable in class illumination.WorkplaneBay iterateRadiosityCalc(Map) - Method in class illumination.Iterator Establishes holding arrays for the view factors between one surface and another. Iterator - class illumination.Iterator. Device that can be used to perform reflections between the inside surfaces of a room. Iteratoro - Constructor for class illumination.lterator Initializes variables J iEndin2 - Variable in class illumination.Surfacelnitializer iStarting - Variable in class illumination.Surfacelnitializer L left - Variable in class illumination.Surfacelnitializer leftMargin - Variable in class illumination.WindowSuite lightBandOnFloorStartEndDistances one - Variable in class illumination.Surfacelnitializer li2htBandOnFloorStartEndDistances two - Variable in class illumination.Surfacelnitializer li2htFractionPassingThroughBlinds - Variable in class illumination.Surfacelnitializer lineOfSightFlag(int, int, int, BlindSet, double) - Method in class illumination.Surfacelnitializer lowResWorkplane - Variable in class illumination.Map M main(Strini[1) - Static method in class illumination.Azimuth 82 main(String[1) - Static method in class illumination.Box main(String[1) - Static method in class illumination.PVTest main(Strinffl) - Static method in class illumination.Quadrant main(Strinell) - Static method in class illumination.WalI makeBlindFactors 1D(int, int) - Method in class illumination.ViewFactorSuite makeBlindFactors 2D(int, int, int) - Method in class illumination.ViewFactorSuite Map - class illumination.Map. Sets up a "room" by creating interior wall, floor, ceiling and window surfaces, plus a set of blinds. Map(Map, SettingSuite) - Constructor for class illumination.Map Used for creating a duplicate copy of an existing Map object. Map(SettingSuite) - Constructor for class illumination.Map Base constructor for Map class. N name - Variable in class illumination.Surface Name of the surface. name - Variable in class illumination.Surfacelnitializer nearAndFarDistances - Variable in class illumination.Surfacelnitializer numberOfBlinds - Variable in class illumination.SettingSuite numberOfSurfaces - Variable in class illumination.Map 0 obliqueIntensityFraction - Variable in class illumination.Surfacelnitializer obstructionFactor(int, int, BlindSet, int, ViewFactorSuite) - Method in class illumination.Workplanelnitializer oneHourWorkplaneLightingEnergyv(double, double, double, double) - Method in class illumination.llumination ONEHOURWORKPLANELIGHTINGENERGY() Returns the required illuminance by artificial means to maintain room brightness at minLightLevel, in Watts per floor area. oneInterpolator - Variable in class illumination.Bilinear mA2 of 83 overhang!Depth - Variable in class illumination.WindowSuite P parallelDistance - Variable in class illumination.Surface Magnitude of the distance across the surface in the direction of "a." parallelDistance - Variable in class illumination.SurfaceInitializer PerspectiveView - class illumination.PerspectiveView. PerspectiveView(Map) - Constructor for class illumination.PerspectiveView PerspectiveView(Map, double, double, double) - Constructor for class illumination.PerspectiveView PerspectiveView(Map, Map) - Constructor for class illumination.PerspectiveView PerspectiveView(Map, Map, double, double, double) - Constructor for class illumination.PerspectiveView Platform - class illumination.Platform. Populates some of the basic arrays for the surface and invokes methods in the superclass to completely create the surface. Platform(Platform) - Constructor for class illumination.Platform Platform(String, int, int, double, double, double, double) - Constructor for class illumination.Platform PlatformInitializer - class illumination.Platformlnitializer. PlatformInitializerO - Constructor for class illumination.Platformlnitializer Point3D - class illumination.Point3D. Point3DO - Constructor for class illumination.Point3D populateArray(int, int, double) - Static method in class illumination.ArrayMaker positionForflour(int, int) - Method in class illumination.SolarlnfoCalculator PVTest - class illumination.PVTest. PVTest() - Constructor for class illumination.PVTest 84 Q Q - Variable o in class illumination.Surface "Q" is the surface radiosity array that updates as the iterations proceed. initial - Variable in class illumination.Surface "Qinitial" is the surface radiosity array that records the initial radiosity of the surface, after the surface has been initialized by illuminating it with sunlight, but before the iterations (reflections) have begun. Quadrant - class illumination.Quadrant. Quadrant(double, double, double, double) - Constructor for class illumination.Quadrant R radToDed(double) - Method in class illumination.Surfacelnitializer rapidFineRoom - Variable in class illumination.WorkplaneBay read(String) - Method in class illumination.WeatherDataReader refindexArray - Variable in class illumination.Resizer removeSpaces(String) - Static method in class illumination. WeatherDataReader replaceFloor(Surface, String) - Method in class illumination.Map replaceSurface(Surface, String) - Method in class illumination.Surface Accomodates different resolutions in the two surfaces involved in the exchange. Resizer - class illumination.Resizer. ResizerO - Constructor for class illumination.Resizer resolutions - Variable in class illumination.Surface right - Variable in class illumination.Surfacelnitializer ri2htMargin - Variable in class illumination.WindowSuite room - Variable in class illumination.WorkplaneBay rowTemplate - Variable in class illumination.Surfacelnitializer S setAngle(double) - Method in class illumination.Blind 85 setCollectiveAnglle(double) - Method in class illumination.BlindSet setCollectiveBlindAngle(double) - Method in class illumination._Map setHArrayTo(double) - Method in class illumination. Surface setInitialLightLevels(Map, WindowSuite, String, double, SolarSuite) - Method in class illumination.Initializer setOO - Method in class illumination.Surface Updates "Q" based on light reflected from another surface. setRadiositv(double) - Method in class illumination.Blind setRadiosity(double, double) - Method in class illumination.BlindSet setRadiosity(int, double) - Method in class illumination.BlindSet SettingSuite - class illumination.SettingSuite. Stores illumination parameters. SettingSuite(double, double, double, double, int, int, int, WindowSuite, int, double) Constructor for class illumination.SettingSuite Base constructor for SettingSuite class. SettingSuite(SettingSuite, int, int, int) - Constructor for class illumination.SettingSuite Used for creating a copy of an existing SettingSuite object, with only the resolution values changed. shade - Variable in class illumination. Wall showReflectionsOnLowResWorkplane(Map) - Method in class illumination.Iterator SideWall - class illumination.SideWall. Populates some of the basic arrays for the surface and invokes methods in the superclass to completely create the surface. SideWall(String, int, int, double, double, double, double) - Constructor for class illumination.SideWall SideWalllnitializer - class illumination.SideWalllnitializer. SideWallnitializer() - Constructor for class illumination.SideWalllnitializer sill - Variable in class illumination.Surfacelnitializer sillHei2ht - Variable in class illumination.WindowSuite silllndex - Variable in class illumination.Surfacelnitializer simulateOneRoom(double, double, double, double) - Method in class illumination.Illumination SIMULATEONEROOMO No-blinds version of the above. 86 simulateOneRoom(double, double, double, double, double) - Method in class illumination.Illum ination SIMULATEONEROOM() Runs a single daylighting calculation, for the purpose of displaying the view of a room interior at a particular point in time. slatAreaO - Method in class illumination.BlindSet solarAngleHorizontal - Variable in class illumination. SolarSuite solarAngleVertical - Variable in class illumination.SolarSuite solarIncoming - Variable in class illumination.SolarSuite solarincoming - Variable in class illumination.Surfacelnitializer SolarInfoCalculator - class illumination.SolarlnfoCalculator. By JIM GOULDSTONE SolarlnfoCalculator(String, String) - Constructor for class illumination.SolarInfoCalculator SolarSuite - class illumination.SolarSuite. SolarSuite(double, double, double, double) - Constructor for class illumination.SolarSuite sort(Map, int, double) - Method in class illumination.BinSorter For one room sort(Map, Map, int, double) - Method in class illumination.BinSorter For two rooms substituteQValues(doubleHl]H) - Method in class illumination.Surface Puts a new array of radiosities in place of the existing Q and Qinitial arrays. sumDefecitValues() - Method in class illumination.WorkplaneBay Surface - class illumination.Surface. The basic storage element of this package. SurfaceO - Constructor for class illumination.Surface SurfaceInitializer - class illumination.Surfacelnitializer. SurfacelnitializerO - Constructor for class illumination.Surfacelnitializer surfaces - Variable in class illumination.Map surfaceToBlindPairings ID - Variable in class illumination.ViewFactorSuite surfaceToBlindPairings 2D - Variable in class illumination.ViewFactorSuite surfaceToSurfacePairings - Variable in class illumination.ViewFactorSuite surfaceType - Variable in class illumination.Surface Category in which the surface is classed. 87 T thirdIsConstant - Variable in class illumination.Surface toDegrees(double) - Static method in class illumination.Azimuth toRadians(double) - Static method in class illumination.Azimuth toStringO - Method in class illumination.Point3D totalNumber - Variable in class illumination.BlindSet totalNumberOfBlinds - Variable in class illumination.Surfacelnitializer V valuelndexArray - Variable in class illumination.Interpolator verticalAngle - Variable in class illumination.Surfacelnitializer viewFactorArray - Variable in class illumination.Map ViewFactorSuite - class illumination.ViewFactorSuite. ViewFactorSuiteO - Constructor for class illumination.ViewFactorSuite ViewFactorSuite(int, int, int, int) - Constructor for class illumination.ViewFactorSuite ViewFactory - class illumination.ViewFactory. ViewFactoryO - Constructor for class illumination.ViewFactory w Wall - class illumination.Wall. Wall(int[l[1, double, double) - Constructor for class illumination.Wall WeatherDataReader - class illumination.WeatherDataReader. WeatherDataReaderO - Constructor for class illumination.WeatherDataReader widthMagnitude - Variable in class illumination.SettingSuite widthResolution - Variable in class illumination.SettingSuite 88 windowSpecs - Variable in class illumination.SettingSuite WindowSuite - class illumination.WindowSuite. WindowSuite(double, double, double, double, double) - Constructor for class illumination.WindowSuite WorkplaneBay - class illumination. WorkplaneBay. WorkplaneBay(SettingSuite, SettingSuite, Initializer, Iterator, double, double) Constructor for class illumination.WorkplaneBay workplaneBlindViewFactorArray - Variable in class illumination.Map WorkplaneInitializer - class illumination.Workplanelnitializer. WorkplaneInitializer() - Constructor for class illumination. WorkplaneInitializer workplaneViewFactorArray - Variable in class illumination.Map x x - Variable in class illumination.Point3D x - Variable in class illumination.Surface "x" (depth) is measured from the window surface in the direction of the back wall. Y y - Variable in class illumination.Point3D y - Variable in class illumination.Surface "y" (height) is measured from the floor in the direction of the ceiling. z z - Variable in class illumination.Point3D z - Variable in class illumination.Surface "z" (width) is measured from sideWalll in the direction of sideWall2. 89 90 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class ArrayMaker public static double[][] populateArray( int rows, double[][] array = new double[rows] [columns]; for ( int i = 0; i for ( int < rows; i++ j = 0; j < columns; j++ array[i]Li] = elementValue; return array; 91 int columns, double elementValue ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; /7 ** A Solar Calculator class -----------------------/ ** 7/ ** Given a set of climate, location, orientation, and date parameters, // ** this class will walk through a series of calculations, eventually // ** resulting in a value for solarRadiationGain to the facade. /7 // // // /7 // // // // // ** ** ** ** ** ** ** ** ** ** 7/ ** 7/ ** /7 ** /7 ** Latitude, facade orientation, and facade tilt remain constant throughout one set of calculations. As such, they are passed to through the constructor and never reset. Date and radiation levels vary from calculation to calculation, they are passed to the calculate() method, which handles all calculations. so The calculate() method returns nothing, but instead sets instance members to results produced throughout the calculations. You may then use the get() methods to retrieve any of the results of the most recent call to calculateO. /7 Useful calculation resources: /7 (Beware. None of them seem to agree about what happens when these // equations are applied to latitude south of the equator.) 7* http://aurora. crest. org/basics/solar/angle/index. htm http://mach.usno.navy.mil/cgi-bin/aa altazw http: //www. arch. gatech. edu/~tmessadi/courses/Arch3231/HANDOUT-SOLAR%20GEMETRY. pdf *7 public class Azimuth double double double double latitude; 7/ radians? dayOfYear, declination, hourAngle; daysInAMonth = 365.25/12.0; // on average tiltOfEarthAxis = toRadians(23.45); double surfaceAzimuth, verticalSurfaceTilt; double altitude, azimuth; double surfaceSolarAzimuth, angleOfIncidence, solarRadiationGain, public static void main (String[] args) { int m = Integer.parselnt(args[0]); int h = Integer.parselnt(args[l]); double dir = (Double. value0f(args[2])). doubleValue(; 92 directRadiationGain, diffuseRadiationGain; C:\Document-s and Settings\Administrator\Desktop\Project Latest\Essential Projec double dif = (Double. valueOf(args[3])). doubleValueo; double lat = (Double. valueOf (args[4])). doubleValueo; Azimuth az = new Azimuth(lat, args[5]); az.calculate(m, } h, dir, dif); // note month here is 0 = January, 1 = Feb, etc public void calculate (int month, int hourOfDay, double directNormalRadiation, double diffuseHorizontalRadiation) { dayOfYear = daysInAMonth * (month + 0. 5); // .5 is to pick day from middle of month //System.out.println("dayOfYear: " + dayOfYear); // assumes first hour of a day is 0 = midnight, noon = 12 declination = calculateDeclination(day0fYear); //System. out. println("declination: " + toDegrees(declination)); hourAngle = calculateHourAngle(hourOfDay); // consider + .5 for halfway through hour? //System. out. println("hourAngle: " + toDegrees(hourAngle)); altitude = calculateAltitude(latitude, declination, hourAngle); //System.out.println("altitude: " + toDegrees(altitude)); azimuth = calculateAzimuth(latitude, declination, altitude, hourAngle); //System.out.println("AZIMUTH: " + toDegrees(azimuth)); //System.out.println("SURFACEaZIMUTH: " + toDegrees(surfaceAzimuth)); surfaceSolarAzimuth = calculateSurfaceSolarAzimuth (azimuth, surfaceAzimuth); " + toDegrees (surfaceSolarAzimuth)); //System. out. println("surfaceSolarAzimuth: angleOf Incidence = calculateAngleOfIncidence (altitude, surfaceSolarAzimuth); " + toDegrees(angleOfIncidence)); //System. out. println("angle0fIncidence: solarRadiationGain = calculateSolarRadiationGain (angleOfIncidence, verticalSurfaceTilt, directNormalRadiation, diffuseHorizontalRadiation, altitude); " + solarRadiationGain); //System. out. println("solarRadiationGain: //System. out. println("verticalSurfaceTilt: " + verticalSurfaceTilt); directRadiationGain = calculateDirectSolarGain( angleOfIncidence, directNormalRadiation diffuseRadiationGain = calculateDiffuseSolarGain( verticalSurfaceTilt, diffuseHorizontalRadiation ); public double getAltitudeo { return altitude; } 93 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public double getAzimuth() I return azimuth; I public double getSolarRadiationGain() { return solarRadiationGain; } public double getSurfaceSolarAzimuthO { return surfaceSolarAzimuth; } public double getDirectRadiationGaino I return directRadiationGain; } public double getDiffuseRadiationGain() { return diffuseRadiationGain; } public Azimuth (double latitude, 7/ in degrees N+ SString orientation, // north, east, south, west double verticalSurfaceTilt) 7/ in degrees 7/ 90 degrees is straight up // 45 leans away from orientaion direction 7/ 145 leans toward orientation direction //(i.e. a 45 facade facing south leans north) this.latitude = toRadians(latitude); if (orientation.equals("north")) { this. surfaceAzimuth = toRadians(180. 0); else if (orientation.equals("east")) { this. surfaceAzimuth = toRadians(90.0); else if (orientation.equals("south")) t this.surfaceAzimuth toRadians(O.0); else { this. surfaceAzimuth toRadians(-90.0); this.verticalSurfaceTilt } toRadians( verticalSurfaceTilt ); /7 shortcut constructor for vertical surface tilt public Azimuth (double latitude, /7 in degrees N+ SString orientation) /7 north, east, south, west { this(latitude, orientation, 90.0 ); } /7 23. 45 accounts for the tilt of the Earth's axis public double calculateDeclination(double day0fYear) { return tilt~fEarthAxis * Math.sin( toRadians( (360.0/365.0) * (284 + day~fYear)); } 94 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec // number of degrees away from noon (solar noon: i.e. Daylight Savings may apply) // assume that the // (before noon is sun moves 15 degrees for every hour of the day +, after noon is -, by convention) /7 does not account for daylight savings time /7 DST would be reflected in the calculation for hourAngle, likely: // hourAngle = (12 - hourOfDay - daylightSavings) * 180; // where daylightSavings = 0 during the summer when 12pm is solar noon // and daylightSavings = 1 during the winter when 11am is solar noon public double calculateHourAngle(double hourOfDay) return toRadians(((12.0 - hourOfDay) / 12.0) * 180); } //azimuth; ... problem if altitude or or latitude 90 degrees for math //surfaceSolarAzi =diff between azi and ori public static double toRadians(double degrees) I return (degrees/180) * Math.PI; public static double toDegrees(double radians) return (radians/Math.PI) * 180; } // arguments are in radians, result is in radians private double calculateAltitude(double latitude, double declination, double hourAngle) { if (hourAngle 0.0) // special solar noon shortcut return (toRadians(90) - latitude + declination); } double altitude altitude += (Math.cos(latitude) * Math. cos(declination) * Math. cos(hourAngle)); (Math. sin(latitude) * Math. sin (declination)); return Math.asin(altitude); I 95 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec 7* The altitude angle is the apparent angular height of the sun in the sky if you are facing it. The azimuth angle is the surface angle between a line on the ground pointing at the sun and a line pointing toward the equator (due south or north depending on which hemisphere you are in). (positive appears to be clockwise) At least in the N hemisphere XX wrong */ /* if dec= 0... if latitude is n, always positive if latitude is s, always negative */ private double calculateAzimuth(double latitude, double declination, double altitude, double hourAngle) double divisor = (Math. cos(altitude) * Math. cos(latitude)); if (divisor == 0.0) { // defend against divide by zero return 0.0; } double azimuth (Math. sin(altitude) * Math. sin(latitude)) azimuth /= divisor; if ( azimuth > - Math. sin(declination); 1 ) // this piece of code added by Matt Lehar, 10/5/02 /* System. out. println( System. out. println( System. out. println( System.out.println( "NaN appearing, line 272 of Azimuth. java" ); "latitude = " +toDegrees(latitude) ); "altitude = " +toDegrees(altitude) ); "declination " +toDegrees(declination) ); */ azimuth = 0; } else azimuth = Math.acos(azimuth); if (hourAngle < 0.0) { azimuth *= -1; return azimuth; } 77 azimuth returned seems to be South always 0 77 then azimuth should take on the sign of the hour angle 77 positive is east of south 96 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec /7 negative is west of south // arecos should return between 0 and 180 always // then modify result to share hour angle sign /7 so, orientation should range between -180 and 180 similarly // to determine the surfacesolarazimuth 7/ azimuth sign must match hour angle sign 7/ direct light is 0 deg /7 opposite direct is 180 / -180 deg /7 we're only taking the cosine, anyhoo // this method can return anything from -360 to +360 (in radians, tho) /7 ideally, it would return a value in the range 0 to 180, // but it doesn't matter as it all falls out in the cosines later public double calculateSurfaceSolarAzimuth(double azimuth, { double ssa = azimuth - surfaceAzimuth; double surfaceAzimuth) return ssa; } public double calculateAngleOfIncidence(double altitude, double solarSurfaceAzimuth, double verticalSurfaceTilt) = Math. cos(altitude) * Math. cos(solarSurfaceAzimuth) * Math.sin(verticalSurfaceTilt); angle += Math. sin(altitude) * Math.cos(verticalSurfaceTilt); double angle return Math.acos(angle); I /7 assume vertical wall version /7 note that I don't override the old calculation /7 to save on unnecessary calculations public double calculateAngleOfIncidence(double altitude, double solarSurfaceAzimuth) I double angle = Math. cos(altitude) * Math. cos(solarSurfaceAzimuth); return Math.acos(angle); } 97 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec 7/ aoi 77 vst 77 dnr 77 dhr angleOfIncidence verticalSurfaceTilt directNormalRadiation diffuseHorizontalRadiation public double calculateSolarRadiationGain (double aoi, double vst, double dnr, double dhr, double altitude) if ((altitude < 0.0) (aoi > toRadians(90. 0))) { // sun is beyond horizon, or facing backside of building, /7 so eliminate direct radiation component return Math.sin(vst) * dhr; } return (Math.cos(aoi) * dnr) + (Math. sin(vst) * dhr); } 7/MATT LEHAR, 8/6/02: THE FOLLOWING TWO METHODS 7/ON cALCULATEsOLARrADIATIONgAIN, BUT ALLOW THE 7/SUNLIGHT COMPONENT TO BE REQUESTED SEPERATELY public double calculateDirectSolarGain if ((altitude < 0.0) (aoi > toRadians(90.O))) return 0; else { return ( Math.cos( aoi ) * dnr ); public double calculateDiffuseSolarGain return ( Math.sin( vst ARE BASED DIRECT FROM THE DIFFUSE ( double aoi, double dnr ) ( double vst, double dhr ) * dhr ); 7* In old calculator, solarEnergy[i] = Math. cos(anglelncidence)*(dirNormRad[i]) where: Fw = (1 + Math.cos(verticalTilt))/2; which doesn't make much sense to me. I include it just in case. */ 98 + (Fw)*(diffHorRad[i]) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class Bilinear { private double private double[][][] array[] []; outputArray; // same as outputArray, without the second level private doublet][] unsmoothedArray; private Fringer public Interpolator private Resizer oneFringer; oneInterpolator; oneResizer; Reads in input array, creates output buffer, assigns dimensions to the output buffer, and puts a fringe on the output buffer */ public Bilinear( double[][] array, int res_a, int resb ) I this.array array; oneFringer oneInterpolator oneResizer new Fringer(; unsmoothedArray new double[res a][res-b]; new Interpolator( array new Resizer(); if ( array.length resa && array[0].length == resb ) { outputArray else f outputArray = oneResizer.getArrayAndIndeces( array = oneResizer.getArrayAndIndeces( array, res-a, resb ) fillUnsmoothedArray( ; } private void fillUnsmoothedArray() { for ( int row = 0; row < unsmoothedArray.length; row++ ) { for ( int column = 0; column < unsmoothedArray[0]. length; column++ ) unsmoothedArray [row] [column] = outputArray [row] [column] [0]; 99 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec private void replaceUnsmoothedArray( f for ( int row = 0; row double[][] replacementArray ) < unsmoothedArray.length; row++ for ( int column = 0; column < unsmoothedArray[0]. length; column++ ) unsmoothedArray[row][column] replacementArray[oneResizer. refIndexArray[row] [column] [0]] [oneResizer.refIndexArray[row][column][1]]; } } I public int getResolutionOfExistinglnputGrida() return array.length; public int getResolutionOfExistingInputGridb( return array[0].length; public double[][] getUnsmoothedArray() public return unsmoothedArray; { double[][] getUnsmoothedArray( double[][] replacementArray ) replaceUnsmoothedArray( replacementArray ); return unsmoothedArray; } public double[][] bilinearInterpolateo { return oneInterpolator. b iIi nearInterpo late( oneFringer.fringeArray( 100 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec outputArray )); } 101 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec // Created 8/15/02 by Matthew Lehar package illumination; public class BinSorter private double min, max; private double[] bins; private double[] cumDistArray; 7/ in W/m^2: per-surface minimum, maximum private double WORLDMINVALUE; // in Cd/m2: comprehensive minimum, maximum private double WORLDMAXVALUE; private double DEFAULTMINVALUE;// in Cd/m^2: lowest significant luminance for room private double DISPLAY MINVALUE;// in Cd/m^2: luminance limits for computer monitor private double DISPLAYMAXVALUE; /* as a fraction of the total number of samples, adjustment iteration *7 private double errorMargin; sets tolerance for the bin-size /* CONSTRUCTOR ------------------------------------------------------------------------public BinSorter( /* the actual recorded minimum value may be 0, but the lowest bin must correspond to the log of the radiosity */ double defaultminValue, double display minValue, double display maxValue WORLD MINVALUE WORLD_MAXVALUE DEFAULTMINVALUE 0; = 0; = defaultminValue; DISPLAY MINVALUE DISPLAYMAXVALUE = displayminValue; = displaymaxValue; /* PUBLIC METHODS ---------------------------------------------------------------------- */ For one room */ public void sort( Map singleRoom, int numberOfBins, min max double errorMargin ) 0; 0; findRoomMinMax( singleRoom ); System. out. println( "One room: max. luminance " +WORLDMAXVALUE +", min. luminance " +WORLDMINVALUE ); createBins( numberOfBins ); addRoomSamplesToBins( singleRoom ); 102 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec createCumDistArray( errorMargin ); For two rooms public void sort( Map room, Map otherRoom, min max int numberOfBins, double errorMargin 0; 0; findTworoomMinMax( room, otherRoom ); +WORLDMAXVALUE System.out.println( "Two room: max. luminance +", min. luminance = " +WORLDMINVALUE ); createBins( numberOfBins ); addRoomSamplesToBins( room addRoomSamplesToBins( otherRoom ); createCumDistArray( errorMargin ); } public double cumulativeDistributionFunction( double input ) if ( WORLDMINVALUE >= WORLDMAXVALUE // i.e. sorting hasn't occurred return 0; else if ( WORLDMINVALUE > DISPLAYMINVALUE &&WORLDMAXVALUE < DISPLAYMAXVALUE ) Linear transfer /* i. e. world luminances already within display range. function used */ / return ( Math. log(limitLows(convertToCandelasPerM2(input))) (Math.log(WORLDMAXVALUE/WORLDMINVALUE)) ); else return cumDistArray[findCorrectBin( limitLows(convertToCandelasPerM2(input)))]; 7*PRIVATE METHODS --------------------------------------------------------------------- private void findTworoomMinMax( Map northRoom, Map southRoom double storageMIN, storageMAX; findRoomMinMax( northRoom ); storageMIN = WORLDMINVALUE; storageMAX = WORLD MAXVALUE; 103 ) */ C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec findRoomMinMax( southRoom ); WORLDMINVALUE = Math.min( WORLD MINVALUE, storageMIN ); WORLDMAXVALUE = Math.nmax( WORLDMAXVALUE, storageMAX ); Map singleRoom ) private void findRoomMinMax( for ( int surfaceCount = 0; surfaceCount < singleRoom.numberOfSurfaces; surfaceCount++ ) m{ singleRoom. surfaces [surfaceCount]. Q[0] [0] max = singleRoom. surfaces [surfaceCount]. Q[0] [0]; minMax ( singleRoom. surfaces [surfaceCount]. Q if ( surfaceCount ==0 ) WORLDMJNVALUE convertToCandelasPerM2( mn WORLDMAXVALUE = convertToCandelasPerM2( max } else { WORLDMINVALUE = Math.min( WORLDMINVALUE, convertToCandelasPerM2( min )); WORLDMAXVALUE = Math. max( WORLDMAXVALUE, convertToCandelasPerM2( max I if ( WORLDMINVALUE < DEFAULTMINVALUE ) { WORLDMINVALUE = DEFAULTMINVALUE; } private void minMax( double[][] array for ( int i 0; i < j for ( int ) array. length; = 0; j < i++ ) array[O].length; j++ ) min = Math.min( min, array[i][j] ); max = Math.max( max, array[i][j] } private void createBins( bins int numberOfBins ) new double[numberOfBins]; for ( int i = 0; i < numberOfBins; bins[i] = 0; 104 i++ ) ); C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec 7* Organizes room radiosity data into bins for a histogram private void addRoomSamplesToBins( Map singleRoom for ) ( int surfaceCount = 0; surfaceCount < singleRoom.numberOfSurfaces; surfaceCount++ for ( int i 0; i ) < singleRoom. surfaces[surfaceCount].Q. length; i++ ) for ( int j = 0; j < singleRoom. surfaces [surfaceCount]. Q[0].length; j++ ) addOneSampleToBin( convertToCandelasPerM2( singleRoom. surfaces[surfaceCount]. Q[i][j] )); } } Accepts a luminance value in candelas per m^2. limited. This value should not be lower- */ private void addOneSampleToBin( double sample ) 7/any value below the default minimum is excluded from the histogram if ( sample >= DEFAULTMINVALUE ) if ( findCorrectBin( sample ) >= bins.length ) System. out.println( "problem with sample. value bins[findCorrectBin( sample )] += 1; " +sample );} private int findCorrectBin( double sample ) /* without this if-statement, an input equal to MAXVALUE would cause an out-of-bounds exception. */ return (( sample > WORLDMAXVALUE - 1 ) ? ( bins.length - 1 : ( new Double( Math. floor( Math. log(sample/WORLDMINVALUE) / ( Math.log(WORLDMAXVALUE/WORLDMINVALUE)) * bins. length )). intValue() )) private void createCumDistArray( double errorMargin int runningTotal = 0; double originalTotal = getBinTotal(); 105 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec double[] originalBins; originalBins = new double[bins.length]; cumDistArray = new double[bins.length]; for ( int i = 0; i < bins.length; i++ ) { originalBins[i] = bins[i]; } /* The total number of samples varies because some bins may be truncated to meet the "ceiling condition" */ truncateBins( errorMargin, WORLDMINVALUE ); if ( getBinTotal() < ( errorMargin * 0.01 * originalTotal )) { System.out.println( "NOTICE 1: iteration did not converge. Trying again with artificial world-minimum." for ( int i = 0; i < bins.length; i++ bins[i] = originalBins[i]; truncateBins( errorMargin, DEFAULTMINVALUE ); if ( getBinTotal( K ( errorMargin * 0.01 * originalTotal System.out.println( "NOTICE 2: iteration again failed to converge. for ( int i = 0; i )) Using linear transfer function." < bins.length; i++ ) bins[i] = originalTotal / bins.length; for ( int i = 0; i < bins.length; i++ cumDistArray[i] ( bins[i] + runningTotal runningTotal += bins[i]; ) / getBinTotal() /* Applies the "ceiling condition" by performing an iteration */ private void truncateBins( double errorMargin, double worldMin double tolerance; double ceiling; double trimmings; tolerance = errorMargin * 0.01 * getBinTotal(); do { 106 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec trimmings = 0; for (int i = 0; i < bins.length; i++ ) ceiling = getBinTotal() / bins.length * Math.log( WORLDMAXVALUE / worldMin ) / Math.log( DISPLAYMAXVALUE / DISPLAYMINVALUE ); if ( bins[i] > ceiling trimmings += (bins[i]-ceiling); bins[i] ceiling; while ( trimmings > tolerance ) private int getBinTotal() int runningTotal = 0; for ( int i = 0; i < bins.length; i++ ) { runningTotal += bins[i]; return runningTotal; private double limitLows( double value return (( value ) < DEFAULTMINVALUE ) ? DEFAULTMINVALUE : value 7* Assumes that each element of a surface radiates uniformly in all directions, so that a sphere enclosing the element at a certain radius would experience a uniform illumination. "Candela: The luminous intensity in a specified direction, of a monochromatic source which has a frequency of 540 x 1012 Hz and which has a radiant intensity, in the specified direction, of (1/683) watt per steradian." - courtesy, www.atis.org */ private double convertToCandelasPerM2( double radiosity { return radiosity * 683 / (4*Math. PI); 107 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class Blind private private private private double double double double width; angle; verticalPosition; radiosity; public Blind( double width, double verticalPosition ) this. width this. angle this.verticalPosition = width; = 0; // by default = verticalPosition; radiosity = 0; public double getVerticalPositiono I return verticalPosition; public void setRadiosity( double radiosity this.radiosity radiosity; public double getRadiosityO return radiosity; // added 8/19/02 by M. Lehar public void setAngle( double angle this. angle ) angle; 108 // by default C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class BlindSet width; private double private double private double private double length; spacing; totalNumber; collectiveAngle private Blind[] blindArray; private double emissivity; public BlindSet( int totalNumber, double length, public int 0; double spacing, double sill, double head, double emissivity { double verticalHeight; this.totalNumber this.length this.spacing = totalNumber; this.emissivity = emissivity; = length; = spacing; if ( totalNumber 0 ) { else width = 0; i width =(head - sill )/totalNumber - spacing; if ( width ==0 ) { totalNumber = 0; else { blindArray = new Blind[ totalNumber ]; for ( int blindNumber = 1; blindNumber <= totalNumber; blindNumber++ verticalHeight sill + ( spacing + width ) * - 1 ) + ( spacing + 0.5 * width ); ( blindNumber blindArray[ blindNumber - 109 ) 1] new Blind( width, C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec verticalHeight); } } } public double getBlindWidth() { return width; } public double getBlindSpacing() { return spacing; } public int getNumBlinds() return totalNumber; public double getEquivalentDistance( int blindNumber, double incidenceAngle, String startOrEnd { Blind blindRef = blindArray[ blindNumber - 1 ]; double centerlineHeight = blindRef.getVerticalPositionO; double distance; if ( startOrEnd.equals( "start" )) distance = centerlineHeight - Math. abs(( width / 2 ) * ( Math. tan( convertToRadians( incidenceAngle )) * Math.cos( convertToRadians( collectiveAngle )) Math.sin( convertToRadians( collectiveAngle )))); else if ( start0rEnd.equals( "end" )) distance = centerlineHeight + Math.abs(( width / 2 ) * ( Math.tan( convertToRadians( incidenceAngle )) * Math.cos( convertToRadians( collectiveAngle )) Math.sin( convertToRadians( collectiveAngle )))) else System.out.println( "Error: neither start nor end of blind requested" ); distance = 0; return distance; public double getProjectedDistance( int blindNumber, 110 String startOrEnd ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec double centerlineHeight double distance; blindArray[ blindNumber -1 ]. getVerticalPosition(); if ( startOrEnd.equals( "start" )) distance = centerlineHeight - Math. abs(( width / 2 ) * Math.sin( convertToRadians( collectiveAngle ))) )) else if ( startOrEnd.equals( "end" distance = centerlineHeight + Math. abs(( width / 2 ) * Math. sin( convertToRadians( collectiveAngle ))); else { System.out.println( "Error: neither start nor end of blind requested" ); distance = 0; return distance; } private double convertToRadians( double degreeValue { return degreeValue*Math.PI/180; } public double getVerticalPosition( int blindNumber ) ) ].getVerticalPosition() return blindArray[ blindNumber - 1 } // added 8/19 by M. Lehar public void setRadiosity( double solar, double sunAngle for ( int blindNumber = 1; blindNumber <= totalNumber; blindNumber++ blindArray[ blindNumber - ) 1 ].setRadiosity( ( 1 - emissivity ) * solar * Math.abs( Math.sin( convertToRadians( sunAngle - collectiveAngle )))); public double getRadiosity( int blindNumber return blindArray[ blindNumber - 1 ].getRadiosityO; } III C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec // added 8/19 by M. Lehar public void setCollectiveAngle( double collectiveAngle ) this. collectiveAngle collectiveAngle; for ( int blindNumber 1; blindNumber blindArray[ blindNumber - <= totalNumber; blindNumber++ ) 1 ]. setAngle( collectiveAngle ) public double getCollectiveAngle() return collectiveAngle; public double centerInZO return length / 2; public double slatAreaO return length * width; public String findIlluminatedSide( double sunAngle ) if ( sunAngle >= collectiveAngle ) return "top"; } else return "bottom"; public void setRadiosity( int blindNumber, double radiosity blindArray[ blindNumber - 1 ].setRadiosity( radiosity ) 112 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; 7* This class does some calculations related to raytracing a rectangular room. An observer stands behind the room (not inside the room). When a line is drawn from the eye of the observer through the rear wall of the room, we want to know where this line intersects another surface (wall, ceiling, or floor) of the room. This intersection is returned as a Point3D. From the observer's perspective, the origin of the room is at the lower left hand corner of the near (rear) wall. */ public class Box private double w; private double h; private double d; // room width (x direction) // room height (y) /7 room depth (z) private double wO; 7/ observer distance from left wall (x direction) private double hO; 7/ observer distance from floor (y) private double dO; /7 observer distance from image plane (z) private private private private Quadrant Quadrant Quadrant Quadrant upperLeftQuad; upperRightQuad; lowerLeftQuad; lowerRightQuad; public static void main (String[] args) { Box b = new Box(5.0, 5.0, 5.0, 2.5, 1.7, 5.0): double x = Double. valueOf (args [0]). doubleValue(; double y = Double. valueOf(args[1]). doubleValue(; Point3D s = b.findStrike(x, y); System.out.println(s.toString()); } public Box (double w, double h, double d, double wObserver, double hObserver, double dObserver) { this.w = w; this.h = h; this.d = d; this.wO = wObserver; this.hO = hObserver; this.dO = dObserver; upperLeftQuad = new Quadrant (wO, upperRightQuad = new Quadrant (w - wO, lowerLeftQuad new Quadrant (wO, lowerRightQuad new Quadrant (w - wO, I h - hO, d, do); h - hO, d, dO); hO, d, dO); hO, d, dO); 113 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec //for a given x,y /return x,y,z of strike public Point3D findStrike (double x, double y) Point3D strike; if (y >= ho) if (x <= wO) //System.out.println("UL Quad"); strike = upperLeftQuad.findStrike(wO strike.x = w - strike.x; strike.y = hO + strike.y; } else - x, y //System.out.println("UR Quad"); strike = upperRightQuad. findStrike(x strike.x = w + strike.x; strike.y = hO + strike.y; wO, y hO); - ho) else f if (x <= wO) //System.out.println("LL Quad"); strike = lowerLeftQuad.findStrike(wO strike.x =w strike.y =h - - x, hO y) strike.x; strike.y; } else f //System.out.println("LR Quad"); strike = lowerRightQuad.findStrike(x - wO, hO - y); strike.x = w + strike.x; strike.y = hO - strike.y; return strike; 114 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; // CLASS FACADE Populates some of the basic arrays for the surface and invokes methods The "Facade" in the superclass to completely create the surface. class of surfaces includes the window. public class Facade extends Surface public Facade( String name, int parallelResolution, int crossResolution, double parallelMagnitude, double crossMagnitude, double emissivity, double constantCoordinate ) surfaceType = new String( "facade" ); constructSurface( name, parallelResolution, crossResolution, parallelMagnitude, crossMagnitude, emissivity, constantCoordinate //OBSOLETE VARIABLES: resolutions[0] = 1; resolutions[l] = 0; resolutions[2] = 0; /* thirdIsConstant is used later on in the program to orient the surface grids properly before they are sent to the viewer program */ thirdIsConstant = false; /* For-loop: populates some of the basic arrays for the surface, including arrays giving position in x, y, and z; alpha, beta, and gamma, each of which has the value 1 if the normal vector to the surface points in the x, y, and z directions, respectively, and has the value 0 otherwise; and A, the differential area of each element of the grid surface. 'a' and 'b' are the lengthwise and widthwise resolutions of the surface. 'parallelDistance' and 'crossDistance' are the length and width of the surface */ for ( int rowCounter = 0; rowCounter < a; rowCounter++ ) f for ( int columnCounter = 115 0; columnCounter < b; columnCounter++) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec I x[rowCounter][columnCounter] y[rowCounter][columnCounter] z[rowCounter][columnCounter] alpha[rowCounter][columnCountei beta[rowCounter][columnCounter] gamma[rowCounter][columnCounter A[rowCounter][columnCounter] constantCoordinate; ( parallelDistance / a ) * ( rowCounter + 0.5 ); ( crossDistance / b ) * ( columnCounter + 0.5 ); ] = 0; 0; parallelDistance ( a * b ); * crossDistance / I } } } 116 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class FacadeInitializer extends SurfaceInitializer String blindShadingScheme; public void initialize( Surface currentSurface, WindowSuite windowSpecs, BlindSet blinds, String blindShadingScheme, boolean isFirstInitialization, ViewFactorSuite blindFactors_lD, SolarSuite solarVars ) { this. blindShadingScheme = blindShadingScheme; initializeSurfaceVariables( currentSurface, blinds, windowSpecs, solarVars imposeBlindSlatShadows( blinds public void imposeBlindSlatShadows( rowTemplate BlindSet blinds new double[a]; rowTemplate this array serves as a mask: when pointwise-multiplied by the radiosity arrays of a surface, it introduces black (zero-valued) bands where the shadow of a blind slat crosses that surface. in the case of the window (facade) surface, these "shadows" are in fact the projected profiles of the blinds in the window, as viewed by an observer at the back of the room for ( int i= 0; i < a; i++ ) rowTemplate[i] = 0; } 117 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec Above, the entire mask is initialized to a value of 0 (black). Below, the middle region of the mask corresponding to the transparent area of the window, is set to a value of 1. */ nearAndFarDistances[0] = sill; nearAndFarDistances[l] = head; indeces0fNearAndFarReacha = findlndeces0fNearAndFarReach( nearAndFarDistances, a, parallelDistance ); for indecesOfNearAndFarReach a[0]; i <= indecesOfNearAndFarReachba[l]; i++ ) ( int i rowTemplate[i] for ( int blindNumber 1; 1; blindNumber <= totalNumberOfBlinds; blindNumber++ ) find indeces that mark the beginnings and endings of blind shadows in the parallel (up/down) direction along the facade *7 blinds. getProjectedDistance( blindNumber, "start" ); blinds. getProjectedDistance( blindStartEndDistances[l] blindNumber, "end" ); findlndecesOfNearAndFarReach( blindStartEndIndeces blindStartEndDistances, a, parallelDistance ); blindStartEndDistances [0] 7* create black spaces in the parallel (row) mask that correspond to the positions of the blind shadows *7 ( int i for blindStartEndIndeces[0]; i <= blindStartEndIndeces[l] ; i++ rowTemplate[i] ) 0; /* for the 0-degree blind angle, so that the blind doesn't completely disappear when viewed side-on */ if ( blindStartEndIndeces[O] > blindStartEndlndeces[l] ) rowTemplate[blindStartEndlndeces[0]]= for ( int il 0; indecesOfNearAndFarReach-a[0]; il <= indeces0fNearAndFarReach a[l]; il++ ) 118 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec { for ( int i2 = 0; i2 { < b; i2++ ) /* set the radiosity of the part of the window surface that remains visible through the blinds */ if ( blindShadingScheme.equals( "focused" )) currentSurface.Qinitial[il][i2] = diffIntensity * rowTemplate[il]; else /* Intensity of diffuse light depends on degree to which blinds are open - ASSUMPTION: blinds meet at the edges when closed *7 currentSurface.Q initial[il][i2] = diffIntensity * Math.cos( degToRad( blinds. getCollectiveAngle()); currentSurface.Q[il][i2] currentSurface. Qinitial[il] [i2] } } /* the following methods must be included for compatibility with the superclass, but are not relevant to the facade case public void calculateFirstReflectionFromBlinds( BlindSet blinds, boolean isFirstInitialization, ViewFactorSuite blindFactors_lD, Surface currentSurface ) {} public void applyPatchOfSunlight( String blindShadingScheme ) public double findAngleOnSurface( double verticalAngle, { return 0; } } 119 {} double horizontalAngle ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; import java.io.*; public class FileOut public static void createSurfaceFile( Surface currentSurface ) try { File outputFile = new File( currentSurface. name. concat( "Array.txt" FileWriter out = new FileWriter( outputFile ); outputValues( out, currentSurface ); out. close() catch ( IOException e System.err.println( e.toString() private static void outputValues( FileWriter out, Surface currentSurface try /*if ( currentSurface.name.equals( "workplane" )) { System. out. println( "received at fileOut: Q[l][10] " +currentSur face.Q[1][10] ); }*/ for ( int i = 0; i for ( int < currentSurface.a; i++ ) i = 0; j < currentSurface.b; j++ ) out.write( ( new Double( currentSurface. Q[i] [j] )).toString( .)); out.write("" out.write( "\n" catch ( IOException e System.err.println( e.toString() public static void createSurfaceFile( double[][] ) currentArray try //System.out.println( "ANNONYMOUS" ); 120 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec /*for ( int i = 0; i < currentArray.length; i++ ) System.out.println( "--NONZERO: " +currentArray[i][i] }*/ File outputFile = new File( "annonymousArray. txt" ); FileWriter out = new FileWriter( outputFile ) ); outputValues( out, currentArray ); out. close 0 catch ( IOException e System.err.println( e.toString( public static void createSurfaceFile( double[][] currentArray, String name ) try File outputFile = new File( name.concat("Array.txt") ); FileWriter out = new FileWriter( outputFile ) outputValues( out, currentArray ); out. close 0 catch ( IOException e System. err. println( e. toStringO ); public static void createSurfaceFile( double[][][] currentArray try //System.out.println( "NONAME" ); /*for ( int i = 0; i < currentArray.length; i++ ) System.out.println( "--NONZERO: " +currentArray[i][i] ); }*/ double] [] subArray = new double [currentArray. length] [currentArray[O ].length]; for ( int i for ( int j 0; i < currentArray.length; i++ ) 0; j < currentArray[O].length; j++ ) subArray[i][i] = currentArray[i][i][0]; File outputFile = new File( "nonameArray.txt" ); 121 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec FileWriter out = new FileWriter( outputFile ) outputValues( out, subArray ); out. close() catch ( IOException e System.err.println( e.toString( ) private static void outputValues( FileWriter out, double[][] currentArray try for ( int i = 0; i < currentArray.length; i++ ) for ( int j = 0; j < currentArray[0]. length; j++ ) { out.write( out.write( ( new Double( currentArray[i][j] )).toString( out.write( "\n" ); catch ( IQException e ) System.err.println( e.toStringO 122 ) ); C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class FloorCeilingInitializer extends PlatformInitializer public void initialize( Surface currentSurface, WindowSuite windowSpecs, BlindSet blinds, String blindShadingScheme, boolean isFirstlnitialization, ViewFactorSuite blindFactors_lD, SolarSuite solarVars { initializeSurfaceVariables( currentSurface, blinds, windowSpecs, solarVars ); imposeBlindSlatShadows( blinds ); applyPatchOfSunlight( blindShadingScheme ); calculateFirstReflectionFromBlinds( blinds, isFirstInitialization, blindFactors -D, currentSurface ); } public void imposeBlindSlatShadows( BlindSet blinds { ) initializeMasksO; for ( int blindNumber 1; blindNumber <= totalNumberOfBlinds; blindNumber++ ) { find indeces that mark the beginnings and endings of blind shadows in the parallel direction along the floor/ceiling */ blindStartEndIndeces = findlndecesOfNearAndFarReach( findNearAndFarDistances( blinds.getEquivalentDistance( blindNumber, verticalAngle, "start" ), blinds.getEquivalentDistance( 123 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec blindNumber, verticalAngle, "end" ), verticalAngle ), a, parallelDistance ); create black spaces in the parallel (column) mask that correspond to the positions of the blind shadows *7 for ( int i blindStartEndIndeces[O]; i <= blindStartEndIndeces[l]; i++ if ( i < 0 ) if ( i > columnTemplate. length columnTemplate[i] = 0; { i = 0; { break; 1) public void applyPatchOfSunlight( String blindShadingScheme ) ) /* "sill" and "head" determine the limits in the DEPTH dimension of the patch of sunlight projected onto the floor/ceiling from the window "blockl" and "block2" are here defined as the side margins of the window area, and limit the patch of sunlight on the floor/ ceiling in the WIDTH dimension */ nearAndFarDistances findNearAndFarDistances( sill, head, verticalAngle blockl = right; block2 = left; obliqueIntensityFraction find0bliqueIntensityFraction( verticalAngle illuminateWithSunlight( blindShadingScheme, 124 obliqueIntensityFraction ) ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class Fringer private boolean foundStartingRow; private boolean foundEndingRow; private boolean foundStartingColumn; private boolean foundEndingColumn; public Fringer() foundStartingRow foundEndingRow foundStartingColumn foundEndingColumn false; = false; = false; = false; Operates on an array consisting of two, 2-D arrays stacked one atop the other (a 3-D array with only two elements in the third dimension). One layer of this array contains information, expanded to a large grid size from a small original array. The second layer contains markers (ones) in a field of zeros, to indicate the center of each data point. The function of this method is to place a fringe of "ones" around the edge of the second layer, so that the new "ones" on the fringe are aligned with the pre-existing grid of "ones," and so that there is a "one" on each corner of the fringed array. The purpose of this fringe is to provide a boundary condition for the bilinear interpolation scheme. */ public double[][][] fringeArray( double[][][] unfringedArray double[][][] fringedArray; fringedArray = new double[( unfringedArray. length + 2 )] [( unfringedArray[O].length + 2)][2]; fringeColumnsAdjacentToStartingRow( fringedArray, if ( !foundStartingRow ) { System. out.println( "ERROR: unfringedArray ); no data detected in array" ); fringedArray, unfringedArray ); fringeColumnsAdjacentToEndingRow( fringeRowsAdjacentToStartingColumn( fringedArray, unfringedArray ); fringeRowsAdjacentToEndingColumn( fringedArray, unfringedArray ); fillInteriorOfFringedArray( fringedArray, unfringedArray ); fillFringingColumns( fringedArray, unfringedArray ); fillFringingRows( fringedArray, unfringedArray ); 125 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec fillCornersOfFringedArray( fringedArray, unfringedArray ); return fringedArray; I private void fringeColumnsAdjacentToStartingRow( double[][][] fringedArray, double[][][] unfringedArray ) I for ( int row = 0; row < unfringedArray.length; row++ ) for ( int column = 0; column < unfringedArray[O]. length; column++ ) if ( unfringedArray[row][column][1]! I 0 ) fringedArray[0][( column + 1 )][l] foundStartingRow = true; if ( foundStartingRow 1; ) break; } } } private void fringeColumnsAdjacentToEndingRow( double[] []] fringedArray, double[][][] unfringedArray for ( int row = unfringedArray. length - 1; row >= 0; row--for ( int column = 0; column ) ) < unfringedArray[O]. length; column++ if ( unfringedArray[row][column][1] != 0 ) fringedArray[( fringedArray.length -- 1 )] [(column + 1 )][1] 1; foundEndingRow = true; if ( foundEndingRow ) break; } } } private void fringeRowsAdjacentToStartingColumn( 126 double[][][] fringedArray, double[][][] unfringedArray ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec for ( int column = 0; column < unfringedArray[0]. length; column++ ) for ( int row = 0; row < unfringedArray.length; row++ ) if ( unfringedArray[row][column][1] != 0 fringedArray[( row + 1 )][0][1] foundStartingColumn = true; if ) 1; ( foundStartingColumn ) break; private void fringeRowsAdjacentToEndingColumn( for double[] [] fringedArray, double[][][] unfringedArray ) ( int column = unfringedArray[O]. length - 1; column >= 0; column-- ) ) for ( int row = 0; row K unfringedArray.length; row++ if ( unfringedArray[row][column][1] !=0 ) fringedArray[( row + 1)] [( fringedArray[O].length foundEndingColumn = true; if - 1 )][1] ( foundEndingColumn break; private void filllnteriorOfFringedArray( for double[][][] fringedArray, double[][][] unfringedArray ) ( int row = 0; row < unfringedArray.length; row++ for ( int column = 0; column < unfringedArray[0]. length; column++ fringedArray[( row + 1 )][( column + 1 127 )] 1; C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec unfringedArray[row][column]; fringedArray[( row + 1 )][( column + 1 )] = unfringedArray[row][column]; } } } private void fillFringingColumns( double[][][] fringedArray, double[][][] unfringedArray for ( int row = 0; row { < ) unfringedArray.length; row++ fringedArray[( row + 1 )][0][0] = unfringedArray[row][0][0]; fringedArray[( row + 1 )][( fringedArray[O]. length - 1 )][0] = unfringedArray [row] [(unfringedArray [0]. length - 1 )][0]; } } private void fillFringingRows( double[][][] fringedArray, double[][][] unfringedArray for ( int column = 0; column < unfringedArray[O]. fringedArray[0][( column + 1 )][0] fringedArray[( fringedArray. length unfringedArray[( ) length; column++ ) unfringedArray[0] [column] [0]; 1 )][( column + 1 )][0] = unfringedArray. length - 1 )][column][0]; } } private void fillCornersOfFringedArray( double[][][] fringedArray, double[][][] unfringedArray ) fringedArray[0][0][1] fringedArray[0][( fringedArray[0].length - 1 )][1] fringedArray[( fringedArray.length - 1 )][0][1] fringedArray[( fringedArray.length - 1 )] [( fringedArray[0].length - 1 )][l] =1 =1; =1 =1 fringedArray[0][0][0] = unfringedArray[0][0][0]; fringedArray[0][( fringedArray[0].length - 1 )][0] unfringedArray[0] [( unfringedArray[0]. length - 1 )] [0]; fringedArray[( fringedArray.length - 1 )][0][0] = unfringedArray[( unfringedArray. length fringedArray[( 1 )] [0] [0]; fringedArray. length - 1 )][( fringedArray[0]. length - 1 )][0]= 128 Latest\Essential Projec C:\Documents and Settings\Administrator\Desktop\Project 1 )][( unfringedArray[0]. length - 1 )][0]; unfringedArray[( unfringedArray. length } } // Driver for BinSorter. java. Created 8/16/02 by Matthew Lehar package illumination; public class GrayScaleConverter // in candelas/m^2 (this is the lowest intensity percep tible by the human eye) = 0.0001; private double RADIOSITYMINVALUE private double DISPLAYMINVALUE private double DISPLAYMAXVALUE = 1; = 200; // in units of gray levels (0-255) private double GRAYSCALEMINVALUE = private double GRAYSCALEMAXVALUE = 255; private double errorMargin = 2.5; // perce nt 1; private BinSorter sorter; public GrayScaleConverter( I Map room, int number0fBins sorter = new BinSorter( RADIOSITYMINVALUE, sorter.sort( room, number0fBins, ) DISPLAYMINVALUE, DISPLAYMAXVALUE ); errorMargin ); } public GrayScaleConverter( Map room, Map otherRoom, int numberOfBins sorter = new BinSorter( RADIOSITYMINVALUE, DISPLAYMINVALUE, DISPLAYMAXVALUE ); sorter. sort( room, otherRoom, number0fBins, errorMargin ); public double convertRadiosityToGrayScale( double radiosity ) return trim( scaleToGrayLevels( Math. log( DISPLAY MINVALUE ) + Math.log( DISPLAYMAXVALUE/ DISPLAYMINVALUE ) * sorter. cuinulativeDistributionFunction( radiosity 129 ))) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } // used for direct mapping of world luminances to gray levels public double convertRadiosityToGrayScale( double radiosity, double gain ) I return trim( radiosity * gain } /* PRIVATE METHODS ----------------------- ---------------------------- private double scaleToGrayLevels( double brightness return GRAYSCALEMINVALUE + ( brightness - Math. log(DISPLAYMINVALUE) / ( Math.log(DISPLAYMAXVALUE / DISPLAYMINVALUE)) * ( GRAYSCALEMAXVALUE - GRAYSCALEMINVALUE ); } private double trim( double output if ( output <= 0 return GRAYSCALEMINVALUE; else if ( output > GRAYSCALEMAXVALUE ) return GRAYSCALEMAXVALUE; else { return output; } 130 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; import qhqc.RoomDescription; /* Modified, August 20, by Matthew Lehar. Drivers for new display software written-in. Program overhauled and cleaned up. /* Modified, August 9, by Matthew Lehar. Lighting-energy averaging methods complete /* Modified, January 28, by Matthew Lehar. Comments added for JavaDoc /* Modified, January 20, by Matthew Lehar. Structural improvements to pace Jim Gouldstone' s update of the display classes /* Modified, January 11, 2002 by Matthew Lehar. Package redisigned for greater readability /* Modified, September 18 by Matthew Lehar. New instructions for linearizing lowresolution surface radiosity output arrays with "Bilinear. java" (may soon be moved to a separate class) /* Modified, June 14 by Matthew Lehar. Methods added to calculate which parts of the inside surfaces are lit by the sun for different sun angles /* Modified, May 15 by Matthew Lehar. Array casting routines, public methods added to Illumination. java /* Modified, April 19-25 by Matthew Lehar. Project simplified, compiled, and tested. /* Modified, March 9 and March 14 by Matthew Lehar, to recast the program in an objectoriented form /* Created February, 2001 by Matthew Lehar, based on the original program written by Leon -- Glicksman in MathCAD ----------------------------------------------------------- 77 CLASS ILLUMINATION Creates Map objects (representing to produce one final "room. " The resolution and iterated rapidly. this time at high resolution, and "rooms") and combines them together Map object is created at low first Then, a second Map object is created, this one is not iterated, the time The low-res Map necessary for a high-res iteration being prohibitive. is then combined with the high-res to produce a hybrid that is finely resolved in respect to the boundaries between sunlight and shadow, but also shows a crude reflection pattern on the interior surfaces not directly illuminated by the sun. */ public class Illumination { // Class Variables private int NUMITERATIONS; private double tempBlindAngle // 0; total number of elements on all surfaces of crude room models private int CRUDECELLCOUNT = new Double(5 * Math.pow(7,2)).intValueo; 131 -------- C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec private int private int FINECELLCOUNT = new Double(5 * Math.pow(100,2)).intValueo; RAPID CELLCOUNT = new Double(5 * Math.pow(10,2)).intValueo; private double private double rl; r2; private int private int private int MONTHSINYEAR DAYSINMONTH HOURSINDAY = 12; = 30; = 24; private double private double WATTSINKILOWATT WATTSPERLUMEN = 1000; = 0.0015; // "0" is the first hour of the day (12-1 am) BEGINHOUR private int ENDHOUR private int timeStep private int private WorkplaneBay currentWorkplaneBay; private SettingSuite settings, fineRoomSettings, rapidFineRoomSettings; 8; 18; 1; // in hours private RoomDescription entireRoomDesc; private Initializer private Iterator onelnitializer; onelterator; private double ][] monthAveragedWorkplane private int private int selectedMonth selectedHour 2 13; 7/ Public Methods SIMULATE0NERO0M() Runs a single daylighting calculation, for the purpose of displaying the view of a room interior at a particular point in time. Returns the high-resolution map in its present state. solarAngleVertical solarAngleHorizontal qSolarIncoming, qDiffuse angle of elevation of sun in sky, measured from horizon upward angle of azimuth of sun in sky, measured from facade's outward-pointing normal vector to rightward sunlight intensity (W/m^2) diffuse light intensity (W/m^2) */ public Map simulate0neRoom( double solarAngleHorizontal, double solarAngleVertical, 132 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec double solarIncoming, double diffIntensity, double collectiveBlindAngle t // Create instance of Map object ("room") new Map( settings Map room new Map( settings Map iteratedRoom ) ) /* Since fineRoom is the output, it must be reassigned each time the method is called, so that the user is given exclusive control over any old versions */ - new Map( fineRoomSettings Map fineRoom // Group the sun-related variables into a single object for convenience SolarSuite solarVars = new SolarSuite( solarAngleHorizontal, solarAngleVertical, solarIncoming, diffIntensity // Perform one simulation setDaylighting( fineRoom, room, iteratedRoom, solarVars, "bilinear", "highRes", collectiveBlindAngle 7/Deliver ) finished Map to user return fineRoom; } SIMULATEONEROOM() No-blinds version of the above. */ public Map simulateOneRoom( double double double double solarAngleHorizontal, solarAngleVertical, solarIncoming, diffIntensity ) return simulateOneRoom( solarAngleHorizontal, solarAngleVertical, solarIncoming, diffIntensity, 0 } ONEHOURWORKPLANELIGHTINGENERGY( Returns the required illuminance by artificial means to maintain room brightness at minLightLevel, in Watts per m_2 of floor area. */ public double oneHourWorkplaneLightingEnergy( 133 double azimuth, double altitude, double direct, C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec double diffuse ) double blindAngle; double tempTotal; direct *= .0015; diffuse *= .0015; // convert from lux to W/m^2 SolarSuite solarVars = new SolarSuite( azimuth, altitude, direct, diffuse ); if ( entireRoomDesc.getWindowUnit ( != null &&entireRoomDesc. getWindowUnit(). getBlinds 0 blindAngle } else blindAngle entireRoomDesc. getWindowUnit 0.getBlinds (. null) getAngle(; tempBlindAngle; setDaylighting ( currentWorkplaneBay. rapidFineRoom, currentWorkplaneBay.room, currentWorkplaneBay.iteratedRoom, solarVars, "none", "highRes", blindAngle ) currentWorkplaneBay. calculateWorkplaneLightLevels ( solarVars, settings.windowSpecs, blindAngle ); tempTotal currentWorkplaneBay.sumDefecitValues(); return tempTotal; GETCOLLECTIVEBLINDANGLE( Returns current blind angle. public double getCollectiveBlindAngle() if ( entireRoomDesc.getWindowUnit( null && entireRoomDesc. getWindowUnito. getBlinds() null) return entireRoomDesc. getWindowUnito. getBlinds(. getAngle( else return tempBlindAngle; 134 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec The following method is only for testing purposes: FINDREQUIREDLIGHTINGENERGY0 Runs many daylighting calculations at different times of the day and during different months of the year. Produces statistics on average lighting energy requirements to keep room adequately illuminated during work hours. public double[] findRequiredLightingEnergy( 7/ VARIABLE String String weatherFile, orient, double workplaneHeight, double minimumLightLevel DECLARATIONS ---------------------------------------------- // Tally of total use of electrical lighting energy for monthlyLightingReq; double[] 1 month (KWh/m^2) /* Amounts by which sunlight falls short of lighting requirement at different locations on workplane: values are in units of EXTRA light intensity required (W/m-2) *7 double[][] defecitArray; /* Object for storing information about sunlight for one particular configuration of the room */ solarInfo; SolarInfoCalculator // 1. Print out city name and building orientation System.out.println("weatherFile: " +weatherFile +" orient: " +orient ); 7/VARIABLE 77 DEFINITIONS ---------------------------------------------- 2. Create storage objects monthlyLightingReq new double[MONTHSINYEAR]; solarInfo new SolarlnfoCalculator( weatherFile, orient // BODY ---------------- /* 3. for ------------- ------------------------------ For each month, find the average hourly demand for electrical lighting energy */ ( int month = 0; month < MONTHSINYEAR; month++ ) monthlyLightingReq[month] = 0; if ( month == selectedMonth initializeAverageArray( currentWorkplaneBay.rapidFineRoom.hiResWorkplane ); for ( int hour = BEGINHOUR; hour < ENDHOUR; hour += timeStep solarlnfo.positionForHour( month, hour ); 135 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec monthlyLightingReq[month] += oneHourWorkplaneLightingEnergy( toDegrees( solarInfo. getAzimuth (), toDegrees( solarlnfo. getAltitude(), solarlnfo. getDirectlntensity(, solarInfo. getDiffuselntensity() if ( month selectedMonth incrementAverageArray ( currentWorkplaneBay. rapidFineRoom. hiResWorkplane ); /7 Find total electrical energy per workplane area for each month monthlyLightingReq[month] = monthlyLightingReq[month] * DAYSINMONTH; if ( month == selectedMonth ) averageAverageArray 0; return monthlyLightingReq; The following method is only for testing purposes: GETMONTHAVERAGEDWORKPLANE 0 */ public double[][] getMonthAveragedWorkplane() return monthAveragedWorkplane; // Constructors /7 Constructor No.1 <B>Base - base constructor constructor for Illumination class.</B> Explanations of the input variables are as follows:<BR> <BR> nameOfJob RESOLUTIONx RESOLUTIONFINEx sillHeight only for your reference<BR> low-res Map resolutionKBR> high-res Map resolutionKBR> height, measured from floor, headHeight transparent part of facadeKBR> height, measured from floor, of top of transparent part of facade<BR> */ 136 of bottom of C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public Illumination( int NUMITERATIONS, double emissivity, double sillHeight, double headHeight, int numberOfBlinds, RoomDescription entireRoomDese ) { double if blindSpacing; ( numberOfBlinds ==0 ) { blindSpacing = .6; } else { blindSpacing = 0; this.NUM_ITERATIONS this.entireRoomDesc this.rl this.r2 1 = NUMITERATIONS; = entireRoomDesc; entireRoomDesc.getDeptho / entireRoomDesc.getHeight(); entireRoomDesc.getHeight() / entireRoomDesc.getWidtho; Define "settings" object to store all parameters for the illumination procedure */ settings new SettingSuite( emissivity, entireRoomDesc.getDepth(), entireRoomDesc.getHeight(), entireRoomDesc.getWidth(), /* depthRes ( CRUDE CELLCOUNT ), heightRes( CRUDECELLCOUNT ), widthRes ( CRUDECELLCOUNT ), new WindowSuite( sillHeight, headHeight, entireRoomDese.getWidth(), 0, entireRoomDesc.getOverhangDeptho numberOfBlinds, ) blindSpacing System. out. println( "Crude total cellcount: +depthRes " ( CRUDECELLCOUNT ) +" by " +heightRes ( CRUDECELLCOUNT +" by " +widthRes ( CRUDECELLCOUNT ) ); System. out. println( "Fine total cellcount: " +depthRes ( FINECELLCOUNT +" by " +heightRes ( FINECELLCOUNT ) +" by " +widthRes ( FINECELLCOUNT ) System. out. println( "Rapid total cellcount: " +depthRes ( RAPIDCELLCOUNT 137 ); ) ), C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec +" by " ) +heightRes ( RAPIDCELLCOUNT +" by " ) +widthRes ( RAPIDCELLCOUNT ); // Define settings for hi-res version of room fineRoomSettings new SettingSuite( settings, depthRes ( FINECELLCOUNT ), heightRes( FINECELLCOUNT ), widthRes ( FINECELLCOUNT )); rapidFineRoomSettings = new SettingSuite( settings, depthRes ( RAPIDCELLCOUNT ), heightRes( RAPIDCELLCOUNT ), widthRes ( RAPIDCELLCOUNT )); oneInitializer onelterator new Initializer() new Iterator(); currentWorkplaneBay new WorkplaneBay( settings, rapidFineRoomSettings, oneInitializer, oneIterator, entireRoomDesc.getWorkplaneHeight(), convertToWM2( entireRoomDesc.getMinimumLightLevel() ) ); if ( entireRoomDesc.getWorkplaneHeight( > currentWorkplaneBay.rapidFineRoom.getHeight()) { System.out.println( "please enter a workplane height that is less than the total height of the room." } } // Constructor No.2 <B>"Pre-constructor" (2) for constructor No. 1 - NO BLINDS.</B> NUMITERATIONS, public Illumination( int double double double double double double double double double this emissivity, sillHeight, headHeight, depth, height, width, workplaneHeight, minLightLevel, ) overhangDepth ( NUMITERATIONS, emissivity, 138 // floor to sill (m) // floor to head (m) 7/ depth into room (m) // height of room (m) 7/ width of window wall (m) /in lux C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec sillHeight, headHeight, 0, new RoomDescription( depth, width, height, null, overhangDepth, 0.0, minLightLevel, 0.0, 0.0 } / Constructor No.3 <B>"Pre-constructor" (3) for constructor No.1 - INCLUDES BLINDS.</B> public Illumination( int double double double double double double int double double double { this ( NUM_ITERATIONS, emissivity, sillHeight, headHeight, depth, height, width, number0fBlinds, workplaneHeight, minLightLevel, overhangDepth ) // floor to sill (m) //7 floor to head (m) //7 depth into room (m) //7 height of room (m) //7 width of window wall NUMITERATIONS, emissivity, sillHeight, headHeight, 20, new RoomDescription( depth, width, height, null, overhangDepth, 0.0, minLightLevel, 0.0, 0.0 } Constructor No.4 for Jim 139 (m) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec <B>"Pre-constructor" (4) for constructor No.1 - INCLUDES BLINDS. </B> public Illumination( RoomDescription newDese this ( 5, 0.3, newDesc.getSillHeight(), /7 wall emissivity (0.3 = approx. white) newDesc.getHeadHeight(), // number 0, of blinds = 0 newDesc } // Constructor No.5 <B>"Pre-constructor" (5) for constructor No.3 - INCLUDES BLINDS.</B> Use this FOR TESTING ONLY if you want to specify the blind angle 11/20/02 *7 NUMITERATIONS, public Illumination( int emissivity, double sillHeight, double //floor to sill (i) headHeight, double floor to head () //7 depth, double depth into room (i) //7 //7 height of room (n) height, double width, width of window wall double //7 double workplaneHeight, minLightLevel, double overhangDepth, double int double numberOfBlinds, blindAngle this ( NUMITERATIONS, emissivity, sillHeight, headHeight, depth, height, width, number0fBlinds, workplaneHeight, minLightLevel, overhangDepth ); tempBlindAngle = blindAngle; 7/ Private Methods 7/ 10/7/02 private double convertToWM2( double lux return ( lux * WATTSPERLUMEN ); 140 ) () C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec In SETDAYLIGHTING() is the principal engine for illuminating a room with daylight. the first section, a crude room is created and reflections (iterations) are performed. Optionally, a second section can then he invoked, in which a second crude, un-iterated room is created, along with an un-iterated fine room. The uniterated room image is subtracted from the fine room, and finally the iterated version of the crude room is added back in, resulting in a fine room with added reflections */ private void setDaylighting( /* "oneFineRoom" can be a reference to either "fineRoom" or "rapidFineRoom" */ Map oneFineRoom, Map room, Map iteratedRoom, SolarSuite solarVars, String smoothing, String lightingResolution, double collectiveBlindAngle ) // BASIC, LOW-RES SIMULATION ------onelnitializer.setInitialLightLevels( ---------------------------/* Cast sunlight upon the inside surfaces of the to-beiterated room iteratedRoom, settings.windowSpecs, "distributed", collectiveBlindAngle, ) solarVars /7 Allow light to reflect among inside surfaces of the to-be-iterated room doDiffuseReflections( iteratedRoom, NUMITERATIONS ); // OPTIONAL, HI-RES SIMULATION -----------------------------------------if ( lightingResolution.equals( "highRes" )) oneInitializer.setInitialLightLevels( room, settings.windowSpecs, "distributed", collectiveBlindAngle, solarVars onelnitializer.setlnitialLightLevels( oneFineRoom, settings.windowSpecs, "focused", collectiveBlindAngle, solarVars /* The net effect of subtracting the radiosities of the UN-iterated "room, " then adding the radiosities of "iteratedRoom, " is to add REFLECTED LIGHT ONLY to the high-resolution "fineRoom." *7 oneFineRoom.addRadiositiesFrom( room, "-, smoothing ); oneFineRoom. addRadiositiesFrom( iteratedRoom, "+", smoothing ) 141 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } DODIFFUSEREFLECTIONSO of the input Map. Performs iterations (reflections of light) between surfaces private void doDiffuseReflections( Map aRoom, int numIterations for ( int iteration = 0; iteration < numIterations; I oneIterator.iterateRadiosityCalc( aRoom ); private void initializeAverageArray( Surface workplane ) iteration±+ ) monthAveragedWorkplane = new double[workplane. a] [workplane. b]; for ( int i for ( int 0; i j < monthAveragedWorkplane.length; i++ ) 0; j < monthAveragedWorkplane[0]. length; j++ inonthAveragedWorkplane[i][j] = 0; private void incrementAverageArray( Surface workplane for ( mt i for (int 0; i K monthAveragedWorkplane.length; 0; i < monthAveragedWorkplane[. nonthAveragedWorkplane[i] Li] i+ length; j++ ) += workplane. Q~i] Li]; private void averageAverageArrayo( for ( t i =0; i K onthAveragedWorkplane.length; i++ for ( int j = 0; j < monthAveragedWorkplane[0]. length; j++ monthAveragedWorkplane[i] [j] /= (ENDHOUR-BEGINHOUR); TODEGREES 0I 142 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec private double toDegrees( double radianValue ) return ( radianValue * 180 / Math.PI ); DEPTHRESO decides how many cells deep the room should be, based on a maximum cellcount for the whole room and on the principle that the number of cells along each edge of the room should be roughly proportional to the length of that edge *7 private int depthRes( int totalcellcount double factor ( 2/rl + 2/(rl*r2) + I/(Math.pow(rl,2)*r2) ); return solveForDimension( totalcellcount, factor ); HEIGHTRES() decides how many cells high the room should be */ private int heightRes( int totalcellcount ) double factor ( 2*rl + 2*rl/r2 + l/r2 return solveForDimension( totalcellcount, factor ); WIDTHRESO decides how many cells wide the room should be */ private int widthRes( int totalcellcount ) double factor ( 2*rl*Math. pow(r2, 2) + 2*rl*r2 + r2 ); return solveForDimension( totalcellcount, factor ); private int solveForDimension( int totalcellcount, double factor ) return ( new Double( Math.ceil( Math.pow( new Integer(totalcellcount). doubleValue( ) / factor ), 0.5 ) ) ).intValue() 7/ class Illumination 143 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class Initializer FloorCeilingInitializer oneFloorCeilingInitializer; oneSideWallInitializer; SideWalllnitializer oneFacadeInitializer; FacadeInitializer oneWorkplanelnitializer; Workplanelnitializer public InitializerO oneFloorCeilingInitializer oneSideWalllnitializer oneFacadelnitializer oneWorkplanelnitializer // = = = = new new new new FloorCeilinglnitializer(); SideWalllnitializer() FacadeInitializer 0; Workplanelnitializer(; PUBLIC METHODS public void setInitialLightLevels( Map room, WindowSuite windowSpecs, String blindShadingScheme, double collectiveBlindAngle, SolarSuite solarVars { initializeBlinds( room, collectiveBlindAngle, solarVars if ( noDirectSun(solarVars.solarAngleHorizontal) I initializeForNoDirectSun( room, ) ) ) windowSpecs, blindShadingScheme, collectiveBlindAngle, solarVars ); } else initializeWholeRoom( room, windowSpecs, blindShadingScheme, collectiveBlindAngle, solarVars ); } public void initializeHiResWorkplane( Map room, WindowSuite windowSpecs, String blindShadingScheme, double collectiveBlindAngle, SolarSuite solarVars 144 ) C:\Documents and Settings\Administrator\Desktop\Project initializeBlinds( room, collectiveBlindAngle, if Latest\Essential Projec solarVars ); ( noDirectSun(solarVars.solarAngleHorizontal) ) surfaceToZero( room.hiResWorkplane ); else oneWorkplanelnitializer.initialize( room.hiResWorkplane, windowSpecs, room.blinds, blindShadingScheme, room.isFirstWorkplanelnitialization, room.workplaneBlindViewFactorArray, solarVars ); room.isFirstWorkplanelnitialization = false; 7/ PRIVATE METHODS ---- --------------- ------------------------ private void initializeBlinds( Map room, double collectiveBlindAngle, SolarSuite solarVars ) room.blinds.setCollectiveAngle( collectiveBlindAngle ); room. blinds. setRadiosity( solarVars.solarIncoming, solarVars.solarAngleVertical ); private boolean noDirectSun( double solarAngleHorizontal return ( solarAngleHorizontal >= 90 ) solarAngleHorizontal <= -90 ); } private void initializeForNoDirectSun( Map room, WindowSuite windowSpecs, String blindShadingScheme, double collectiveAngle, SolarSuite solarVars for ( int surfaceIndex = 0; surfaceIndex ) < room. number0fSurfaces; surfaceIndex++ ) surfaceToZero( room.surfaces[surfaceIndex] ); } oneFacadelnitializer.initialize( room.surfaces[room. getNumberCorrespondingToSurfaceName( "window" ) - 1], windowSpecs, room.blinds, blindShadingScheme, room.isFirstInitialization, room.blindViewFactorArray[room. 145 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec getNumberCorrespondingToSurfaceName( "window" ) 1], solarVars private void initializeWholeRoom( Map room, WindowSuite windowSpecs, String blindShadingScheme, double collectiveAngle, SolarSuite solarVars ) if ( room.isFirstInitialization ) { createBlindViewFactorArray( room for ( int surfaceIndex = 0; surfaceIndex < room. number0fSurfaces; surfacelndex++ initializeSurface( room.surfaces[surfacelndex], windowSpecs, room.blinds, blindShadingScheme, room.isFirstInitialization, room.blindViewFactorArray[surfacelndex], solarVars room.isFirstInitialization = false; private void createBlindViewFactorArray( Map room for ( int i = 0; i < room.number0fSurfaces; i++ f room. blindViewFactorArray[i] = new ViewFactorSuiteO; private void surfaceToZero( Surface aSurface for ( int i = 0; i < aSurface.Q.length; i++ ) for ( int j = 0; j < aSurface.Q[0].length; j++ ) aSurface.Q-initial[i][j] aSurface.Q[i][j] = 0; = 0; private void initializeSurface( Surface currentSurface, WindowSuite windowSpecs, BlindSet blinds, 146 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec String blindShadingScheme, boolean isFirstInitialization, ViewFactorSuite blindFactors, SolarSuite solarVars ) if ( currentSurface.surfaceType.equals( "platform" )) oneFloorCeilinglnitializer. initialize( currentSurface, windowSpecs, blinds, blindShadingScheme, isFirstlnitialization, blindFactors, solarVars ); else if ( currentSurface.surfaceType.equals( "sideWall" )) oneSideWallInitializer.initialize( currentSurface, windowSpecs, blinds, blindShadingScheme, isFirstInitialization, blindFactors, solarVars ) else if ( currentSurface.surfaceType.equals( "facade" )) oneFacadeInitializer.initialize( currentSurface, windowSpecs, blinds, blindShadingScheme, isFirstlnitialization, blindFactors, solarVars ); else {} 147 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; . public class Interpolator public int[][][] private double[][] valueIndexArray; outputArrayFinal; public Interpolator( double[][] array ) /* The valueIndexArray contains the coordinates of the node-points. A "node-point" is the center of each field of identical numbers in the expanded version of "array." The row coordinate is stored in the first level of valueIndexArray, and the column coordinate is stored in the second level. valueIndexArray = new int[( array. length + 2 )] [( array[0]. length + 2 )][2]; public double[][] bilinearlnterpolate( double[][][] outputArrayFringed ) int rowCounter = 0; int colCounter = 0; int rowCounterIncremented; int colCounterIncremented; double t; double u; fillValueIndexArray( outputArrayFringed ); for ( int row = 0; row < outputArrayFringed. length; row++ /* The "checker" variable is used to find out if the current values of "row" and "column" correspond to a node-point. If so, "rowCounter" and "colCounter" are incremented accordingly. */ for ( int checker = 0; checker < valueIndexArray. length; checker++ 148 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec 0) if ( valueIndexArray[checker] [0] [0] == row &&row rowCounter++; for ( int column = 0; column < outputArrayFringed[O]. length; column++ if ) ( outputArrayFringed[row] [column] [1] == 0 for ( int checker = 0; checker < valuelndexArray[0].length; checker++ ) if ( valuelndexArray[O][checker][1] column && column 0) colCounter++; /* rowCounterIncremented is not necessarily the next point over in the positive-row dimension. As you approach the far side of the array, you run out of "next points" in that direction, and must reverse the direction in which your coordinate point is incremented. */ rowCounterIncremented = rowCounter + 1; colCounterIncremented = colCounter + 1; if ( outputArrayFringed. length - 1 )) ( row rowCounterlncremented = rowCounter - 1; if ( column ( outputArrayFringed[0]. length - 1)) colCounterIncremented = colCounter - 1; /* u is the distance between the node-point (rowCounter,colCounter) and the present position (row,column) in the "row" direction, divided by the distance between (rowCounter,colCounter) and the next nodepoint over (rowCounterIncremented, colCounterIncremented). */ u ( new Integer( row - valueIndexArray [rowCounter][colCounter][0] ).doubleValue 0) / ( new Integer( valueIndexArray[ ( rowCounterIncremented )] [colCounter][0] 149 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec - valuelndexArray[ rowCounter] [colCounter][0] ). doubleValueO) /* t is the distance between the node-point (rowCounter,colCounter) and the present position (row,column) in the "column" direction, divided by the distance between (rowCounter,colCounter) and the next nodepoint over (rowCounterIncremented, colCounterIncremented). */ t ( new Integer( column - valuelndexArray[ rowCounter] [colCounter][1] ). doubleValue 0) / ( new Integer( valueIndexArray[ rowCounter] [( colCounterIncremented )][1] -- valueIndexArrayL rowCounter] [colCounter] [1] ). doubleValue() outputArrayFringed[row][column][0] getPositionAveragedPointValue( u, t, rowCounter, colCounter, rowCounterIncremented, colCounterIncremented, outputArrayFringed ); }/ end if-statement else if ( column =0 ) { colCounter++; } }/ end for-loop for columns colCounter = 0; } // end for-loop for rows return fillOutputArrayFinal( outputArrayFringed ); // end bilinearInterpolate( See explanation of variable "valueIndexArray," above. *7 private void fillValueIndexArray( double[][][] outputArrayFringed ) int rowCounter = 0; int colCounter = 0; boolean rowEmpty true; 150 C:\Documents and Settings\Administrator\Desktop\Project for ( int row = 0; row < Latest\Essential Projec outputArrayFringed.length; row++ ) { for ( int column = 0; column if < outputArrayFringed[O]. length; column++ ) ( outputArrayFringed[row][column][1] != 0 ) value{ndexArray[rowCounter][colCounter][0] valuelndexArray[rowCounter][colCounter][ row; = column; colCounter++; rowEmpty colCounter false; 0; if ( !rowEmpty ) rowCounter++; rowEmpty = true; The core of the bilinear interpolation. Takes a grid position in column-and-row coordinates u and t and calculates the appropriate value at that point, as a function of the values at the surrounding node-points. */ private double getPositionAveragedPointValue( double u, double t, int rowCounter, int colCounter, int rowCounterIncremented, int colCounterIncremented, double[][][] outputArrayFringed return (( * 1( t ) * ( 1 - u) outputArrayFringed[( valueIndexArray[rowCounter][colCounter][0] )] [( valuelndexArray[rowCounter][colCounter] [1] )][0] ) (1-u) t* * ( outputArrayFringed[( valuelndexArray[rowCounter][colCounter][0] [( valueIndexArray[rowCounter] [( colCounterIncremented )][1] )][0] ) t *u 151 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec * ( valueIndexArray[( outputArrayFringed[( [( (1l * t ) * u outputArrayFringed[( rowCounterIncremented valueIndexArray[( rowCounterIncremented )] [colCounter][0] )] valueIndexArray[rowCounter][colCounter] [1] )][0] ) private double[][] fillOutputArrayFinal( double[][][] outputArrayFringed outputArrayFinal = new double[( outputArrayFringed. length - 2 [( ( ) - ( [( for )] [colCounter][0] )] valueIndexArray[rowCounter] [( colCounterIncremented )][1] )][0] )] outputArrayFringed[0]. length - 2 )]; int row = 0; row < outputArrayFinal. length; row++ for ( int column = 0; column < outputArrayFinal[O]. length; column++ ) outputArrayFinal[row][column] outputArrayFringed[( return outputArrayFinal; 152 row + 1 )][( column + 1 )][0]; C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; // CLASS ITERATOR Device that can be used to perform reflections between the inside surfaces of a room. public class Iterator { private ViewFactory oneViewFactory; Initializes variables */ public Iterator() { new ViewFactory(); oneViewFactory } Establishes holding arrays for the view factors between one surface and another. Runs one iteration (one series of reflections involving all the surfaces in a room) */ public void iterateRadiosityCalc( Map room if ) ( room. isFirstIteration ) for {nt i for r( 0; i < room.numberfSurfaces; i+) t = 0; j <j room.numberfSurfaces; j++ room.viewFactorArray[i][j]= new ViewFactorSuite( room.surfaces[i].a, room.surfaces[i].b, room.surfaces[j].a, room.surfaces[j].b ); I} // Reset H arrays for ( int surfaceIndex = 0; surfaceIndex < room. numberOfSurfaces; surfaceIndex++ { initializeHArray( room, surfacelndex, 153 0 ); ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec 7/ Run iteration for ( int surfaceIndex = 0; surfaceIndex < room. number0fSurfaces; surfacelndex++ ) radiosityCalc( room, surfaceIndex ); // Update Q arrays for ( int surfaceIndex = 0; surfaceIndex < room. numberOfSurfaces; surfacelndex++ setQ( room, surfaceIndex ) ) room.isFirstlteration = false; public void showReflectionsOnLowResWorkplane( Map room ) // Create storage for view factors of workplane w.r.t. rest of room if ( room. isFirstWorkplanelteration ) for ( int i 0; i < room. numberOfSurfaces; i++ ) room. workplaneViewFactorArray[i] new ViewFactorSuite( room. lowResWorkplane. a, room.lowResWorkplane.b, room. surfaces[i]. a, room.surfaces[i].b 7/ Reset H array room. lowResWorkplane. setHArrayTo( 0 ); 7/ Do one set of reflections onto workplane lowResWorkplaneRadiosityCalc( room 7/ Update workplane Q array room.lowResWorkplane.setQo; room. isFirstWorkplanelteration /*------------------------- false; */ ---------------- -------------- private void initializeHArray( Map room, int surfaceIndex, room. surfaces [surfaceIndex]. setHArrayTo( Hinitial 154 double H initial ) ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec private void radiosityCalc( Map room, int surfaceIndex ) for ( int otherSurfaceNumber = 1; otherSurfaceNumber < room.numberOfSurfaces; otherSurfaceNumber++ ) updateVariables( room, surfaceIndex, getOtherSurfaceIndex( surfaceIndex, otherSurfaceNumber )); private void lowResWorkplaneRadiosityCalc( Map room ) for ( int otherSurfaceIndex = 0; otherSurfaceIndex < room. number0fSurfaces; otherSurfaceIndex++ ) updateWorkplaneVariables( room, otherSurfaceIndex ) private void setQ( Map room, int surfaceIndex { room. surfaces[ surfaceIndex]. setQO; } /*---------an "index" is on the ----------------- ---------------------------------------*/ 0-upwards scale, and a "number" is on the 1-upwards scale */ private int getOtherSurfaceIndex( int surfaceIndex, if ( otherSurfaceNumber int otherSurfaceNumber ) <= surfaceIndex ) return otherSurfaceNumber - 1; else { return otherSurfaceNumber; private void updateVariables( Map room, int surfaceIndex, int otherSurfaceIndex {room.surfaces[surfacelndex]; Surface surface = room.surfaces[otherSurfaceIndex]; Surface otherSurface int a = surface.a; int b = surface.b; int other a = otherSurface.a; int otherb = otherSurface.b; 155 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec for ( int il = 0; il for for ( int i2 ( int ji for ( int j2 if < a; il++ ) 0; i2 < b; i2++ ) 0; il 0; j2 < other-a; jl++ < other_b; j2++ ( room. isFirstIteration ) room. viewFactorArray[surfacelndex] [otherSurfaceIndex]. surfaceToSurfacePairings[il][i2][jl][j2] oneViewFactory.computeViewFactor( otherSurface.alpha[jl][j2], otherSurface.beta[jl][j2], otherSurface. gamma[jl] [j2], surface.alpha[il][i2], surface. beta[il] [i2], surface.gamma[ill[i2], otherSurface.x[jl][j2], surface. x[il] [i2], otherSurface.y[jl][j2], surface. y[il] [i2], otherSurface.z[jl][j2], surface. z[il] [i2], surface. A[il] [i2] ) surface.H[il][i2] + otherSurface.Q[jl][j2] * otherSurface.A[jl][j2] private void updateWorkplaneVariables( Surface otherSurface * room. / viewFactorArray[surfacelndex] [otherSurfaceIndex]. surfaceToSurfacePairings[il][i2] [jl][j2] surface. A[il] [i2]; Map room, int otherSurfaceIndex room. surfaces [otherSurfaceIndex]; 156 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec int a = room.lowResWorkplane.a; int b = room.lowResWorkplane.b; int othera = otherSurface.a; int otherb = otherSurface.b; for ( int il for for ( int i2 ( int j 0; il 0; i2 < b; i2++ ) 0; jl for ( int j2 if < a; il++ ) 0; j2 < othera; jl++ < otherb; j2++ ) ( room.isFirstWorkplanelteration ) if ( otherSurface. y[jl] [j2] > room. lowResWorkplane. constantCoordinate ) room.workplaneViewFactorArray[otherSurfacelndex]. surfaceToSurfacePairings[il][i2][ji][j2] oneViewFactory.computeViewFactor( otherSurface.alpha[jl][j2], otherSurface.beta[jl][j2], otherSurface.gamma[jl][j2], room.lowResWorkplane.alpha[il][i2], room.lowResWorkplane.beta[il][i2], room.lowResWorkplane.gamma[il][i2], otherSurface.x[jl][j2], room.lowResWorkplane.x[il][i2], otherSurface.y[jl][j2], room.lowResWorkplane.y[il][i2], otherSurface. z[jI] [j2], room.lowResWorkplane.z[il][i2], room.lowResWorkplane.A[il][i2] ); } else { room.workplaneViewFactorArray[otherSurfacelndex]. surfaceToSurfacePairings[il][i2][jl][j2] = 0; room.lowResWorkplane.H[il][i2] += otherSurface.Q[jl][j2] * otherSurface.A[jl][j2] * room. 157 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec / workplaneViewFactorArray[otherSurfacelndex]. surfaceToSurfacePairings[il][i2][jl][j2] room. lowResWorkplane. A[il][i2]; } 158 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; // CLASS MAP Sets up a "room" by creating interior wall, floor, ceiling and window surfaces, plus a set of blinds. It also declares an array to contain view factors for every possible pairing of the discrete elements that make up the areas of the interior surfaces. Note that a new copy of "settings" is created and associated permanently with each instance of "Map." public class Map { public int numberOfSurfaces = 5; //private SettingSuite settings; public ViewFactorSuite[]L] public ViewFactorSuite viewFactorArray; workplaneViewFactorArray; blindViewFactorArray; workplaneBlindViewFactorArray; public BlindSet public Surface[] blinds; surfaces; public ViewFactorSuiteL] public ViewFactorSuite[] the 2 workplanes will eventually be combined into // public Platform lowResWorkplane, hiResWorkplane; private private private private // double double double double 1 depth; height; width; emissivity; public boolean public boolean isFirstInitialization; isFirstWorkplaneInitialization; public boolean public boolean isFirstIteration; isFirstWorkplaneIteration; CONSTRUCTOR No.1 <B>Base constructor for Map class.</B> */ 159 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public Map( SettingSuite settings /* Settings are read in from a SettingSuite object, where they are all defined *7 width = settings.depthMagnitude; = settings.heightMagnitude; = settings.widthMagnitude; emissivity = settings.emissivity; depth height new Surface[numberOfSurfaces]; surfaces viewFactorArray workplaneViewFactorArray blindViewFactorArray workplaneBlindViewFactorArray = new ViewFactorSuite[numberOfSurfaces] [numberOfSurfaces]; = new ViewFactorSuite[numberOfSurfaces]; = new ViewFactorSuite[numberOfSurfaces]; = new ViewFactorSuiteO; isFirstInitialization isFirstWorkplaneInitialization = true; isFirstIteration isFirstWorkplanelteration = true; = true; blinds surfaces[0] = true; new BlindSet( settings.numberOfBlinds, settings.widthMagnitude, settings.blindSpacing, settings.windowSpecs.sillHeight, settings.windowSpecs.headHeight, settings.emissivity = new Platform( "floor", settings.depthResolution, settings.widthResolution, settings.depthMagnitude, settings.widthMagnitude, settings.emissivity, 0 ) surfaces[1] new SideWall( "sideWalll", settings.depthResolution, settings.heightResolution, settings.depthMagnitude, settings.heightMagnitude, settings.emissivity, 0 surfaces[2] new SideWall( "sideWall2", settings.depthResolution, settings.heightResolution, settings.depthMagnitude, settings.heightMagnitude, settings.emissivity, settings.widthMagnitude ) 160 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec surfaces[3] new Platform( "ceiling", settings.depthResolution, settings.widthResolution, settings.depthMagnitude, settings.widthMagnitude, settings.emissivity, settings.heightMagnitude ) surfaces[4] new Facade( "window", settings.heightResolution, settings.widthResolution, settings.heightMagnitude, settings.widthMagnitude, settings.emissivity, 0 }// constructor No.1 ---------------------------------- CONSTRUCTOR No.2 ------------------------ <B>Used for creating a duplicate copy of an existing Map object. </B> */ public Map( Map room, SettingSuite settings this( settings for ( int i = 0; i < numberOfSurfaces; i++ ) surfaces[i]. substituteQValues( } }// constructor No.2 Returns the in-out dimension of the room public double getDeptho return depth; Returns the up-down dimension of the room */ public double getHeighto return height; Returns the left-right dimension of the room */ 161 room. surfaces[i].Q ); C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public double getWidtho return width; Returns a value between 0 and 255 corresponding to the radiosity levels at the specified coordinates. <BR> The following conventions apply when using this method:<BR> <BR> "x" corresponds to the depth (in-out) dimension<BR> y" corresponds to the height (up-down) dimension<BR> "z" corresponds to the width (left-right) dimension<BR> <BR> All coordinates are measured from an origin at the lower, right-hand corner of the window surface, assuming the window is viewed from inside the room. <BR> Surface numbers run as follows:<BR> <BR> 0: floor<BR> 1: sideWalll (right-hand side)<BR> 2: sideWall2 (left-hand side, looking toward window from inside)<BR> 3: ceiling<BR> 4: window public double findRadiosityAtPoint( double x, double y, double z, GrayScaleConverter grayValues int surfaceNumber; if ( x == 0 ) // surface must therefore be a window surfaceNumber = 4; return getRadiosity( surfaceNumber, grayValues, y, if ( y == 0 ) // z ); surface must therefore be a floor surfaceNumber = 0; return getRadiosity( surfaceNumber, grayValues, x, z ); if ( y == height ) // surface must therefore be a ceiling surfaceNumber = 3; return getRadiosity( surfaceNumber, grayValues, x, z ); if } ( z == 0 ) // surface must therefore be a sideWalll surfaceNumber = 1; return getRadiosity( surfaceNumber, grayValues, x, y ); if I z == width ) // surface must therefore be a sideWall2 surfaceNumber = 2; 162 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec return getRadiosity( surfaceNumber, grayValues, x, y ) } System.out.println( "point requested does not lie on a surface of this room" ); return 0; 7* Given a surface index ("N," the number from 0 to 4 corresponding to one of the surfaces in the room - see definitions under "findRadiosityAtPoint"), uses the "GrayScaleConverter" class to return a value between 0 and 255 corresponding to the radiosity level at the specified coordinates on the surface. */ private double getRadiosity( int N, GrayScaleConverter grayValues, double surfaceCoordinatel, double surfaceCoordinate2 return grayValues.convertRadiosityToGrayScale( surfaces[N].Q[ findlndex0fReach( surfaceCoordinatel, surfaces [N]. a, surfaces[N].parallelDistance )] [ findlndexOfReach( surfaceCoordinate2, surfaces [N]. b, surfaces[N].crossDistance )] private int findlndex0fReach( double distance, int resolutionInDirection0fReach, double totalDistance double returnValue_D; int indexOfReach; returnValueD = distance / totalDistance * resolutionInDirectionOfReach; /* the ceiling value of (returnValueD 1) is taken instead of the floor of returnValue_D, in case returnValueD is a whole number. */ indexOfReach = new Double( Math. ceil( returnValueD - 1 )). intValue() if (indexOfReach < 0) { return 0; } return indexOfReach; 163 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec Adds or subtracts the radiosity values of the input Map from the dereferenced Map. The two Map objects may have different resolutions, but in that case, the resolution of the output will be that of the dereferenced Map. The input string "smoothing" provides the option of using bilinear interpolation to smooth the data points of the input Map before it is added or subtracted. public void addRadiositiesFrom( Map addedRoom, String operation, String smoothing for ( int i = 0; i f < numberOfSurfaces; i++ ) surfaces[i]. addRadiositiesFrom( addedRoom. surfaces[i], operation, smoothing ); } } public void createWorkplanes( double workplaneHeight, lowResWorkplane int lowRes a, int lowRes_b, int hiResa, int hiRes-b new Platform( "workplane", lowRes_a, lowResb, depth, width, emissivity, workplaneHeight hiResWorkplane new Platform( "workplane", hiRes a, hiResa, depth, width, emissivity, workplaneHeight } public int getFloorResolutiona() { return surfaces[0].a; } public int getFloorResolutionb() return surfaces[0].b; 164 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public void replaceFloor( Surface workplane, String smoothing ) I surfaces[0].replaceSurface( workplane, smoothing ); } public String getSurfaceNameCorrespondingToNumber( int number ) switch ( number ) case 1: return "floor"; case 2: return "sideWalll"; case 3: return "sideWall2"; case 4: return "ceiling"; case 5: return "window"; default: return null; public int getNumberCorrespondingToSurfaceName( if ( surfaceName.equals( "floor" String surfaceName )) return 1; else if ( surfaceName.eequals( "sideWalll" )) "sideWall2" )) return 2; } else if ( surfaceName.equals( return 3; else if ( surfaceName.equals( "ceiling" )) return 4; else if ( surfaceName.equals( "window" )) return 5; } else I return 0; 165 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public void cleanUpo // Resets Map to its virgin state clearBilinearGrids (; clearViewFactorArrays 0; private void clearBilinearGrids( for ( int i = 0; i < number0fSurfaces; i++ ) surfaces[i]. clearBilinearGrid(); private void clearViewFactorArrays() isFirstInitialization isFirstWorkplanelnitialization = true; = true; public void setCollectiveBlindAngle( double newBlindAngle blinds.setCollectiveAngle( newBlindAngle public double getCollectiveBlindAngleo return blinds.getCollectiveAngle(; 166 ) ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class PerspectiveView I int fullPixelWidth; int fullPixelHeight; int roomPixelWidth; int roomPixelHeight; int marginPixelHeight; int marginPixelWidth; boolean preserveAspectRatio = true; double roomWidth; double roomHeight; double roomDepth; double observerWidth; 7/ from left wall double observerHeight; // from floor double observerDepth; /7 from near wall Wall Wall Wall Wall Wall farWall; leftWall; rightWall; ceiling; floor; */ Map room; // Added 8/22/02 by Matthew Lehar Map otherRoom; boolean accountFor0therViewInHistogram = false; /* public PerspectiveView (double roomWidth, double roomHeight, double roomDepth, double observerWidth, double observerHeight, double observerDepth, Wall farWall, Wall leftWall, Wall rightWall, Wall ceiling, Wall floor) 167 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec { this.roomWidth = roomWidth; this.roomHeight = roomHeight; this.roomDepth = roomDepth; this.observerWidth = observerWidth; this.observerHeight = observerHeight; this.observerDepth = observerDepth; this.farWall = farWall; this.leftWall = leftWall; this.rightWall = rightWall; = ceiling; this.ceiling = floor; this.floor I public PerspectiveView (double roomWidth, Wall farWall, Wall leftWall, Wall rightWall, Wall ceiling, Wall floor) double roomHeight, double roomDepth, roomWidth; roomHeight; roomDepth; this.roomWidth this.roomHeight this.roomDepth this.observerWidth = 0.5 * roomWidth; this.observerHeight = 0.5 * roomHeight; this.observerDepth = roomDepth; this.farWall = farWall; this.leftWall = leftWall; this.rightWall = rightWall; = ceiling; this.ceiling = floor; this.floor } public PerspectiveView (Map room, double observerWidth, double observerHeight, double observerDepth) I this.room = room; this.roomWidth = room.getWidth(); this.roomHeight = room.getHeight(); this.roomDepth = room.getDepth(; //System.out.println( roomDepth ); this.observerWidth = observerWidth; this.observerHeight = observerHeight; this.observerDepth = observerDepth; } 168 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec // ADDED 8/22/02 by Matthew Lehar // for the case in which both rooms are to b public PerspectiveView (Map room, e included in the brightness histogram Map otherRoom, double observerWidth, double observerHeight, double observerDepth) this( room, observerWidth, observerHeight, observerDepth ); //System. out. println( "using 2-room cons tructor for perspectiveView" ); this.otherRoom = otherRoom; accountForOtherViewInHistogram = true; public PerspectiveView (Map room) this.room = room; this.roomWidth = room.getWidth(; this.roomHeight = room.getHeight(); this.roomDepth = room.getDepth(; this.observerWidth = 0.5 * this.roomWidth; this.observerHeight = 0.5 * this.roomHeight; this.observerDepth = this.roomDepth; } /7 ADDED 10/6/02 by Matt-hew Lehar public PerspectiveView (Map room, Map otherRoom) { this( room, otherRoom, 0.5 * room.getWidth(, 0.5 * room.getHeighto, room.getDepth( ) I private void setPixelDimensions(int pixelWidth, int pixelHeight) { fullPixelWidth = pixelWidth; fullPixelHeight = pixelHeight; if (! preserveAspectRatio) roomPixelWidth = fullPixelWidth; roomPixelHeight = fullPixelHeight; marginPixelWidth = 0; marginPixelHeight = 0; 169 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } else { if ((double) fullPixelWidth / (double) fullPixelHeight >= roomWidth / roomHeight) { // side margins roomPixelWidth = (int) Math.round(fullPixelHeight * (roomWidth / roomHeight)); roomPixelHeight = fullPixelHeight; marginPixelWidth = (fullPixelWidth - roomPixelWidth) / 2; marginPixelHeight = 0; else { // top/bottom margins roomPixelWidth = fullPixelWidth; roomPixelHeight = (int) Math.round(fullPixelWidth * (roomHeight / roomWidth)); marginPixelWidth = 0; marginPixelHeight = (fullPixelHeight roomPixelHeight) / 2; System.out.println("roomPixelWidth: " System.out.println("roomPixelHeight: System. out. println("marginPixelWidth: System. out. println("marginPixelHeight: roomPixelWidth); + roomPixelHeight); + marginPixelWidth); + marginPixelHeight); public int[][] drawImage(int pixelWidth, int pixelHeight, int number0fBins setPixelDimensions (pixelWidth, pixelHeight) Box box = new Box (roomWidth, roomHeight, roomDepth, observerWidth, observerHeight, observerDepth); Point3D strike; int shade; double x, y; GrayScaleConverter grayScale = createGrayScaleConverter( number0fBins ); int[][] image = new int[fullPixelWidth][fullPixelHeight]; for (int px=0; px < roomPixelWidth; px++) x = (((double) px + 0.5) / roomPixelWidth) * roomWidth; for (int py=O; py < roomPixelHeight; py++) y = (((double) py + 0.5) / roomPixelHeight) * roomHeight; //System. out.println("px:" + px + " py:" + py); //System. out.println("x:" + x + " y:" + y); 170 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec strike = box.findStrike(x, y); //System. out. printin (strike. toString()); 77 Note that the origin is in a different position in the room (Map) /7 Note also that depth and width are switched shade = (int) room. findRadiosityAtPoint(roomDepth - strike. z, strike.y, roomWidth - strike.x, grayScale); /if (shade > 20) {System.out.println( "halleluja" );} /* if (strike.z == roomDepth) { // struck far wall shade = farWall. getShade (strike. x, strike. y) } else if (strike.x == roomWidth) { // struck right wall shade = rightWall. getShade(roomDepth - strike. z, roomHeight } else if (strike.y == roomHeight) strike. y) 7/ struck ceiling shade = ceiling. getShade (strike. x, strike. z) } else if (strike.x == 0.0) f // struck left wall /7 shade = leftWall.getShade(strike.z, strike.y); shade = leftWall. getShade (strike. z, roomHeight - strike. y) } else // (strike.y == 0.0) { // struck floor shade = floor. getShade(strike.x, roomDepth - strike. z); */ 1 image[marginPixelWidth + px][marginPixelHeight + (roomPixelHeight return image; private GrayScaleConverter createGrayScaleConverter( I if ( accountFor~therViewInHistogram) 171 int number0fBins ) py)] shade C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec { return new GrayScaleConverter( room, otherRoom, numberOfBins ); else { return new GrayScaleConverter( room, numberOfBins ); } } package illumination; // CLASS PLATFORM Populates some of the basic arrays for the surface and invokes methods in the superclass to completely create the surface. The "Platform" class of surfaces includes floor and ceiling. */ public class Platform extends Surface public Platform( Platform onePlatform this( ) onePlatform.name, onePlatform.a, onePlatform.b, onePlatform.parallelDistance, onePlatform.crossDistance, onePlatform.emissivity, onePlatform.constantCoordinate ); substituteQValues( onePlatform.Q ); } public Platform( String name, int parallelResolution, int crossResolution, double parallelMagnitude, double crossMagnitude, double emissivity, double constantCoordinate I surfaceType = new String( "platform" ); constructSurface( name, parallelResolution, crossResolution, parallelMagnitude, crossMagnitude, emissivity, constantCoordinate 172 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec //OBSOLETE VARIABLES: resolutions[O] = 0; resolutions[1] = 1; resolutions[2] = 0; /* thirdIsConstant is used later on in the program to orient the surface grids properly before they are sent to the viewer program thirdIsConstant = false; 'a' and 'b' are the lengthwise and widthwise resolutions of the surface. 'parallelDistance' and 'crossDistance' are the length and width of the surface */ for ( int rowCounter = 0; rowCounter < a; rowCounter++ ) for ( int columnCounter = 0; columnCounter < b; columnCounter++ x[rowCounter][columnCounter] * = constantCoordinate; = ( crossDistance / b ) * ( columnCounter + 0.5 ); y[rowCounter][columnCounter] z[rowCounter][columnCounter] alpha[rowCounter][columnCounter] beta[rowCounter][columnCounter] gamma[rowCounter][columnCounter] A[rowCounter][columnCounter] 173 ( parallelDistance / a ) ( rowCounter + 0.5 ); = 0; = 1; = 0; = parallelDistance * crossDistance / ( a * b ); C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public abstract class PlatformInitializer extends SurfaceInitializer class contains initialization instructions specific to "platform" surfaces (i.e. floors or ceilings) Only one view factor is computed between each blind slat and each element of the platform (i. e. floor or ceiling) grid. The center of the blind slat is the reference position, but in order to avoid making it appear as though the center of the slat is the origin of all refelcted light, the view factors between the slat and all the floor elements in a horizontal (widthwise) row are averaged. The resulting average view factor is then used for all floor elements in that row.<BR> <BR> The radiosity of each blind surface is applied to each platform element, attenuated by the average view factor and also by a flag ("lineOfSightFlag"). This flag takes the value 0 if there is an obstruction between the lit surface of the blind and the platform element in question. public void calculateFirstReflectionFromBlinds( if ( isFirstInitialization BlindSet blinds, boolean isFirstInitialization, ViewFactorSuite blindFactorslD, Surface currentSurface ) ) //System.out.println( "done!" ); blindFactors_lD.makeBlindFactors lD( currentSurface. a, blinds. totalNumber ); for ( int i if 0; i < currentSurface.a; i++ ) ( isFirstInitialization ) for ( int blindIndex = 0; blindIndex < blinds. totalNumber; blindlndex++ for ( int j = 0; j ) < currentSurface. b; j++ ) blindViewFactorSum[i] [blindIndex] += lineOfSightFlag( i, j, ( blindIndex + 174 1 ), C:\Documents and Settings\Adininistrator\Desktop\Project Latest\Essential Projec blinds, verticalAngle ) * oneViewFactory. computeViewFactorWithBlinds( currentSurface, i, j, ( blindlndex + 1 ), blinds, verticalAngle ); blindFactorsiD.surfaceToBlindPairings_lD[i][blindlndex] blindViewFactorSum[i][blindIndex] / currentSurface.b; } for ( int j j < currentSurface.b; j++ ) 0; { for ( int blindNumber = 1; blindNumber <= blinds.totalNumber; blindNumber++ ) currentSurface.Q initial[i][j] += blinds. getRadiosity( blindNumber ) * blinds. slatAreaO * blindFactors lD.surfaceToBlindPairingslD[i][blindNumber - 1] /* * lineOfSightFlag( i, j, blindNumber, blinds, verticalAngle ) * ( 1 - emissivity ) / currentSurface.A[i][i]; */ currentSurface.Q[i][j] = currentSurface. Q-initial[i][j]; public double findAngleOnSurface( double verticalAngle, double horizontalAngle 7* the "angleOnSurface" is the angle defining the amount of diagonal slant of the sides of the patch of sunlight that resides on the platform surface *7 return horizontalAngle; 175 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; A simple point in 3D space. (x, y, z) public class Point3D I public double x; public double y; public double z; public Point3D() f } public String toString() r return ("( + x + " ,"+ z + "" 176 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; This class does some calculations related to raytracing a rectangular room. Specifically, this class is used by Box to simplify calculations. Basically, we have an observer standing behind a box at some distance away. From the The observer always stands "in line" with the origin of the box. observer's perspective, the origin (0,0,0) is at the lower left corner of the near face of the box. He stands at (0,0, some-depth). When a line is drawn from the eye of the observer through the rear wall of the room, we want to know where this line intersects another surface (wall, ceiling, or floor) of the room. This intersection is returned as a Point3D. public class Quadrant I private double w; private double h; // quad width (x direction) /7 quad height (y) private double d; /7 private double dO; quad depth 7/ observer (z) distance from image plane (z direction) public static void main (String[] args) f Quadrant q = new Quadrant (10. 0, 10. 0, 10. 0, 10. 0); double x = Double. valueof (args[0]). doubleValue(; double y = Double. valueOf(args[]). doubleValueo; Point3D s = q.findStrike(x, y); System.out.println(s.toStringo); } public Quadrant (double w, double h, double d, double observerDistance) f this.w w; this.h h; this.d d; this.dO = observerDistance; } //for a given x,y //return x, y, z of strike public Point3D findStrike (double x, double y) { 177 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec Point3D strike = new Point3DO; 7/ fwx: x of where ray strikes plane of far wall (far wall y) y of where ray strikes plane of far wall // Both are measured from where the observer's (far wall x) 7/ fwy: 7/ direct line of sight intersects the far wall. double fwx = x * (do + d) / dO; double fwy = y * (dO + d) / dO; //System.out.println("fwx: " + fwx); //System.out.println("fwy: " + fwy); if (fwx <= w && fwy <= h) I // strikes far wall strike.x = fwx; strike.y = fwy; strike.z = d; } else I 7/awz: 7/ cgz: (adj wall z) z of where ray strikes plane of adjacent wall (ceilling z) z of where ray strikes plane of ceiling double awz = dO * (w double cgz = dO * (h - x) / x; y) / y; // x coord of where ray strikes adjacent wall 77 y coord of where ray strikes adjacent wall //System. out.println("awz: " + awz); //System.out.println("cgz: " + cgz); if (awz == cgz) 77 strikes edge between adjacent wall and ceiling // note that if this case is not included the 77 77 calculation of strike.y may wind up very slightly greater than the height (incorrectly) due to 77 problems with large decimal math. strike.x = w; strike.y = h; strike.z = awz; I else if (awz { // strikes strike.x = strike.y = strike.z = < cgz) adjacent wall W; (awz + do) * y / dO; awz; else 7/ strikes ceiling/floor strike.x = (cgz + do) * x / dO; strike.y = h; strike.z = cgz; } 178 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } return strike; I } package illumination; public class Resizer private double public int[][][] temporary; refIndexArray; public Resizer() public double[][][] { getArrayAndlndeces( double[][] array double outputArray[][] [] new double[array.length][array[O].length] [2]; new int[array.length][array[0].length] [2]; refIndexArray for ( int rowlndex = 0; rowIndex { for ( int collndex = { 0; < array.length; rowIndex++ ) collndex < array[0]. length; collndex++) outputArray[rowIndex][collndex][0] array[rowlndex] outputArray[rowlndex][collndex][1] 1; [collndex]; refIndexArray[rowIndex][collndex][0] reflndexArray[rowIndex][colIndex][1] = rowlndex; = colIndex; return outputArray; Takes a pair of resolutions and returns a 2-D array of two layers (actually a 3-D array). On the first layer, the data from the array called "array" has been stretched out to the grid size specified by "surfaceWidth" and "surfaceHeight." The second layer is a grid of the same size as the first, but filled with zeros. Ones are placed among the zeros to indicate, in parallel with the first layer, the center of a region that has been scaled up from a single data point in the original array 179 ("array"). C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec *7 public double[][][] getArrayAndlndeces( double[][] array, int a, int b ) double outputArray[][][]; double double double double double double numRows double; numCols-double; a_double; b_double; i_double; j-double; double rowIndex-nought; double colIndex-nought; int rowIndex int colIndex 0; 0; int lastRowValue int lastColValue 0; 0; int rowCounter 0; int colCounter 0; refIndexArray new int[a][b][2]; numRowsdouble numColsdouble new Integer (array. length). doubleValue() new Integer(array[0]. length). doubleValueO; a double b double new Integer(a).doubleValueo; new Integer(b).doubleValueo; outputArray new double[a] [b] [2]; // for an explanation of the "+ 1," for ( int i = 0; i colCounter for ( int { see comment at "rowlndexnought," below < a + 1; i++ ) 0; j 0; j i_double jdouble < b + 1; j++ ) new Integer(i). doubleValue() ; new Integer(j). doubleValueo; /* The first value taken by rowIndex_nought is 0, and the last is the length of the array minus 1, just as usual for array indexing. There is a different number (generally more) of values of rowIndex_nought than elements in the original array. The "adjustIndex" method is used to "stretch out" the crushed-together rowIndex nought values, so that the first aligns with the front 180 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec edge of the first cell of the original array, the last with the back edge of the last cell, and the others are spaced equally in-between, except that there is only a half-measure space between the first and second, and penultimate and last, cells. i double / a-double ) * ( numRowsdouble - 1 ); colIndex nought =( jdouble / b double ) * ( numColsdouble - 1) rowIndex nought = rowIndex = new Double( adjustIndex( rowIndex numRowsdouble colIndex = new Double( adjustlndex( collndex numColsdouble nought, )).intValue(); nought, )).intValue(); if ( rowIndex != lastRowValue &&colIndex != lastColValue ) /* Each time a new row is reached, places a "1" among the zeros of the 2nd layer of the "outputArray" array. The "1" corresponds to the point positioned in the center of the field of numbers that each single element of the original array has been expanded to fill. */ outputArray [( i - [( j - new Double( Math.ceil( new Integer( rowCounter ). doubleValueo / 2 )). intValue 0)] new Double( Math.ceil( new Integer( colCounter ). doubleValue( / 2 )). intValue())] [1] = lastColValue colCounter 1; = colIndex; = 0; } if ( i I < a &&j < b ) outputArray[i][j][0] = array[rowlndex] [collndex]; refIndexArray[i][j][0] refIndexArray[i][j][1] colCounter++; } if ( rowlndex != lastRowValue ) { 181 = rowIndex; = collndex; C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec = rowIndex; = 0; lastRowValue rowCounter lastColValue = 0; rowCounter++; return outputArray; If the indeces represent the centers of cell-elements, then the following method re-distributes those indeces so that the first index is aligned with the front edge of the first cell, the last index with the back edge of the last cell, and all These indeces are the other indeces evenly spaced in-between. then rounded, and any negative results made zero. */ private double adjustIndex( double index_nought, double inputResolution ( inputResolution - 1 temporary = Math.round(( indexnought ( inputResolution / ( inputResolution ( inputResolution - 1 ) / 2 ) if ( temporary < 1 temporary 0; return temporary; 182 ) ) / 2) * - 1 )) + C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; // CLASS SETTINGSUITE Stores illumination parameters. public class SettingSuite public double emissivity; public double public double public double depthMagnitude; heightMagnitude; widthMagnitude; public int public int public int depthResolution; heightResolution; widthResolution; public WindowSuite windowSpecs; public int public double numberOfBlinds; blindSpacing; // Constructor No.1 - base constructor <B>Base constructor for SettingSuite class.</B> public SettingSuite( double emissivity, double depth, double height, double width, int RESOLUTION_i, int RESOLUTION j, int RESOLUTION_k, WindowSuite windowSpecs, int numberOfBlinds, double blindSpacing 183 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec this.emissivity = emissivity; this.depthMagnitude this.heightMagnitude = depth; = height; = width; this.widthMagnitude this.widthResolution = RESOLUTIONi; = RESOLUTIONj; = RESOLUTION-k; this.windowSpecs = windowSpecs; this.numberOfBlinds this.blindSpacing = numberOfBlinds; = blindSpacing; this.depthResolution this.heightResolution } // Constructor No.2 <B>Usec for creating a copy of an existing SettingSuite object, with only the resolution values changed.</B> public SettingSuite( SettingSuite int int int settings, RESOLUTION_i, RESOLUTION-j, RESOLUTION k ) f this( settings.emissivity, settings.depthMagnitude, settings.heightMagnitude, settings.widthMagnitude, RESOLUTION-i, RESOLUTION-j, RESOLUTION-k, settings.windowSpecs, settings.numberOfBlinds, settings.blindSpacing } } 184 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; // CLASS SIDEWALL Populates some of the basic arrays for the surface and invokes methods in the superclass to completely create the surface. The "SideWall" class of surfaces includes sideWalll and sideWall2. *7 public class SideWall extends Surface{ public SideWall( String name, int parallelResolution, int crossResolution, double parallelMagnitude, double crossMagnitude, double emissivity, double constantCoordinate ) { surfaceType = new String( "sideWall" ); constructSurface( name, parallelResolution, crossResolution, parallelMagnitude, crossMagnitude, emissivity, constantCoordinate //OBSOLETE VARIABLES: resolutions[0] = 0; resolutions[l] = 0; resolutions[2] = 1; /* thirdIsConstant is used later on in the program to orient the surface grids properly before they are sent to the viewer program */ thirdIsConstant = true; /* For-loop: populates some of the basic arrays for the surface, including arrays giving position in x, y, and z; alpha, beta, and gamma, each of which has the value 1 if the normal vector to the surface points in the x, y, and z directions, respectively, and has the value 0 otherwise; and A, the differential area of each element of the grid surface. 185 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec a' and 'b' are the lengthwise and widthwise resolutions of the surface. parallelDistance' and 'crossDistance' are the length and width of the surface */ for ( int rowCounter = 0; rowCounter < a; rowCounter++ ) for ( int columnCounter = 0; columnCounter < b; columnCounter++ ) I x[rowCounter][columnCounter] ( parallelDistance / a ) * ( rowCounter + 0.5); ( crossDistance / b ) y[rowCounter][columnCounter] * ( columnCounter + 0.5 ); z[rowCounter][columnCounter] = constantCoordinate; alpha[rowCounter][columnCounter beta[rowCounter][columnCounter] gamma[rowCounter][columnCounter A[rowCounter][columnCounter] = ] 0; 1; parallelDistance * crossDistance / } I } } 186 ( a * b ); C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class SideWallInitializer extends SurfaceInitializer public SideWallInitializero public void initialize( Surface currentSurface, WindowSuite windowSpecs, BlindSet blinds, String blindShadingScheme, boolean isFirstInitialization, ViewFactorSuite blindFactors_2D, SolarSuite solarVars ) initializeSurfaceVariables( currentSurface, blinds, windowSpecs, solarVars ); imposeBlindSlatShadows( blinds ); applyPatchOfSunlight( blindShadingScheme ); calculateFirstReflectionFromBlinds( blinds, isFirstInitialization, blindFactors_2D, currentSurface ) public void calculateFirstReflectionFromBlinds( BlindSet blinds, boolean isFirstInitialization, ViewFactorSuite blindFactors_2D, Surface currentSurface if ( isFirstInitialization ) blindFactors_2D.makeBlindFactors_2D( currentSurface.a, currentSurface.b, blinds. totalNumber for ( int i < 0; i for ( int j currentSurface.a; = 0; j< i++ ) currentSurface.b; 187 j++ ) ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec if ( isFirstInitialization ) for ( int blindIndex = 0; blindIndex < blinds. totalNumber; blindIndex++ ) blindFactors_2D. surfaceToBlindPairings_2D[i] [j] [blindIndex] lineOfSightFlag( i, j, ( blindlndex + 1 ), blinds, verticalAngle ) * oneViewFactory. computeViewFactorWithBlinds ( currentSurface, i, ( blindIndex + 1 ), blinds, verticalAngle ); for ( int blindNumber 1; blindNumber <= blinds.totalNumber; blindNumber++ ) /* The radiosity of each blind surface is applied to each platform element, attenuated by the average view factor and also by a flag ("lineOfSightFlag"). This flag takes the value 0 if there is an obstruction between the lit surface of the blind and the platform element in question. currentSurface.Q initial [i] [i] += blinds. getRadiosity( blindNumber ) * blinds. slatArea() * blindFactors_2D. surfaceToBlindPairings_2D[i] [j] [blindNumber /* * lineOfSightFlag( i, j, blindNumber, blinds, verticalAngle * ( 1 emissivity ) / currentSurface.A[i][i]; currentSurface. Q[i] [j] public void imposeBlindSlatShadows( BlindSet blinds 1] ) */ currentSurface. Q initial[i][j]; ) initializeMaskso; for ( int blindNumber = 1; blindNumber <= totalNumber0fBlinds; blindNumber++ 188 ) Latest\Essential Projec C:\Documents and Settings\Administrator\Desktop\Project find indeces that mark the beginnings and endings of blind shadows in the crosswise direction along the sideWall = blinds. getEquivalentDistance( blindNumber, verticalAngle, "start" ); blindStartEndDistances[I] = blinds. getEquivalentDistance( blindNumber, verticalAngle, "end" ); blindStartEndDistances[0] blindStartEndIndeces = findIndecesOfNearAndFarReach( blindStartEndDistances, b, crossDistance ) /* create black spaces in the crosswise (row) mask that correspond to the positions of the blind shadows *7 for ( int i blindStartEndIndeces[O]; i <= blindStartEndIndeces[1]; i++ if ( i < 0 ) if ( i > rowTemplate.length rowTemplate[i] = public void applyPatchOfSunlight( ) { i = 0; 1) { break; } 0; String blindShadingScheme /* "right" and "left" determine the limits in the DEPTH dimension of the patch of sunlight projected onto the sideWall from the window "blockl" and "block2" are here defined as the sill and head of the window area, and limit the patch of sunlight on the sideWall in the HEIGHT dimension */ nearAndFarDistances = findNearAndFarDistances( right, left, horizontalAngle ) blockl = sill; block2 = head; obliqueIntensityFraction = find0bliqueIntensityFraction( illuminateWithSunlight( blindShadingScheme, public double findAngleOnSurface( obliqueIntensityFraction ); double verticalAngle, 189 horizontalAngle ); double horizontalAngle C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec the "angleOnSurface" is the angle defining the amount of diagonal slant of the sides of the patch of sunlight that resides on the sideWall surface return -verticalAngle; The minus sign is a necessary correction: vertical angle is defined as the angle from the horizon upward to the sun' s position, but to make this angle compatible with the definition of the horizontal angle (to the right as you look out of the window), so that they will work interchangably as the angles of light cast on the surfaces of the room, we need to reverse the sign. 190 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; import java.io.*; By JIM GOULDSTONE public class SolarInfoCalculator { private private private private double double double double dnr dhr altitude azimuth = = = = 0; 0; 0; 0; private double directIntensity = 0; private double diffuselntensity = 0; private WeatherDataReader weather; private Azimuth azCalc; public double getAltitude( { return altitude; } public double getAzimuth() { return azimuth; } public double getDirectlntensityo { return directIntensity; } public double getDiffuselntensityo { return diffuseIntensity; } public SolarlnfoCalculator( String weatherFile, String orientation try // First create and initialize the weather reader weather = new WeatherDataReader 0; weather.read(weatherFile); // then, the azimuth calculator azCalc = new Azimuth( weather.getLatitude(), orientation ); System. out. println( "LATITUDE READ: " +weather. getLatitude 0); 191 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec catch (IOException iox) System.out.println(iox.toString()); public void positionForHour( int month, int hourOfDay dnr weather.getDirectNormalRadiation(month, hourOfDay); dhr = weather. getDiffuseHorizontalRadiation(month, hourOfDay); System.out.println("dnr: " + dnr); System.out.println("dhr: " + dhr); */ 7/ Call calculate method of Azimuth. // This will not return answers. Instead, it stores // several relevant values within Azimuth to be // accessed by other methods. azCalc.calculate (month, hourOfDay, dnr, dhr); // Grab solar angle info from azimuth. altitude = azCalc.getAltitudeO; /7 MATT LEHAR, 8/6/02: I TAKE THE NEGATIVE OF THE 77 sURFACEsOLARaZIUMTH TO MAKE IT CONSISTENT WITH /7 THE WAY IN WHICH AN AZIMUTH IS DEFINED IN THE // REST OF THE ILLUMINATION PACKAGE azimuth = -1 * azCalc.getSurfaceSolarAzimutho; directIntensity azCalc.getDirectRadiationGaino; diffuseIntensity azCalc.getDiffuseRadiationGain(; //System. out. println("alt: //System. out. println("azi: " " + Azimuth. toDegrees (altitude)) + Azimuth. toDegrees (azimuth)) /* System.out.println( "dir: " +directIntensity ); System.out.println( "diff: "+diffuselntensity ); */ /7 Regarding altitude: 7/ 0' 77 90' 77 < 0' 77 > 90' sun is sun is sun is should on horizon overhead below horizon never happen. /7 Regarding azimuth (surface solar azimuth): 77 77 77 77 77 77 This is the horizontal position of the sun w/ respect to the facade surface. 0' sun is striking surface head on (horizontally, anyway) -90' thru 90' means sun is striking surface (Sorry, when this was written we weren't concerned with which side was which. I'll check into this soon.) 192 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec /7 - 7/ MY CODE. SIDE NOTE: I JUST CHECKED INTO THIS AND CHANGED THE CONVENTION IN SOLARINFOCALCULATOR (SEE ABOVE) TO AGREE WITH THE REST OF AZIMUTH IS NOW // POSITIVE IF MEASURED TO THE RIGHT OF DEAD-AHEAD, 77 IFMEASURED TO THE LEFT. - MATT LEHAR, 8/5/02 77 If the angle is greater than 90' or less than -90', // the sun is striking the back of the facade. // the facade is in shadow. Effectively, 77 While I discuss DEGREES here, all values returned by 77 Azimuth are in RADIANS. Use static method Azimuth.toDegrees() 77 to convert. 193 NEGATIVE C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class SolarSuite public public public public double double double double solarAngleHorizontal; solarAngleVertical; solarIncoming; diffIntensity; public SolarSuite( double solarAngleHorizontal, ouble solarAngleVertical, ouble ouble { solarIncoming, diffIntensity this.solarAngleHorizontal this.solarAngleVertical this.solarIncoming this.diffIntensity ) solarAngleHorizontal; solarAngleVertical; solarIncoming; diffIntensity; } } 194 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; // ABSTRACT CLASS SURFACE Conisists of grids of The basic storage element of this package. information representing properties across the span of the surface, including position coordinates, direction of orientation, and radiosities for each differential area of the surface. public abstract class Surface Name of the surface. public String name; This will depend on Category in which the surface is classed. the particular subclass of "Surface. java" that was called in the creation of this surface. public String surfaceType; Resolution in the <B>principalK/B> dimension of the surface. of the surface's two dimensions principal dimension is first as they appear in the following list:<BR> The <BR> 1. Depth<BR> 2. HeightKBR> 3. Width public int a; Resolution in the <B>second</B> dimension of the surface. The second dimension is second of the surface's two dimensions as they appear in the following list:<BR> <BR> 1. Depth<BR> 2. HeightKBR> 3. Width public int b; 195 C:\Documents and Settings\Administrator\Desktop\Project public double Latest\Essential Projec emissivity; Magnitude of the distance across the surface in the direction of "a." */ public double parallelDistance; Magnitude of the distance across the surface in the direction of "b." *7 public double crossDistance; Position of the surface in the dimension normal to the surface. For example, a floor would have constantCoordinate = 0, whereas a ceiling would have constantCoordinate = (height of the room). */ public double 7/ constantCoordinate; GRID VALUES--------------------------------------- "x" (depth) is measured from the window surface in the direction of the back wall. *7 public double x[][]; "y" (height) is measured from the floor in the direction of the ceiling. *7 public double y[][]; "z" (width) is measured from sideWalll in the direction of sideWall2. That is, from the left to the right as you look towards the window from inside the room. */ public double z[][]; "alpha," "beta," and "gamma" take values of either 1 or 0. A value of 1 for alpha, beta or gamma indicates that the normal to the surface is oriented in the x, y, or z directions, respectively. A value of 0 indicates that the normal vector has no component in the corresponding direction. */ public double alpha[][], beta[][], gamma[][; Array of differential areas of each element that makes up the surface. 196 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec *7 public double A[][]; "Q initial" is the surface radiosity array that records the initial radiosity of the surface, after the surface has been initialized by illuminating it with sunlight, but before the iterations (reflections) have begun. */ public double Q-initial[][]; "Q" is the surface radiosity array that updates as the iterations proceed. *7 public double Q[][]; "H" is the array of values of the intensity of light that is reflected from a surface. */ public double H[][]; private Bilinear bilinearGrid; private boolean bilinearInstantiated; // OBSOLETE VARIABLES resolutions = new int[3]; public int[] public boolean thirdIsConstant; Defines surface variables and allocates space for the surface's data arrays. */ public void constructSurface( String name, int parallelResolution, int crossResolution, double parallelMagnitude, double crossMagnitude, double emissivity, double constantCoordinate this.name = name; this.emissivity = emissivity; a parallelResolution; b crossResolution; this.parallelDistance = parallelMagnitude; this.crossDistance = crossMagnitude; this.constantCoordinate = constantCoordinate; x = new double[a][b]; y = new double[a][b]; z = new double[a][b]; 197 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec alpha beta gamma new double[a][b]; new double[a] [b]; new double[a][b]; A new double[a][b]; Q Q-initial H new double[a][b]; = new double[a][b]; = new double[a] [b]; bilinearInstantiated = false; //System. out. println( name +" parallel magnitude: " +parallelMagnitude // ARRAY FORMATTING METHODS ----------------public void setHArrayTo( double H initial for ( int il for 0; il K a; il++ ------- -------------- ) ( int i2 = 0; i2 < b; i2±+ ) H[il][i2] = H initial; Updates "Q" based on light reflected from another surface. public void setQ() for ( int i =0; i for ( int j < a; i++ ) 0; j < b; j++ ) Q[i] [j] = Q_initial [i] [j] + Hil [j] //if ( name.equals( "sideWalll" //System. out. println( "Q0] [4]: * ) " +Q[0] [4] Puts a new array of radiosities in place of the existing Q and Q initial arrays. */ public void substituteQValues( double[][] for ( int i =0; i < a; i++ ) 198 qSizedArray ) ( 1 - emissivity ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec for ( int j = 0; j < b; j++ ) Q initial[i][i] = qSizedArray[i][i]; Q[i][j] = qSizedArray[i][j]; } } } 7* Pointwise-adds or pointwise-subtracts an input array from the surface's radiosity grid. private void addQValues( I for ( int i double[][] 0; i String operation ) < a; i++ ) for ( int j if qSizedArray, 0; j < b; j++ ) ( operation.equals( "+" )) { Q[i][j] = Q[i][j] + qSizedArray[i][i]; } else if ( operation.equals( Q[i][j] = Q[i][j] - qSizedArray[i][j]; else I System.out.println( "Invalid operator passed to addQValues: only permissible operators are \"+\" and \"\"." } } } } // Unit conversion methods ------------------private double degToRad( double angleInDegrees return ( Math. PI/180 )*angleInDegrees; } private double radToDeg( double angleInRadians { return ( 180/Math. PI )*angle InRadians; } // // Methods included for backwards-compatibility with obsolete versions of the software 199 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public int getSurfaceDimension( String dimension if ( dimension.equals( "a" )) return a; } else if ( dimension.equals( "b" )) return b; } else if ( dimension.equals( "width2D" )) if ( thirdIsConstant ) return a; else { return b; } else if ( dimension.equals( "height2D" { if ( thirdIsConstant ){ return b; else { return a; )) I else if ( dimension.equals( "thirdIsConstant" )) { if ( thirdIsConstant return 1; else I return 0; ) } else { return 0; } } public int getSurfaceNewResolution( String dimension, int new a, newb; if ( resolutions[O] ==0 ) newa = newResj; new b = newResk; } else if ( resolutions[L] 0 newa = newResi; newb = newResk; else newa newb newResi; newRes-j; 200 int newRes-i, int newResj, int newRes_k ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } if ( dimension. equals( "width2D" )) if ( thirdIsConstant ) return new-a; } else { return newb; else if ( dimension. equals( "height2D" )) if ( thirdIsConstant ) return newb; else { return new a; else { return 0; Accomodates different resolutions in the two surfaces involved in the exchange. <BR> <BR> Ups resolution of input surface to the level of the replaced surface. Follows pattern of "Map. addRadiositiesFrom". public void replaceSurface( if ( smoothing. Surface replacementSurface, equals( "bilinear" ) String smoothing ) !sameResolution( replacementSurface ) bilinearGrid = new Bilinear( replacementSurface.Q, a, b ); if ( smoothing.equals( "bilinear" )) substituteQValues( else { substituteQValues( bilinearGrid. bilinearInterpolate(); bilinearGrid. getUnsmoothedArrayo) bilinearInstantiated = true; else substituteQValues( bilinearGrid. getUnsmoothedArray( replacementSurface.Q )); 201 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public void addRadiositiesFrom( Surface addedSurface, if ( smoothing. equals( "bilinear" ) String operation, String smoothing !sameResolution( addedSurface )) ( smoothing.equals( "bilinear" ) && !bilinearInstantiated ) !resolutionOfExistingSurfaceEquals( addedSurface //System.out.println( "USING A..." ); bilinearGrid = new Bilinear( addedSurface.Q, if ( smoothing.equals( "bilinear" a, b ) ) )) addQValues( bilinearGrid. bilinearInterpolate(, operation ); } else addQValues ( bilinearGrid. getUnsmoothedArray(), operation ); bilinearInstantiated = true; else addQValues( bilinearGrid. getUnsmoothedArray( addedSurface.Q ), operation private boolean sameResolution( Surface newSurface if ) ( bilinearInstantiated ) ( newSurface.a return bilinearGrid. getResolutionOfExistinglnputGrida() bilinearGrid. getResolutionOfExistinglnputGridb 0); && newSurface.b else return alse; public void clearBilinearGrid( if ( bilinearInstantiated ) bilinearGrid = null; bilinearInstantiated = false; 202 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec I//class package illumination; // CLASS SURFACEINITIALIZER public abstract class SurfaceInitializer // Variables transferred from room currentSurface; public Surface public String name; public int public int public double public double a b; crossDistance; parallelDistance; public double solarIncoming; diffIntensity; verticalAngle; horizontalAngle; emissivity; public public public public double double double double public double public double public double sill, head, left, right; blockl block2 = = 0; 0; // Variables specific to the initialization process // 1. Sunlight variables: angle0nSurface; public double public double[] nearAndFarDistances public int[] indecesOfNearAndFarReacha, ndeces0fNearAndFarReach_b; public int Starting, jEnding; public int illIndex; public int eadIndex; public double bliqueIntensityFraction; // 2. Blind variables: public int public double[] public int[] public double public double public double[][] = new double[2]; otalNumber0fBlinds; lindStartEndDistances lindStartEndIndeces lindWidth; lindSpacing; lindViewFactorSum; 203 = new double[2]; = new int[2]; C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec //public double[][] public double[] public double[] public double blindViewFactorAverage; lightBandOnFloorStartEndDistances_one; lightBandOnFloorStartEndDistances_two; lightFractionPassingThroughBlinds; // 3. Templates: public double[] public double[] rowTemplate; columnTemplate; ViewFactory //BlindSet oneViewFactory blinds; // ABSTRACT METHODS ----- new ViewFactory();; ------------------------------ ----- public abstract void initialize( Surface currentSurface, WindowSuite windowSpecs, BlindSet blinds, String blindShadingScheme, boolean isFirstInitialization, ViewFactorSuite blindFactors_lD, SolarSuite solarVars ); public abstract void calculateFirstReflectionFromBlinds( BlindSet blinds, boolean isFirstInitialization, ViewFactorSuite blindFactors lD, Surface currentSurface ); public abstract void imposeBlindSlatShadows( BlindSet blinds ); public abstract void applyPatchOfSunlight( String blindShadingScheme ) public abstract double findAngleOnSurface( double verticalAngle, double horizontalAngle ); Defines variables that are surface-specific, and therefore not covered by "constructSurfaceInitializerInAbstract." Also initializes surface radiosity arrays to zero. */ public void initializeSurfaceVariables( Surface BlindSet WindowSuite SolarSuite this.solarIncoming this.diffIntensity this.verticalAngle this.horizontalAngle sill head currentSurface, blinds, windowSpecs, solarVars solarVars.solarIncoming; solarVars.diffIntensity; solarVars.solarAngleVertical; solarVars.solarAngleHorizontal; = windowSpecs.sillHeight; = windowSpecs.headHeight; 204 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec // modified over Flemish telephone if (! currentSurface.name.equals("window")) = windowSpecs.headHeight - shadowLength( head windowSpecs.overhangDepth, (90-verticalAngle) ); } if ( head < sill sill; } head left right windowSpecs.leftMargin; windowSpecs.rightMargin; totalNumberOfBlinds blindWidth blindSpacing blinds. getNumBlinds(); blinds. getBlindWidthO blinds.getBlindSpacing(); lightBandOnFloorStartEndDistancesone = new double[2]; lightBandOnFloorStartEndDistances two = new double[2]; = = = = = = = this.currentSurface name this.emissivity a b crossDistance parallelDistance blindViewFactorSum currentSurface; currentSurface.name; currentSurface.emissivity; currentSurface.a; currentSurface.b; currentSurface.crossDistance; currentSurface.parallelDistance; new double[a][totalNumberOfBlinds]; if ( totalNumberOfBlinds == 0 lightFractionPassingThroughBlinds = 1; else calculateLightFractionPassingThroughBlinds( blinds for ( int i = 0; i < a; i++ ) I for ( int blindNumber = 1; blindNumber ) <= totalNumber0fBlinds; blindNumber++ blindViewFactorSum[i][blindNumber - 1] = 0; } } for ( int i = 0; i < a; i++ ) for ( int j 0; j < b; j++ ) currentSurface.Qinitial[i][j] = 0; currentSurface.Q[i][j] = 0; 205 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec For use by low-resolution Map objects: calculates the dimming factor to be applied to sunlight on interior surfaces, so that a sunlit area broken up by blinds can be displayed as a solid region of a uniform, but lower, equivalent brightness. */ private void calculateLightFractionPassingThroughBlinds( BlindSet blinds lightBandOnFloorStartEndDistancesone findNearAndFarDistances( blinds. getEquivalentDistance( blinds. getEquivalentDistance( verticalAngle ); lightBandOnFloorStartEndDistancestwo verticalAngle, verticalAngle, "start" "end" ), 2, verticalAngle, 2, verticalAngle, "start" ), "end" ), ( 1 lightBandOnFloorStartEndDistances_one [1] lightBandOnFloorStartEndDistancesone[0] ) / ( lightBand0nFloorStartEndDistances_two[0] lightBand0nFloorStartEndDistancesone [0] ); if ( lightBand0nFloorStartEndDistances one[l] > lightBand0nFloorStartEndDistances two[0] lightFractionPassingThroughBlinds if 0; ( Math. abs( blinds. getCollectiveAngle( - verticalAngle ) < 1 lightFractionPassingThroughBlinds > 1 lightFractionPassingThroughBlinds 1; else {} rowTemplate columnTemplate these arrays serve as masks: when pointwise-multiplied by the radiosity arrays of a surface, they introduce black (zero-valued) bands where the shadow of a blind slat crosses that surface. */ 206 ), findNearAndFarDistances( blinds. getEquivalentDistance( blinds. getEquivalentDistance( verticalAngle ); lightFractionPassingThroughBlinds 1, 1, ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec public void initializeMasks() rowTe{plate columnTemplate new doubleEb]; = new double[a]; for ( int i = 0; i < a; i++) columnTemplate[i] = 1; } for ( int i =0; i < b; i++ ) rowTemplate[i] = 1; Applies brightness to selected elements of the surface grid, according to a calculation of which parts of the surface would be reached by the sunlight. */ public void illuminateWithSunlight( String blindShadingScheme, double obliqueIntensityFraction indecesOfNearAndFarReacha = findlndeces0fNearAndFarReach( nearAndFarDistances, a, parallelDistance ); if ( nearAndFarDistances[0] < parallelDistance ) angleOnSurface = findAngleOnSurface( verticalAngle, horizontalAngle ); silllndex = findColumnlndexInRow( "starting", angleOnSurface, indecesOfNearAndFarReach a[0], blockl, block2, crossDistance headIndex = findColumnlndexInRow( "ending", angleOnSurface, indeces0fNearAndFarReach a[0], blockl, block2, crossDistance if ( silllndex == -1) sillIndex = 0; if ( headlndex ==b ) headIndex = b - 1; for ( int i = indecesOfNearAndFarReacha[0]; i <= indecesOfNearAndFarReach-a[l]; i++ jStarting = findColumnIndexInRow( "starting", 207 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec angleOnSurface, i, jEnding = findColumnIndexInRow( if (( iStarting == -1 blocki, block2, crossDistance ) "ending", angleOnSurface, i, blocki, block2, crossDistance ) &&jEnding == -1 ) II ( jStarting b && jEnding b )) else if ( iStarting == -1 ) jStarting = 0; else if ( jStarting ==b jStarting ) b - 1; else {} if ( jEnding == -1 ) jEnding = 0; else if ( jEnding == b jEnding = b - 1; else {} for ( int j if jStarting; j <= jEnding; j++ ) ( blindShadingScheme.equals( "focused")) currentSurface.Q initial[i][j] solarIncoming * obliqueIntensityFraction * ( 1 - emissivity ) * rowTemplate[ j ( jEnding headIndex )] * columnTemplate[i]; else currentSurface.Qinitial[i][j] solarIncoming 208 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec * obliqueIntensityFraction * ( 1 - emissivity ) * lightFractionPassingThroughBlinds; } currentSurface.Q[i][j] = currentSurface.Q initial[i][i]; } } } } } Returns a 2-element array containing the near and far extent, in the surface's <B>principalK/B> direction, of the patch of sunlight projected from the window upon the walls or floor. public double[] findNearAndFarDistances( double nearAndFarDistances[] if ( sunAngle != double sillHeight, = new double[2]; 0 && surfacelsIlluminated( nearAndFarDistances[0 nearAndFarDistances[l] double headHeight, double sunAngle name, sunAngle )) shadowLength( sillHeight, sunAngle ) = shadowLength( headHeight, if ( nearAndFarDistances[0] > parallelDistance sunAngle ); ) /* assigns a value that will fail the test in initializeQandJArrays(). Incident solar energy on surface will be initialized to 0. */ nearAndFarDistances[0] = parallelDistance + 1; if nearAndFarDistances[l] > parallelDistance nearAndFarDistances[1] = parallelDistance; else nearAndFarDistances[0] parallelDistance + 1; nearAndFarDistances[l] = parallelDistance; } return nearAndFarDistances; } private double shadowLength( double perpendicularDistance, double sunAngle ) return ( perpendicularDistance / Math.abs( Math. tan( degToRad(sunAngle)))); 209 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec Returns a 2-element array containing the indeces of the elements on the surface grid corresponding to the near and far extent, in the surface's <B>principal</B> direction, of the projection of sunlight. public int[] findlndecesOfNearAndFarReach( double[] nearAndFarDistances, int resolutionInDirectionOfReach, double totalDistance ) double returnValue_D; int indecesOfNearAndFarReach[] = new int[2]; returnValueD = nearAndFarDistances[0] indecesOfNearAndFarReach[O] / totalDistance * resolutionlnDirectionOfReach; = new Double( Math. floor( returnValueD )). intValue () returnValueD = nearAndFarDistances[1] / totalDistance * resolutionInDirectionOfReach; /* the ceiling value of (returnValue__D - 1) is taken instead of the floor of returnValue_D, in case returnValueD is a whole number. */ indecesOfNearAndFarReach[l] = new Double( Math. ceil( returnValueD - 1 )). intValue ( return indecesOfNearAndFarReach; Returns an index corresponding to the near or far extent, in the surface' s <B>secondary(/B> direction, and within a particular row of elements specified by "presentIndex," patch of sunlight on a surface. */ public int findColumnlndexInRow( String which, double angleOnSurface, int presentIndex, double sillHeight, double headHeight, double totalHeight ) double presentIndex D double aresolution D double b resolutionD of the = new Integer( presentIndex ).doubleValueo; = new Double( a ). doubleValue(); = new Double( b ). doubleValue() double returnValue_D; int indexValue; 210 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec (((( presentIndexD + 0.5 ) / a-resolutionD ) returnVa lue D * parallelDistance ) * Math.abs( Math.tan( degToRad( angleOnSurface )))); if ( whi ch.equals( "starting" )) if ( angleOnSurface > 0 ) indexValue { = } else indexValue else if { new Double( Math.floor( ( sillHeight + returnValueD ) / crossDistance * b_resolutionD )) intValue() new Double( Math.floor( ( sillHeight - returnValueD ) / crossDistance * bresolutionD )) intValueO ( which.equals( "ending" )) if ( angleOnSurface > 0 ) { indexValue ( - 1 ) - new Double( Math. floor( ((totalHeight - headHeight ) - returnValueD ) / crossDistance * bresolution D ) ).intValue(); } else I indexValue } } else I indexValue if ( indexValue > indexValue if ( indexValue (b - 1 ) 0; 1)) (b b; <0 ) indexValue -1 return indexValue; } // Unit conversion methods ------------------- public double degToRad( double angleInDegrees ) 211 - new Double( Math.floor( (( totalHeight - headHeight ) + returnValueD ) / crossDistance * bresolution D ) ).intValueO; C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec { return ( Math.PI/180 )*angleInDegrees; } public double radToDeg( double angleInRadians { return ( 180/Math.PI )*angleInRadians; } private boolean surfaceIsIlluminated( String name, if ( name. equals( "floor" ) if ( sunAngle > 0 double sunAngle ) name. equals( "workplane" ) name.equals( "sideWall2" )) ) return true; else { return false; else if ( name.equals( "ceiling" ) if ( sunAngle name. equals( "sideWalll" )) <0 ) return true; else { return false; else if { ( name.equals( "window" )) return true; } else { return false; public double lineOfSightFlag( int cl, int c2, int blindNumber, BlindSet blinds, double sunAngle double angle = angleToBlind( cl, c2, blindNumber, blinds ); // TEST WHETHER ILLUMINATED SIDE IS EXPOSED TO VIEW (return 0 if not)if ( angle > blinds.getCollectiveAngle() && blinds.findIlluminatedSide( sunAngle ).equals( "top" )) return 0; else if ( angle < blinds.getCollectiveAngleo &&blinds. findIlluminatedSide( sunAngle ).equals( "bottom" { return 0; 212 )) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } else {} /* TEST FOR FIRST OR LAST BLIND (no obstructions from below or above, respectively) ----------------------------------------------if (( angle >= 0 && blindNumber == 1 ( angle < 0 &&blindNumber == blinds. getNumBlindso )) return 1; // if TEST FOR OBSTRUCTIONS FROM BELOW OR ABOVE -----------------------( angle >= 0 &&blinds.getEquivalentDistance(( blindNumber - 1 ), angle, "end" < blinds.getVerticalPosition( blindNumber )) { return 1; } else if ( angle < ), 0 && blinds.getEquivalentDistaice(( blindNumber + 1 angle, "start" > blinds.getVerticalPosition( blindNumber )) f return 1; else { return 0; // "z" does not come into it. private double angleToBlind( { int cl, int c2, int blindNumber, BlindSet blinds ) double yBlind = blinds.getVerticalPosition( blindNumber ); return radToDeg( Math.acos( currentSurface.x[cl][c2] / Math.pow( ( Math.pow( currentSurface.x[cl][c2], 2 ) + Math.pow(( yBlind - currentSurface.y[cl][c2] ), 2 )), * ( yBlind - currentSurface.y[cl][c2] ) / Math.abs( yBlind - currentSurface.y[cl][c2] )); public double findObliqueIntensityFraction( return Math.abs( Math.sin( double angle degToRad( angle ))); } } 213 ) 0.5 )) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class ViewFactorSuite public double[][][][] surfaceToSurfacePairings; public double[][] surfaceToBlindPairingslD; public double[][][] surfaceToBlindPairings_2D; public ViewFactorSuite( int first a, int firstb, int second_a, int secondb ) surfaceToSurfacePairings = new double[first a] [f irst b] [second-a] [second b]; public ViewFactorSuite() public void makeBlindFactors lD( int first-a, int numberOfBlinds ) surfaceToBlindPairingslD = new double[first-a] [numberOfBlinds]; public void makeBlindFactors2D( int firsta, int firstb, int numberOfBlinds surfaceToBlindPairings_2D = new double [firsta] [f irst b] [numberOfBlinds]; } 214 Latest\Essential Projec C:\Documents and Settings\Administrator\Desktop\Project package illumination; public class ViewFactory public ViewFactory() double double double double double double double double double double double double double public double computeViewFactor( return Math.abs(( alphal * * ( alpha2 alphal, betal, gammal, alpha2, beta2, gamma2, xl, x2, yl, y2, zl, z2, A2 ) ( x1 - x2 ) + betal yI - y2) + gammal Zl z2 )) * * * ( x - x2 ) + beta2 ( y- y2 ) + gamma2 ( l z2 )) * A2 / ( Math.pow( computeRVector( xl, x2, yl, y2, zl, z2 ), 2 ) * MathPI )); Computes the SQUARE of the R-vector private double computeRVector( double xl, double x2, double yl, double y2, double zl, double z2 return Math.pow((xl - x2), 2) + Math.pow((yl - y2), ) 2) + Math.pow((zl - z2), 2); 215 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec /* -------------------------------------------------------- */ public double computeViewFactorWithBlinds( Surface thisSurface, int cl, int c2, int blindNumber, BlindSet blinds, double sunAngle ) int oneIfIlluminatedSideUp; if ( blinds. findllluminatedSide( sunAngle ).equals( "top" )) onelfIlluminatedSideUp = 1; else if ( blinds. findIlluminatedSide( sunAngle ).equals( "bottom" )) oneIfllluminatedSideUp = -1; } else onelfIlluminatedSideUp = 0; if ((Math. sin( degToRad( blinds. getCollectiveAngle()) * ( thisSurface.x[cl][c2] - 0 ) + Math. cos( degToRad( blinds. getCollectiveAngle()) * ( thisSurface.y[cl][c2] - blinds. getVerticalPosition( blindNumber * onelfIlluminatedSideUp ))) <0 ) return 0; return computeViewFactor ( Math.sin( degToRad( blinds. getCollectiveAngle()), Math.cos( degToRad( blinds. getCollectiveAngle 0)), 0, thisSurface. alpha[ci] [c2], thisSurface. beta[cl] [c2], thisSurface. gamma[ci] [c2], 0, thisSurface. x[cl] [c2], blinds.getVerticalPosition( blindNumber thisSurface. y[cl] [c2], ), blinds. centerInZ(, thisSurface. z[ci] [c2], thisSurface. A[ci] [c2] 216 ) C:\Documents and Settings\Administrator\Desktop\Project private double degToRad( double angleInDegrees return ( Math.PI/180 )*angleInDegrees; private double radToDeg( double angleInRadians return ( 180/Math.PI )*angleInRadians; 217 Latest\Essential Projec C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class Wall { private double width; private double height; //private int pixelWidth; //private int pixelHeight; public int[][] shade; public Wall (int[][] shade, double width, double height) { this.shade shade; this.width width; this.height height; /* public Wall (int[][] shade) { this.shade = shade; this.width = shade.length; this.height = shade[O].length; } public int getShade (double x, double y) { int xTile = (int) ((x/width) * shade.length); int yTile = (int) ((y/height) * shade[0].length); { xTile--; } shade.length) shade[O].length) { yTile---; //System.out.println("x:" + x + " xTile:" + xTile); if (xTile if (yTile // System.out.println("y:" + y + " yTile:" + yTile); return shade[xTile][yTile]; } private int I int xTile int yTile if (xTile if (yTile getShade (int[][] surface, double x, = (int) (x * surface. length); = (int) (y * surface[]. length); surface. length) { xTile--; } ==surface.length) {yTile-; 218 double y) C:\Documents and Settings\Administrator\Desktop\Project return surface[xTile][yTile]; public static void main (String[] args) I int a = 4; int b = 1; System.out. println (b/a); double c = b/a; System.out. println (c); } } 219 Latest\Essential Projec C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; //import java.util.*; //import java.lang.*; import java.io.*; public class WeatherDataReader double latitude; double[][] dirNormRad = new double[12][24]; double[][] diffHorRad = new double[12][24]; double[][] dryBulbTemp = new double[12][24]; public double getLatitudeo { return latitude; I public double getDirectNormalRadiation(int month, int hour0fDay) { return dirNormRad[month][hourOfDay]; public double getDiffuseHorizontalRadiation(int month, int hourofDay) return diffHorRad[month][hour0fDay]; } public double getDryBulbTemperature(int month, f return dryBulbTemp[month][hourOfDay]; } int hour0fDay) /* A few sample lines from the weather file 263 Los Angeles -8 N 33 56 W 118 11 10 95010101000000000000?40000?40000?40000140000I40000I49999?001E701E70118E70062E7068E71012E729 3E7011E79999?099999?099999999?0014E7999?0999?099?0 95010102000000000000?40000?40000?40000140000I40000I49999?001E701E70118E70062E7068E71012E729 3E7008E79999?099999?099999999?0014E7999?0999?099?0 95010103000000000000?40000?40000?40000140000I40000I49999?001E701E70114E70062E7070E71012E729 3E7007E79999?099999?099999999?0014E7999?0999?099?0 95010104000000000000?40000?40000?40000I40000I40000I49999?001E701E70113E70062E7071E71012E729 3E7008E79999?099999?099999999?0014E7999?0999?099?0 220 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec 95010105000000000000?40000?40000?40000I40000140000I49999?001E701E70111E70062E7072E71012E729 3E7008E79999?099999?099999999?0014E7999?0999?099?0 95010106000000000000?40000?40000?40000I40000I40000149999?001E701E70113E70062E7071E71012E729 3E7009E79999?099999?099999999?0014E7999?0999?099?0 95010107000000000000?40000?40000?40000140000I40000149999?001E701E70109E70062E7072E71012E729 3E7007E79999?099999?099999999?0014E7999?0999?099?0 95010108141201240060?40208?40042?40061I40051I40057149999?001E701E70121E70063E7067E71012E729 3E7011E79999?099999?099999999?0014E7999?0999?099?0 95010109141203660156?40192?40107?40166140128I40133I49999?006E703E70137E70064E7061E71012E729 3E7011E79999?099999?099999999?0015E7999?0999?099?0 95010110141205610262?40209?40179?40287140194I40210I49999?006E703E70150E70065E7056E71012E729 3E7029E79999?099999?099999999?0015E7999?0999?099?0 95010111141206980431?40534?40167?40463140489140221149999?003E701E70157E70066E7055E71012E729 3E7031E79999?099999?099999999?0015E7999?0999?099?0 95010112141207660407?40298?40245?40438I40269140292149999?005E703E70170E70067E7050E71012E729 3E7034E79999?099999?099999999?0015E7999?0999?099?0 // // // // // // // // // // // // // ** ** ** ** ** ** ** ** ** ** ** ** ** Ok, supposedly there were some speed issues with this calculation code. It used to perform individual calculations for every hour of every day of the year. To cut down on the number of calculations, this was reduced to performing one calc for: Every hour of one representative day for each month. All weather data is still read in, however it is averaged on the fly and only 24 values are stored per month. (i.e. we read in a month of data, take the weather values at lam Jan 1, lam Jan 2, etc up to lam Jan 30- average those values, and store the result in January, lam. We then do this for 2am, 3am, 4am etc. Then we move on to Feb and repeat. public void read (String filename) throws IOException { // open the weather data file BufferedReader br = new BufferedReader (new FileReader(filename)); // parse unique first line String data = br.readLineo; 7/ ** NOTE: the following are unused by this code, and so I've 7/ nixed reading them in: // 7/ lstm (hours behind GMT, I believe) 7/ longitude (degrees and minutes) /7 eastV (direction of longitude) 7/ lstm = (Double. valueOf(firstLine. substring(32, 36))). doubleValueo; /7 eastV = firstLine. substring( 45, 46); 7/ longitudD = (Double. valueOf(firstLine. substring(47, 50))). doubleValue() 221 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec /7 longitudM 7/ latitude (Double. value0f (firstLine. substring(51, here is in degrees North is +, South is 53))). doubleValue( - String latitudeDirection = data. substring(37, 38); double latitudeDegrees = (Double. value0f (data. substring (39, double latitudeMinutes = (Double. value0f (data. substring (42, latitude = latitudeDegrees + (latitudeMinutes if (! latitudeDirection. equals ("N")) latitude *= -1; } 41))). doubleValue ( 44))). doubleValue 0 / 60. 0) int month, day, hour; // loop counters // arrays to store information to be averaged over each month double[] dnr = new double[24]; double[] dhr = new double[24]; double[] dbt = new double[24]; for (month 0; month < 12; month++) /7 beginning of a new month, initialise monthly values to 0 for (hour = 0; hour < 24; hour++) dnr[hour] 0; dhr[hour] = 0; dbt[hour] = 0; } for (day = 0; day < 30; day++) for (hour = 0; hour < 24; hour++) data = br. readLine() 7/DryBulbTemp values are expressed in Celcius in the file, /7 taking the form 0146. This means 14.6 degrees Celcius. 7/DirectNormalRadiation and DiffuseNormalRadiation values 7/are read in as 4 digit numbers (no decimal point) /7 the leading digit is usually a 0, and both values /7 drop to 0 at night (predictably). ux dnr[hour] += (Double. valueOf(data. substring(41, 45))). doubleValue() * 100; //23, 27))).doubleValue(; dhr[hour] += (Double. value0f (data. substring(47, 51))). doubleValue( * 100; //29, 33))). doubleValue (; dbt[hour] += (Double. valueOf(data. substring(67, 71))).doubleValue( / 10; 222 /7 1 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } 77 CHANGED BY MATT LEHAR, 8/5/02: 7/ end of a month, calculate and store values for (hour = 0; hour < 24; hour++) { dirNormRad [month][hour] += dnr[hour]/30; diffHorRad [month][hour] += dhr[hour]/30; dryBulbTemp[month][hour] += dht[hour]/30; } } br. } close(); four letters in that string /7 Given a string, returns the first 7/ Case is maintained. If less than four letters exist, less are returned. 7/ e.g. Los Angeles -> LosA -- > NY NY // 7/ Brussels -- > Brus public static String removeSpaces(String city) { char[] s = new char[4]; int j = 0; char c; for (int i = 0; i < city. length() ; i++) { c = city.charAt(i); if ((c >= 'a' && c <= 'z') I s[j++] = c; } (c >= 'A' &&c <= 'Z')) if (j >= 4) i = city.lengtho; } return new String(s, 0, } j); } 223 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class WindowSuite{ public public public public public double double double double double sillHeight; headHeight; leftMargin; rightMargin; overhangDepth; public WindowSuite( double double double double double this.sillHeight this.headHeight this.leftMargin this.rightMargin this.overhangDepth sillHeight, headHeight, leftMargin, rightMargin, overhangDepth = sillHeight; = headHeight; = leftMargin; = rightMargin; = overhangDepth; } I 224 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec package illumination; public class WorkplaneBay private final double private final double INCANDESCENTLIGHTEFFICIENCY = 0.0189; FLUORESCENTLIGHTEFFICIENCY = 0.135; private Initializer private Iterator private double oneInitializer; onelterator; minLightLevel; Map room, iteratedRoom, rapidFineRoom; public public WorkplaneBay( SettingSuite SettingSuite Initializer coarseSettings, fineSettings, oneInitializer, onelterator, workplaneHeight, minLightLevel ) Iterator double double { this.oneInitializer this.oneIterator this.minLightLevel // 1. = oneInitializer; = onelterator; = minLightLevel; Create instance of Map object ("room"). room iteratedRoom new Map( coarseSettings ); new Map( coarseSettings ) // 2. Create rapidFineRoom, a lower--resolution version of fineRoom rapidFineRoom = new Map( fineSettings ); 225 C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec /* 3. Create both high- and low-resolution workplanes at the resolutions of the high- and low-res floor surfaces */ rapidFineRoom.createWorkplanes( workplaneHeight, room.getFloorResolutiona(, room.getFloorResolutionbo, rapidFineRoom.getFloorResolution_ao, rapidFineRoom.getFloorResolution bO ); } CALCULATEWORKPLANELIGHTLEVELS() */ public void calculateWorkplaneLightLevels( SolarSuite solarVars, WindowSuite windowSpecs, double collectiveBlindAngle ) 7/ Initialize "hiResWorkplane." (Essential for re-zero-ing the workplane) onelnitializer.initializeHiResWorkplane( rapidFineRoom, windowSpecs, "focused", collectiveBlindAngle, solarVars ) /* Cast reflections from room onto low-res workplane NOTE: the reason why the high- and low-res workplanes are both housed in the same hi-res room is that if the two workplanes were in different rooms, it would be harder to reflect the hi-res light onto the low-res workplane */ onelterator. showReflectionsOnLowResWorkplane ( rapidFineRoom ) rapidFineRoom.hiResWorkplane.addRadiositiesFrom( // Add only reflections to hi- res workplane rapidFineRoom.lowResWorkplane, "n+ none } public double sumDefecitValues() double defecit; double total = 0; for ( int i = 0; i < rapidFineRoom.hiResWorkplane.a; i++ ) f for ( int j = 0; j < rapidFineRoom.hiResWorkplane.b; j++) { defecit ( minLightLevel rapidFineRoom.hiResWorkplane.Q[i][j] / ( 1 rapidFineRoom.hiResWorkplane.emissivity )); total += (( defecit > 0 ) ? defecit : 0 total /= ( rapidFineRoom. hiResWorkplane. a 226 ) * rapidFineRoom. C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec hiResWorkplane.b ); return ( total / FLUORESCENT LIGHTEFFICIENCY ); // units of W/m"2 // or INCANDESCENTLIGHTEFFICIENCY ); package illumination; public class WorkplaneInitializer extends PlatformInitializer All arguments to oneWorkplaneInitializer must be from the same room object, except for blindShadingScheme. public void initialize( Surface workplane, WindowSuite windowSpecs, BlindSet blinds, String blindShadingScheme, boolean isFirstWorkplaneInitialization, ViewFactorSuite blindFactors_lD, SolarSuite solarVars ) t This method, contained in the superclass, reads address of input Surface "workplane" into "currentSurface" initializeSurfaceVariables( workplane, blinds, windowSpecs, solarVars ); calculateFirstReflectionFromBlinds( blinds, isFirstWorkplaneInitialization, blindFactors lD, currentSurface ); imposeBlindSlatShadows( blinds ); applyPatchOfSunlight( blindShadingScheme 227 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec } public double obstructionFactor( int i, return int j, BlindSet blinds, int blindNumber, ViewFactorSuite blindFactors ) ( 1 - emissivity ) * lineOfSightFlag( i, j, blindNumber, blinds, verticalAngle ) * blindFactors. surfaceToBlindPairings lD[i] [blindNumber - 1] * blindSlatAboveLevelOfWorkplaneFlag( blinds, blindNumber ); Prevents light reflected off the top surface of blinds that are BELOW the workplane from illuminating the workplane FROM BENEATH. private double blindSlatAboveLevelOfWorkplaneFlag( BlindSet blinds, int blindNumber ) if ( blinds.findllluminatedSide( verticalAngle ).equals( "top" { return 0; } else return 1; )) public void imposeBlindSlatShadows( BlindSet blinds ) double startingEquivalentDistance; double endingEquivalentDistance; initializeMaskso; for ( int blindNumber = 1; blindNumber <= totalNumberOfBlinds; blindNumber++ find indeces that mark the beginnings and endings of blind shadows in the parallel direction along the workplane. This is different from the floor/ceiling case only in the sense that a certain distance must be subtracted from the "equivalentDistance" of the starting or ending points of the blinds across the surface of the window in the vertical direction. 228 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec startingEquivalentDistance = b linds.getEquivalentDistance( blindNumber, verticalAngle, "start" ) - currentSurface. constantCoordinate; endingEquivalentDistance = b linds.getEquivalentDistance( blindNumber, verticalAngle, "end" ) - currentSurface. constantCoordinate; if ( endingEquivalentDistance > 0 ) I if ( startingEquivalentDistance < 0 ) 0 0; startingEquivalentDistance = I blindStartEndIndeces = findlndecesOfNearAndFarReach( findNearAndFarDistances( startingEquivalentDistance, endingEquivalentDistance, verticalAngle ), a, parallelDistance ) create black spaces in the parallel (column) mask that correspond to the positions of the blind shadows for ( int i = blindStartEndIndeces[0]; i <= blindStartEndIndeces[l]; i++ columnTemplate[i] = 0; I } } } public void applyPatchOfSunlight( String blindShadingScheme ) double normalizedSill; double normalizedHead; "sill" and "head" determine the limits in the DEPTH dimension of the patch of sunlight projected onto the floor/ceiling from the window 229 ) C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec "blockl" and "block2" are here defined as the side margins of the window area, and limit the patch of sunlight on the floor/ ceiling in the WIDTH dimension As in the case of "imposeBlindSlatShadowso," above, to make the standard shadowing algorthithms work for an elevated workplane, the sill and head heights must be adjusted by an amount equal to the distance between the workplane and the floor. normalizedSill sill normalizedHead = hea if - currentSurface. constantCoordinate; currentSurface.constantCoordinate; ( normalizedHead > 0 ) if ( normalizedSill K 0 ) normalizedSill 0; nearAndFarDistances = findNearAndFarDistances( normalizedSill, normalizedHead, verticalAngle ); blockl = right; block2 = left; obliquelntensityFraction = find0bliqueIntensityFraction( verticalAngle ); illuminateWithSunlight( blindShadingScheme, obliquelntensityFraction } 230 )