From 2a1a8d70abbecc4ec159ae34f34ea694a35fb95e Mon Sep 17 00:00:00 2001
From: Chien Si Harriman
Date: Mon, 11 Jan 2016 22:31:31 -0500
Subject: [PATCH 1/3] Code with Unit Conversions in Progress
Conversions not yet completed for Surface Tests
---
.gitattributes | 22 +
.gitignore | 215 +
XMLValidatorWeb.jmconfig | 1 +
XMLValidatorWeb.sln | 20 +
.../DOEgbXMLClass/DOEgbXMLBasics.cs | 188 +
.../DOEgbXMLClass/DOEgbXMLParser.cs | 5849 ++++++++++++
.../DOEgbXMLClass/DOEgbXMLReportingObj.cs | 75 +
.../DOEgbXMLClass/DOEgbXMLSurface.cs | 28 +
.../DOEgbXMLTestCriteriaObject.cs | 318 +
.../DOEgbXMLClass/DOEgbXMLTestDetail.cs | 124 +
.../DOEgbXMLClass/DOEgbXMLValidator.cs | 76 +
XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs | 43 +
XMLValidatorWeb/DOEgbXMLClass/Vector.cs | 86 +
XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs | 39 +
XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs | 19 +
XMLValidatorWeb/Default.aspx | 10 +
XMLValidatorWeb/Default.aspx.cs | 22 +
XMLValidatorWeb/Default.aspx.designer.cs | 24 +
XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd | 6478 +++++++++++++
XMLValidatorWeb/Images/TmpImage.gif | Bin 0 -> 6820 bytes
XMLValidatorWeb/Images/header01.jpg | Bin 0 -> 51337 bytes
XMLValidatorWeb/Images/header_new.png | Bin 0 -> 21124 bytes
XMLValidatorWeb/MasterPage.Master | 34 +
XMLValidatorWeb/MasterPage.Master.cs | 17 +
XMLValidatorWeb/MasterPage.Master.designer.cs | 60 +
.../Pages/PrintFriendlyTablePage.aspx | 18 +
.../Pages/PrintFriendlyTablePage.aspx.cs | 26 +
.../PrintFriendlyTablePage.aspx.designer.cs | 33 +
XMLValidatorWeb/Pages/TestDetailPage.aspx | 18 +
XMLValidatorWeb/Pages/TestDetailPage.aspx.cs | 103 +
.../Pages/TestDetailPage.aspx.designer.cs | 51 +
XMLValidatorWeb/Pages/TestPage.aspx | 52 +
XMLValidatorWeb/Pages/TestPage.aspx.cs | 234 +
.../Pages/TestPage.aspx.designer.cs | 105 +
XMLValidatorWeb/Properties/AssemblyInfo.cs | 35 +
XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js | 8061 +++++++++++++++++
XMLValidatorWeb/Scripts/jquery-1.4.1.js | 6111 +++++++++++++
XMLValidatorWeb/Scripts/jquery-1.4.1.min.js | 167 +
XMLValidatorWeb/SupportFiles/Conversions.cs | 363 +
.../TestFiles/Test Case 1 - Standard File.xml | 2541 ++++++
.../TestFiles/Test Case 2 - Standard File.xml | Bin 0 -> 106294 bytes
.../Test Case 25 - Standard File.xml | Bin 0 -> 215912 bytes
.../Test Case 28 - Standard File.xml | Bin 0 -> 130294 bytes
.../TestFiles/Test Case 3 - Standard File.xml | Bin 0 -> 223036 bytes
.../TestFiles/Test Case 4 - Standard File.xml | Bin 0 -> 367706 bytes
.../TestFiles/Test Case 5 - Standard File.xml | Bin 0 -> 126526 bytes
.../TestFiles/Test Case 7 - Standard File.xml | Bin 0 -> 132990 bytes
.../TestFiles/Test Case 8 - Standard File.xml | Bin 0 -> 126846 bytes
.../XSD/GreenBuildingXML_Ver5.10.xsd | 6478 +++++++++++++
XMLValidatorWeb/Web.Debug.config | 30 +
XMLValidatorWeb/Web.Release.config | 31 +
XMLValidatorWeb/XMLValidatorWeb.csproj | 201 +
.../bootstrap/css/bootstrap-responsive.css | 1092 +++
.../css/bootstrap-responsive.min.css | 9 +
XMLValidatorWeb/bootstrap/css/bootstrap.css | 6039 ++++++++++++
.../bootstrap/css/bootstrap.min.css | 9 +
.../img/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes
.../bootstrap/img/glyphicons-halflings.png | Bin 0 -> 12799 bytes
XMLValidatorWeb/bootstrap/js/bootstrap.js | 2159 +++++
XMLValidatorWeb/bootstrap/js/bootstrap.min.js | 6 +
XMLValidatorWeb/css/gbXML.css | 31 +
XMLValidatorWeb/web.config | 38 +
62 files changed, 47789 insertions(+)
create mode 100644 .gitattributes
create mode 100644 .gitignore
create mode 100644 XMLValidatorWeb.jmconfig
create mode 100644 XMLValidatorWeb.sln
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/Vector.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs
create mode 100644 XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs
create mode 100644 XMLValidatorWeb/Default.aspx
create mode 100644 XMLValidatorWeb/Default.aspx.cs
create mode 100644 XMLValidatorWeb/Default.aspx.designer.cs
create mode 100644 XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd
create mode 100644 XMLValidatorWeb/Images/TmpImage.gif
create mode 100644 XMLValidatorWeb/Images/header01.jpg
create mode 100644 XMLValidatorWeb/Images/header_new.png
create mode 100644 XMLValidatorWeb/MasterPage.Master
create mode 100644 XMLValidatorWeb/MasterPage.Master.cs
create mode 100644 XMLValidatorWeb/MasterPage.Master.designer.cs
create mode 100644 XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx
create mode 100644 XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.cs
create mode 100644 XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.designer.cs
create mode 100644 XMLValidatorWeb/Pages/TestDetailPage.aspx
create mode 100644 XMLValidatorWeb/Pages/TestDetailPage.aspx.cs
create mode 100644 XMLValidatorWeb/Pages/TestDetailPage.aspx.designer.cs
create mode 100644 XMLValidatorWeb/Pages/TestPage.aspx
create mode 100644 XMLValidatorWeb/Pages/TestPage.aspx.cs
create mode 100644 XMLValidatorWeb/Pages/TestPage.aspx.designer.cs
create mode 100644 XMLValidatorWeb/Properties/AssemblyInfo.cs
create mode 100644 XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js
create mode 100644 XMLValidatorWeb/Scripts/jquery-1.4.1.js
create mode 100644 XMLValidatorWeb/Scripts/jquery-1.4.1.min.js
create mode 100644 XMLValidatorWeb/SupportFiles/Conversions.cs
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 1 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 2 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 25 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 28 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 3 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 4 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 5 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 7 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 8 - Standard File.xml
create mode 100644 XMLValidatorWeb/SupportFiles/XSD/GreenBuildingXML_Ver5.10.xsd
create mode 100644 XMLValidatorWeb/Web.Debug.config
create mode 100644 XMLValidatorWeb/Web.Release.config
create mode 100644 XMLValidatorWeb/XMLValidatorWeb.csproj
create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap-responsive.css
create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap-responsive.min.css
create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap.css
create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap.min.css
create mode 100644 XMLValidatorWeb/bootstrap/img/glyphicons-halflings-white.png
create mode 100644 XMLValidatorWeb/bootstrap/img/glyphicons-halflings.png
create mode 100644 XMLValidatorWeb/bootstrap/js/bootstrap.js
create mode 100644 XMLValidatorWeb/bootstrap/js/bootstrap.min.js
create mode 100644 XMLValidatorWeb/css/gbXML.css
create mode 100644 XMLValidatorWeb/web.config
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..412eeda
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs diff=csharp
+*.sln merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b9d6bd9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,215 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+build/
+[Bb]in/
+[Oo]bj/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+*.pubxml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+#packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+#############
+## Windows detritus
+#############
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac crap
+.DS_Store
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist/
+build/
+eggs/
+parts/
+var/
+sdist/
+develop-eggs/
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
diff --git a/XMLValidatorWeb.jmconfig b/XMLValidatorWeb.jmconfig
new file mode 100644
index 0000000..10eea63
--- /dev/null
+++ b/XMLValidatorWeb.jmconfig
@@ -0,0 +1 @@
+false
\ No newline at end of file
diff --git a/XMLValidatorWeb.sln b/XMLValidatorWeb.sln
new file mode 100644
index 0000000..a252c91
--- /dev/null
+++ b/XMLValidatorWeb.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XMLValidatorWeb", "XMLValidatorWeb\XMLValidatorWeb.csproj", "{D9E0A2E6-768A-4377-AF62-675D156F8813}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D9E0A2E6-768A-4377-AF62-675D156F8813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D9E0A2E6-768A-4377-AF62-675D156F8813}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D9E0A2E6-768A-4377-AF62-675D156F8813}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D9E0A2E6-768A-4377-AF62-675D156F8813}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs
new file mode 100644
index 0000000..4cfe40f
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Xml;
+
+namespace DOEgbXML
+{
+ public class DOEgbXMLBasics
+ {
+ public static bool SliversAllowed = true;
+
+ public enum MeasurementUnits
+ {
+ cubicft,
+ sqft,
+ ft,
+ spaces,
+ levels,
+ }
+
+ public class Tolerances
+ {
+ public const double ToleranceDefault = -999;
+ public const double VolumeTolerance = 1.0;
+ public const double AreaTolerance = 1.0;
+ public const double SpaceAreaPercentageTolerance = 0.025;
+
+ //Level (aka - story) height difference tolerance in feet
+ public const double LevelHeightTolerance = 0.1;
+ public const double VectorAngleTolerance = 2.5;
+ public const double SpaceAreaTolerance = 1;
+ //all count tolerances
+ public const double SpaceCountTolerance = 0;
+ public const double LevelCountTolerance = 0;
+ public const double SurfaceCountTolerance = 0;
+ public const double ExteriorWallCountTolerance = 0;
+ public const double InteriorWallCountTolerance = 0;
+ public const double InteriorFloorCountTolerance = 0;
+ public const double RoofCountTolerance = 0;
+ public const double AirWallCountTolerance = 0;
+ public const double OpeningCountTolerance = 0;
+ public const double FixedWindowCountTolerance = 0;
+ public const double OperableWindowCountTolerance = 0;
+ public const double FixedSkylightCountTolerance = 0;
+ public const double OperableSkylightCountTolerance = 0;
+ public const double SlidingDoorCountTolerance = 0;
+ public const double NonSlidingDoorCountTolerance = 0;
+ public const double AirOpeningCountTolerance = 0;
+
+ //surface tolerances
+ public const double SurfaceHeightTolerance = 0.5; //feet
+ public const double SurfaceWidthTolerance = 0.5; //feet
+ public const double SurfaceTiltTolerance = 2.5; // degrees
+ public const double SurfaceAzimuthTolerance = 2.5; //degrees
+ public const double SurfaceInsPtXTolerance = 0.5; //feet
+ public const double SurfaceInsPtYTolerance = 0.5; //feet
+ public const double SurfaceInsPtZTolerance = 0.5; //feet
+ public const double SurfacePLCoordTolerance = 0.5; //feet (3 inches)
+ public const double SliverDimensionTolerance = 0.25; //feet
+ public const double SurfaceAreaPercentageTolerance = 0.025;
+
+ //opening tolerances
+ public const double OpeningHeightTolerance = 0.5; //feet
+ public const double OpeningWidthTolerance = 0.5; //feet
+ public const double OpeningSurfaceInsPtXTolerance = 0.5; //feet
+ public const double OpeningSurfaceInsPtYTolerance = 0.5; //feet
+ public const double OpeningSurfaceInsPtZTolerance = 0.5; //feet
+ public const double OpeningAreaPercentageTolerance = 0.025;
+ }
+
+ public class Conversions
+ {
+ //the idea is, it searches through the document and finds items to switch out
+ //it is called when needed by a user or programmer
+ public XmlDocument ConvertFtToMeter(XmlDocument origdoc, XmlNamespaceManager gbXMLns1)
+ {
+ //number of feet in a meter
+ double convrate = 3.280839895;
+
+ XmlDocument retdoc = (XmlDocument)origdoc.Clone();
+ //by default, I will always change these nodes because they are the minimum that must be presented
+
+
+ //surface polyloop
+ //surface lower left hand corner
+ //building storeys
+ XmlNodeList nodes = retdoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey", gbXMLns1);
+ if (nodes.Count > 0)
+ {
+ foreach (XmlNode Node in nodes)
+ {
+ XmlNodeList childnodes = Node.ChildNodes;
+ foreach (XmlNode childnode in childnodes)
+ {
+ if (childnode.Name == "Level")
+ {
+ childnode.Value = Convert.ToString(Convert.ToDouble(childnode.Value) / convrate);
+ }
+ else if (childnode.Name == "PlanarGeometry")
+ {
+ //change the planar geometry
+ foreach (XmlNode PolyLoops in childnode)
+ {
+ //gathers all the cartesian points in a given polyloop
+ foreach (XmlNode cartesianPoints in PolyLoops)
+ {
+ foreach (XmlNode coordinate in cartesianPoints)
+ {
+ if (coordinate.Name == "Coordinate")
+ {
+ coordinate.Value = Convert.ToString(Convert.ToDouble(coordinate.Value) / convrate);
+ }
+ else
+ {
+ //this is bad, should terminate somehow
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //space planar geometry
+ //space shell geometry
+ //space space boundaries
+ XmlNodeList spacenodes = retdoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Spaces", gbXMLns1);
+ if (nodes.Count > 0)
+ {
+ foreach (XmlNode Node in nodes)
+ {
+ XmlNodeList childnodes = Node.ChildNodes;
+ foreach (XmlNode childnode in childnodes)
+ {
+ if (childnode.Name == "PlanarGeometry")
+ {
+ //change the planar geometry
+ foreach (XmlNode PolyLoops in childnode)
+ {
+ //gathers all the cartesian points in a given polyloop
+ foreach (XmlNode cartesianPoints in PolyLoops)
+ {
+ foreach (XmlNode coordinate in cartesianPoints)
+ {
+ if (coordinate.Name == "Coordinate")
+ {
+ coordinate.Value = Convert.ToString(Convert.ToDouble(coordinate.Value) / convrate);
+ }
+ else
+ {
+ //this is bad, should terminate somehow
+ }
+ }
+ }
+ }
+ }
+ else if (childnode.Name == "ShellGeometry")
+ {
+ //this should always be the ClosedShell element
+ XmlNode closedShell = childnode.FirstChild;
+ foreach (XmlNode PolyLoops in childnode)
+ {
+ //gathers all the cartesian points in a given polyloop
+ foreach (XmlNode cartesianPoints in PolyLoops)
+ {
+ foreach (XmlNode coordinate in cartesianPoints)
+ {
+ if (coordinate.Name == "Coordinate")
+ {
+ coordinate.Value = Convert.ToString(Convert.ToDouble(coordinate.Value) / convrate);
+ }
+ else
+ {
+ //this is bad, should terminate somehow
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return retdoc;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs
new file mode 100644
index 0000000..2b557ea
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs
@@ -0,0 +1,5849 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml;
+using System.Xml.XPath;
+using System.Text.RegularExpressions;
+using VectorMath;
+using System.Web;
+using DOEgbXML;
+using UnitConversions;
+
+namespace DOEgbXML
+{
+ class OpeningDefinitions
+ {
+ //creates instances of an object that store information about surfaces in a gbXML file
+ public string OpeningType;
+ public string OpeningId;
+ public string ParentSurfaceId;
+ public double ParentAzimuth;
+ public double ParentTilt;
+ public double Azimuth;
+ public double Tilt;
+ public double Height;
+ public double Width;
+ public double surfaceArea;
+ public Vector.CartCoord InsertionPoint;
+ public List PlCoords;
+ public Vector.CartVect PlRHRVector;
+ }
+
+ class XMLParser
+ {
+
+ //this is the output string
+ public string output;
+ public string log;
+ public string table;
+ bool overallPassTest = true;
+ DOEgbXMLTestCriteriaObject TestCriteria;
+ DOEgbXMLTestDetail TestDetail;
+ gbXMLMatches globalMatchObject;
+ string TestToRun;
+ XmlDocument gbXMLStandardFile;
+ XmlDocument gbXMLTestFile;
+ public string summaryTable;
+ public List ReportList;
+
+ //a List of strings with all the test files that I want to test
+ //eventually this will be a dynamically created list based on what has been uploaded.
+ //this list should be the list of all the test
+
+ static Dictionary filepaths = new Dictionary()
+ {
+ {"Test1" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 1 - Standard File.xml")},
+ {"Test2" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 2 - Standard File.xml")},
+ {"Test3" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 3 - Standard File.xml")},
+ {"Test4" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 4 - Standard File.xml")},
+ {"Test5" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 5 - Standard File.xml")},
+ {"Test7" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 7 - Standard File.xml")},
+ {"Test8" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 8 - Standard File.xml")},
+ {"Test25" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 25 - Standard File.xml")},
+ {"Test28" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 28 - Standard File.xml")},
+ };
+
+
+ //Shell Geometry RHR Dictionaries
+ static Dictionary> TFShellGeomRHRes = new Dictionary>();
+ static Dictionary> SFShellGeomRHRes = new Dictionary>();
+
+ //minimum number of points to define a plane
+ static int minPlanePoints = 3;
+ //value to hold, starting arbitrarily large
+ static double StoryHeightMin = 100.0;
+
+ #region Test Report
+ public void StartTest(XmlReader xmldoc, string testToRun, string username)
+ {
+ Conversions c = new Conversions();
+
+ TestToRun = testToRun;
+ globalMatchObject = new gbXMLMatches();
+ globalMatchObject.Init();
+
+ //first create a list of lists that is indexed identically to the drop down list the user selects
+ TestDetail = new DOEgbXMLTestDetail();
+ //then populate the list of lists. All indexing is done "by hand" in InitializeTestResultStrings()
+ TestDetail.InitializeTestResultStrings();
+
+ //create report list reportlist will store all the test result
+ ReportList = new List();
+
+ //Load an XML File for the test at hand
+ gbXMLTestFile = new XmlDocument();
+ gbXMLTestFile.Load(xmldoc);
+
+ gbXMLStandardFile = new XmlDocument();
+ // gbXMLStandardFile.Load(filepaths[testToRun]);
+
+ if (!TestFileIsAvailable())
+ return;
+
+ //Define the namespace
+ XmlNamespaceManager gbXMLns1 = new XmlNamespaceManager(gbXMLTestFile.NameTable);
+ gbXMLns1.AddNamespace("gbXMLv5", "http://www.gbxml.org/schema");
+ XmlNamespaceManager gbXMLns2 = new XmlNamespaceManager(gbXMLStandardFile.NameTable);
+ gbXMLns2.AddNamespace("gbXMLv5", "http://www.gbxml.org/schema");
+
+ //is the test file metric or not?
+ bool isMetric = false;
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML", gbXMLns1);
+ Conversions.volumeUnitEnum testVol = Conversions.volumeUnitEnum.CubicFeet;
+ Conversions.volumeUnitEnum standardVol = Conversions.volumeUnitEnum.CubicFeet;
+ Conversions.areaUnitEnum testArea = Conversions.areaUnitEnum.SquareFeet;
+ Conversions.areaUnitEnum standardArea = Conversions.areaUnitEnum.SquareFeet;
+ Conversions.lengthUnitEnum testLength = Conversions.lengthUnitEnum.Feet;
+ Conversions.lengthUnitEnum standardLength = Conversions.lengthUnitEnum.Feet;
+ double lengthConversion = 1;
+ double areaConversion = 1;
+ double volumeConversion = 1;
+ foreach (XmlNode Node in nodes)
+ {
+ XmlAttributeCollection spaceAtts = Node.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "volumeUnit")
+ {
+ string type = at.Value;
+ testVol = (Conversions.volumeUnitEnum)System.Enum.Parse(typeof(Conversions.volumeUnitEnum), type, true);
+ //we know the test files are in cubic feet
+ volumeConversion = c.GetVolumeUnitConversion(testVol,Conversions.volumeUnitEnum.CubicFeet);
+ if(volumeConversion == -999)
+ {
+ //return with an error message stating contact system administrator with a code
+ }
+
+ }
+ else if (at.Name == "areaUnit")
+ {
+ string type = at.Value;
+ testArea = (Conversions.areaUnitEnum)System.Enum.Parse(typeof(Conversions.areaUnitEnum), type, true);
+ areaConversion = c.GetAreaConversion(testArea,Conversions.areaUnitEnum.SquareFeet);
+ if(areaConversion == -999)
+ {
+ //return with an error message stating contact system administrator with a code
+ }
+ }
+ else if (at.Name == "lengthUnit")
+ {
+ string type = at.Value;
+ testLength = (Conversions.lengthUnitEnum)System.Enum.Parse(typeof(Conversions.lengthUnitEnum), type, true);
+ lengthConversion = c.GetLengthConversion(testLength,Conversions.lengthUnitEnum.Feet);
+ if (lengthConversion == -999)
+ {
+ //return with an error message stating contact system administrator with a code
+ }
+ }
+ }
+ }
+
+ //if isMetric is true, then we would like to convert the test file's numbers to US-IP units
+ if(isMetric) gbXMLTestFile = ConvertMetricToUS(gbXMLTestFile);
+
+ List gbXMLdocs = new List();
+ gbXMLdocs.Add(gbXMLTestFile);
+ gbXMLdocs.Add(gbXMLStandardFile);
+ List gbXMLnsm = new List();
+ gbXMLnsm.Add(gbXMLns1);
+ gbXMLnsm.Add(gbXMLns2);
+
+ //Create a Log file that logs the success or failure of each test.
+ //Eventually maybe I want to create a little HTML factory
+
+ output = "";
+ log = "";
+ table += "" +
+ "
" + "Test Sections" + "
";
+ table += "
";
+ table += "" +
+ "| " + "Test Section Name" + " | " +
+ "" + "Standard Result" + " | " +
+ "" + "Test File Result" + " | " +
+ "" + "Tolerances" + " | " +
+ "" + "Pass/Fail" + " | " +
+ "
";
+
+ string units;
+ DOEgbXMLReportingObj report = new DOEgbXMLReportingObj();
+ report.standResult = new List();
+ report.testResult = new List();
+ report.idList = new List();
+ report.MessageList = new List();
+ report.TestPassedDict = new Dictionary();
+
+ //Set up the Global Pass/Fail criteria for the test case file
+ TestCriteria = new DOEgbXMLTestCriteriaObject();
+ TestCriteria.InitializeTestCriteriaWithTestName(testToRun);
+
+ //Test 2 execute
+ report.tolerance = DOEgbXMLBasics.Tolerances.AreaTolerance;
+ report.testType = TestType.Building_Area;
+ units = DOEgbXMLBasics.MeasurementUnits.sqft.ToString();
+ report = GetBuildingArea(gbXMLdocs, gbXMLnsm, report, standardArea, testArea, areaConversion);
+ AddToOutPut("Building Area Test Passed: ", report, true);
+
+ //Test 3 execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.SpaceCountTolerance;
+ report.testType = TestType.Space_Count;
+ units = DOEgbXMLBasics.MeasurementUnits.spaces.ToString();
+ report = GetBuildingSpaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Building Space Quantity Count Test Passed: ", report, true);
+
+
+ ////Test 4 execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.LevelCountTolerance;
+ report.testType = TestType.Building_Story_Count;
+ units = DOEgbXMLBasics.MeasurementUnits.levels.ToString();
+ report = GetBuildingStoryCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Building Story Count Test Passed: ", report, true);
+
+
+ //Test 5 execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.LevelHeightTolerance;
+ report.testType = TestType.Building_Story_Z_Height;
+ units = DOEgbXMLBasics.MeasurementUnits.ft.ToString();
+ report = GetStoryHeights(gbXMLdocs, gbXMLnsm, report, standardLength, testLength, lengthConversion);
+ AddToOutPut("Building Story Z-Height Test: ", report, true);
+
+
+ //Test 6 execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.VectorAngleTolerance;
+ report.testType = TestType.Building_Story_PolyLoop_RHR;
+ units = "degrees";
+ report = TestBuildingStoryRHR(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Building Story PolyLoop Right Hand Rule Test Result:", report, true);
+
+
+ //String spShellGeometrySurfaceNum = TestShellGeomSurfaceNum(gbXMLTestFile, gbXMLns);
+
+ //Space Tests .............................................................
+ //Test 7 execute
+ //only needs to test the test file
+ report.Clear();
+ report.testType = TestType.SpaceId_Match_Test;
+ report = UniqueSpaceIdTest(gbXMLdocs, gbXMLnsm, report);
+ AddToOutPut("SpaceId Match Test: ", report, true);
+
+
+ //Test 8 execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.SpaceAreaTolerance;
+ report.testType = TestType.Space_Area;
+ units = DOEgbXMLBasics.MeasurementUnits.sqft.ToString();
+ report = TestSpaceAreas(gbXMLdocs, gbXMLnsm, report, standardArea,testArea,areaConversion);
+ AddToOutPut("Space Areas Test: ", report, true);
+
+
+ //Test 9 execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.VolumeTolerance;
+ report.testType = TestType.Space_Volume;
+ units = DOEgbXMLBasics.MeasurementUnits.cubicft.ToString();
+ report = TestSpaceVolumes(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Space Volumes Test: ", report, true);
+
+
+ //Test 10 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.VectorAngleTolerance;
+ report.testType = TestType.Shell_Geom_RHR;
+ units = "degrees";
+ report = TestShellGeomPLRHR(gbXMLdocs, gbXMLnsm, report, units);
+ //AddToOutPut("Shell Geometry RHR Test: ",report);
+
+ //Surface Element tests
+ //Test 11 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.SurfaceCountTolerance;
+ report.testType = TestType.Total_Surface_Count;
+ units = "";
+ report = GetSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Surface Count Test Result: ", report, true);
+
+
+ //Surface Element tests
+ //Test 12 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.ExteriorWallCountTolerance;
+ report.testType = TestType.Exterior_Wall_Surface_Count;
+ units = "";
+ report = GetEWSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Exterior Wall Surface Count Test Result: ", report, true);
+
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.SurfaceCountTolerance;
+ report.testType = TestType.Underground_Surface_Count;
+ units = "";
+ report = GetUGSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Underground Wall Count Test Result: ", report, true);
+
+ //Surface Element tests
+ //Test 13 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.InteriorWallCountTolerance;
+ report.testType = TestType.Interior_Wall_Surface_Count;
+ units = "";
+ report = GetIWSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Interior Wall Surface Count Test Result: ", report, true);
+
+ //Surface Element tests
+ //Test 13 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.InteriorFloorCountTolerance;
+ report.testType = TestType.Interior_Floor_Surface_Count;
+ units = "";
+ report = GetIFSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Interior Floor Surface Count Test Result: ", report, true);
+
+
+ //Surface Element tests
+ //Test 14 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.InteriorWallCountTolerance;
+ report.testType = TestType.Roof_Surface_Count;
+ units = "";
+ report = GetRoofSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Roof Surface Count Test Result: ", report, true);
+
+
+ //Surface Element tests
+ //Test 15 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.InteriorWallCountTolerance;
+ report.testType = TestType.Shading_Surface_Count;
+ units = "";
+ report = GetShadeSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Shading Surface Count Test Result: ", report, true);
+
+
+ //Test 16 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.AirWallCountTolerance;
+ report.testType = TestType.Air_Surface_Count;
+ units = "";
+ report = GetAirSurfaceCount(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Air Surface Count Test Result: ", report, true);
+
+
+ #region surface detailed test
+ //Jan 31-2012: We may not want to perform these if the surface counts fail, but for now, we will include these tests
+ //Detailed Surface Checks
+ //Store Surface Element Information
+ List TestSurfaces = new List();
+ XmlDocument TestFile = gbXMLdocs[0];
+ XmlNamespaceManager TestNSM = gbXMLnsm[0];
+ List StandardSurfaces = new List();
+ XmlDocument StandardFile = gbXMLdocs[1];
+ XmlNamespaceManager StandardNSM = gbXMLnsm[1];
+ TestSurfaces = GetFileSurfaceDefs(TestFile, TestNSM);
+ StandardSurfaces = GetFileSurfaceDefs(StandardFile, StandardNSM);
+ string TestSurfaceTable = " ";
+ TestSurfaceTable += "" +
+ "| " + "Test Section Name" + " | " +
+ "" + "Stand Surface ID" + " | " +
+ "" + "Test Surface ID" + " | " +
+ "" + "Stand Surface Tilt" + " | " +
+ "" + "Test Surface Tilt" + " | " +
+ "" + "Stand Surface Azimuth" + " | " +
+ "" + "Test Surface Azimuth" + " | " +
+ "" + "Stand Surface Height" + " | " +
+ "" + "Test Surface Height" + " | " +
+ "" + "Stand Surface Width" + " | " +
+ "" + "Test Surface Width" + " | " +
+ "" + "Pass/Fail" + " | " +
+ "
";
+ //Test Surfaces Planar Test
+ //all polyloops must be such that the surface defined by the coordinates is planar
+ report.Clear();
+ report.testType = TestType.Surface_Planar_Test;
+ report = TestSurfacePlanarTest(TestSurfaces, report);
+
+ if (!report.passOrFail)
+ {
+ AddToOutPut("Test File Planar Surface Check: ", report, true);
+ report.Clear();
+ }
+ //only run detailed surface checks if the surfaces are planar
+ else
+ {
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //Execute Tests
+
+
+ // globalMatchObject.MatchedSurfaceIds = new Dictionary>();
+ int i = 1;
+
+ foreach (SurfaceDefinitions surface in StandardSurfaces)
+ {
+ report.Clear();
+ //multiple tolerances used
+ report.testType = TestType.Detailed_Surface_Checks;
+ report.subTestIndex = i;
+
+ //multiple units used, so ignore units
+ report = GetPossibleSurfaceMatches(surface, TestSurfaces, report);
+
+ AddToOutPut("Test 17 for Surface number " + i + " Result: ", report, false);
+
+ foreach (SurfaceDefinitions ts in TestSurfaces)
+ {
+ if (globalMatchObject.MatchedSurfaceIds.ContainsKey(surface.SurfaceId))
+ {
+ foreach (string id in globalMatchObject.MatchedSurfaceIds[surface.SurfaceId])
+ {
+ if (ts.SurfaceId == id)
+ {
+ if (report.passOrFail)
+ TestSurfaceTable += "" +
+ "| " + "" +
+ "Detailed Surface Checks " + report.subTestIndex + "" + " | " +
+
+ "" + surface.SurfaceId + " | " +
+ "" + ts.SurfaceId + " | " +
+ "" + String.Format("{0:#,0.00}", surface.Tilt) + " | " +
+ "" + String.Format("{0:#,0.00}", ts.Tilt) + " | " +
+ "" + String.Format("{0:#,0.00}", surface.Azimuth) + " | " +
+ "" + String.Format("{0:#,0.00}", ts.Azimuth) + " | " +
+ "" + String.Format("{0:#,0.00}", surface.Height) + " | " +
+ "" + String.Format("{0:#,0.00}", ts.Height) + " | " +
+ "" + String.Format("{0:#,0.00}", surface.Width) + " | " +
+ "" + String.Format("{0:#,0.00}", ts.Width) + " | " +
+ "" + "Pass" + " | " +
+ "
";
+ }
+
+ }
+
+ }
+ }
+ //if didn't find match means it failed the test
+ if (!report.passOrFail)
+ TestSurfaceTable += "" +
+ "| " + "" +
+ "Detailed Surface Checks " + report.subTestIndex + "" + " | " +
+ "" + surface.SurfaceId + " | " +
+ "" + "--- | " +
+ "" + String.Format("{0:#,0.00}", surface.Tilt) + " | " +
+ "" + "--- | " +
+ "" + String.Format("{0:#,0.00}", surface.Azimuth) + " | " +
+ "" + "--- | " +
+ "" + String.Format("{0:#,0.00}", surface.Height) + " | " +
+ "" + "--- | " +
+ "" + String.Format("{0:#,0.00}", surface.Width) + " | " +
+ "" + "--- | " +
+ "" + "Fail" + " | " +
+ "
";
+ i += 1;
+ }
+
+ TestSurfaceTable += "
";
+ }
+ #endregion
+
+ //test 18 CountFixedWindows
+ //Test 18 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.FixedWindowCountTolerance;
+ report.testType = TestType.Fixed_Windows_Count;
+ units = "";
+ report = CountFixedWindows(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Fixed Windows Count Test Result: ", report, true);
+
+ //test 19 CountOperableWindows
+ //Test 19 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.OperableWindowCountTolerance;
+ report.testType = TestType.Operable_Windows_Count;
+ units = "";
+ report = CountOperableWindows(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Operable Windows Count Test Result: ", report, true);
+
+ //test 20 CountFixedSkylights
+ //Test 20 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.FixedSkylightCountTolerance;
+ report.testType = TestType.Fixed_Skylight_Count;
+ units = "";
+ report = CountFixedSkylights(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Fixed Skylight Count Test Result: ", report, true);
+
+ //test 21 CountOperableSkylights
+ //Test 21 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.OperableSkylightCountTolerance;
+ report.testType = TestType.Operable_Skylight_Count;
+ units = "";
+ report = CountOperableSkylights(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Operable Skylight Count Test Result: ", report, true);
+
+
+ //test 22 CountSlidingDoors
+ //Test 22 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.SlidingDoorCountTolerance;
+ report.testType = TestType.Sliding_Doors_Count;
+ units = "";
+ report = CountSlidingDoors(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Sliding Doors Count Test Result: ", report, true);
+
+ //test 23 CountNonSlidingDoors
+ //Test 23 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.NonSlidingDoorCountTolerance;
+ report.testType = TestType.Non_Sliding_Doors_Count;
+ units = "";
+ report = CountNonSlidingDoors(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Non Sliding Doors Count Test Result: ", report, true);
+
+ //test 24 CountAirOpenings
+ //Test 24 Execute
+ report.Clear();
+ report.tolerance = DOEgbXMLBasics.Tolerances.AirOpeningCountTolerance;
+ report.testType = TestType.Air_Openings_Count;
+ units = "";
+ report = CountAirOpenings(gbXMLdocs, gbXMLnsm, report, units);
+ AddToOutPut("Air Openings Count Test Result: ", report, true);
+
+
+ #region opending detailed test
+ //openings detailed tests
+ List TestOpenings = new List();
+ XmlDocument testFile = gbXMLdocs[0];
+ XmlNamespaceManager testNSM = gbXMLnsm[0];
+ List StandardOpenings = new List();
+ XmlDocument standardFile = gbXMLdocs[1];
+ XmlNamespaceManager standardNSM = gbXMLnsm[1];
+ TestOpenings = GetFileOpeningDefs(TestFile, TestNSM);
+ StandardOpenings = GetFileOpeningDefs(StandardFile, StandardNSM);
+
+ string TestOpeningTable = "";
+ report.Clear();
+ report.testType = TestType.Opening_Planar_Test;
+ report = TestOpeningPlanarTest(TestOpenings, report);
+
+ if (!report.passOrFail)
+ {
+ AddToOutPut("Test File Planar Opening Check: ", report, true);
+ report.Clear();
+ }
+ //only run detailed opening checks if the opening are planar
+ else
+ {
+ TestOpeningTable = "";
+ TestOpeningTable += "" +
+ "| " + "Test Section Name" + " | " +
+ "" + "Standard Opening Id" + " | " +
+ "" + "Test Opening Id" + " | " +
+ "" + "Standard Parent Surface Id" + " | " +
+ "" + "Test Parent Surface Id" + " | " +
+ "" + "Standard Parent Azimuth" + " | " +
+ "" + "Test Parent Azimuth" + " | " +
+ "" + "Standard Parent Tilt" + " | " +
+ "" + "Test Parent Tilt" + " | " +
+ "" + "Standard Surface Area" + " | " +
+ "" + "Test Surface Area" + " | " +
+ "" + "Pass/Fail" + " | " +
+ "
";
+
+ globalMatchObject.MatchedOpeningIds = new Dictionary>();
+ int i = 1;
+ //if no openings remove the table.
+ if (StandardOpenings.Count < 1)
+ TestOpeningTable = "";
+ //compare the openings
+ foreach (OpeningDefinitions opening in StandardOpenings)
+ {
+ report.Clear();
+
+ report.testType = TestType.Detailed_Opening_Checks;
+ report.subTestIndex = i;
+
+ report = GetPossibleOpeningMatches(opening, TestOpenings, report);
+
+ AddToOutPut("Test 17 for Opening number " + i + " Result: ", report, false);
+
+ foreach (OpeningDefinitions to in TestOpenings)
+ {
+ if (globalMatchObject.MatchedOpeningIds.ContainsKey(opening.OpeningId))
+ {
+ foreach (string id in globalMatchObject.MatchedOpeningIds[opening.OpeningId])
+ {
+ if (to.OpeningId == id)
+ {
+ if (report.passOrFail)
+ TestOpeningTable += "" +
+ "| " + "" +
+ "Detailed Opening Checks " + report.subTestIndex + "" + " | " +
+ "" + opening.OpeningId + " | " +
+ "" + to.OpeningId + " | " +
+ "" + opening.ParentSurfaceId + " | " +
+ "" + to.ParentSurfaceId + " | " +
+ "" + String.Format("{0:#,0.00}", opening.ParentAzimuth) + " | " +
+ "" + String.Format("{0:#,0.00}", to.ParentAzimuth) + " | " +
+ "" + String.Format("{0:#,0.00}", opening.ParentTilt) + " | " +
+ "" + String.Format("{0:#,0.00}", to.ParentTilt) + " | " +
+ "" + String.Format("{0:#,0.00}", opening.surfaceArea) + " | " +
+ "" + String.Format("{0:#,0.00}", to.surfaceArea) + " | " +
+ "" + "Pass" + " | " +
+ "
";
+ }
+
+ }
+
+ }
+ }
+ //if didn't find match means it failed the test
+ if (!report.passOrFail)
+ TestOpeningTable += "" +
+ "| " + "" +
+ "Detailed Opening Checks " + report.subTestIndex + "" + " | " +
+ "" + opening.OpeningId + " | " +
+ "" + "---" + " | " +
+ "" + opening.ParentSurfaceId + " | " +
+ "" + "---" + " | " +
+ "" + String.Format("{0:#,0.00}", opening.ParentAzimuth) + " | " +
+ "" + "---" + " | " +
+ "" + String.Format("{0:#,0.00}", opening.ParentTilt) + " | " +
+ "" + "---" + " | " +
+ "" + String.Format("{0:#,0.00}", opening.surfaceArea) + " | " +
+ "" + "---" + " | " +
+ "" + "Fail" + " | " +
+ "
";
+ i += 1;
+
+ }
+ }
+ TestOpeningTable += "
";
+ #endregion
+
+ //close table
+ table += "
";
+ //add TestSurfaceTable
+ table += TestSurfaceTable + TestOpeningTable;
+
+ CreateSummaryTable();
+
+ }
+ private void AddToOutPut(string title, DOEgbXMLReportingObj report, bool createTable)
+ {
+ //add report to report list
+ //have to deep copy the report before put report in the list
+ DOEgbXMLReportingObj tmpreport = report.Copy();
+ ReportList.Add(tmpreport);
+
+ //title
+ output += "" + title + "
";
+ log += title + System.Environment.NewLine;
+
+ //message
+ var passTest = report.TestPassedDict.Values;
+ bool individualTestBool = true;
+ foreach (bool testResult in passTest)
+ {
+ if (testResult == false)
+ {
+ individualTestBool = false;
+ break;
+ }
+ }
+ if (report.passOrFail && individualTestBool)
+ output += "" + report.longMsg + "
";
+ else
+ {
+ output += "" + report.longMsg + "
";
+ overallPassTest = false;
+ }
+
+ log += report.longMsg + System.Environment.NewLine;
+
+ //message list, print out each message in the list if there are any
+ if (report.MessageList.Count > 0)
+ for (int i = 0; i < report.MessageList.Count; i++)
+ {
+ output += "" + report.MessageList[i] + "
";
+ log += report.MessageList[i] + System.Environment.NewLine;
+ }
+
+ output += "
";
+ log += System.Environment.NewLine;
+
+ //create table row
+ if (createTable)
+ {
+
+ if (report.standResult.Count == 0)
+ {
+ report.standResult.Add("---");
+ report.testResult.Add("---");
+ report.idList.Add("");
+ }
+
+ //for eachout put
+ for (int i = 0; i < report.standResult.Count; i++)
+ {
+ bool sameString = false;
+ if (report.standResult[i] == report.testResult[i])
+ sameString = true;
+
+ //check if test pass or fail
+ if ((report.passOrFail && individualTestBool) || sameString)
+ table += "";
+ else
+ {
+ table += "
";
+ overallPassTest = false;
+ }
+
+ table += "| " + "" + title + " " + report.idList[i] + "" + " | ";
+
+ if ((report.passOrFail && individualTestBool) || sameString)
+ {
+ table += "" + report.standResult[i] + " " + report.unit + " | " +
+ "" + report.testResult[i] + " " + report.unit + " | " +
+ "" + "±" + report.tolerance + " " + report.unit + " | " +
+ "Pass | " +
+ "
";
+ }
+ else
+ table += "" + report.standResult[i] + " " + report.unit + " | " +
+ "" + report.testResult[i] + " " + report.unit + " | " +
+ "" + "±" + report.tolerance + " " + report.unit + " | " +
+ "Fail | " +
+ "";
+
+ }
+ }
+
+ }
+ private void CreateSummaryTable()
+ {
+ //create overall summary table
+ //find the right testdetail
+ //check if the user pass the test
+ bool passTest = true;
+ bool aceTest = true;
+ foreach (DOEgbXMLReportingObj tmpreport in ReportList)
+ {
+ if (TestCriteria.TestCriteriaDictionary.ContainsKey(tmpreport.testType))
+ {
+ if (TestCriteria.TestCriteriaDictionary[tmpreport.testType] && !tmpreport.passOrFail)
+ passTest = false;
+ if (!TestCriteria.TestCriteriaDictionary[tmpreport.testType] && !tmpreport.passOrFail)
+ aceTest = false;
+ }
+ else if (tmpreport.testType == TestType.Detailed_Surface_Checks)
+ {
+
+ }
+
+ else
+ {
+
+ }
+ }
+ foreach (DOEgbXMLTestDetail detail in TestDetail.TestDetailList)
+ if (detail.testName == TestToRun)
+ {
+ summaryTable = "Result Summary
";
+ summaryTable += "";
+
+ summaryTable += "" +
+ "| " + "gbXML schema Test" + " | " +
+ "" + "" + " | " +
+ "" + "Pass" + " | " +
+ "
";
+
+ if (passTest && aceTest)
+ summaryTable += "";
+ else if (passTest)
+ summaryTable += "
";
+ else
+ summaryTable += "
";
+
+ summaryTable += "| " + "gbXML Test" + " | " +
+ "" + detail.shortTitle + " | ";
+
+ if (passTest && aceTest)
+ summaryTable += "" + detail.passString + " | " + "
";
+ else if (passTest)
+ summaryTable += "" + "You pass the test with minor errors" + " | " + "";
+ else
+ summaryTable += "" + detail.failString + " | " + "";
+
+ summaryTable += "
";
+ break;
+ }
+ }
+ private bool TestFileIsAvailable()
+ {
+ //check if the file available
+ if (filepaths.ContainsKey(TestToRun))
+ {
+ gbXMLStandardFile.Load(filepaths[TestToRun]);
+ return true;
+ }
+ else
+ {
+ //create overall summary table
+ summaryTable = "Result Summary
";
+ summaryTable += "";
+
+ summaryTable += "" +
+ "| " + "gbXML schema Test" + " | " +
+ "" + "" + " | " +
+ "" + "Pass" + " | " +
+ "
";
+
+ summaryTable += "";
+
+ summaryTable += "| " + "gbXML Test" + " | " +
+ "" + "Test File Currently Not available" + " | ";
+
+ summaryTable += "" + "Error Error Error" + " | " + "
";
+
+ summaryTable += "
";
+ return false;
+ }
+ }
+ #endregion
+
+ private XmlDocument ConvertMetricToUS(XmlDocument mdoc)
+ {
+ XmlDocument ipdoc = new XmlDocument();
+
+ return ipdoc;
+ }
+
+
+
+ #region Test Functions
+ private DOEgbXMLReportingObj GetUGSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"UndergroundWall\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this SurfaceType in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+
+
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "surfaceType")
+ {
+ string type = at.Value;
+ if (type == "UndergroundWall")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " exterior wall surfaces in the Standard File and " + resultsArray[i - 1] + " exterior wall surfaces in the Test File.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ private DOEgbXMLReportingObj GetPossibleOpeningMatches(OpeningDefinitions standardOpening, List TestOpenings, DOEgbXMLReportingObj report)
+ {
+ report.testSummary = "This test checks the geometric accuracy of each opening in your test file against the standard file.";
+ report.testSummary += " For each opening (window, door, skylight) this validator seeks out a similar opening in your test file and";
+ //match surfaces at this stage so we know which surface is associated with the window
+ report.testSummary += " The validator first seeks to find all openings that have a parent surface (roof, external wall, etc.) with";
+ report.testSummary += " the same azimuth and tilt. If it finds more than one opening candidate that matches the parent surface tilt and azimuth,";
+ report.testSummary += " the validator will make all of these openings possible candidates.";
+ report.testSummary += " The validator then takes these candidates and looks at their polyloop coordinates. ";
+ report.testSummary += " and will keep only those openings that have similar polyLoop coordinates";
+ report.testSummary += " Next it matches the area, then the width and height, if applicable, and finally checks the insertion";
+ report.testSummary += " point coordinates. If all of these come back within tolerance, the opening has found a match.";
+ report.testSummary += " Otherwise, the test will fail.";
+ report.testSummary += " The summary at the bottom of the page will show the logic of how the test arrived at its conclusion.";
+
+
+ bool matchedParentAz = false;
+ bool matchedParentTilt = false;
+ bool matchedPolyLoopCoords = false;
+
+ List possibleMatches = new List();
+ List possibleMatches2 = new List();
+ try
+ {
+ //find match of parent surface
+ //try matching based on the surface matches
+ //if that does not work, then just try to match the parent tilt and parent azimuth to one another
+ int i = 0;
+ report.MessageList.Add("Starting Parent Azimuth and Tilt Match test....");
+ report.MessageList.Add("");
+ while (true)
+ {
+ //reset
+ matchedParentAz = false;
+ matchedParentTilt = false;
+ OpeningDefinitions testOpening = TestOpenings[i];
+ if (testOpening.ParentAzimuth == standardOpening.ParentAzimuth && testOpening.ParentTilt == standardOpening.ParentTilt)
+ {
+ report.MessageList.Add("Candidate Found. Test file opening has EXACTLY matched its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]");
+ report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]");
+
+ matchedParentAz = true;
+ matchedParentTilt = true;
+ }
+ else
+ {
+ double azDifference = Math.Abs(testOpening.ParentAzimuth - standardOpening.ParentAzimuth);
+ double tiltDifference = Math.Abs(testOpening.ParentTilt - standardOpening.ParentTilt);
+ if (azDifference < DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance && tiltDifference < DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance)
+ {
+ report.MessageList.Add("Candidate found. Test file opening HAS matched WITHIN ALLOWABLE TOLERANCE its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]");
+ report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]");
+
+ matchedParentAz = true;
+ matchedParentTilt = true;
+ }
+ else
+ {
+ report.MessageList.Add("Candidate rejected. Test file opening HAS NOT matched WITHIN ALLOWABLE TOLERANCE its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]");
+ report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]");
+ report.MessageList.Add("");
+ }
+ }
+
+ if (matchedParentAz && matchedParentTilt)
+ {
+ possibleMatches.Add(testOpening);
+ report.MessageList.Add("Successful Match Candidate Identified.");
+ report.MessageList.Add("");
+ }
+ i++;
+
+ if (i == TestOpenings.Count)
+ {
+ if (possibleMatches.Count == 0)
+ {
+ //no candidates found
+ report.MessageList.Add("No candidates found in the test file to match standard file opening " + standardOpening.OpeningId);
+ report.passOrFail = false;
+ report.longMsg = "Test to find suitable opening candidate in the test file has failed. Parent Tilt and Azimuth matches could not be established.";
+ //no need to go further
+ return report;
+ }
+ break;
+ }
+
+ }
+ report.MessageList.Add("");
+ report.MessageList.Add("Starting Opening PolyLoop Coordinate Match test.........");
+ i = 0;
+ while (true)
+ {
+ OpeningDefinitions testOpening = possibleMatches[i];
+ //continue to next test
+
+ //continue the next batch of tests
+ //polyloop absolute coordinates
+ //check the polyLoop coordinates
+ foreach (Vector.CartCoord standardPolyLoopCoord in standardOpening.PlCoords)
+ {
+ report = GetOpeningPolyLoopCoordMatch(standardPolyLoopCoord, testOpening, report, standardOpening.OpeningId);
+ if (report.passOrFail)
+ {
+ matchedPolyLoopCoords = true;
+ continue;
+ }
+ else
+ {
+ report.MessageList.Add("Could not find a coordinate match in the test opening polyloop.");
+ matchedPolyLoopCoords = false;
+ break;
+ }
+ }
+ //if matchePolyLoopCoords comes back true, then a candidate has been found that matches all polyloop coords within tolerance
+ if (matchedPolyLoopCoords == true)
+ {
+ possibleMatches2.Add(testOpening);
+ }
+ i++;
+
+ if (i == possibleMatches.Count)
+ {
+ if (possibleMatches2.Count == 0)
+ {
+ report.MessageList.Add("No candidates found in the test file to match standard file opening " + standardOpening.OpeningId);
+ report.passOrFail = false;
+ report.longMsg = "Test to find suitable opening candidate in the test file has failed. Parent Tilt and Azimuth matches were established, but these candidates did not produce good polyLoop coordinate matches.";
+ //no need to go further
+ return report;
+ }
+ break;
+ }
+ }
+ //next set of tests
+ //polyloop area tests
+ report.MessageList.Add("");
+ report.MessageList.Add("Starting Opening Surface Area Match test.........");
+ possibleMatches.Clear();
+ i = 0;
+ while (true)
+ {
+ #region
+ OpeningDefinitions testOpening = possibleMatches2[i];
+
+ if (Math.Abs(standardOpening.PlRHRVector.X) == 1 && standardOpening.PlRHRVector.Y == 0 && standardOpening.PlRHRVector.Z == 0)
+ {
+ List coordList = new List();
+ foreach (Vector.CartCoord coord in standardOpening.PlCoords)
+ {
+ //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same
+ coord.X = 0;
+ coordList.Add(coord);
+
+ }
+ double area = Math.Abs(GetAreaFrom2DPolyLoop(coordList));
+ standardOpening.surfaceArea = area;
+ if (area == -999)
+ {
+ //these messages should never occur and are a sign of some sort of serious, as of yet unknown error
+ //March 20 2013
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+ report.longMsg = "Fatal error. Please contact gbXML administrator";
+ report.passOrFail = false;
+ return report;
+
+ }
+ double testOpeningArea = 0;
+
+ if (Math.Abs(testOpening.PlRHRVector.X) == 1 && testOpening.PlRHRVector.Y == 0 &&
+ testOpening.PlRHRVector.Z == 0)
+ {
+ List testCoordList = new List();
+ foreach (Vector.CartCoord coord in testOpening.PlCoords)
+ {
+ coord.X = 0;
+ testCoordList.Add(coord);
+ }
+ testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList));
+ testOpening.surfaceArea = testOpeningArea;
+ if (testOpeningArea == -999)
+ {
+ //these messages should never occur and are a sign of some sort of serious, as of yet unknown error
+ //March 20 2013
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.longMsg = "Fatal error. Please contact gbXML administrator";
+ report.passOrFail = false;
+ return report;
+ }
+ double difference = Math.Abs(area) - Math.Abs(testOpeningArea);
+ if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance)
+ {
+
+ if (difference == 0)
+ {
+ //then it perfectly matches, go on to check the poly loop coordinates
+ //then check the insertion point
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard opening: " + standardOpening.OpeningId + " exactly.");
+ possibleMatches.Add(testOpening);
+ }
+ else
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance.");
+ possibleMatches.Add(testOpening);
+ }
+ }
+ else
+ {
+ report.MessageList.Add("The standard file opening cannot find a match for its surface area of opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test opening: " + testOpening.OpeningId);
+ //don't return here, it will be returned below
+ }
+ }
+ else
+ {
+ //by definition, the Window opening should always use coordinates that create a normal vector that points in the
+ //positive or negative X direction. If the test file does not do this, then this is in violation of the
+ //gbXML spec
+ report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates ");
+ report.longMsg += (" that do not have the same normal vector as the standard opening.");
+ report.passOrFail = false;
+ }
+ }
+ else if (standardOpening.PlRHRVector.X == 0 && Math.Abs(standardOpening.PlRHRVector.Y) == 1 && standardOpening.PlRHRVector.Z == 0)
+ {
+ List coordList = new List();
+ foreach (Vector.CartCoord coord in standardOpening.PlCoords)
+ {
+ //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same
+ coord.Y = 0;
+ coordList.Add(coord);
+
+ }
+ double area = Math.Abs(GetAreaFrom2DPolyLoop(coordList));
+ standardOpening.surfaceArea = area;
+ if (area == -999)
+ {
+ //these messages should never occur and are a sign of some sort of serious, as of yet unknown error
+ //March 20 2013
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+ report.longMsg = "Fatal error. Please contact gbXML administrator";
+ report.passOrFail = false;
+ return report;
+
+ }
+ double testOpeningArea = 0;
+
+ if (testOpening.PlRHRVector.X == 0 && Math.Abs(testOpening.PlRHRVector.Y) == 1 &&
+ testOpening.PlRHRVector.Z == 0)
+ {
+ List testCoordList = new List();
+ foreach (Vector.CartCoord coord in testOpening.PlCoords)
+ {
+ coord.Y = 0;
+ testCoordList.Add(coord);
+ }
+ testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList));
+ testOpening.surfaceArea = testOpeningArea;
+ if (testOpeningArea == -999)
+ {
+ //these messages should never occur and are a sign of some sort of serious, as of yet unknown error
+ //March 20 2013
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.longMsg = "Fatal error. Please contact gbXML administrator";
+ report.passOrFail = false;
+ return report;
+ }
+ double difference = Math.Abs(area) - Math.Abs(testOpeningArea);
+ if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance)
+ {
+
+ if (difference == 0)
+ {
+ //then it perfectly matches, go on to check the poly loop coordinates
+ //then check the insertion point
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly.");
+ possibleMatches.Add(testOpening);
+ }
+ else
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance.");
+ possibleMatches.Add(testOpening);
+ }
+ }
+ else
+ {
+ report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId);
+ //don't return here, it will be returned below
+ }
+ }
+ else
+ {
+ //by definition, the Window opening should always use coordinates that create a normal vector that points in the
+ //positive or negative X direction. If the test file does not do this, then this is in violation of the
+ //gbXML spec
+ report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates ");
+ report.longMsg += (" that do not have the same normal vector as the standard opening.");
+ report.passOrFail = false;
+ }
+ }
+ else if (standardOpening.PlRHRVector.X == 0 && standardOpening.PlRHRVector.Y == 0 && Math.Abs(standardOpening.PlRHRVector.Z) == 1)
+ {
+ List coordList = new List();
+ foreach (Vector.CartCoord coord in standardOpening.PlCoords)
+ {
+ //only take the X and Y coordinates and throw out the Z because we can assume that they are all the same
+ coord.Z = 0;
+ coordList.Add(coord);
+
+ }
+ double area = Math.Abs(GetAreaFrom2DPolyLoop(coordList));
+ standardOpening.surfaceArea = area;
+ if (area == -999)
+ {
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+
+ }
+ double testOpeningArea = 0;
+
+ if (testOpening.PlRHRVector.X == 0 && testOpening.PlRHRVector.Y == 0 &&
+ Math.Abs(testOpening.PlRHRVector.Z) == 1)
+ {
+ List testCoordList = new List();
+ foreach (Vector.CartCoord coord in testOpening.PlCoords)
+ {
+ coord.Z = 0;
+ testCoordList.Add(coord);
+ }
+ testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList));
+ testOpening.surfaceArea = testOpeningArea;
+ if (testOpeningArea == -999)
+ {
+ //these messages should never occur and are a sign of some sort of serious, as of yet unknown error
+ //March 20 2013
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.longMsg = "Fatal error. Please contact gbXML administrator";
+ report.passOrFail = false;
+ return report;
+ }
+ double difference = Math.Abs(area) - Math.Abs(testOpeningArea);
+ if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance)
+ {
+
+ if (difference == 0)
+ {
+ //then it perfectly matches, go on to check the poly loop coordinates
+ //then check the insertion point
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly.");
+ possibleMatches.Add(testOpening);
+ }
+ else
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance.");
+ possibleMatches.Add(testOpening);
+ }
+ }
+ else
+ {
+ report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId);
+ //don't return here, it will be returned below
+ }
+ }
+ else
+ {
+ //by definition, the Window opening should always use coordinates that create a normal vector that points in the
+ //positive or negative X direction. If the test file does not do this, then this is in violation of the
+ //gbXML spec
+ report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates ");
+ report.longMsg += (" that do not have the same normal vector as the standard opening.");
+ report.passOrFail = false;
+ }
+
+ }
+ //the opening is not aligned along a reference frame axis
+ else
+ {
+ report.MessageList.Add("This standard Opening is not aligned along a reference plane axis, and will be rotated into a new coordinate frame.");
+ report.MessageList.Add("Commencing rotation to 2-D.");
+ //New Z Axis for this plane is the normal vector, does not need to be created
+ //Get New Y Axis which is the surface Normal Vector cross the original global reference X unit vector (all unit vectors please
+ Vector.CartVect localY = new Vector.CartVect();
+ Vector.CartVect globalReferenceX = new Vector.CartVect();
+ globalReferenceX.X = 1;
+ globalReferenceX.Y = 0;
+ globalReferenceX.Z = 0;
+ localY = Vector.CrossProduct(standardOpening.PlRHRVector, globalReferenceX);
+ localY = Vector.UnitVector(localY);
+
+ //new X axis is the localY cross the surface normal vector
+ Vector.CartVect localX = new Vector.CartVect();
+ localX = Vector.CrossProduct(localY, standardOpening.PlRHRVector);
+ localX = Vector.UnitVector(localX);
+
+ //convert the polyloop coordinates to a local 2-D reference frame
+ //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane
+ List translatedCoordinates = new List();
+ Vector.CartCoord newOrigin = new Vector.CartCoord();
+ newOrigin.X = 0;
+ newOrigin.Y = 0;
+ newOrigin.Z = 0;
+ translatedCoordinates.Add(newOrigin);
+ for (int j = 1; j < standardOpening.PlCoords.Count; j++)
+ {
+ //randomly assigns the first polyLoop coordinate as the origin
+ Vector.CartCoord origin = standardOpening.PlCoords[0];
+ //captures the components of a vector drawn from the new origin to the
+ Vector.CartVect distance = new Vector.CartVect();
+ distance.X = standardOpening.PlCoords[j].X - origin.X;
+ distance.Y = standardOpening.PlCoords[j].Y - origin.Y;
+ distance.Z = standardOpening.PlCoords[j].Z - origin.Z;
+ Vector.CartCoord translatedPt = new Vector.CartCoord();
+ //x coordinate is distance vector dot the new local X axis
+ translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
+ //y coordinate is distance vector dot the new local Y axis
+ translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
+ translatedPt.Z = 0;
+ translatedCoordinates.Add(translatedPt);
+
+ }
+ double area = GetAreaFrom2DPolyLoop(translatedCoordinates);
+ standardOpening.surfaceArea = area;
+ if (area == -999)
+ {
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+
+ }
+ //get the area of the test candidates using the polyloop coordinates
+ Vector.CartVect testlocalY = new Vector.CartVect();
+ Vector.CartVect testglobalReferenceX = new Vector.CartVect();
+ globalReferenceX.X = 1;
+ globalReferenceX.Y = 0;
+ globalReferenceX.Z = 0;
+ testlocalY = Vector.CrossProduct(testOpening.PlRHRVector, testglobalReferenceX);
+ testlocalY = Vector.UnitVector(testlocalY);
+
+ //new X axis is the localY cross the surface normal vector
+ Vector.CartVect testlocalX = new Vector.CartVect();
+ testlocalX = Vector.CrossProduct(testlocalY, testOpening.PlRHRVector);
+ testlocalX = Vector.UnitVector(testlocalX);
+
+ //convert the polyloop coordinates to a local 2-D reference frame
+ //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane
+ List testtranslatedCoordinates = new List();
+ Vector.CartCoord newOriginTest = new Vector.CartCoord();
+ newOrigin.X = 0;
+ newOrigin.Y = 0;
+ newOrigin.Z = 0;
+ testtranslatedCoordinates.Add(newOriginTest);
+ for (int j = 1; j < testOpening.PlCoords.Count; j++)
+ {
+ //randomly assigns the first polyLoop coordinate as the origin
+ Vector.CartCoord origin = testOpening.PlCoords[0];
+ //captures the components of a vector drawn from the new origin to the
+ Vector.CartVect distance = new Vector.CartVect();
+ distance.X = testOpening.PlCoords[j].X - origin.X;
+ distance.Y = testOpening.PlCoords[j].Y - origin.Y;
+ distance.Z = testOpening.PlCoords[j].Z - origin.Z;
+ Vector.CartCoord translatedPt = new Vector.CartCoord();
+ //x coordinate is distance vector dot the new local X axis
+ translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
+ //y coordinate is distance vector dot the new local Y axis
+ translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
+ translatedPt.Z = 0;
+ testtranslatedCoordinates.Add(translatedPt);
+
+ }
+ double testOpeningArea = GetAreaFrom2DPolyLoop(translatedCoordinates);
+ testOpening.surfaceArea = testOpeningArea;
+ if (testOpeningArea == -999)
+ {
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ }
+ double difference = Math.Abs(area) - Math.Abs(testOpeningArea);
+ if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance)
+ {
+
+ if (difference == 0)
+ {
+ //then it perfectly matches, go on to check the poly loop coordinates
+ //then check the insertion point
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly.");
+ possibleMatches.Add(testOpening);
+ }
+ else
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance.");
+ possibleMatches.Add(testOpening);
+ }
+ }
+ else
+ {
+ report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId);
+ //don't return here, it will be returned below
+ }
+
+ }
+ i++;
+ if (i == possibleMatches2.Count)
+ {
+ if (possibleMatches.Count == 0)
+ {
+ report.MessageList.Add("No area match could be found for standard opening: " + standardOpening.OpeningId + ".");
+ report.longMsg = "The search routine has ended and could not find a match for opening: " + standardOpening.OpeningId +
+ ". Attempt to match the area of the standard file with test file openings failed.";
+ return report;
+
+ }
+ else
+ {
+ //you are good to go with some more matches
+ report.MessageList.Add("Area matching SUCCESS for standard file Opening id: " + standardOpening.OpeningId);
+ report.MessageList.Add("Commencing comparisons of height, width, and insertion point.");
+ break;
+ }
+ }
+
+ #endregion
+ }
+ //test the width and height, if applicable
+ report.MessageList.Add("");
+ report.MessageList.Add("Starting Width and Height Match test.........");
+ possibleMatches2.Clear();
+ i = 0;
+ //surface area using the coordinates of the polyloop. We already assume that they are planar, as previously tested
+ while (true)
+ {
+ //see if the openings are regular
+ bool isStandardRegular = IsOpeningRegular(standardOpening);
+ bool isTestRegular = IsOpeningRegular(possibleMatches[i]);
+ //if they are...go ahead and use width and height, otherwise the values are not reliable
+ if (isStandardRegular)
+ {
+ //output something
+ if (isTestRegular)
+ {
+ //output something
+ //perform tests
+
+ OpeningDefinitions testOpening = possibleMatches[i];
+ double testWidth = testOpening.Width;
+ double standardWidth = standardOpening.Width;
+ double testHeight = testOpening.Height;
+ double standardHeight = standardOpening.Height;
+ double widthDifference = Math.Abs(testWidth - standardWidth);
+ double heightDiffefence = Math.Abs(testHeight - standardHeight);
+
+ if (widthDifference <= DOEgbXMLBasics.Tolerances.OpeningWidthTolerance)
+ {
+ if (widthDifference == 0)
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Width value matches the Width value of the standard Opening: " + standardOpening.OpeningId + " exactly.");
+ }
+ else
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Width value matches the Width value of the standard Opening: " + standardOpening.OpeningId + " within the allowable tolerance.");
+ }
+ //check the height
+ if (heightDiffefence <= DOEgbXMLBasics.Tolerances.OpeningHeightTolerance)
+ {
+ if (heightDiffefence == 0)
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Height value matches the Height value of the standard Opening: " + standardOpening.OpeningId + " exactly.");
+ possibleMatches2.Add(testOpening);
+ }
+ else
+ {
+ report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Height value matches the Height value of the standard Opening: " + standardOpening.OpeningId + " within the allowable tolerance.");
+ possibleMatches2.Add(testOpening);
+ }
+ }
+ else
+ {
+ //fail, did not match height
+ report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + "The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " after comparison its Height value with test opening: " + testOpening.OpeningId);
+ report.passOrFail = false;
+ continue;
+ }
+ }
+ else
+ {
+ //failed, did not match width
+ report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + " cannot find a match for its width after comparison the width value of test Opening: " + testOpening.OpeningId);
+ report.passOrFail = false;
+ continue;
+ }
+ }
+ else
+ {
+ //let them know the the test opening is not a square or rectangle, but the standard file opening is
+ //go ahead and break out of the while loop because we aren't testing for width and height
+ report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + " is a rectangle or square, but the test file Opening: " + standardOpening.OpeningId + " is not. Cannot test for a valid width and height.");
+ report.MessageList.Add("Searching for another test Opening.");
+ continue;
+ }
+ }
+ else
+ {
+ //tell them that the widths and Heights will Not be checked
+ //because the standard file opening is not a square or rectangle
+ report.MessageList.Add("Will not be testing for the Width and Height values for standard Opening: " + standardOpening.OpeningId + ". The Opening is not shaped like a rectangle or square.");
+ report.MessageList.Add("Going on to check insertion point accuracy.");
+ //needed to transfer values over to possibleMatches2, so deep copy
+ possibleMatches2 = new List(possibleMatches);
+ break;
+ }
+ i++;
+ if (possibleMatches.Count == i)
+ {
+ //means that there is no match for width and height
+ if (possibleMatches2.Count == 0)
+ {
+ report.MessageList.Add("There is no match found for the width and height for Opening: " + standardOpening.OpeningId);
+ report.passOrFail = false;
+ report.longMsg = "The opening test has ended at the search for width and height values equal to standard Opening: " + standardOpening.OpeningId;
+ return report;
+ }
+ break;
+ }
+
+ }
+ report.MessageList.Add("");
+ report.MessageList.Add("Starting Insertion Point Coordinate Match test.........");
+ possibleMatches.Clear();
+ //test the insertion point coordinates
+ i = 0;
+ while (true)
+ {
+ OpeningDefinitions testOpening = possibleMatches2[i];
+ double diffX = Math.Abs(testOpening.InsertionPoint.X - standardOpening.InsertionPoint.X);
+ double diffY = Math.Abs(testOpening.InsertionPoint.Y - standardOpening.InsertionPoint.Y);
+ double diffZ = Math.Abs(testOpening.InsertionPoint.Z - standardOpening.InsertionPoint.Z);
+
+ if (diffX <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtXTolerance && diffY <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtYTolerance &&
+ diffZ <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtZTolerance)
+ {
+ if (diffX == 0)
+ {
+ //perfect X coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point X-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ if (diffY == 0)
+ {
+ //perfect Y coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ if (diffZ == 0)
+ {
+ //perfect Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ possibleMatches.Add(testOpening);
+
+ }
+ else
+ {
+ // Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with Test opening: " + testOpening.OpeningId);
+ //we continue because we search for other matches if there are any
+ possibleMatches.Add(testOpening);
+
+ }
+ }
+ else
+ {
+ //y-coordinate is within tolerance
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Y-Coordinate when compared with Test opening: " + testOpening.OpeningId);
+ if (diffZ == 0)
+ {
+ //perfect Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with Test opening: " + testOpening.OpeningId);
+ possibleMatches.Add(testOpening);
+
+ }
+ else
+ {
+ //perfect Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ //we continue because we search for other matches if there are any
+ possibleMatches.Add(testOpening);
+
+ }
+ }
+
+ }
+ // X is within tolerance
+ else
+ {
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point X-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ if (diffY == 0)
+ {
+ //perfect Y coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ if (diffZ == 0)
+ {
+ //perfect Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ possibleMatches.Add(testOpening);
+
+ }
+ else
+ {
+ //perfect Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ //we continue because we search for other matches if there are any
+ possibleMatches.Add(testOpening);
+
+ }
+ }
+ else
+ {
+ //y-coordinate is within tolerance
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ if (diffZ == 0)
+ {
+ //perfect Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ possibleMatches.Add(testOpening);
+
+ }
+ else
+ {
+ //perfect Z coordinate match
+ report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId);
+ //we continue because we search for other matches if there are any
+ possibleMatches.Add(testOpening);
+
+ }
+ }
+ }
+ }
+ report.MessageList.Add("Standard Opening Ins Pt: (" + standardOpening.InsertionPoint.X.ToString() + "," + standardOpening.InsertionPoint.Y.ToString() + "," + standardOpening.InsertionPoint.Z.ToString() + ")");
+ report.MessageList.Add("Test File Opening Ins Pt: (" + testOpening.InsertionPoint.X.ToString() + "," + testOpening.InsertionPoint.Y.ToString() + "," + testOpening.InsertionPoint.Z.ToString() + ")");
+ i++;
+ if (possibleMatches2.Count == i)
+ {
+ if (possibleMatches.Count == 1)
+ {
+ List openingMatch = new List();
+ openingMatch.Add(possibleMatches[0].OpeningId);
+ report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " is matched to test file Opening: " + testOpening.OpeningId);
+ globalMatchObject.MatchedOpeningIds.Add(standardOpening.OpeningId, openingMatch);
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ if (possibleMatches.Count == 0)
+ {
+ report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " found no match for insertion point in the test file of the remaining candidates.");
+ report.passOrFail = false;
+ return report;
+ }
+ else
+ {
+ report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " is matched to multiple openings:");
+ foreach (OpeningDefinitions opening in possibleMatches)
+ {
+ report.MessageList.Add("Test Opening:" + opening.OpeningId + "matched insertion point");
+ }
+ //resolve by trying to match to the standard opening and test opening parent surfaces.
+ //for the standard opening
+ if (globalMatchObject.MatchedSurfaceIds.ContainsKey(standardOpening.ParentSurfaceId))
+ {
+ List possibleSurfaceMatches = globalMatchObject.MatchedSurfaceIds[standardOpening.ParentSurfaceId];
+ if (possibleSurfaceMatches.Count == 1)
+ {
+ //then a match was found originally during get possible surface matches. That is good, we only want one
+ foreach (OpeningDefinitions openingRemaining in possibleMatches)
+ {
+ if (openingRemaining.ParentSurfaceId == possibleSurfaceMatches[0])
+ {
+ //this is the match we want
+ //else we would have to continue
+ report.MessageList.Add("The test Opening: " + openingRemaining.OpeningId + " has been matched to the standard Opening: " + standardOpening.OpeningId +
+ ". Their parent surface ids have been matched. Thus the conflict has been resolved. (Standard opening parent surface Id, test opening parent surface Id" + standardOpening.ParentSurfaceId + "," + openingRemaining.ParentSurfaceId);
+ report.passOrFail = true;
+ List openingMatch = new List();
+ openingMatch.Add(possibleMatches[0].OpeningId);
+ globalMatchObject.MatchedOpeningIds.Add(standardOpening.OpeningId, openingMatch);
+ return report;
+ }
+ else
+ {
+ //do nothing. Maybe report that the parent Surface Id does not match the standard Opening
+ report.MessageList.Add("Test Opening:" + openingRemaining.OpeningId + " does not match the standard Opening: " + standardOpening.OpeningId +
+ ". Their parent surface ids do not coincide. (Standard Opening parent surface id, test Opening parent surface id)" + standardOpening.ParentSurfaceId + "," + openingRemaining.ParentSurfaceId);
+ }
+ }
+ }
+ }
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ }
+
+ }
+
+ //finished
+
+ }
+ catch (Exception e)
+ {
+ report.longMsg = e.ToString();
+ }
+ return report;
+ }
+
+ private List GetFileOpeningDefs(XmlDocument TestFile, XmlNamespaceManager TestNSM)
+ {
+ List openings = new List();
+ try
+ {
+
+ XmlNodeList nodes = TestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", TestNSM);
+ foreach (XmlNode openingNode in nodes)
+ {
+ //initialize a new instance of the class
+ OpeningDefinitions openingDef = new OpeningDefinitions();
+
+ openingDef.PlCoords = new List();
+ openingDef.InsertionPoint = new Vector.CartCoord();
+ openingDef.PlRHRVector = new Vector.CartVect();
+
+ //get parent id
+ XmlAttributeCollection parentSurfaceAttributes = openingNode.ParentNode.Attributes;
+ foreach (XmlAttribute parentAt in parentSurfaceAttributes)
+ {
+ if (parentAt.Name == "id")
+ {
+ openingDef.ParentSurfaceId = parentAt.Value;
+ break;
+ }
+ }
+ //get Parent Azimuth and Tilt
+ XmlNode surfaceParentNode = openingNode.ParentNode;
+ if (surfaceParentNode.HasChildNodes)
+ {
+ XmlNodeList surfaceParentNodesChillun = surfaceParentNode.ChildNodes;
+ foreach (XmlNode chileNode in surfaceParentNodesChillun)
+ {
+ if (chileNode.Name == "RectangularGeometry")
+ {
+ if (chileNode.HasChildNodes)
+ {
+ foreach (XmlNode grandchileNode in chileNode)
+ {
+ if (grandchileNode.Name == "Tilt") { openingDef.ParentTilt = Convert.ToDouble(grandchileNode.InnerText); }
+ else if (grandchileNode.Name == "Azimuth") { openingDef.ParentAzimuth = Convert.ToDouble(grandchileNode.InnerText); }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+
+ }
+ //get surface Id and Opening Type
+ XmlAttributeCollection openingAtts = openingNode.Attributes;
+ foreach (XmlAttribute at in openingAtts)
+ {
+ if (at.Name == "id")
+ {
+ openingDef.OpeningId = at.Value;
+ }
+ else if (at.Name == "openingType")
+ {
+ openingDef.OpeningType = at.Value;
+ }
+ }
+ if (openingNode.HasChildNodes)
+ {
+ XmlNodeList surfChildNodes = openingNode.ChildNodes;
+ foreach (XmlNode node in surfChildNodes)
+ {
+
+ if (node.Name == "RectangularGeometry")
+ {
+ if (node.HasChildNodes)
+ {
+ XmlNodeList rectGeomChildren = node.ChildNodes;
+ foreach (XmlNode rgChildNode in rectGeomChildren)
+ {
+ if (rgChildNode.Name == "Azimuth") { openingDef.Azimuth = Convert.ToDouble(rgChildNode.InnerText); }
+ else if (rgChildNode.Name == "CartesianPoint")
+ {
+ if (rgChildNode.HasChildNodes)
+ {
+ XmlNodeList coordinates = rgChildNode.ChildNodes;
+ int pointCount = 1;
+ foreach (XmlNode coordinate in coordinates)
+ {
+ switch (pointCount)
+ {
+ case 1:
+ openingDef.InsertionPoint.X = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 2:
+ openingDef.InsertionPoint.Y = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 3:
+ openingDef.InsertionPoint.Z = Convert.ToDouble(coordinate.InnerText);
+ break;
+ }
+ pointCount++;
+ }
+ }
+ }
+ else if (rgChildNode.Name == "Tilt") { openingDef.Tilt = Convert.ToDouble(rgChildNode.InnerText); }
+ else if (rgChildNode.Name == "Height") { openingDef.Height = Convert.ToDouble(rgChildNode.InnerText); }
+ else if (rgChildNode.Name == "Width") { openingDef.Width = Convert.ToDouble(rgChildNode.InnerText); }
+ }
+ }
+ }
+ else if (node.Name == "PlanarGeometry")
+ {
+ XmlNode polyLoop = node.FirstChild;
+ if (polyLoop.HasChildNodes)
+ {
+ XmlNodeList cartesianPoints = polyLoop.ChildNodes;
+ foreach (XmlNode coordinatePt in cartesianPoints)
+ {
+ Vector.CartCoord coord = new Vector.CartCoord();
+ if (coordinatePt.HasChildNodes)
+ {
+ XmlNodeList coordinates = coordinatePt.ChildNodes;
+ int pointCount = 1;
+ foreach (XmlNode coordinate in coordinatePt)
+ {
+
+ switch (pointCount)
+ {
+ case 1:
+ coord.X = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 2:
+ coord.Y = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 3:
+ coord.Z = Convert.ToDouble(coordinate.InnerText);
+ break;
+ }
+ pointCount++;
+ }
+ openingDef.PlCoords.Add(coord);
+ }
+ }
+ }
+ }
+ }
+ }
+ Vector.CartVect plRHRVect = GetPLRHR(openingDef.PlCoords);
+ openingDef.PlRHRVector = plRHRVect;
+ //may want to forego the above since the orientation is embedded in the parent object. It may be smarter to just include the azimuth and tilt of the parent object?
+ openings.Add(openingDef);
+ }
+
+ return openings;
+ }
+ catch (Exception e)
+ {
+ return openings;
+ }
+ }
+
+ private DOEgbXMLReportingObj TestSurfacePlanarTest(List TestSurfaces, DOEgbXMLReportingObj report)
+ {
+ //ensure that each set of RHR tests result in parallel or anti-parallel resultant vectors, or else fail the test
+
+ foreach (SurfaceDefinitions ts in TestSurfaces)
+ {
+ Dictionary> surfaceXProducts = new Dictionary>();
+ List xProducts = new List();
+ for (int i = 0; i < ts.PlCoords.Count - 2; i++)
+ {
+ //Get the Cross Product
+ VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(ts.PlCoords[i], ts.PlCoords[i + 1]);
+ VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(ts.PlCoords[i + 1], ts.PlCoords[i + 2]);
+ Vector.CartVect xProd = Vector.CrossProduct(v1, v2);
+ xProd = Vector.UnitVector(xProd);
+ xProducts.Add(xProd);
+ }
+ surfaceXProducts.Add(ts.SurfaceId, xProducts);
+ for (int j = 0; j < xProducts.Count - 1; j++)
+ {
+ //parallel and anti parallel
+ if (xProducts[j].X == xProducts[j + 1].X && xProducts[j].Y == xProducts[j + 1].Y && xProducts[j].Z == xProducts[j + 1].Z)
+ {
+ continue;
+ }
+ //anti-parallel
+ else if (xProducts[j].X == -1 * xProducts[j + 1].X && xProducts[j].Y == -1 * xProducts[j + 1].Y && xProducts[j].Z == -1 * xProducts[j + 1].Z)
+ {
+ continue;
+ }
+ else if (Math.Abs(xProducts[j].X) - Math.Abs(xProducts[j + 1].X) < .0001 && Math.Abs(xProducts[j].Y) - Math.Abs(xProducts[j + 1].Y) < .0001 &&
+ Math.Abs(xProducts[j].Z) - Math.Abs(xProducts[j + 1].Z) < 0.0001)
+ {
+ continue;
+ }
+ else
+ {
+ report.MessageList.Add("Test file's Surface, id: " + ts.SurfaceId + " has polyLoop coordinates that do not form a planar surface. This fails the detailed surface tests and will not continue.");
+ report.passOrFail = false;
+ report.longMsg = "Detailed surface test failed during the planar surface checks. Without planar surfaces, this test cannot be safely executed.";
+ return report;
+ }
+ }
+ }
+ report.MessageList.Add("All test file's surfaces have polyloop descriptions that describe a planar surface. Planar surface test succeeded.");
+ report.passOrFail = true;
+ return report;
+
+ }
+
+ private DOEgbXMLReportingObj TestOpeningPlanarTest(List TestOpenings, DOEgbXMLReportingObj report)
+ {
+ //ensure that each set of RHR tests result in parallel or anti-parallel resultant vectors, or else fail the test
+
+ foreach (OpeningDefinitions to in TestOpenings)
+ {
+ Dictionary> surfaceXProducts = new Dictionary>();
+ List xProducts = new List();
+ for (int i = 0; i < to.PlCoords.Count - 2; i++)
+ {
+ //Get the Cross Product
+ VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(to.PlCoords[i], to.PlCoords[i + 1]);
+ VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(to.PlCoords[i + 1], to.PlCoords[i + 2]);
+ Vector.CartVect xProd = Vector.CrossProduct(v1, v2);
+ xProd = Vector.UnitVector(xProd);
+ xProducts.Add(xProd);
+ }
+ surfaceXProducts.Add(to.OpeningId, xProducts);
+ for (int j = 0; j < xProducts.Count - 1; j++)
+ {
+ //parallel
+ if (xProducts[j].X == xProducts[j + 1].X && xProducts[j].Y == xProducts[j + 1].Y && xProducts[j].Z == xProducts[j + 1].Z)
+ {
+ continue;
+ }
+ //anti-parallel
+ else if (xProducts[j].X == -1 * xProducts[j + 1].X && xProducts[j].Y == -1 * xProducts[j + 1].Y && xProducts[j].Z == -1 * xProducts[j + 1].Z)
+ {
+ continue;
+ }
+ else
+ {
+ report.MessageList.Add("Test file's Opening, id: " + to.OpeningId +
+ " has polyLoop coordinates that do not form a planar surface. This fails the detailed surface tests and will not continue.");
+ report.passOrFail = false;
+ report.longMsg = "Detailed opening test failed during the planar surface checks. Without planar polygons, this test cannot be safely executed.";
+ return report;
+ }
+ }
+ }
+ report.MessageList.Add("All test file's surfaces have polyloop descriptions that describe a plana polygon. Planar opening test succeeded.");
+ report.passOrFail = true;
+ return report;
+
+ }
+
+ public static DOEgbXMLReportingObj GetBuildingArea(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, Conversions.areaUnitEnum standardUnits,Conversions.areaUnitEnum testUnits, double conversion)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary = "This test compares the values stored in the Building Area node of the standard and test gbXML files.";
+ report.testSummary += " This Building area is the sum total of the areas of all spaces created in gbXML.";
+ report.testSummary += " For example, if a small building has five spaces of area = 100 square feet each, then the sum of that area is";
+ report.testSummary += " 5 x 100 = 500 square feet. The building area value would be 500 square feet.";
+ report.testSummary += " We have built a tolerance in this test, meaning the building areas do not need to match perfectly in the";
+ report.testSummary += " standard file and test file. As long as your test file's value for Building Area is +/- this tolerance, the";
+ report.testSummary += " test will pass. Using the previous example, if the allowable tolerance is 1% (1% of 500 is 5 sf), then the test file may have a building area ranging from 495 to 505 square feet, and will still be declared to pass this test.";
+
+ report.unit = standardUnits.ToString();
+ string testUOM = testUnits.ToString();
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ var node = gbXMLDocs[i].SelectSingleNode("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Area", gbXMLnsm[i]);
+ string area = node.InnerText;
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = area;
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ if(conversion != 1) { report.MessageList.Add("Converted the test file from " + testUOM + " to " + report.unit + "."); }
+ //apply the conversion factor on the test file always, regardless.
+ double standardArea = Convert.ToDouble(resultsArray[i]);
+ double testArea = Convert.ToDouble(resultsArray[(i - 1)]) * conversion;
+ report.standResult.Add(String.Format("{0:#,0.00}", standardArea.ToString()));
+ report.testResult.Add(String.Format("{0:#,0.00}", testArea.ToString()));
+ report.idList.Add("");
+
+
+ double difference = standardArea - testArea;
+ if (Math.Abs(difference) == 0)
+ {
+ report.longMsg = "The test file's " + report.testType + "matches the standard file Building Area exactly.";
+ report.passOrFail = true;
+ return report;
+ }
+
+ else if (Math.Abs(difference) <= report.tolerance)
+ {
+ report.longMsg = "The test file's " + report.testType + " is within the allowable tolerance of = " + report.tolerance.ToString() + " " + report.unit;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The test file's " + report.testType + " is not within the allowable tolerance of " + report.tolerance.ToString() + " " + report.unit + "The difference between the standard and test file is " + difference.ToString() + ".";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ public static DOEgbXMLReportingObj GetBuildingSpaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary = "This test compares the number of spaces (it counts them) in the standard and test files. It does this";
+ report.testSummary = " by counting the number of occurrences of the Space element in the gbXML files. The number of spaces should";
+ report.testSummary = " match exactly. If you test has failed, this is because it is required that the space count match. If the number";
+ report.testSummary = " of spaces does not match, there could be a number of reasons for this, but most likely, the test file has";
+ report.testSummary = " not been constructed as per the instructions provided by the gbXML Test Case Manual.";
+
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbXMLns);
+ int nodecount = nodes.Count;
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = " The test file's " + report.testType + " matches the standard file exactly.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = " The test file's " + report.testType + " matches the standard file " + report.testType + ", the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The test file's " + report.testType + " is not within the allowable tolerance of " + report.tolerance.ToString() + " " + Units + " The difference between the standard and test file is " + difference.ToString() + " " + Units;
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate Building " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ public static DOEgbXMLReportingObj GetBuildingStoryCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary = "This test compares the number of stories (it counts them) in the standard and test files. It does so by";
+ report.testSummary += " counting the number of occurances of a Building Storey element in the gbXML files.";
+ report.testSummary += " The number of stories should match exactly. If your test failed, the number of stories in your file does";
+ report.testSummary += " not match the standard file. If the number of stories does not match, ";
+ report.testSummary += " most likely, the test file has not been constructed as per the instructions provided by the";
+ report.testSummary += " gbXML Test Case Manual.";
+ report.testSummary += " In some instances, it is not required that the number of stories match. If you notice that the number";
+ report.testSummary += " of stories do not match, but the test summary showed your file passed, then this is normal. Refer to the pass/fail";
+ report.testSummary += " summary sheet for more information.";
+
+ report.unit = Units;
+
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey", gbXMLns);
+ int nodecount = nodes.Count;
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = " The test file's " + report.testType + " matches the standard file exactly.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = " The test file's " + report.testType + " matches the standard file " + report.testType + ", the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The test file's " + report.testType + " is not within the allowable tolerance of " + report.tolerance.ToString() + " " + Units + " The difference between the standard and test file is " + difference.ToString() + " " + Units;
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg += " Failed to locate Building " + report.testType + " in the XML file.";
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ return report;
+ }
+
+ public static DOEgbXMLReportingObj GetStoryHeights(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, Conversions.lengthUnitEnum standardLength, Conversions.lengthUnitEnum testLength, double conversion)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added March 14 2013
+ report.testSummary = "This test compares Z-coordinates in each one of the levels of the standard and test file. It does so by";
+ report.testSummary += " gathering the Z-coordinate of a Building Storey element's PolyLoop in the gbXML files.";
+ report.testSummary += " The z-heights should match exactly. If this test has failed, then one of the z-heights in your file does";
+ report.testSummary += " not match the standard file. There is no tolerance for error in this test. If any of the z-heights do not match, ";
+ report.testSummary += " most likely, the test file has not been constructed as per the instructions provided by the";
+ report.testSummary += " gbXML Test Case Manual.";
+ report.testSummary += " In some instances, it is not required that the z-heights match. If you notice that this test has failed";
+ report.testSummary += " but your file overall has still passed, then this is as designed. Refer to the pass/fail";
+ report.testSummary += " summary sheet for more information.";
+
+ report.unit = standardLength.ToString();
+ string testUOM = testLength.ToString();
+ //small dictionaries I make to keep track of the story level names and heights
+ //standard file
+ Dictionary standardStoryHeight = new Dictionary();
+ //Test File
+ Dictionary testStoryHeight = new Dictionary();
+ string key = null;
+ string val = null;
+ string standLevel = "";
+
+
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ try
+ {
+ //assuming that this will be plenty large for now
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey", gbXMLns);
+ int nodecount = nodes.Count;
+ foreach (XmlNode node in nodes)
+ {
+ XmlNodeList childNodes = node.ChildNodes;
+ foreach (XmlNode childNode in childNodes)
+ {
+ if (childNode.Name.ToString() == "Level") { key = childNode.InnerText; }
+ else if (childNode.Name.ToString() == "Name") { val = childNode.InnerText; }
+ else { continue; }
+ if (i % 2 != 0)
+ {
+ if (key != null && val != null)
+ {
+ double testlevelvalue = Convert.ToDouble(val) * conversion;
+ testStoryHeight.Add(key, testlevelvalue);
+ key = null;
+ val = null;
+ }
+ else
+ {
+
+ }
+ }
+ else
+ {
+ if (key != null && val != null)
+ {
+ double standardlevelvalue = Convert.ToDouble(val);
+ standardStoryHeight.Add(key, standardlevelvalue);
+ key = null;
+ val = null;
+ }
+ else
+ {
+
+ }
+ }
+ }
+ }
+
+ //reporting
+ if (i % 2 != 0)
+ {
+ if (standardStoryHeight.Count == 0)
+ {
+ report.longMsg = "Test cannot be completed. Standard File Level Count returns Zero.";
+ report.passOrFail = false;
+ return report;
+ }
+ else if (testStoryHeight.Count == 0)
+ {
+ report.longMsg = "Test cannot be completed. Test File Level Count returns Zero.";
+ report.passOrFail = false;
+ return report;
+ }
+ else
+ {
+ //set pass to true
+ report.passOrFail = true;
+ int count = 0;
+ foreach (KeyValuePair standardPair2 in standardStoryHeight)
+ {
+ count++;
+ double difference;
+ StoryHeightMin = 10000;
+ string equivLevel = "";
+ if (testStoryHeight.ContainsKey(standardPair2.Key))
+ {
+ double matchkeydiff = Math.Abs(standardPair2.Value - testStoryHeight[standardPair2.Key]);
+ if(matchkeydiff == 0)
+ {
+ report.MessageList.Add("Matched Standard File's " + standardPair2.Value + " with Test File's " + testStoryHeight[standardPair2.Key] + " @ " + standardPair2.Key + report.unit + " Exactly");
+ report.TestPassedDict.Add(standardPair2.Value.ToString(), true);
+ continue;
+ }
+ else if(matchkeydiff < report.tolerance)
+ {
+ report.MessageList.Add("Matched Standard File's " + standardPair2.Value + " with Test File's " + testStoryHeight[standardPair2.Key] + " @ " + standardPair2.Key + report.unit + " within allowable tolerance.");
+ report.TestPassedDict.Add(standardPair2.Value.ToString(), true);
+ continue;
+ }
+ else
+ {
+ report.MessageList.Add("Did NOT Match Standard File's " + standardPair2.Value + " with Test File's " + testStoryHeight[standardPair2.Key] + " @ " + standardPair2.Key + report.unit + " within allowable tolerance.");
+ report.TestPassedDict.Add(standardPair2.Value.ToString(), true);
+ continue;
+ }
+
+ }
+ foreach (KeyValuePair testPair in testStoryHeight)
+ {
+ //setup standard result and test result
+
+ report.standResult.Add(standardPair2.Key);
+ report.testResult.Add(testPair.Key);
+ report.idList.Add(Convert.ToString(count));
+
+ difference = Math.Abs(Convert.ToDouble(standardPair2.Key) - Convert.ToDouble(testPair.Key)*conversion);
+ //store all levels and the difference between them
+ if (StoryHeightMin > difference)
+ {
+ StoryHeightMin = difference;
+ standLevel = standardPair2.Value.ToString();
+ }
+ }
+ if (StoryHeightMin < report.tolerance)
+ {
+ report.MessageList.Add("Matched Standard File's " + standardPair2.Value + " @ " + standardPair2.Key + report.unit + " within the Tolerance allowed");
+ report.TestPassedDict.Add(standLevel, true);
+ }
+ else
+ {
+ report.MessageList.Add("Standard File's " + standardPair2.Value + " equivalent was not found in the test file. The closest level in the test file was found at " + equivLevel + " in the test file. The difference in heights was " + StoryHeightMin.ToString() + report.unit);
+ report.TestPassedDict.Add(standLevel, false);
+ }
+
+ }
+ return report;
+ }
+ }
+ }
+
+ catch (Exception e)
+ {
+ report.longMsg = e.ToString();
+ report.MessageList.Add(" Failed to locate Building " + report.testType + " in the XML file.");
+ report.passOrFail = false;
+ return report;
+ }
+
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ public static DOEgbXMLReportingObj TestBuildingStoryRHR(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary = "This test analyzes each of the story PolyLoop coordinates in the standard and test files. These PolyLoop ";
+ report.testSummary += "coordinates define the z-height and orientation of each story plane. This test analyzes the normal vector ";
+ report.testSummary += "created by the PolyLoop coordinates. The PolyLoop coordinates must be sequenced in a counterclockwise manner ";
+ report.testSummary += " such that when the right hand rule is applied to this sequence of coordinates, a resultant normal vector ";
+ report.testSummary += " will point in the +z direction.";
+ report.testSummary += " If the PolyLoop coordinates do not form vectors that point in the +Z direction";
+ report.testSummary += " (when the right hand rule is applied), then this test will fail. It is assumed that the vectors that define";
+ report.testSummary += " the story plane will be parallel to the X-Y axis.The tolerance is always zero for this test, ";
+ report.testSummary += "meaning the resulting unit vector will point in the positive Z direction with no margin for error.";
+
+ report.unit = Units;
+
+ //stores the level's z heights
+ List LevelZs = new List();
+ //stores the list of z heights for both files
+ List> fileLevelZz = new List>();
+ //stores the RHR x product and the corresonding z height for a level
+ Dictionary levelVct = new Dictionary();
+ //stores a list of the RHR x product and corresponding z height for both files
+ List> fileLevelVct = new List>();
+
+ VectorMath.Vector.CartVect vector = new VectorMath.Vector.CartVect();
+
+ int errorCount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+
+
+ try
+ {
+ //refresh
+ LevelZs.Clear();
+ levelVct.Clear();
+
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+ //maybe it would be good if the test result spits out the name of the story? TBD
+ XmlNodeList PlanarGeometry = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry", gbXMLns);
+ XmlNodeList PolyLoops = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry/gbXMLv5:PolyLoop", gbXMLns);
+ int nodecount = PolyLoops.Count;
+ //get the normals for each level in the Standard File
+ //get the z-coordinate for each level (we assume that the levels are going to be parallel to Z
+ LevelZs = GetLevelZs(PlanarGeometry, LevelZs);
+ foreach (string level in LevelZs)
+ {
+ //a simple attempt to filter out exceptions, which could be returned in some instances
+ if (level.Length < 10)
+ {
+ vector = GetPolyLoopXProduct(PlanarGeometry, level, report.testType);
+ string levelValue = level;
+ //if (i == 0) { levelValue += "-T"; }
+ //else { levelValue += "-S"; }
+ levelVct.Add(levelValue, vector);
+ }
+ }
+ fileLevelZz.Add(LevelZs);
+ fileLevelVct.Add(levelVct);
+
+ //reporting
+ if (i % 2 != 0)
+ {
+ Dictionary standDict = fileLevelVct[1];
+ Dictionary testDict = fileLevelVct[0];
+ foreach (KeyValuePair pair in standDict)
+ {
+
+ if (testDict.ContainsKey(pair.Key))
+ {
+ report.MessageList.Add("While searching for matching building levels, there has been a Successful match. Building Story Level " + pair.Key + " in the Standard file found a match in the Test File.");
+ report.passOrFail = true;
+ //perform cross product again of the two vectors in question. The result should be a zero since they should be parallel
+ VectorMath.Vector.CartVect rhrTestVector = VectorMath.Vector.CrossProduct(testDict[pair.Key], standDict[pair.Key]);
+ if (rhrTestVector.X == 0 && rhrTestVector.Y == 0 && rhrTestVector.Z == 0)
+ {
+ report.MessageList.Add("For this level match, there is Normal Vector Test Success. The right hand rule test identified a parallel normal vector for Level " + pair.Key + " in both the Standard and Test gbXML Files.");
+ report.passOrFail = true;
+ }
+ else
+ {
+ VectorMath.Vector.CartVect rhrTestVectorU = VectorMath.Vector.UnitVector(rhrTestVector);
+ //create a test to determine the angular difference between the two vectors is within tolerance
+ //|A||B|cos theta = A x B
+
+ //if the angle is within the allowable tolerance, then pass the test with a note that the vectors
+ //were not parallel
+ }
+
+ }
+ else
+ {
+ report.MessageList.Add("The right hand rule test for Level " + pair.Key + " in the Standard File could not be completed. A match for this level could not be found in the test file.");
+ report.passOrFail = false;
+ errorCount++;
+ }
+ }
+
+ }
+ else { continue; }
+
+ //need to comapre and have if then statement depending on the outcome of the accuracy tests
+ if (errorCount == 0)
+ {
+ report.longMsg = "Test Success: Building Stories RHR in the Test File match the RHR in the Standard File for all Levels.";
+ }
+ else
+ {
+ report.longMsg = "Not all levels in the Standard File found equivalent levels and normal vectors in the Test File.";
+ }
+ return report;
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to complete RHR Test for the Building Storey Nodes. Exception noted.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ return report;
+ }
+
+ //this is a support function used by the GetLevelHeights function above. It is not directly,
+ //iteslf, a test
+ private static List GetLevelZs(XmlNodeList PlanarGeometry, List LevelZs)
+ {
+ string result = "";
+ int polyLoopCount = 0;
+ try
+ {
+ int nodecount = PlanarGeometry.Count;
+ VectorMath.Vector.CartCoord[] vCoords = new VectorMath.Vector.CartCoord[nodecount];
+ foreach (XmlNode PolyLoops in PlanarGeometry)
+ {
+ //gathers all the cartesian points in a given polyloop
+ foreach (XmlNode cartesianPoints in PolyLoops)
+ {
+
+ //test the polyloop RHR convention
+ //count the total number of cartesian coordinates
+ int coordcount = cartesianPoints.ChildNodes.Count;
+ //I may want to test the number of coordinates to make sure it matches
+ //I do want to ensure I have a minimum number of coords
+ if (coordcount < minPlanePoints)
+ {
+ result += "Insufficient number of cartesian points to define a plane";
+ LevelZs.Add(result);
+ return LevelZs;
+ }
+ else
+ {
+ int cartPtCount = 0;
+ //gets a set of XYZ coordinates, one at a time
+ foreach (XmlNode coordinates in cartesianPoints.ChildNodes)
+ {
+ //I will only test one Z-coordinate in each set of coordinates
+ if (cartPtCount < 1)
+ {
+ VectorMath.Vector.CartCoord vC = new VectorMath.Vector.CartCoord();
+ vCoords[polyLoopCount] = vC;
+ }
+ else { break; }
+
+ int crdCount = 1;
+ //gets each coordinate one at a time
+ foreach (XmlNode coordinate in coordinates.ChildNodes)
+ {
+ double coord = Convert.ToDouble(coordinate.InnerText);
+ switch (crdCount)
+ {
+ case 1:
+ vCoords[polyLoopCount].X = coord;
+ break;
+ case 2:
+ vCoords[polyLoopCount].Y = coord;
+ break;
+ case 3:
+ vCoords[polyLoopCount].Z = coord;
+ break;
+ default:
+ break;
+ }
+ crdCount++;
+ }
+ cartPtCount++;
+ }
+ }
+
+ }
+ polyLoopCount++;
+ }
+ //create the List that holds the z-values of each level
+ for (int z = 0; z < nodecount; z++)
+ {
+ LevelZs.Add(vCoords[z].Z.ToString());
+ }
+
+ return LevelZs;
+ }
+
+ catch (Exception e)
+ {
+ result += e.ToString();
+ LevelZs.Add(result);
+ return LevelZs;
+ }
+ }
+ //this is a simple way to get the polyLoop X product.
+ //this is a support function used by the Function TestBuildingStory RHR above
+ //This X Product routine is the first attempt to produce a X product from coordinates Since the coordinates used to define
+ //a level plane never create an irregular polygon, this scheme worked.
+ //it will only assuredly work properly for a triangle, square, or rectangle. Shapes other than these should use subsequent XProduct
+ //functions as created below.
+ //Created by CHarriman, Senior Product Manager Carmel Software
+ //Nov 2012
+ public static VectorMath.Vector.CartVect GetPolyLoopXProduct(XmlNodeList PlanarGeometry, string level, TestType testType)
+ {
+ int cartPtCount = 0;
+ VectorMath.Vector.CartVect xProd = new VectorMath.Vector.CartVect();
+ //gathers all the cartesian points in a given polyloop
+ int nodecount = PlanarGeometry.Count;
+ VectorMath.Vector.CartCoord[] vCoords = new VectorMath.Vector.CartCoord[3];
+ foreach (XmlNode PolyLoops in PlanarGeometry)
+ {
+ foreach (XmlNode cartesianPoints in PolyLoops)
+ {
+
+ //test the polyloop RHR convention
+ //count the total number of cartesian coordinates
+ int coordcount = cartesianPoints.ChildNodes.Count;
+ //I may want to test the number of coordinates to make sure it matches, or if it has a minimum number of coords
+ if (coordcount < minPlanePoints)
+ {
+ //result += "Insufficient number of cartesian points to define a plane";
+ return xProd;
+ }
+ else
+ {
+ cartPtCount = 0;
+ //gets a set of XYZ coordinates, one at a time
+ foreach (XmlNode coordinates in cartesianPoints.ChildNodes)
+ {
+ if (cartPtCount < 3)
+ {
+ VectorMath.Vector.CartCoord vC = new VectorMath.Vector.CartCoord();
+ vCoords[cartPtCount] = vC;
+ }
+ else { break; }
+
+ int crdCount = 1;
+ //gets each coordinate one at a time
+ //filtering through the inner children of the PolyLoop
+ foreach (XmlNode coordinate in coordinates.ChildNodes)
+ {
+ double coord = Convert.ToDouble(coordinate.InnerText);
+ switch (crdCount)
+ {
+ case 1:
+ vCoords[cartPtCount].X = coord;
+ break;
+ case 2:
+ vCoords[cartPtCount].Y = coord;
+ break;
+ case 3:
+ vCoords[cartPtCount].Z = coord;
+ break;
+ default:
+ break;
+ }
+ if (vCoords[cartPtCount].Z.ToString() == level) { break; };
+ crdCount++;
+ }
+
+ cartPtCount++;
+ }
+
+ }
+ }
+ if (vCoords[(cartPtCount - 1)].Z.ToString() == level) { break; }
+ }
+ //Get the Cross Product
+ VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(vCoords[0], vCoords[1]);
+ VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(vCoords[1], vCoords[2]);
+ xProd = VectorMath.Vector.CrossProduct(v1, v2);
+ xProd = Vector.UnitVector(xProd);
+ return xProd;
+
+ }
+
+ //this test was originally invented for the case where the proposed and test cases did not have to be identical
+ //it was designed simply to ensure that only the TEST file had unique SpaceId values.
+ //Created by CHarriman Senior Product Manager Carmel Software
+ //Nov 2012
+ public static DOEgbXMLReportingObj UniqueSpaceIdTest(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary = "This test reviews the test file's Space id values, and ensures that they are all unique. If there are any duplicate Space id values, then this test will fail. If there are duplicates, the remainder of the tests in the testbed are not executed and the test will end here until the test file is properly updated. Each Space id must be unique for the test bed to successfully execute. If you have failed this test, please review the documents for this test and resubmit the test.";
+
+ report.MessageList = new List();
+ report.TestPassedDict = new Dictionary();
+ List standardIdList = new List();
+ List testIDList = new List();
+ report.standResult = new List();
+ report.testResult = new List();
+ report.idList = new List();
+ // report.testType = "UniqueId";
+ try
+ {
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbXMLns);
+ foreach (XmlNode node in nodes)
+ {
+ //looks to see if the spaceId is already included in the list of space IDs being generated
+ string spaceId;
+ if (i % 2 != 0)
+ {
+ spaceId = node.Attributes[0].Value.ToString();
+ testIDList.Add(spaceId);
+ }
+ else
+ {
+ spaceId = node.Attributes[0].Value.ToString();
+ standardIdList.Add(spaceId);
+ }
+ }
+ }
+ //now that I have all of the spaceIds, I will loop through and make sure I have perfect matches
+ //the order of the spaces is not enforced
+ //create a list that holds the index of the standardIdList when a match is found
+ //the list should be the same length as standardIdlist and each value should be unique
+ List indexFound = new List();
+ for (int j = 0; j < standardIdList.Count; j++)
+ {
+ string standardId = standardIdList[j];
+ foreach (string testspaceId in testIDList)
+ {
+ if (testspaceId == standardId)
+ {
+ indexFound.Add(j);
+ report.MessageList.Add("The standard file space id: " + standardId + "has found a spaceId match in the test file.");
+ }
+ }
+ }
+ //search the list to make sure that it is unique and has the proper count
+ if (indexFound.Count == standardIdList.Count)
+ {
+ report.MessageList.Add("The standard file has found a match only once in the test file. All spaceIds have been matched.");
+ report.passOrFail = true;
+ report.longMsg = "SpaceId Match test has passed.";
+ return report;
+ }
+ else
+ {
+ report.passOrFail = false;
+ string index = "";
+ foreach (int p in indexFound)
+ {
+ index += p.ToString() + ", ";
+ }
+ report.MessageList.Add(index);
+ report.longMsg = "SpaceId Match test has failed.";
+ return report;
+ }
+
+ //if (standardIdList.Contains(spaceId))
+ //{
+ // report.testResult.Add("Not Unique");
+
+ // report.longMsg = "Unique SpaceID Test Failed. " + spaceId + " is already included once in the test file.";
+ // report.passOrFail = false;
+ // report.TestPassedDict[spaceId] = false;
+ // return report;
+ //}
+ //else
+ //{
+ // report.testResult.Add("Is Unique");
+
+ // spaceId = node.Attributes[0].Value.ToString();
+ // standardIdList.Add(spaceId);
+ // report.passOrFail = true;
+ // report.TestPassedDict.Add(spaceId, true);
+ // report.MessageList.Add(spaceId + " is unique.");
+ //}
+ }
+ catch (Exception e)
+ {
+ report.longMsg = e.ToString();
+ report.passOrFail = false;
+ return report;
+ }
+ return report;
+ }
+
+ public static DOEgbXMLReportingObj TestSpaceAreas(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, Conversions.areaUnitEnum standardUnits, Conversions.areaUnitEnum testUnits, double conversion)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary = "This test compares the square footage of spaces in the test and standard files. It does this by searching";
+ report.testSummary += "for a unique Space id in both the test and standard files, and finding a match. Once a match is found, it then";
+ report.testSummary += " finds the square footage reported for the Space area, and compares them to ensure they are the same or";
+ report.testSummary += " within tolerance. For example, if the standard file has a Space with id = \"Space-1\" with an area of";
+ report.testSummary += "250 square feet, then this test searches through the test file for a Space with the identical id.";
+ report.testSummary += " Once this space has been located, the test then compares the Area to 250 square feet. ";
+ report.testSummary += "If they are identical, the test is done, and passes. We have built a tolerance in this test, meaning the";
+ report.testSummary += " areas do not need to match perfectly in the standard file and test file. As long as your test file's value";
+ report.testSummary += " for Space Area is +/- this tolerance, the test will pass. Using the previous example, if the allowable";
+ report.testSummary += " tolerance is 1% (1% of 250 is 2.5 sf), then the test file may have a space area ranging from 247.5 to 252.5";
+ report.testSummary += " square feet, and the test will still delcare \"Pass\".";
+
+
+ report.unit = standardUnits.ToString();
+ report.passOrFail = true;
+ string spaceId = "";
+ //assuming that this will be plenty large for now
+ Dictionary standardFileAreaDict = new Dictionary();
+ Dictionary testFileAreaDict = new Dictionary();
+
+ try
+ {
+
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList spaceNodes = gbXMLDocs[i].SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:Area", gbXMLnsm[i]);
+ //make lists of the areas in each project
+ foreach (XmlNode spaceNode in spaceNodes)
+ {
+ string area = spaceNode.InnerText;
+ if (i % 2 != 0)
+ {
+ spaceId = spaceNode.ParentNode.Attributes[0].Value;
+ //no conversion necessary
+ standardFileAreaDict.Add(spaceId, Convert.ToDouble(area));
+ }
+ else
+ {
+ spaceId = spaceNode.ParentNode.Attributes[0].Value;
+ double convertedArea = Convert.ToDouble(area) * conversion;
+ testFileAreaDict.Add(spaceId, convertedArea);
+ }
+ }
+ }
+ var standardKeys = standardFileAreaDict.Keys;
+
+ foreach (string key in standardKeys)
+ {
+ if (testFileAreaDict.ContainsKey(key))
+ {
+ double testFileSpaceArea = testFileAreaDict[key];
+ double standardFileSpaceArea = standardFileAreaDict[key];
+
+
+ report.standResult.Add(String.Format("{0:#,0.00}",Convert.ToString(standardFileSpaceArea)));
+ report.testResult.Add(String.Format("{0:#,0.00}", Convert.ToString(testFileSpaceArea)));
+ report.idList.Add(key);
+
+ double difference = Math.Abs(testFileSpaceArea - standardFileSpaceArea);
+ if (difference == 0)
+ {
+ report.MessageList.Add("For Space Id: " + key + ". Success finding matching space area. The Standard File and the Test File both have a space with an area = " + String.Format("{0:#,0.00}", testFileSpaceArea.ToString()) + " " + report.unit + ". ");
+ report.TestPassedDict.Add(key, true);
+ }
+ else if (difference < report.tolerance)
+ {
+ report.MessageList.Add("For Space Id: " + key + ". Success finding matching space area. The Standard File space area of " + String.Format("{0:#,0.00}", standardFileSpaceArea.ToString()) + " and the Test File space area of " + String.Format("{0:#,0.00}", testFileSpaceArea.ToString()) + " " + report.unit + " is within the allowable tolerance of " + report.tolerance.ToString() + " " + report.unit);
+ report.TestPassedDict.Add(key, true);
+ }
+ else
+ {
+ report.MessageList.Add("For space Id: " + key + ". Failure to find an space area match. THe area equal to = " + String.Format("{0:#,0.00}", standardFileSpaceArea.ToString()) + " " + report.unit + " in the Standard File could not be found in the Test File. ");
+ report.TestPassedDict.Add(key, false);
+ }
+ }
+ else
+ {
+ report.standResult.Add("---");
+ report.testResult.Add("Could not be matched");
+ report.idList.Add(key);
+ //failure to match spaceIds
+ report.MessageList.Add("Test File and Standard File space names could not be matched. SpaceId: " + key + " could not be found in the test file.");
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ return report;
+ }
+
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = "Failed to complete the " + report.testType + ". See exceptions noted.";
+ report.passOrFail = false;
+ return report;
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ public static DOEgbXMLReportingObj TestSpaceVolumes(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.passOrFail = true;
+ string spaceId = "";
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ Dictionary standardFileVolumeDict = new Dictionary();
+ Dictionary testFileVolumeDict = new Dictionary();
+
+ try
+ {
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList spaceNodes = gbXMLDocs[i].SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:Volume", gbXMLnsm[i]);
+ //make lists of the areas in each project
+ foreach (XmlNode spaceNode in spaceNodes)
+ {
+ string volume = spaceNode.InnerText;
+ if (i % 2 != 0)
+ {
+ spaceId = spaceNode.ParentNode.Attributes[0].Value;
+ testFileVolumeDict.Add(spaceId, Convert.ToDouble(volume));
+ }
+ else
+ {
+ spaceId = spaceNode.ParentNode.Attributes[0].Value;
+ standardFileVolumeDict.Add(spaceId, Convert.ToDouble(volume));
+ }
+ }
+ }
+ var standardKeys = standardFileVolumeDict.Keys;
+ foreach (string key in standardKeys)
+ {
+ if (testFileVolumeDict.ContainsKey(key))
+ {
+ double standardFileVolume = standardFileVolumeDict[key];
+ double testFileVolume = testFileVolumeDict[key];
+
+ report.standResult.Add(Convert.ToString(standardFileVolume));
+ report.testResult.Add(Convert.ToString(testFileVolume));
+ report.idList.Add(key);
+
+ double difference = Math.Abs(testFileVolume - standardFileVolume);
+ if (difference == 0)
+ {
+ report.MessageList.Add("For Space Id: " + key + ". Success finding matching space volume. The Standard and Test Files both have identical volumes: " + testFileVolume + " " + Units + "for Space Id: " + key);
+ report.TestPassedDict.Add(key, true);
+ }
+ else if (difference < report.tolerance)
+ {
+ report.MessageList.Add("For Space Id: " + key + ". Success finding matching space volume. The Standard Files space volume of " + standardFileVolume.ToString() + " " + Units + "and the Test File space volume: " + testFileVolume + " are within the allowed tolerance of" + report.tolerance.ToString() + " " + Units + ".");
+ report.TestPassedDict.Add(key, true);
+ }
+ else
+ {
+ //at the point of failure, the test will return with details about which volume failed.
+ report.MessageList.Add("For Space Id: " + key + ". Failure to find a volume match. The Volume in the Test File equal to: " + testFileVolume.ToString() + " " + Units + " was not within the allowed tolerance. SpaceId: " + key + " in the Standard file has a volume: " + standardFileVolume.ToString() + " .");
+ report.TestPassedDict.Add(key, false);
+ }
+ }
+ else
+ {
+ report.standResult.Add("Space Id: " + key);
+ report.testResult.Add("Could not be matched");
+ report.idList.Add("");
+
+ //at the point of failure, the test will return with details about which volume failed.
+ report.MessageList.Add("Test File and Standard File space names could not be matched. SpaceId: " + key + " could not be found in the test file.");
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ return report;
+ }
+
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to complete the " + report.testType + ". See exceptions noted.";
+ report.passOrFail = false;
+ return report;
+ }
+
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ //this function was abandoned until the second phase
+ //Created Dec 2012 by CHarriman Senior Product Manager Carmel Software Corp
+
+ public static DOEgbXMLReportingObj TestShellGeomPLRHR(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ string result = "";
+ string floorarea = "";
+ report.unit = Units;
+ List VectList = new List();
+
+ //keeps a dictionary of the shell geometry points for each space of the test file key = spaceId, value = List of Coordinates
+ Dictionary> shellGeomPtsTF = new Dictionary>();
+ //keeps a dictionary of the shell geometry points for each space of the standard file key = spaceId, value = List of Coordinates
+ Dictionary> shellGeomPtsSF = new Dictionary>();
+ //keeps a dictinary of the RHR vectors of the Test file
+ Dictionary> shellGeomRHRTF = new Dictionary>();
+ //keeps a dictionary of the RHR vectors of the Standard file
+ Dictionary> shellGeomRHRSF = new Dictionary>();
+
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+ //for each space, gather some kind of qualifying information
+ XmlNodeList spaceNodes = gbXMLDocs[i].SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbXMLns);
+ foreach (XmlNode space in spaceNodes)
+ {
+ XmlNodeList spaceChildren = space.ChildNodes;
+ foreach (XmlNode spaceChild in spaceChildren)
+ {
+ if (spaceChild.Name == "ShellGeometry")
+ {
+ XmlNode closedShell = spaceChild.FirstChild;
+ switch (i)
+ {
+ case 0:
+ shellGeomPtsTF = GetShellGeomPts(closedShell);
+ break;
+ case 1:
+ shellGeomPtsSF = GetShellGeomPts(closedShell);
+ break;
+ default:
+ break;
+ }
+ //Determine if matches found everywhere
+
+ //Test the two sets of data points to find matches return the coordinate matches in the same order they
+ //are presented in the gbXML file
+
+ switch (i)
+ {
+ case 0:
+ shellGeomRHRTF = GetShellGeomPolyRHR(shellGeomPtsTF);
+ break;
+ case 1:
+ shellGeomRHRSF = GetShellGeomPolyRHR(shellGeomPtsSF);
+ break;
+ default:
+ break;
+
+ }
+
+ }
+
+ }
+ }
+
+
+ }
+ catch (Exception e)
+ {
+
+ }
+ return report;
+ }
+ return report;
+ }
+ //this is a support tool for TestShellGeomPLRHR
+ public static Dictionary> GetShellGeomPts(XmlNode closedShell)
+ {
+ Dictionary> PtsDict = new Dictionary>();
+
+ string spaceId = "none";
+
+ int cartPtCount;
+ try
+ {
+ //get the name of the space for which this point is defined
+ XmlNode spaceNode = closedShell.ParentNode;
+ XmlAttributeCollection spaceAtts = spaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "id")
+ {
+ spaceId = at.Value;
+ break;
+ }
+
+ }
+ //keep track of the number of polyloops in the closed shell
+ int pLCount = 1;
+ //store the geometry points
+ foreach (XmlNode PolyLoops in closedShell)
+ {
+ List vCoords = new List();
+ List PtsList = new List();
+ cartPtCount = 0;
+ foreach (XmlNode cartesianPoints in PolyLoops)
+ {
+ //reset surface area and unitRHR (this is how I know that there may be a problem
+ //and these values are returned as points. It is not perfect
+ Vector.CartCoord Pts = new Vector.CartCoord();
+ Pts.X = -999;
+ Pts.Y = -999;
+ Pts.Z = -999;
+ PtsList.Add(Pts);
+ int crdCount = 1;
+ //gets a set of XYZ coordinates, one at a time
+ foreach (XmlNode coordinate in cartesianPoints.ChildNodes)
+ {
+ double coord = Convert.ToDouble(coordinate.InnerText);
+ switch (crdCount)
+ {
+ case 1:
+
+ PtsList[cartPtCount].X = coord;
+ break;
+ case 2:
+
+ PtsList[cartPtCount].Y = coord;
+ break;
+ case 3:
+
+ PtsList[cartPtCount].Z = coord;
+ break;
+ default:
+ break;
+
+
+ }
+ crdCount++;
+ }
+ cartPtCount++;
+ }
+ string spaceSurface = spaceId + "/" + pLCount.ToString();
+
+ PtsDict.Add(spaceSurface, PtsList);
+ pLCount++;
+ //PtsList.Clear();
+ }
+ }
+ catch (Exception e)
+ {
+
+ }
+ //I may want to test the number of coordinates to make sure it matches, or if it has a minimum number of coords
+ return PtsDict;
+ }
+
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //Designed to take a Dictionary
+ //Each set of points are then turned into vectors, which are then put through a cross product to determine the
+ //normal vector. we only arbitrarily take the first three points in the list, which potentially could cause some issue.
+ //This is planned to be fixed in a future release.
+ //The normal vector calculated is the value in the key value pair, the key being the spaceId+surfaceNumber,
+ //The Dictionary is returned with it includes a key value pair for each surface it has analyzed.
+ //Therefore, if the Dictionary sent to it has 12 key value pairs, then it will return 12 key value pairs as well.
+ //This is not checked for explicitly but mentioned for clarity.
+ public static Dictionary> GetShellGeomPolyRHR(Dictionary> PtsList)
+ {
+ //reg expressions
+ string iDPatt = "(.+)[^/][0-9]";
+ string numPatt = "[0-9]+";
+
+ //initialize variables needed in this method
+ VectorMath.Vector.CartVect unitRHR = new VectorMath.Vector.CartVect();
+ List vCoords = new List();
+ List vVect = new List();
+ string spaceId = "none";
+ string spacenum = "";
+ //dictionary that will be returned by this method
+ Dictionary> plRHRDict = new Dictionary>();
+
+ //begin iterating through the Cartesian Points passed into the method (PtsList)
+ for (int i = 0; i < PtsList.Count; i++)
+ {
+ //get the identification strings associated with each list of points in the dictionary passed to the method
+ string spaceSurf = PtsList.Keys.ElementAt(i);
+ foreach (Match match in Regex.Matches(spaceSurf, iDPatt))
+ {
+ spaceId = match.ToString();
+ }
+ string spaceSurf2 = PtsList.Keys.ElementAt(i);
+ foreach (Match match in Regex.Matches(spaceSurf2, numPatt))
+ {
+ spacenum = match.ToString();
+ }
+
+ //take the list of coordinates and store them locally
+ //this step does not need to be taken, but it does simplify the coding a little bit.
+ foreach (Vector.CartCoord coord in PtsList.Values.ElementAt(i))
+ {
+ vCoords.Add(coord);
+ }
+ //just arbitrarily take the first 3 coordinates
+ //this can lead to bad results, but is used until the next release of the software
+ VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(vCoords[0], vCoords[1]);
+ VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(vCoords[1], vCoords[2]);
+ unitRHR = VectorMath.Vector.CrossProduct(v1, v2);
+ unitRHR = Vector.UnitVector(unitRHR);
+ vVect.Add(unitRHR);
+ vCoords.Clear();
+
+ }
+ plRHRDict.Add(spaceId, vVect);
+ return plRHRDict;
+ }
+
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //A simple method that reports the number of all surface elements in a test file and standard file
+ //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces.
+ public static DOEgbXMLReportingObj GetSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements in the test and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears in both files. If the ";
+ report.testSummary += "quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface";
+ report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test may pass even though this test failed.";
+ report.testSummary += " Refer to the pass/fail summary sheet for more information.";
+
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ int nodecount = nodes.Count;
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference;
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //A simple method that reports the number of surface elements whose surfaceType attribute = "ExteriorWall in a test file and standard file
+ //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces.
+ public static DOEgbXMLReportingObj GetEWSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"ExteriorWall\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this SurfaceType in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface";
+ report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed.";
+ report.testSummary += " Refer to the pass/fail summary sheet for more information.";
+
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "surfaceType")
+ {
+ string type = at.Value;
+ if (type == "ExteriorWall")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " exterior wall surfaces in the Standard File and " + resultsArray[i - 1] + " exterior wall surfaces in the Test File.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //A simple method that reports the number of surface elements whose surfaceType attribute = "InterirWall" in a test file and standard file
+ //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces.
+ public static DOEgbXMLReportingObj GetIWSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"InteriorWall\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this SurfaceType in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface";
+ report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed.";
+ report.testSummary += " Refer to the pass/fail summary sheet for more information.";
+
+ report.unit = Units;
+
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "surfaceType")
+ {
+ string type = at.Value;
+ if (type == "InteriorWall")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The Test File's" + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " interior wall surfaces in the standard file and " + resultsArray[i - 1] + " interior wall surfaces in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //A simple method that reports the number of surface elements whose surfaceType attribute = "InteriorFloor" in a test file and standard file
+ //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces.
+ public static DOEgbXMLReportingObj GetIFSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"InteriorFloor\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface";
+ report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed.";
+ report.testSummary += " Refer to the pass/fail summary sheet for more information.";
+
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "surfaceType")
+ {
+ string type = at.Value;
+ if (type == "InteriorFloor")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The Test File's" + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " interior floor surfaces in the standard file and " + resultsArray[i - 1] + " interior floor surfaces in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //A simple method that reports the number of surface elements whose surfaceType attribute = "Roof" in a test file and standard file
+ //If the number of roof surface elements is not the same, the method returns false and displays the difference in the number of surfaces.
+ public static DOEgbXMLReportingObj GetRoofSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"Roof\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface";
+ report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed.";
+ report.testSummary += " Refer to the pass/fail summary sheet for more information.";
+
+ report.unit = Units;
+
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "surfaceType")
+ {
+ string type = at.Value;
+ if (type == "Roof")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The Test File's" + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " roof surfaces in the standard file and " + resultsArray[i - 1] + " roof surfaces in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //A simple method that reports the number of surface elements whose surfaceType attribute = "Shade" in a test file and standard file
+ //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces.
+ public static DOEgbXMLReportingObj GetShadeSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"Shade\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface";
+ report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed.";
+ report.testSummary += " Refer to the pass/fail summary sheet for more information.";
+
+ report.unit = Units;
+
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "surfaceType")
+ {
+ string type = at.Value;
+ if (type == "Shade")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ if (difference == 0)
+ {
+ report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " shading surfaces in the standard file and " + resultsArray[i - 1] + " shading surfaces in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //A simple method that reports the number of surface elements whose surfaceType attribute = "Air" in a test file and standard file
+ //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces.
+ public static DOEgbXMLReportingObj GetAirSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"Air\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+ report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface";
+ report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed.";
+ report.testSummary += " Refer to the pass/fail summary sheet for more information.";
+
+ report.unit = Units;
+
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "surfaceType")
+ {
+ string type = at.Value;
+ if (type == "Air")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference == 0)
+ {
+ report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero.";
+ report.passOrFail = true;
+ return report;
+ }
+ else if (difference <= report.tolerance)
+ {
+ report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " air surfaces in the standard file and " + resultsArray[i - 1] + " air surfaces in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+ //
+ //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation
+ //This method will take each surface element and convert the xml language into an instance of a SurfaceDefinition
+ //Each surface is converted in this way, with the resulting instance being stored in a list that is returned for later use
+ //----------------------
+ //This is an important method because it stores all of the information about a surface in a gbXML file in a list
+ //This list can later be recalled to perform analytics on the surfaces and the data contained within
+ private static List GetFileSurfaceDefs(XmlDocument xmldoc, XmlNamespaceManager xmlns)
+ {
+ List surfaces = new List();
+ try
+ {
+
+ XmlNodeList nodes = xmldoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", xmlns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ //initialize a new instance of the class
+ SurfaceDefinitions surfDef = new SurfaceDefinitions();
+ surfDef.AdjSpaceId = new List();
+ surfDef.PlCoords = new List();
+ surfDef.InsertionPoint = new Vector.CartCoord();
+ surfDef.PlRHRVector = new Vector.CartVect();
+
+ //get id and surfaceType
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "id")
+ {
+ surfDef.SurfaceId = at.Value;
+ }
+ else if (at.Name == "surfaceType")
+ {
+ surfDef.SurfaceType = at.Value;
+ }
+ }
+ if (surfaceNode.HasChildNodes)
+ {
+ XmlNodeList surfChildNodes = surfaceNode.ChildNodes;
+ foreach (XmlNode node in surfChildNodes)
+ {
+ if (node.Name == "AdjacentSpaceId")
+ {
+ XmlAttributeCollection adjSpaceIdAt = node.Attributes;
+ foreach (XmlAttribute at in adjSpaceIdAt)
+ {
+ if (at.Name == "spaceIdRef")
+ {
+ surfDef.AdjSpaceId.Add(at.Value);
+ }
+ }
+ }
+ else if (node.Name == "RectangularGeometry")
+ {
+ if (node.HasChildNodes)
+ {
+ XmlNodeList rectGeomChildren = node.ChildNodes;
+ foreach (XmlNode rgChildNode in rectGeomChildren)
+ {
+ if (rgChildNode.Name == "Azimuth") { surfDef.Azimuth = Convert.ToDouble(rgChildNode.InnerText); }
+ else if (rgChildNode.Name == "CartesianPoint")
+ {
+ if (rgChildNode.HasChildNodes)
+ {
+ XmlNodeList coordinates = rgChildNode.ChildNodes;
+ int pointCount = 1;
+ foreach (XmlNode coordinate in coordinates)
+ {
+ switch (pointCount)
+ {
+ case 1:
+ surfDef.InsertionPoint.X = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 2:
+ surfDef.InsertionPoint.Y = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 3:
+ surfDef.InsertionPoint.Z = Convert.ToDouble(coordinate.InnerText);
+ break;
+ }
+ pointCount++;
+ }
+ }
+ }
+ else if (rgChildNode.Name == "Tilt") { surfDef.Tilt = Convert.ToDouble(rgChildNode.InnerText); }
+ else if (rgChildNode.Name == "Height") { surfDef.Height = Convert.ToDouble(rgChildNode.InnerText); }
+ else if (rgChildNode.Name == "Width") { surfDef.Width = Convert.ToDouble(rgChildNode.InnerText); }
+ }
+ }
+ }
+ else if (node.Name == "PlanarGeometry")
+ {
+ XmlNode polyLoop = node.FirstChild;
+ if (polyLoop.HasChildNodes)
+ {
+ XmlNodeList cartesianPoints = polyLoop.ChildNodes;
+ foreach (XmlNode coordinatePt in cartesianPoints)
+ {
+ Vector.CartCoord coord = new Vector.CartCoord();
+ if (coordinatePt.HasChildNodes)
+ {
+ XmlNodeList coordinates = coordinatePt.ChildNodes;
+ int pointCount = 1;
+ foreach (XmlNode coordinate in coordinatePt)
+ {
+
+ switch (pointCount)
+ {
+ case 1:
+ coord.X = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 2:
+ coord.Y = Convert.ToDouble(coordinate.InnerText);
+ break;
+ case 3:
+ coord.Z = Convert.ToDouble(coordinate.InnerText);
+ break;
+ }
+ pointCount++;
+ }
+ surfDef.PlCoords.Add(coord);
+ }
+ }
+ }
+ }
+ }
+ }
+ Vector.CartVect plRHRVect = GetPLRHR(surfDef.PlCoords);
+ surfDef.PlRHRVector = plRHRVect;
+ surfaces.Add(surfDef);
+ }
+ return surfaces;
+ }
+ catch (Exception e)
+ {
+ return surfaces;
+ }
+
+ }
+
+ private static Vector.CartVect GetPLRHR(List plCoords)
+ {
+ Vector.CartVect plRHRVect = new Vector.CartVect();
+ //this list will store all of the rhr values returned by any arbitrary polyloop
+ List RHRs = new List();
+
+ int coordCount = plCoords.Count;
+ for (int i = 0; i < coordCount - 2; i++)
+ {
+ Vector.CartVect v1 = Vector.CreateVector(plCoords[i], plCoords[i + 1]);
+ Vector.CartVect v2 = Vector.CreateVector(plCoords[i + 1], plCoords[i + 2]);
+ Vector.CartVect uv = Vector.UnitVector(Vector.CrossProduct(v1, v2));
+ RHRs.Add(uv);
+ }
+ int RHRVectorCount = RHRs.Count;
+ List distinctRHRs = new List();
+ //the Distinct().ToList() routine did not work because, we believe, the item in the list is not recognized by Distinct()
+ //distinctRHRs = RHRs.Distinct().ToList();
+ //so we took the following approach to try and find unique vectors and store them
+ distinctRHRs.Add(RHRs[0]);
+ for (int j = 1; j < RHRVectorCount; j++)
+ {
+ foreach (Vector.CartVect distinctVector in distinctRHRs)
+ {
+ //this could contain wacky RHRs that are removed below
+ if (RHRs[j].X != distinctVector.X && RHRs[j].Y != distinctVector.Y && RHRs[j].Z != distinctVector.Z)
+ {
+ distinctRHRs.Add(RHRs[j]);
+ }
+ }
+ }
+
+ int RHRDistinctVectCount = distinctRHRs.Count;
+ if (RHRDistinctVectCount == 1)
+ {
+ plRHRVect = distinctRHRs[0];
+ return plRHRVect;
+ }
+ else
+ {
+ Dictionary uniqueVectorCount = new Dictionary();
+ //determine which vector shows up the most often
+ foreach (Vector.CartVect distinctVector in distinctRHRs)
+ {
+ int count = 0;
+ foreach (Vector.CartVect vect in RHRs)
+ {
+ if (distinctVector.X == vect.X && distinctVector.Y == vect.Y && distinctVector.Z == vect.Z)
+ {
+ count++;
+ }
+ }
+ uniqueVectorCount.Add(count, distinctVector);
+ }
+
+ //returns the vector that has the largest count
+ //get the largest integer in the list of
+ //may also be able to use
+ //uniqueVectorCount.Keys.Max();
+ List keysList = uniqueVectorCount.Keys.ToList();
+ keysList.Sort();
+ int max = 0;
+
+ foreach (int key in keysList)
+ {
+ if (key > max) { max = key; }
+ }
+ plRHRVect = uniqueVectorCount[max];
+ return plRHRVect;
+ }
+ }
+
+ private DOEgbXMLReportingObj GetPossibleSurfaceMatches(SurfaceDefinitions surface, List TestSurfaces, DOEgbXMLReportingObj report)
+ {
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Mar 14 2013
+ report.testSummary = "This test tries to match each Surface element in the standard file with an equivalent in your test file";
+ report.testSummary += " To be as flexible about what constitutes a \"Good Match\", this test finds a pool of possible candidate ";
+ report.testSummary += "surfaces in your test file and then begins to eliminate them as they fail different tests.";
+ report.testSummary += " At the end, there should be only one surface candidate remaining that constitutes a good match. ";
+ report.testSummary += "You can see the result of this filtering process by reviewing the mini-report that is provided for you below.";
+ report.testSummary += "";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added March 14 2013
+ report.testSummary += " The search routine first tries to find all surfaces that have the same SurfaceType and adjacentSpaceIds.";
+ report.testSummary += " Everytime there is a match found in the test file, meeting these criteria, a message will appear in the ";
+ report.testSummary += "mini-report, indicating that a match has been found.";
+ report.testSummary += " There may be more than one match in your test file.";
+ report.testSummary += " If there are no matches found for SurfaceType and AdjacencyId, this message will be printed (and the test will end as failed):";
+ report.testSummary += " In the test file, no matches could be found in the standard file that have the same AdjacentSpaceId(s) and SurfaceType.";
+ report.testSummary += "";
+ report.testSummary += " If this set of tests is successful, the routine next tries to remove those surfaces that do not meet";
+ report.testSummary += " the tilt and azimuth tolerances. Let's pretend for example that the tilt and azimuth for the standard surface";
+ report.testSummary += " in question are both 90 degrees. If the tilt and azimuth test tolerance are 1 degree, then the search";
+ report.testSummary += " routine will only keep those walls that have 89<=tilt<=91 && <=89azimuth<=91 && match the SurfaceType and";
+ report.testSummary += " adjacency relationships.";
+ report.testSummary += " The mini-report will let you know which surfaces pass the tilt and azimuth test and which do not.";
+ report.testSummary += "";
+ report.testSummary += " Next the search routine takes any of the remaining surface candidates that have passed all the tests so far, ";
+ report.testSummary += "and tries to determine if the Surface Areas defined by the polyLoops match to within a pre-defined % tolerance.";
+ report.testSummary += "";
+ report.testSummary += " the final tests are to physically test the coordinates of the polyloop and insertion point to make sure";
+ report.testSummary += " that a match for the standard surface can be found.";
+ report.testSummary += " You should see additional messages telling you which surface in your test file matches, or doesn't match";
+ report.testSummary += " the standard surface being searched against. If there is no match, the mini-report tells you.";
+ report.testSummary += " By making the tests this way, it is hoped that you can see exactly why your test file is failing against";
+ report.testSummary += " the standard file's surface definitions.";
+
+ try
+ {
+ report.MessageList.Add("Standard Surface Id: " + surface.SurfaceId);
+ report.MessageList.Add("");
+ //initialize the return list
+ //alternate between these two to filter out bad matches
+ List possiblesList1 = new List();
+ List possiblesList2 = new List();
+
+ bool adjSpaceIdMatch = false;
+ //try to find a surface in the test file that has the same:
+ //adjacent space Id signature
+ //surfaceType
+ //free list is 1
+ //list 2 is not used
+ foreach (SurfaceDefinitions testSurface in TestSurfaces)
+ {
+ //has to have the same number of Adjacent Space Ids
+ if (testSurface.AdjSpaceId.Count == surface.AdjSpaceId.Count)
+ {
+ //an exception for a shading device
+ if (surface.AdjSpaceId.Count == 0) { adjSpaceIdMatch = true; }
+
+ foreach (string testAdjSpaceId in testSurface.AdjSpaceId)
+ {
+ //loop only returns true if all AdjSpaceIds in both surfaces are identical
+ adjSpaceIdMatch = false;
+ foreach (string standardAdjSpaceId in surface.AdjSpaceId)
+ {
+ if (testAdjSpaceId == standardAdjSpaceId) { adjSpaceIdMatch = true; }
+ }
+ }
+ //if adjacent space Ids match and the surface types match, note this
+ if (adjSpaceIdMatch && testSurface.SurfaceType == surface.SurfaceType)
+ {
+ report.MessageList.Add("AdjancentSpaceId(s) and surfaceType Match.");
+ report.MessageList.Add("Surface id: " + testSurface.SurfaceId + " is a candidate.");
+ report.MessageList.Add("");
+ possiblesList1.Add(testSurface);
+ }
+ }
+ }
+ if (possiblesList1.Count == 1)
+ {
+ report.MessageList.Add("Based on a comparison of the surface Type and Adjacent SpaceIds, there is " + possiblesList1.Count.ToString() + " surface in the test file that is a possible match for " + surface.SurfaceId + " of the Standard File.");
+ report.MessageList.Add("
");
+ }
+ else if (possiblesList1.Count > 1)
+ {
+ report.MessageList.Add("Based on a comparison of the surface Type and Adjacent SpaceIds, there are " + possiblesList1.Count.ToString() + " surface in the test file that are possible matches for " + surface.SurfaceId + " of the Standard File.");
+ report.MessageList.Add("
");
+ }
+ else
+ {
+ report.longMsg = "In the test file, no matches could be found in the standard file that have the same AdjacentSpaceId(s) and SurfaceType.";
+ report.passOrFail = false;
+ return report;
+ }
+ //begin to filter back this list
+ //tilt
+ //azimuth
+ //list 1 is analyzed
+ //list 2 is free
+
+ if (possiblesList1.Count > 0)
+ {
+ foreach (SurfaceDefinitions testSurface in possiblesList1)
+ {
+ double tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt);
+ double azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth);
+ //if the tilt and azimuth is outside of tolerance
+ if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance || azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance)
+ {
+ report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: ");
+ report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")");
+ report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString());
+ report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching.");
+ report.MessageList.Add("");
+ continue;
+ }
+ //if the tilt and azimuth is within tolerance
+ else
+ {
+ //add to the free List
+ possiblesList2.Add(testSurface);
+ if (tiltDifference == 0 && azimuthDifference == 0)
+ {
+ report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " matches the standard surface tilt and azimuth exactly.");
+ report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")");
+ report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString());
+
+ report.MessageList.Add("");
+ }
+ else
+ {
+ report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " is within the azimuth and tilt tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance + " and " + DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance + ", respectively. It matches the standard file surface within the allowable tolerance.");
+ report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")");
+ report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString());
+
+ report.MessageList.Add("");
+ }
+ }
+ }
+ }
+ // report to the user that no matches could be found
+ else
+ {
+ report.longMsg = "In the test file, surfaces could be found that match the standard file's AdjacentSpaceId and SurfaceType, but of these matches, none could be identified that also have a tilt or azimuth that exactly matches the standard file's, or is within the allowable tolerance.";
+ report.passOrFail = false;
+ return report;
+ }
+ //clear the first list
+ possiblesList1.Clear();
+ //start to loop through the new refined list
+ //generally want to look at the polyLoop coordinates
+ //list 2 is analyzed
+ //list 1 is free
+ report.MessageList.Add("Starting Surface Area Match tests......");
+ report.MessageList.Add("");
+ if (possiblesList2.Count > 0)
+ {
+ //simple method from this point forward is just to simply start doing a polyloop check
+ //check the standard surface PolyLoop and the test Surface(s) polyloop(s)
+ //check the absolute coordinates of the testSurface(s) polyloop(s)
+
+ if (possiblesList2.Count == 1)
+ {
+ report.MessageList.Add("Only one Surface Candidate remaining from the original test pool.");
+ report.MessageList.Add("
");
+ //meaning there is only one candidate still available
+ //go on to test the polyLoop coordinates and the insertion point
+ possiblesList1.Add(possiblesList2[0]);
+
+
+ }
+ //more than one candidate still exists even after the adjacency test, surfaceType test, and tilt and azimuth tests, so filter through
+ else
+ {
+ //The user should be able to determine, based on output which surfaces are left for consideration
+ //Option 1: (easiest) find the one best candidate
+ //do so based on an area match, matching the area of the test surface with the area of the test surface
+ //(without regard for absolute polyloop coordinates)
+
+ //We find the area using area formulas for both regular polygons and irregular polygons
+ //first we check for the type of surface that it is (regular polygon or not), and we then take it from there
+ //in the case of a rectangular polygon, we only count rectangles or squares as regular, everything else is
+ //assumed to be irregular, though this does not fit the classic definition of a classic polygon.
+ //The language is just semantics
+
+ //first try to find if the standard file has a regular rectangular or square profile
+ report.MessageList.Add("Checking if the surface is a square or rectangle.");
+ bool isRegular = IsSurfaceRegular(surface);
+ foreach (SurfaceDefinitions regSurface in possiblesList2)
+ {
+ //ensures likewise that all the test surface candidates are regular,
+ //if they are not, then the entire set is assumed to be irregular
+ isRegular = IsSurfaceRegular(regSurface);
+ if (isRegular == false) break;
+ }
+ if (isRegular)
+ {
+ //we take a shortcut and use the width and height as a way to simplify the area checking scheme
+ //we assume that the width and height are properly entered in this simplified case
+ report.MessageList.Add("Rectangle or Square = TRUE");
+ report.MessageList.Add("Comparisons of the Width and Height values will be used as a proxy for surface Area.");
+ foreach (SurfaceDefinitions testsurface in possiblesList2)
+ {
+ //it first analyzes the test file to see if slivers are present. If they are, it will fail the test
+ //if slivers are not allowed for the test. This is the first time we check for slivers
+ if (testsurface.Width <= DOEgbXMLBasics.Tolerances.SliverDimensionTolerance || testsurface.Height <= DOEgbXMLBasics.Tolerances.SliverDimensionTolerance)
+ {
+ if (!DOEgbXMLBasics.SliversAllowed)
+ {
+ report.MessageList.Add("This test does not allow slivers less than " + DOEgbXMLBasics.Tolerances.SliverDimensionTolerance + " ft. A sliver has been detected. Test surface id: " + testsurface.SurfaceId + " is a sliver.");
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ //otherwise, if the sliver test passes
+ double widthDiff = Math.Abs(testsurface.Width - surface.Width);
+ double heightDiff = Math.Abs(testsurface.Height - surface.Height);
+ if (widthDiff > DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance ||
+ heightDiff > DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance)
+ {
+ report.MessageList.Add("Test file's Surface id: " + testsurface.SurfaceId + " width and height do not both match the standard file surface id: " + surface.SurfaceId + ". This surface has been removed as a candidate.");
+ continue;
+ }
+ else
+ {
+ //this surface is a candidate
+ possiblesList1.Add(testsurface);
+ if (widthDiff == 0 && heightDiff == 0)
+ {
+ report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " matches the width and height exactly of the standard file.");
+ //go ahead and now check the polyLoop coordinates, and then the insertion point
+ }
+ else
+ {
+ report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " is within the width and height tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance + " ft and " + DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance + "ft, respectively.");
+ //go ahead and now check the polyloop coordinates, and then the insertion point
+ }
+ }
+ }
+ }
+ //It is not "regular". Find the one surface with the area that most closely matches, and then check its polyloops
+ //1. get the polyloop area of the standard file's surface polyloops
+ //2. get the area of the test file surface candidates using the polyloop coordinates
+ else
+ {
+ report.MessageList.Add("The surface is not a square or rectangle.");
+ report.MessageList.Add("PolyLoop coordinates will be used to calculate the area.");
+ //there are two basic cases, one where we get the area using greens theorem when the surface is parallel
+ //to one of the axes of the project global reference frame
+ //and the second where the surface is not parallel to one of the axes of the global reference frame
+ //Surface normal Parallel to global reference frame X Axis
+ if (Math.Abs(surface.PlRHRVector.X) == 1 && surface.PlRHRVector.Y == 0 && surface.PlRHRVector.Z == 0)
+ {
+ List coordList = new List();
+ foreach (Vector.CartCoord coord in surface.PlCoords)
+ {
+ //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same
+ coord.X = 0;
+ coordList.Add(coord);
+
+ }
+ double area = GetAreaFrom2DPolyLoop(coordList);
+ if (area == -999)
+ {
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+
+ }
+ double testSurfacesArea = 0;
+
+ foreach (SurfaceDefinitions testSurface in possiblesList2)
+ {
+ if (Math.Abs(testSurface.PlRHRVector.X) == 1 && testSurface.PlRHRVector.Y == 0 &&
+ testSurface.PlRHRVector.Z == 0)
+ {
+ List testCoordList = new List();
+ foreach (Vector.CartCoord coord in testSurface.PlCoords)
+ {
+ coord.X = 0;
+ testCoordList.Add(coord);
+ }
+ testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList);
+ if (testSurfacesArea == -999)
+ {
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ }
+ double difference = Math.Abs(area - testSurfacesArea);
+ if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance)
+ {
+ possiblesList1.Add(testSurface);
+ if (difference == 0)
+ {
+ //then it perfectly matches, go on to check the poly loop coordinates
+ //then check the insertion point
+ report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly.");
+ }
+ else
+ {
+ report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance.");
+ }
+ }
+ else
+ {
+ report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates");
+ //don't return here, it will be returned below
+ }
+ }
+ else
+ {
+ //do nothing, it will be handled by the more general case and then translated to a 2-D surface
+ }
+ }
+
+
+ }
+ //Surface normal Parallel to global reference frame y Axis
+ else if (surface.PlRHRVector.X == 0 && Math.Abs(surface.PlRHRVector.Y) == 1 && surface.PlRHRVector.Z == 0)
+ {
+ List coordList = new List();
+ foreach (Vector.CartCoord coord in surface.PlCoords)
+ {
+ //only take the X and Z coordinates and throw out the Y because we can assume that they are all the same
+ coord.Y = 0;
+ coordList.Add(coord);
+
+ }
+ double area = GetAreaFrom2DPolyLoop(coordList);
+ if (area == -999)
+ {
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+
+ }
+ double testSurfacesArea = 0;
+
+ foreach (SurfaceDefinitions testSurface in possiblesList2)
+ {
+ if (Math.Abs(testSurface.PlRHRVector.X) == 0 && Math.Abs(testSurface.PlRHRVector.Y) == 1 && testSurface.PlRHRVector.Z == 0)
+ {
+ List testCoordList = new List();
+ foreach (Vector.CartCoord coord in testSurface.PlCoords)
+ {
+ coord.Y = 0;
+ testCoordList.Add(coord);
+ }
+ testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList);
+ if (testSurfacesArea == -999)
+ {
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ }
+ double difference = Math.Abs(area - testSurfacesArea);
+ if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance)
+ {
+ possiblesList1.Add(testSurface);
+ if (difference == 0)
+ {
+ //then it perfectly matches, go on to check the poly loop coordinates
+ //then check the insertion point
+ report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly.");
+ }
+ else
+ {
+ report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance.");
+ }
+ }
+ else
+ {
+ report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates");
+ //don't return here, it will be returned below
+ }
+ }
+ else
+ {
+ //do nothing, it will be handled by the more general code below and translated to 2D
+ }
+ }
+ }
+ else if (surface.PlRHRVector.X == 0 && surface.PlRHRVector.Y == 0 && Math.Abs(surface.PlRHRVector.Z) == 1)
+ {
+ List coordList = new List();
+ foreach (Vector.CartCoord coord in surface.PlCoords)
+ {
+ //only take the X and Y coordinates and throw out the Z because we can assume that they are all the same
+ coord.Z = 0;
+ coordList.Add(coord);
+
+ }
+ double area = GetAreaFrom2DPolyLoop(coordList);
+ if (area == -999)
+ {
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+
+ }
+ double testSurfacesArea = 0;
+
+ foreach (SurfaceDefinitions testSurface in possiblesList2)
+ {
+ if (Math.Abs(testSurface.PlRHRVector.X) == 0 && testSurface.PlRHRVector.Y == 0 && Math.Abs(testSurface.PlRHRVector.Z) == 1)
+ {
+ List testCoordList = new List();
+ foreach (Vector.CartCoord coord in testSurface.PlCoords)
+ {
+ coord.Z = 0;
+ testCoordList.Add(coord);
+ }
+ testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList);
+ if (testSurfacesArea == -999)
+ {
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ }
+ double difference = Math.Abs(area - testSurfacesArea);
+ if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance)
+ {
+ possiblesList1.Add(testSurface);
+ if (difference == 0)
+ {
+ //then it perfectly matches, go on to check the poly loop coordinates
+ //then check the insertion point
+ report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly.");
+ }
+ else
+ {
+ report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance.");
+ }
+ }
+ else
+ {
+ report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates");
+ //don't return here, it will be returned below
+ }
+ }
+ else
+ {
+ //do nothing. The code below will handle the more general case where it is not aligned with reference frame axes
+ }
+ }
+ }
+ //the surface is not aligned with one of the reference frame axes, which requires a bit more work to determine the right answer.
+ else
+ {
+ report.MessageList.Add("The standard surface is not aligned along an axis, and will be rotated into a new coordinate frame");
+ //New Z Axis for this plane is the normal vector, does not need to be created
+ //Get New Y Axis which is the surface Normal Vector cross the original global reference X unit vector (all unit vectors please
+ Vector.CartVect localY = new Vector.CartVect();
+ Vector.CartVect globalReferenceX = new Vector.CartVect();
+ globalReferenceX.X = 1;
+ globalReferenceX.Y = 0;
+ globalReferenceX.Z = 0;
+ localY = Vector.CrossProduct(surface.PlRHRVector, globalReferenceX);
+ localY = Vector.UnitVector(localY);
+
+ //new X axis is the localY cross the surface normal vector
+ Vector.CartVect localX = new Vector.CartVect();
+ localX = Vector.CrossProduct(localY, surface.PlRHRVector);
+ localX = Vector.UnitVector(localX);
+
+ //convert the polyloop coordinates to a local 2-D reference frame
+ //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane
+ List translatedCoordinates = new List();
+ Vector.CartCoord newOrigin = new Vector.CartCoord();
+ newOrigin.X = 0;
+ newOrigin.Y = 0;
+ newOrigin.Z = 0;
+ translatedCoordinates.Add(newOrigin);
+ for (int j = 1; j < surface.PlCoords.Count; j++)
+ {
+ //randomly assigns the first polyLoop coordinate as the origin
+ Vector.CartCoord origin = surface.PlCoords[0];
+ //captures the components of a vector drawn from the new origin to the
+ Vector.CartVect distance = new Vector.CartVect();
+ distance.X = surface.PlCoords[j].X - origin.X;
+ distance.Y = surface.PlCoords[j].Y - origin.Y;
+ distance.Z = surface.PlCoords[j].Z - origin.Z;
+ Vector.CartCoord translatedPt = new Vector.CartCoord();
+ //x coordinate is distance vector dot the new local X axis
+ translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
+ //y coordinate is distance vector dot the new local Y axis
+ translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
+ translatedPt.Z = 0;
+ translatedCoordinates.Add(translatedPt);
+
+ }
+ double area = GetAreaFrom2DPolyLoop(translatedCoordinates);
+ if (area == -999)
+ {
+ report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ report.MessageList.Add("Test may be inaccurate and requires gbXML.org support");
+
+ }
+ //get the area of the test candidates using the polyloop coordinates
+ foreach (SurfaceDefinitions testSurface in possiblesList2)
+ {
+ Vector.CartVect testlocalY = new Vector.CartVect();
+ Vector.CartVect testglobalReferenceX = new Vector.CartVect();
+ globalReferenceX.X = 1;
+ globalReferenceX.Y = 0;
+ globalReferenceX.Z = 0;
+ testlocalY = Vector.CrossProduct(surface.PlRHRVector, testglobalReferenceX);
+ testlocalY = Vector.UnitVector(testlocalY);
+
+ //new X axis is the localY cross the surface normal vector
+ Vector.CartVect testlocalX = new Vector.CartVect();
+ testlocalX = Vector.CrossProduct(testlocalY, surface.PlRHRVector);
+ testlocalX = Vector.UnitVector(testlocalX);
+
+ //convert the polyloop coordinates to a local 2-D reference frame
+ //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane
+ List testtranslatedCoordinates = new List();
+ Vector.CartCoord newOriginTest = new Vector.CartCoord();
+ newOrigin.X = 0;
+ newOrigin.Y = 0;
+ newOrigin.Z = 0;
+ testtranslatedCoordinates.Add(newOriginTest);
+ for (int j = 1; j < surface.PlCoords.Count; j++)
+ {
+ //randomly assigns the first polyLoop coordinate as the origin
+ Vector.CartCoord origin = testSurface.PlCoords[0];
+ //captures the components of a vector drawn from the new origin to the
+ Vector.CartVect distance = new Vector.CartVect();
+ distance.X = testSurface.PlCoords[j].X - origin.X;
+ distance.Y = testSurface.PlCoords[j].Y - origin.Y;
+ distance.Z = testSurface.PlCoords[j].Z - origin.Z;
+ Vector.CartCoord translatedPt = new Vector.CartCoord();
+ //x coordinate is distance vector dot the new local X axis
+ translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
+ //y coordinate is distance vector dot the new local Y axis
+ translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
+ translatedPt.Z = 0;
+ testtranslatedCoordinates.Add(translatedPt);
+
+ }
+ double testarea = GetAreaFrom2DPolyLoop(translatedCoordinates);
+ if (testarea == -999)
+ {
+ report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined.");
+ report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D");
+ }
+ double difference = Math.Abs(area - testarea);
+ if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance)
+ {
+ possiblesList1.Add(testSurface);
+ //within reason
+ if (difference == 0)
+ {
+ report.MessageList.Add
+ ("The test surface: " + testSurface.SurfaceId +
+ " polyloop surface area matches the polyLoop surface area of the standard surface: "
+ + surface.SurfaceId + " exactly.");
+ }
+ else
+ {
+ report.MessageList.Add
+ ("The test surface: " + testSurface.SurfaceId +
+ " polyloop surface area matches the polyLoop surface area of the standard surface: "
+ + surface.SurfaceId + " within the allowable area percentage tolerance.");
+ }
+ }
+ else
+ {
+ //not within reason, so the test will fail
+ //don't return yet, it will be returned below when possiblesList1 is found empty
+ }
+ }
+ }
+ }
+ }
+
+ possiblesList2.Clear();
+ //polyLoop absolute coordinates
+ //list 1 is analyzed
+ //list 2 is free
+ report.MessageList.Add("");
+ report.MessageList.Add("Starting PolyLoop coordinate comparisons.......");
+ report.MessageList.Add("");
+ if (possiblesList1.Count > 0)
+ {
+
+ foreach (SurfaceDefinitions testSurface in possiblesList1)
+ {
+ //check the polyLoop coordinates
+ foreach (Vector.CartCoord standardPolyLoopCoord in surface.PlCoords)
+ {
+ report = GetPolyLoopCoordMatch(standardPolyLoopCoord, testSurface, report, surface.SurfaceId);
+ if (report.passOrFail)
+ {
+ continue;
+ }
+ else
+ {
+ report.MessageList.Add("Could not find a coordinate match in the test surface polyloop.");
+ break;
+ }
+ }
+ if (report.passOrFail)
+ {
+ possiblesList2.Add(testSurface);
+ }
+ }
+ }
+ else
+ {
+ report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, and Surface Area. Failed when attempting to match the surface area.";
+ report.passOrFail = false;
+ return report;
+ }
+ possiblesList1.Clear();
+ report.MessageList.Add("");
+ report.MessageList.Add("Starting Insertion Point Coordinate comparisons.......");
+ report.MessageList.Add("");
+ if (possiblesList2.Count > 0)
+ {
+ //check the insertion point coordinate
+ foreach (SurfaceDefinitions testSurface in possiblesList2)
+ {
+ //now match the differences
+ double insPtXDiff = Math.Abs(testSurface.InsertionPoint.X - surface.InsertionPoint.X);
+ double insPtYDiff = Math.Abs(testSurface.InsertionPoint.Y - surface.InsertionPoint.Y);
+ double insPtZDiff = Math.Abs(testSurface.InsertionPoint.Z - surface.InsertionPoint.Z);
+ if (insPtXDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance || insPtYDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance || insPtZDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance)
+ {
+ report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " insertion point coordinates do not both match the standard file surface id: " + surface.SurfaceId + ". It has been removed as a candidate.");
+ continue;
+ }
+ else
+ {
+ //possible match
+ possiblesList1.Add(testSurface);
+ if (insPtXDiff == 0 && insPtYDiff == 0 && insPtZDiff == 0)
+ {
+ //perfect match
+ report.MessageList.Add("Test file's Surface with id: " + testSurface.SurfaceId + " matches the insertion point in the standard file exactly.");
+ }
+ else
+ {
+ //perfect match
+ report.MessageList.Add(" Test file's Surface with id: " + testSurface.SurfaceId + " has an insertion point that is within the allowable tolerances of X:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance + " ft, Y:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance + "ft, Z:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance + "ft.");
+ }
+ }
+
+ }
+ }
+ else
+ {
+ report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, and PolyLoop Coordinates. Failed when matching PolyLoop coordinates.";
+ report.passOrFail = false;
+ return report;
+ }
+ if (possiblesList1.Count == 1)
+ {
+ report.longMsg = "Advanced Surface Test found a match for Standard file surface id: " + surface.SurfaceId + " in the test file. Only one match was found to be within all the tolerances allowed. Surface id: " + possiblesList2[0].SurfaceId + ".";
+ report.passOrFail = true;
+ List testFileSurfIds = new List();
+ foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); }
+
+ globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds);
+ return report;
+ }
+ else if (possiblesList1.Count == 0)
+ {
+ report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, PolyLoop Coordinates, and Insertion Point. Failed when attempting to match the insertion point coordinates.";
+ report.passOrFail = false;
+ return report;
+ }
+ else if (possiblesList1.Count > 1)
+ {
+ report.longMsg = "Advanced Surface Test found more than one match for Standard file surface id: " + surface.SurfaceId + " in the test file. It was not possible to determine only one unique surface.";
+ report.passOrFail = false;
+ //List testFileSurfIds = new List();
+ //foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); }
+ //report.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds);
+ return report;
+ }
+ return report;
+ }
+ return report;
+
+ }
+ catch (Exception e)
+ {
+ report.longMsg = (e.ToString());
+ return report;
+ }
+ }
+
+ private static DOEgbXMLReportingObj GetPolyLoopCoordMatch(Vector.CartCoord standardPolyLoopCoord, SurfaceDefinitions testSurface, DOEgbXMLReportingObj report, string standardSurfaceId)
+ {
+ List possibleMatch = new List();
+ List exactMatch = new List();
+ report.MessageList.Add("Testing Polyloop coordinates for Standard surface " + standardSurfaceId);
+ report.MessageList.Add(" X: " + standardPolyLoopCoord.X.ToString() + ", Y: " + standardPolyLoopCoord.Y.ToString() + ", Z: " + standardPolyLoopCoord.Z.ToString());
+ foreach (Vector.CartCoord testPolyLoopCoord in testSurface.PlCoords)
+ {
+
+ //find an appropriate match
+ double diffX = Math.Abs(testPolyLoopCoord.X - standardPolyLoopCoord.X);
+ if (diffX < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //found a perfect X Match
+ if (diffX == 0)
+ {
+ //test Y
+ double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y);
+ if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Y Match
+ if (diffY == 0)
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " exactly");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ exactMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ //not a perfect Z match but within bounds
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " X and Y coordinates exactly. Z coordinate within allowable tolerance.");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ else
+ {
+ //z coordinate not within tolerance
+ continue;
+ }
+ }
+ //Y Match is within the allowable tolerance
+ else
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " in the X and Z coordinates, exactly. Y coordinate is within tolerance.");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " X exactly. Y and Z coordinates are within tolerance.");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ else
+ {
+ //z coordinate is not within tolerance
+ continue;
+ }
+ }
+ }
+ else
+ {
+ //a y match could not be found within tolerance
+ continue;
+ }
+
+ }
+ else
+ {
+ //not a perfect X match, but within tolerance
+ //test Y
+ double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y);
+ if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Y Match
+ if (diffY == 0)
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Y and Z coordinate exactly. X is within tolerance.");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Y coordinate exactly. X and Z is within tolerance.");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ else
+ {
+ //z is not matched so continue
+ continue;
+ }
+ }
+ // the Y match is not perfect but within tolerance
+ else
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Z coordinate exactly. The X and Y coordinates are within tolerance.");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + ". The X, Y, and Z coordinates are within tolerance.");
+ report.MessageList.Add("Test Surface " + testSurface.SurfaceId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ // no match found for the Z
+ else
+ {
+ continue;
+ }
+ }
+ }
+ //no match could be found for the Y
+ else
+ {
+ continue;
+ }
+ }
+ }
+ else
+ {
+ //not a match found for the X and continue
+ continue;
+ }
+ }
+ if (exactMatch.Count > 1)
+ {
+ report.MessageList.Add("Error, overlapping polyLoop coordinates found in the Test Surface PolyLoop.");
+ report.passOrFail = false;
+ return report;
+ }
+ else if (exactMatch.Count == 1)
+ {
+ report.MessageList.Add("One coordinate candidate found. Exact match");
+ report.passOrFail = true;
+ return report;
+ }
+ if (possibleMatch.Count > 1)
+ {
+ report.MessageList.Add("No exact solution for a match of the polyLoop coordinate. More than one coordinate candidate found.");
+ report.passOrFail = false;
+ return report;
+ }
+ else if (possibleMatch.Count == 1)
+ {
+ report.MessageList.Add("One coordinate candidate found.");
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.MessageList.Add("No coordinate candidate found.");
+ report.passOrFail = false;
+ return report;
+ }
+
+ }
+
+ private static DOEgbXMLReportingObj GetOpeningPolyLoopCoordMatch(Vector.CartCoord standardPolyLoopCoord, OpeningDefinitions testOpening, DOEgbXMLReportingObj report, string standardOpeningId)
+ {
+ List possibleMatch = new List();
+ List exactMatch = new List();
+ report.MessageList.Add("Testing Polyloop coordinates for Standard opening " + standardOpeningId);
+ report.MessageList.Add(" X: " + standardPolyLoopCoord.X.ToString() + ", Y: " + standardPolyLoopCoord.Y.ToString() + ", Z: " + standardPolyLoopCoord.Z.ToString());
+ foreach (Vector.CartCoord testPolyLoopCoord in testOpening.PlCoords)
+ {
+
+ //find an appropriate match
+ double diffX = Math.Abs(testPolyLoopCoord.X - standardPolyLoopCoord.X);
+ if (diffX < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //found a perfect X Match
+ if (diffX == 0)
+ {
+ //test Y
+ double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y);
+ if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Y Match
+ if (diffY == 0)
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " exactly");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ exactMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ //not a perfect Z match but within bounds
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " X and Y coordinates exactly. Z coordinate within allowable tolerance.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ else
+ {
+ //z coordinate not within tolerance
+ continue;
+ }
+ }
+ //Y Match is within the allowable tolerance
+ else
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " in the X and Z coordinates, exactly. Y coordinate is within tolerance.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " X exactly. Y and Z coordinates are within tolerance.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ else
+ {
+ //z coordinate is not within tolerance
+ continue;
+ }
+ }
+ }
+ else
+ {
+ //a y match could not be found within tolerance
+ continue;
+ }
+
+ }
+ else
+ {
+ //not a perfect X match, but within tolerance
+ //test Y
+ double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y);
+ if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Y Match
+ if (diffY == 0)
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " Y and Z coordinate exactly. X is within tolerance.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " Y coordinate exactly. X and Z is within tolerance.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ else
+ {
+ //z is not matched so continue
+ continue;
+ }
+ }
+ // the Y match is not perfect but within tolerance
+ else
+ {
+ double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z);
+ if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance)
+ {
+ //perfect Z match
+ if (diffZ == 0)
+ {
+ report.MessageList.Add("Test opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " Z coordinate exactly. The X and Y coordinates are within tolerance.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ else
+ {
+ report.MessageList.Add("Test opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + ". The X, Y, and Z coordinates are within tolerance.");
+ report.MessageList.Add("Test Opening " + testOpening.OpeningId);
+ report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString());
+ possibleMatch.Add(testPolyLoopCoord);
+ }
+ }
+ // no match found for the Z
+ else
+ {
+ continue;
+ }
+ }
+ }
+ //no match could be found for the Y
+ else
+ {
+ continue;
+ }
+ }
+ }
+ else
+ {
+ //not a match found for the X and continue
+ continue;
+ }
+ }
+ if (exactMatch.Count > 1)
+ {
+ report.MessageList.Add("Error, overlapping polyLoop coordinates found in the Test Opening PolyLoop.");
+ report.passOrFail = false;
+ return report;
+ }
+ else if (exactMatch.Count == 1)
+ {
+ report.MessageList.Add("One coordinate candidate found. Exact match");
+ report.passOrFail = true;
+ return report;
+ }
+ if (possibleMatch.Count > 1)
+ {
+ report.MessageList.Add("No exact solution for a match of the polyLoop coordinate. More than one coordinate candidate found.");
+ report.passOrFail = false;
+ return report;
+ }
+ else if (possibleMatch.Count == 1)
+ {
+ report.MessageList.Add("One coordinate candidate found.");
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.MessageList.Add("No coordinate candidate found.");
+ report.passOrFail = false;
+ return report;
+ }
+
+ }
+
+
+
+ //March15 2013
+ //by CHarriman Senior Product Manager Carmel Software Corporation
+ //this is a function only used internally. It is used to verify if a surface object only has four coordinates, and if those coordinates form
+ //a square or rectangle.
+ private static bool IsSurfaceRegular(SurfaceDefinitions Surface)
+ {
+ //tests to see if all candidate surfaces and the standard surface are regular (rectangular polygons)
+
+ bool isRegularPolygon = true;
+ //see if the standard surface has four coordinates defining its polyloop (one marker of a rectangle)
+ int standSurfaceCoordinateCount = Surface.PlCoords.Count;
+ if (standSurfaceCoordinateCount == 4)
+ {
+ //check the two potentially parallel sides, to ensure they are indeed parallel
+ Vector.CartVect v1 = Vector.CreateVector(Surface.PlCoords[0], Surface.PlCoords[1]);
+ Vector.CartVect v2 = Vector.CreateVector(Surface.PlCoords[2], Surface.PlCoords[3]);
+ Vector.CartVect v1xv2 = Vector.CrossProduct(v1, v2);
+ v1xv2 = Vector.UnitVector(v1xv2);
+ double magnitudev1xv2 = Vector.VectorMagnitude(v1xv2);
+ Vector.CartVect v3 = Vector.CreateVector(Surface.PlCoords[1], Surface.PlCoords[2]);
+ Vector.CartVect v4 = Vector.CreateVector(Surface.PlCoords[3], Surface.PlCoords[0]);
+ Vector.CartVect v3xv4 = Vector.CrossProduct(v3, v4);
+ v3xv4 = Vector.UnitVector(v3xv4);
+ double magnitudev3xv4 = Vector.VectorMagnitude(v3xv4);
+ //the unit vector will not be a number NaN if the Cross product detects a zero vector (indicating parallel vectors)
+ if (double.IsNaN(magnitudev1xv2) && double.IsNaN(magnitudev3xv4))
+ {
+ isRegularPolygon = true;
+ }
+ else
+ {
+ isRegularPolygon = false;
+ }
+ }
+ else
+ {
+ //might as well stop here because
+ isRegularPolygon = false;
+ return isRegularPolygon;
+ }
+ return isRegularPolygon;
+
+ }
+
+ //March15 2013
+ //by CHarriman Senior Product Manager Carmel Software Corporation
+ //this is a function only used internally. It is used to verify if an opening object only has four coordinates, and if those coordinates form
+ //a square or rectangle.
+ private static bool IsOpeningRegular(OpeningDefinitions Opening)
+ {
+ //tests to see if all candidate surfaces and the standard surface are regular (rectangular polygons)
+
+ bool isRegularPolygon = true;
+ //see if the standard surface has four coordinates defining its polyloop (one marker of a rectangle)
+ int standSurfaceCoordinateCount = Opening.PlCoords.Count;
+ if (standSurfaceCoordinateCount == 4)
+ {
+ //check the two potentially parallel sides, to ensure they are indeed parallel
+ Vector.CartVect v1 = Vector.CreateVector(Opening.PlCoords[0], Opening.PlCoords[1]);
+ Vector.CartVect v2 = Vector.CreateVector(Opening.PlCoords[2], Opening.PlCoords[3]);
+ Vector.CartVect v1xv2 = Vector.CrossProduct(v1, v2);
+ v1xv2 = Vector.UnitVector(v1xv2);
+ double magnitudev1xv2 = Vector.VectorMagnitude(v1xv2);
+ Vector.CartVect v3 = Vector.CreateVector(Opening.PlCoords[1], Opening.PlCoords[2]);
+ Vector.CartVect v4 = Vector.CreateVector(Opening.PlCoords[3], Opening.PlCoords[0]);
+ Vector.CartVect v3xv4 = Vector.CrossProduct(v3, v4);
+ v3xv4 = Vector.UnitVector(v3xv4);
+ double magnitudev3xv4 = Vector.VectorMagnitude(v3xv4);
+ //the unit vector will not be a number NaN if the Cross product detects a zero vector (indicating parallel vectors)
+ if (double.IsNaN(magnitudev1xv2) && double.IsNaN(magnitudev3xv4))
+ {
+ isRegularPolygon = true;
+ }
+ else
+ {
+ isRegularPolygon = false;
+ }
+ }
+ else
+ {
+ //might as well stop here because
+ isRegularPolygon = false;
+ return isRegularPolygon;
+ }
+ return isRegularPolygon;
+
+ }
+ //February 20 2013
+ //Created by Chien Si Harriman Senior Product Manager for the Carmel Software Corporation
+ //Currently the tool assumes that the polyloop is a valid one (counterclockwise coordinates) Previous checks ensure this is the case?
+ //and the segments of the polygon are not self-intersecting (there are no previous tests for this as of the date above)
+ private static double GetAreaFrom2DPolyLoop(List coordList)
+ {
+ int count = coordList.Count;
+ double areaprod = 0;
+ bool XisZero = true;
+ bool YisZero = true;
+ bool ZisZero = true;
+ //the following calculates the area of any irregular polygon
+ foreach (Vector.CartCoord coord in coordList)
+ {
+ if (coord.X != 0) XisZero = false;
+ if (coord.Y != 0) YisZero = false;
+ if (coord.Z != 0) ZisZero = false;
+ }
+ if (!XisZero && !YisZero && !ZisZero) return -999;
+
+ if (XisZero)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (i < count - 1)
+ {
+ areaprod += (coordList[i].Y * coordList[i + 1].Z - coordList[i].Z * coordList[i + 1].Y);
+ }
+ else if (i == count - 1)
+ {
+ areaprod += (coordList[i].Y * coordList[0].Z - coordList[i].Z * coordList[0].Y);
+ }
+ }
+ areaprod = areaprod / 2;
+ }
+ else if (YisZero)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (i < count - 1)
+ {
+ areaprod += (coordList[i].X * coordList[i + 1].Z - coordList[i].Z * coordList[i + 1].X);
+ }
+ else if (i == count - 1)
+ {
+ areaprod += (coordList[i].X * coordList[0].Z - coordList[i].Z * coordList[0].X);
+ }
+ }
+ areaprod = areaprod / 2;
+ }
+ else if (ZisZero)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (i < count - 1)
+ {
+ areaprod += (coordList[i].X * coordList[i + 1].Y - coordList[i].Y * coordList[i + 1].X);
+ }
+ else if (i == count - 1)
+ {
+ areaprod += (coordList[i].X * coordList[0].Y - coordList[i].Y * coordList[0].X);
+ }
+ }
+ areaprod = areaprod / 2;
+ }
+ return areaprod;
+ }
+
+ private static DOEgbXMLReportingObj CountFixedWindows(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.testSummary = "This test compares the total number of Opening elements with the openingType=\"FixedWindow\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type FixedWindow counts are the same, or the test fails.";
+ //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML
+ //added Feb 13 2013
+
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "openingType")
+ {
+ string type = at.Value;
+ if (type == "FixedWindow")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " fixed windows in the standard file and " + resultsArray[i - 1] + " fixed windows in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ private static DOEgbXMLReportingObj CountOperableWindows(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.testSummary = "This test compares the total number of Opening elements with the openingType=\"OperableWindow\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type FixedWindow counts are the same, or the test fails.";
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "openingType")
+ {
+ string type = at.Value;
+ if (type == "OperableWindow")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " operable windows in the standard file and " + resultsArray[i - 1] + " operable windows in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ private static DOEgbXMLReportingObj CountFixedSkylights(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.testSummary = "This test compares the total number of Opening elements with the openingType=\"FixedSkylight\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type FixedSkylight counts are the same, or the test fails.";
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "openingType")
+ {
+ string type = at.Value;
+ if (type == "FixedSkylight")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " fixed skylights in the standard file and " + resultsArray[i - 1] + " fixed skylights in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ private static DOEgbXMLReportingObj CountOperableSkylights(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.testSummary = "This test compares the total number of Opening elements with the openingType=\"OperableSkylights\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type OperableSkylights counts are the same, or the test fails.";
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "openingType")
+ {
+ string type = at.Value;
+ if (type == "OperableSkylight")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " operable skylights in the standard file and " + resultsArray[i - 1] + " operable skylights in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ private static DOEgbXMLReportingObj CountSlidingDoors(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.testSummary = "This test compares the total number of Opening elements with the openingType=\"SlidingDoor\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type SlidingDoor counts are the same, or the test fails.";
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "openingType")
+ {
+ string type = at.Value;
+ if (type == "SlidingDoor")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " sliding doors in the standard file and " + resultsArray[i - 1] + " sliding doors in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ private static DOEgbXMLReportingObj CountNonSlidingDoors(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.testSummary = "This test compares the total number of Opening elements with the openingType=\"NonSlidingDoor\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type NonSlidingDoor counts are the same, or the test fails.";
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "openingType")
+ {
+ string type = at.Value;
+ if (type == "NonSlidingDoor")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " non-sliding doors in the standard file and " + resultsArray[i - 1] + " non-sliding doors in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+
+ private static DOEgbXMLReportingObj CountAirOpenings(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units)
+ {
+ report.testSummary = "This test compares the total number of Opening elements with the openingType=\"Air\" in the test";
+ report.testSummary += " and standard files. It does this by";
+ report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files.";
+ report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. ";
+ report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type Air counts are the same, or the test fails.";
+ report.unit = Units;
+ //assuming that this will be plenty large for now
+ string[] resultsArray = new string[50];
+ int nodecount = 0;
+ for (int i = 0; i < gbXMLDocs.Count; i++)
+ {
+ nodecount = 0;
+ try
+ {
+ XmlDocument gbXMLTestFile = gbXMLDocs[i];
+ XmlNamespaceManager gbXMLns = gbXMLnsm[i];
+
+ XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns);
+ foreach (XmlNode surfaceNode in nodes)
+ {
+ XmlAttributeCollection spaceAtts = surfaceNode.Attributes;
+ foreach (XmlAttribute at in spaceAtts)
+ {
+ if (at.Name == "openingType")
+ {
+ string type = at.Value;
+ if (type == "Air")
+ {
+ nodecount++;
+ }
+ break;
+ }
+ }
+ }
+
+ //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result
+ resultsArray[i] = nodecount.ToString();
+ if (i % 2 != 0)
+ {
+ //setup standard result and test result
+ report.standResult.Add(resultsArray[i]);
+ report.testResult.Add(resultsArray[i - 1]);
+ report.idList.Add("");
+
+ double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)]));
+ if (difference <= report.tolerance)
+ {
+ report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units;
+ report.passOrFail = true;
+ return report;
+ }
+ else
+ {
+ report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference
+ + ". " + resultsArray[i] + " air openings in the standard file and " + resultsArray[i - 1] + " air openings in the test file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ else { continue; }
+
+ }
+ catch (Exception e)
+ {
+ report.MessageList.Add(e.ToString());
+ report.longMsg = " Failed to locate " + report.testType + " in the XML file.";
+ report.passOrFail = false;
+ return report;
+ }
+ }
+ report.longMsg = "Fatal " + report.testType + " Test Failure";
+ report.passOrFail = false;
+ return report;
+ }
+ #endregion
+ }
+}
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs
new file mode 100644
index 0000000..e95125b
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace DOEgbXML
+{
+ public class DOEgbXMLReportingObj
+ {
+ //new ReportingObj strings created Feb 13 2013
+ public string testSummary;
+ public string testReasoning;
+ // public Dictionary globalTestCriteria;
+ //original ReportingObj created Jan 1 2013
+ public List standResult;
+ public List testResult;
+ public List idList;
+ public double tolerance;
+ public TestType testType;
+ public int subTestIndex = -1;
+ public string unit;
+ public Dictionary TestPassedDict;
+ public bool passOrFail;
+ public List MessageList;
+ public string longMsg;
+ // public Dictionary> MatchedSurfaceIds;
+ // public Dictionary> MatchedOpening;
+
+ public void Clear()
+ {
+
+ if (standResult != null)
+ standResult.Clear();
+
+ if (testResult != null)
+ testResult.Clear();
+
+ if (idList != null)
+ idList.Clear();
+ tolerance = DOEgbXMLBasics.Tolerances.ToleranceDefault;
+ testType = TestType.None;
+ subTestIndex = -1;
+ passOrFail = false;
+ if (MessageList != null) { MessageList.Clear(); }
+ if (TestPassedDict != null) { TestPassedDict.Clear(); }
+ longMsg = "";
+ }
+
+ public DOEgbXMLReportingObj Copy()
+ {
+ DOEgbXMLReportingObj report = new DOEgbXMLReportingObj();
+
+ report.standResult = new List(this.standResult);
+ report.testResult = new List(this.testResult);
+ report.idList = new List(this.idList);
+ report.TestPassedDict = new Dictionary(this.TestPassedDict);
+ report.MessageList = new List(this.MessageList);
+ // if (this.MatchedSurfaceIds != null)
+ // report.MatchedSurfaceIds = new Dictionary>(this.MatchedSurfaceIds);
+
+
+ report.tolerance = this.tolerance;
+ report.testType = this.testType;
+ report.subTestIndex = this.subTestIndex;
+ report.unit = this.unit;
+ report.passOrFail = this.passOrFail;
+ report.longMsg = this.longMsg;
+
+ report.testSummary = this.testSummary;
+
+ return report;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs
new file mode 100644
index 0000000..f5c6862
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using VectorMath;
+
+namespace DOEgbXML
+{
+ class SurfaceDefinitions
+ {
+ //creates instances of an object that store information about surfaces in a gbXML file
+ public string SurfaceType;
+ public string SurfaceId;
+ public List AdjSpaceId;
+ public double Azimuth;
+ public double Tilt;
+ public double Height;
+ public double Width;
+ public Vector.CartCoord InsertionPoint;
+ public List PlCoords;
+ public Vector.CartVect PlRHRVector;
+ }
+ class SurfaceResults
+ {
+ public int matchCount;
+ public Dictionary> SurfaceIdMatch;
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs
new file mode 100644
index 0000000..476c31b
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs
@@ -0,0 +1,318 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace DOEgbXML
+{
+ public class DOEgbXMLTestCriteriaObject
+ {
+ public Dictionary TestCriteriaDictionary;
+
+
+ public void InitializeTestCriteriaWithTestName(string testname)
+ {
+ TestCriteriaDictionary = new Dictionary();
+
+
+ if (testname == "Test1")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add( TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add( TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add( TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test , true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume , true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count , false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count,false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count,false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test2")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shades must match
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test3")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test4")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shades must match
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test5")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, true);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shading surface must match
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test7")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test8")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, true);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test25")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count,false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count,false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+ else if (testname == "Test28")
+ {
+ DOEgbXMLBasics.SliversAllowed = true;
+ TestCriteriaDictionary.Add(TestType.Building_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Count, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true);
+ TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true);
+ TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true);
+ TestCriteriaDictionary.Add(TestType.Space_Area, true);
+ TestCriteriaDictionary.Add(TestType.Space_Volume, true);
+ TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shading count must match
+ TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false);
+ TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true);
+ TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false);
+ TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false);
+ TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false);
+ TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false);
+ TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true);
+ TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true);
+ //As of Feb 13 2013, this test is for a future release. Placeholder only
+ TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false);
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs
new file mode 100644
index 0000000..923c51c
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace DOEgbXML
+{
+ public class DOEgbXMLTestDetail
+ {
+ public string testName;
+ public string testSummary;
+ public string passString;
+ public string failString;
+ public string shortTitle;
+ //holds a bunch of strings for a given test
+ //this list will have this format: TestShortTitle, Pass String, Fail String, Summary String
+ // public List testString = new List();
+
+ //this List will store all the test Detail
+ public List TestDetailList;
+
+ public void InitializeTestResultStrings()
+ {
+ //holds the Detail object for all the tests
+ TestDetailList = new List();
+
+ //get the strings for the summary page table
+ //initialize the testdetails for all the tests
+ DOEgbXMLTestDetail test1detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test2detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test3detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test4detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test5detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test7detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test8detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test25detail = new DOEgbXMLTestDetail();
+ DOEgbXMLTestDetail test28detail = new DOEgbXMLTestDetail();
+ //create the strings
+ //Test1
+ test1detail.testName = "Test1";
+ test1detail.shortTitle = "2 Walls of Different Thicknesses with Parallel Aligned Faces";
+ test1detail.testSummary = "This test is designed to make sure that when walls of different thicknesses are joined with their faces aligned, that the centerline offset does not create extra walls during the gbXML creation process. If these extra sliver walls are found in the gbXML file, this test will fail.";
+ test1detail.passString = "This test has passed.";
+ test1detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test1detail);
+
+ //test 2
+ test2detail.testName = "Test2";
+ test2detail.shortTitle = "Single window with overhang that bisects the window's height.";
+ test2detail.testSummary = "A 1-zone, one story, simple model with exterior shading devices that act as overhangs and exterior light shelves for windows on the south façade. Light shelves are 1” thick and split a single window instance in the BIM along its centerline. This test is designed to ensure that this window should be represented as two windows in gbXML, the one window that is above the overhang, and the other that is below.";
+ test2detail.passString = "This test has passed.";
+ test2detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test2detail);
+
+ //test 3
+ test3detail.testName = "Test3";
+ test3detail.shortTitle = "Interior walls and Floor Second Level Space Boundary Test ";
+ test3detail.testSummary = "A 5-zone model with overlapping zones and a double-height zone. This test is designed to ensure that the tool used to create the zones can properly follow the basic conventions for second level space boundaries.";
+ test3detail.passString = "This test has passed.";
+ test3detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test3detail);
+
+ //test 4
+ test4detail.testName = "Test4";
+ test4detail.shortTitle = "Double height space with hole cut in floor and a skylight";
+ test4detail.testSummary = "This test is a large open atrium with a hole cut in the floor to allow light to penetrate through to the floor below.";
+ test4detail.passString = "This test has passed.";
+ test4detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test4detail);
+
+ //test 5
+ test5detail.testName = "Test5";
+ test5detail.shortTitle = "Basement walls that extend above grade and bound two different spaces";
+ test5detail.testSummary = "A two zone model that ensures exterior walls can properly be defined as underground and above grade. A single wall has been drawn by the user that begins below grade, and terminates above grade. Above grade, the walls bound a space that is above grade. Below grade, the walls bound a space that is entirely below grade.";
+ test5detail.passString = "This test has passed.";
+ test5detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test5detail);
+
+ //test 7
+ test7detail.testName = "Test7";
+ test7detail.shortTitle = "Folded roof element.";
+ test7detail.testSummary = "This is the first in a proposed series of tests that focus on roof elements that grow in geometric complexity.";
+ test7detail.passString = "This test has passed.";
+ test7detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test7detail);
+
+ //test 8
+ test8detail.testName = "Test8";
+ test8detail.shortTitle = "Sloping slab on grade";
+ test8detail.testSummary = "Ensures that sloping slab on grade comes through properly in gbXML, and that walls, which terminate at grade, are turned into the appropriate surfaceType (\"UndergroundWall\")";
+ test8detail.passString = "This test has passed.";
+ test8detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test8detail);
+
+ //test 25
+ test25detail.testName = "Test25";
+ test25detail.shortTitle = "Stacked interior walls with openings";
+ test25detail.testSummary = "A simplified 4-zone model of a building that has interior walls stacked on top of one another. The interior walls each have openings cut into them, to simulate something that may be drawn as a hallway by a designer.";
+ test25detail.passString = "This test has passed.";
+ test25detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test25detail);
+
+ //test 28
+ test28detail.testName = "Test28";
+ test28detail.shortTitle = "Roof eaves are turned into shading devices automatically";
+ test28detail.testSummary = "A simplified 3-zone model of a building shaped like a residential home has been created. The home is a simple two story example that has a small attic formed by a roof with a 30 degree pitch which slopes along one of the site’s Cartesian axes. This test is a simple test that ensures the authoring tool is able to automatically break the roof into a space bounding object and shade object appropriately without any user intervention.";
+ test28detail.passString = "This test has passed.";
+ test28detail.failString = "This test has failed.";
+ //ADD list to local testStrings List of Lists
+ TestDetailList.Add(test28detail);
+
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs
new file mode 100644
index 0000000..9dbce76
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Xml;
+using System.IO;
+using System.Xml.Schema;
+
+namespace DOEgbXML
+{
+ public class DOEgbXMLValidator
+ {
+
+ public int nErrors = 0;
+ public int nWarnings = 0;
+ private string strErrorMsg = string.Empty;
+ public string Errors { get { return strErrorMsg; } }
+ public string BigError;
+
+ public bool IsValidXmlEx(XmlReader xmlStream)
+ {
+ bool bStatus = false;
+ try
+ {
+ // Declare local objects
+ string xsdSchemaLocalLocation = Path.Combine(HttpRuntime.AppDomainAppPath, "SupportFiles/XSD/GreenBuildingXML_Ver5.10.xsd");
+ XmlReaderSettings rs = new XmlReaderSettings();
+ rs.ValidationType = ValidationType.Schema;
+ rs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation | XmlSchemaValidationFlags.ReportValidationWarnings;
+ rs.ValidationEventHandler += new ValidationEventHandler(rs_ValidationEventHandler);
+
+ //add schema
+ rs.Schemas.Add(null, xsdSchemaLocalLocation);
+
+
+ using (XmlReader xmlValidatingReader = XmlReader.Create(xmlStream, rs))
+ {
+ while (xmlValidatingReader.Read())
+ {
+ }
+ }
+
+ ////Exception if error.s
+ if (nErrors > 0)
+ {
+ throw new Exception(strErrorMsg);
+ }
+ else { bStatus = true; }//Success
+ }
+ catch (Exception error)
+ {
+ BigError = "BIG ERROR: " + error + "
";
+ bStatus = false;
+ }
+
+ return bStatus;
+ }
+
+ void rs_ValidationEventHandler(object sender, ValidationEventArgs e)
+ {
+
+ if (e.Severity == XmlSeverityType.Warning)
+ {
+ strErrorMsg += "" + "WARNING: " + e.Exception.Message + " Line Position " + e.Exception.LinePosition + " Line Number: " + e.Exception.LineNumber + "
";
+ nWarnings++;
+ }
+ else if(!e.Exception.Message.Contains("The element cannot contain white space. Content model is empty."))
+ {
+
+ strErrorMsg += "" + "ERROR: " + e.Exception.Message + " Line Position " + e.Exception.LinePosition + " Line Number: " + e.Exception.LineNumber + "
";
+ nErrors++;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs
new file mode 100644
index 0000000..a790f92
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace DOEgbXML
+{
+ public enum TestType
+ {
+ None,
+ Building_Area,
+ Space_Count,
+ Building_Story_Count,
+ Building_Story_Z_Height,
+ Building_Story_PolyLoop_RHR,
+ SpaceId_Match_Test,
+ Space_Area,
+ Space_Volume,
+ Total_Surface_Count,
+ Exterior_Wall_Surface_Count,
+ Underground_Surface_Count,
+ Interior_Wall_Surface_Count,
+ Interior_Floor_Surface_Count,
+ Roof_Surface_Count,
+ Shading_Surface_Count,
+ Air_Surface_Count,
+ Surface_Planar_Test,
+ Detailed_Surface_Checks,
+ Fixed_Windows_Count,
+ Operable_Windows_Count,
+ Fixed_Skylight_Count,
+ Operable_Skylight_Count,
+ Sliding_Doors_Count,
+ Non_Sliding_Doors_Count,
+ Air_Openings_Count,
+ Opening_Planar_Test,
+ Detailed_Opening_Checks,
+ Shell_Geom_RHR
+ }
+ public class DOEgbXMLenum
+ {
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/Vector.cs b/XMLValidatorWeb/DOEgbXMLClass/Vector.cs
new file mode 100644
index 0000000..4392ab3
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/Vector.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace VectorMath
+{
+ public class Vector
+ {
+ public class CartCoord
+ {
+ public double X { get; set; }
+ public double Y { get; set; }
+ public double Z { get; set; }
+ }
+
+ public class CartVect
+ {
+ public double X { get; set; }
+ public double Y { get; set; }
+ public double Z { get; set; }
+ }
+
+ public static CartVect CreateVector(CartCoord cd1, CartCoord cd2)
+ {
+ CartVect vector = new CartVect();
+ vector.X = cd2.X - cd1.X;
+ vector.Y = cd2.Y - cd1.Y;
+ vector.Z = cd2.Z - cd1.Z;
+ return vector;
+ }
+
+ public static Double VectorMagnitude(CartVect vector)
+ {
+ double magnitude= 0.0;
+
+ magnitude = Math.Sqrt(Math.Pow((vector.X),2) + Math.Pow((vector.Y),2) + Math.Pow((vector.Z),2));
+ return magnitude;
+ }
+
+ public static CartVect UnitVector(CartVect vector)
+ {
+ CartVect UV = new CartVect();
+ double magnitude = VectorMagnitude(vector);
+
+ UV.X = vector.X / magnitude;
+ UV.Y = vector.Y / magnitude;
+ UV.Z = vector.Z / magnitude;
+ return UV;
+ }
+
+ public static CartVect CrossProduct(CartVect vector1, CartVect vector2)
+ {
+ CartVect xProd = new CartVect();
+
+ xProd.X = vector2.Z * vector1.Y - vector1.Z * vector2.Y;
+ xProd.Y = vector2.Z * vector1.X - vector1.Z * vector2.X;
+ xProd.Z = vector2.Y * vector1.X - vector1.Y * vector2.X;
+ return xProd;
+ }
+
+ public double getPlanarSA(List polygonVect)
+ {
+ List normalizedPlane = new List();
+ //the new plane's first coordinate is arbitrarily set to zero
+ normalizedPlane[0].X = 0;
+ normalizedPlane[0].Y = 0;
+ normalizedPlane[0].Z = 0;
+ double diffX = 0;
+ double diffY = 0;
+ double diffZ = 0;
+
+ double surfaceArea = -1;
+ int numPoints = polygonVect.Count;
+ for(int i=0; i 0)
+ {
+
+ }
+ }
+ return surfaceArea;
+ }
+ }
+}
diff --git a/XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs b/XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs
new file mode 100644
index 0000000..958b9b5
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Xml;
+using System.IO;
+
+namespace XMLValidatorWeb.DOEgbXMLClass
+{
+ public class gbXML2IDF
+ {
+ public void gbXMLToIDF(string filelocation)
+ {
+ XmlDocument gbxf = new XmlDocument();
+
+ //getXMLFile
+ gbxf.Load(filelocation);
+ XmlNamespaceManager gbxmlns = new XmlNamespaceManager(gbxf.NameTable);
+ gbxmlns.AddNamespace("gbXMLv5", "http://www.gbxml.org/schema");
+
+ //make zone file
+ string zonestring = makeZones(gbxf, gbxmlns);
+
+ }
+
+ public string makeZones(XmlDocument gbxf,XmlNamespaceManager gbxmlns)
+ {
+ string zones = "";
+ XmlNodeList nodes = gbxf.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbxmlns);
+ int nodecount = nodes.Count;
+ foreach (XmlNode node in nodes)
+ {
+
+ }
+
+ return zones;
+ }
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs b/XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs
new file mode 100644
index 0000000..93f4da8
--- /dev/null
+++ b/XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace DOEgbXML
+{
+ public class gbXMLMatches
+ {
+ public Dictionary> MatchedSurfaceIds;
+ public Dictionary> MatchedOpeningIds;
+
+ public void Init()
+ {
+ MatchedSurfaceIds = new Dictionary>();
+ MatchedOpeningIds = new Dictionary>();
+ }
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/Default.aspx b/XMLValidatorWeb/Default.aspx
new file mode 100644
index 0000000..4d0cf43
--- /dev/null
+++ b/XMLValidatorWeb/Default.aspx
@@ -0,0 +1,10 @@
+<%@ Page Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true"
+ CodeBehind="Default.aspx.cs" Inherits="XMLXSDValidator._Default" %>
+
+
+
+
diff --git a/XMLValidatorWeb/Default.aspx.cs b/XMLValidatorWeb/Default.aspx.cs
new file mode 100644
index 0000000..10b620f
--- /dev/null
+++ b/XMLValidatorWeb/Default.aspx.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Web;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Xml;
+using System.Xml.Schema;
+using System.IO;
+
+namespace XMLXSDValidator
+{
+ public partial class _Default : System.Web.UI.Page
+ {
+
+
+
+ protected void LoginView1_ViewChanged1(object sender, EventArgs e)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/XMLValidatorWeb/Default.aspx.designer.cs b/XMLValidatorWeb/Default.aspx.designer.cs
new file mode 100644
index 0000000..ac28f88
--- /dev/null
+++ b/XMLValidatorWeb/Default.aspx.designer.cs
@@ -0,0 +1,24 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace XMLXSDValidator {
+
+
+ public partial class _Default {
+
+ ///
+ /// HyperLink1 control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.HyperLink HyperLink1;
+ }
+}
diff --git a/XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd b/XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd
new file mode 100644
index 0000000..737de2c
--- /dev/null
+++ b/XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd
@@ -0,0 +1,6478 @@
+
+
+
+
+ gbXML version 5.10 - maintained by gbXML.org.
+
+
+ Change Log:
+
+5.10
+ 10/2012
+
+1. Added new element: ProjectEntity under ProgramInfo and it contains three new elements Filename, URI, and GUID.
+2. Added new element: Filename for storing filenames of project files that created or modified the gbXML file.
+3. Added new element: URI for storing location of filename or project that created or modified the gbXML file.
+4. Added new element: GUID for storing unique ids for models, projects, simulations, and files that created or modified the gbXML file. GUID also has entity attribute that uses entityType enumeration.
+5. Added new enumeration: entityType which has four values, Model, File, Project, Run.
+6. Added programId attribute to the following elements; LightPowerPerArea, EquipPowerPerArea, InfiltrationFlow, PeopleNumber, PeopleHeatGain, Temperature, PeakDomesticHotWaterFlow, Weather, Schedule, IntEquip, ExtEquip, OAFlowPerPerson, OAFlowPerArea, DesignHeatT, DesignCoolT, Construction, HydronicLoop, HydronicLoopEquipment, AirLoop, AirLoopEquipment, LightingSystem, LightingControl, Lighting, WindowType, Vegetation, Weather, Meter, Transportation, Zone, ShadeControl, AltEnergySource, FlowPerArea, FlowPerPerson, and Flow.
+7. Added Lux and Phot to illuminanceUnitEnum.
+8. Added Damper, Boiler, Chiller to controlTypeEnum.
+9. Added unit attribute using temperatureUnitEnum to DesignTemp, MinTemp, and MaxTemp.
+10. Added unit attribute using flowUnitEnum to DesignFlow, MaximumFlow, and MinimumFlow.
+11. Added LPM to flowUnitEnum.
+12. Added primaryLoopId attribute to HydronicLoop.
+13. Added Location element to Weather element.
+14. Remove City, Country, StateorProvince elements from Weather element as Location element superceeds it.
+15. Added Modeled to stationTypeEnumeration.
+16. Added DataCenter to buildingTypeEnum.
+17. Added ServerRoom to spaceTypeEnum.
+18. Remove CADModelId from CreatedBy element as ProgramInfo and ProjectEntites superceeds it.
+19. Changed minOccurs value to 4 for Surface sub-element of Campus main element
+20. Changed minOccurs value to 0 for Surface main element
+
+5.01
+ 4/2012
+
+1. Deleted "surfaceNormalConvention" element. No longer used.
+2. Deleted "surfaceNormalEnum" enumeration. No longer used.
+
+5.00
+ 10/2011
+
+1. Added new element: YearModeled. It consists of BeginDate, EndDate, and HolidaysModeled child elements.
+2. Added new element: HolidaysModeled. It consists of Name, Description, and HolidayDate child elements.
+3. Added new element: HolidayDate (type: date)
+4. Added YearModeled child element to Campus element
+5. Added 5 new enumeration items to the extEquipTypeEnum enumeration (Types of exterior equipment):
+a. WindTurbine
+b. Photovoltaic
+c. CogenDiesel
+d. CogenFuelCell
+e. CogenGasTurbine
+6. Added new element: HeatRejectedtoSpace with unitlessUnitEnum attribute
+7. Added new element: Weight with attribute weightUnitEnum
+8. Added Weight, HeatRejectedtoSpace child elements to IntEquip element
+9. Added Weight child element to ExtEquip, airLoopEquip, HydronicEquip elements
+10 Added new element: HeatRejectedtoSpace (type: decimal). Also added annotation explaining this element
+11. Added HeatRejectedtoSpace child element to intEquip
+12. Added Exhaust item to enumeration systemTypeEnum
+13. Added new enumeration: resetTemperatureTypeEnum with 3 items: None, Automatic, OutdoorAirBased
+14. Added new element: ResetTemperature with attributes: temperatureUnitEnum, resetTemperatureTypeEnum
+15. Added ResetTemperature child element to AirLoopEquipment element
+16. Updated the annotation of the AirLoopEquipment element to explain how they should be ordered in an AirLoop
+17. Added new element: MotorInAirstream (type: boolean)
+18. Added MotorInAirstream child element to AirLoopEquipment element
+19. Added new element: Enthalpy with attribute enthalpyUnitEnum
+20. Added new enumeration: enthalpyUnitEnum with 2 items: BTUPerLb and KJPerKg
+21. Added Enthalpy child element to AirLoopEquipment element
+22. Added 2 enumeration items to equipmentTypeEnum: EvaporativePreCooler, PreHeatCoil
+23. Added 2 enumeration items to efficiencyTypeEnum: BTUPerHourPerF, kWPerC. Also, added annotation saying that this applies to StandByLoss for water heaters
+24. Updated SolarHeatGainCoeff child element of Opening element so that it is unbounded (i.e. - many SHGC values for an Opening)
+25. Updated AdjacentSpaceId annotation to better explain its use
+26. Updated PolyLoop annotation to better explain its use
+27. Added ProductName, Version, Platform elements (All of type: string)
+28. Added AirChangesPerHour child element to Space element
+29. Updated ShellGeometry annotation with clarification
+30. Updated SpaceBoundary annotation with clarification
+31. Added oppositeIdRef attribute (type: IDREF) to SpaceBoundary
+32. Added SpaceBoundary child element to Building element along with annotation
+33. Added new element: FamilyName (type: string)
+34. Added FamilyName child element to Surface
+35. Added new elements: Address1, Address2, City, State, ZipCode, Country, PhoneNumber (all of type: string)
+36. Added Address1, Address2, City, State, ZipCode, Country, PhoneNumber child elements to PersonInfo element
+37. Added ExtEquipId child element to both Construction and WindowType elements for purposes of modeling BIPV.
+38. Added 2 enumeration items to powerTypeEnum: Diesel, Biogas
+39. Added 1 enumeration item to powerUseTypeEnum: ElectricityGeneration
+40. Added 2 enumeration items to tempTypeEnum: HighTempLockout, LowTempLockout
+41. Added new enumeration: windSpeedEnum with 3 items: RatedWindSpeed, CutInWindSpeed, CutOutWindSpeed
+42. Added new element: WindSpeed with attributes velocityUnitEnum, windSpeedEnum
+43. Added WindSpeed child element to ExtEquip element
+44. Added ResetTemperature child element to HydronicLoopEquipment element
+45. Updated Equation element documentation to clarify dependent vs. independent variables
+45. Updated IndependentVariable child element of Equation element to allow for infinite number of independent variables
+46. Updated all instances of text "Dependent" and "Independent". It was misspelled.
+47. Updated Performance element documentation to clarify that it can represent all types of performance metrics
+
+0.37
+ 12/08
+ Added version attribute to gbXML element.
+ Added the ability to have additional SolarHeatGainCoeff values for Openings and WindowTypes for different angles of incidence defined by a new attribute in the SolarHeatGainCoeff element.
+ Added the Photometry element to the LightingSystem element.
+ Added the CADModelID to the CreatedBy element to track the CAD/BIM model the gbXML was created from.
+ Added CoefficientOfUtilization element to Lighting element.
+ Added PhotometryOrientation element to Lighting element.
+ Added Radiator to hydronicEquipTypeEnum.
+ Added 25 additional systemTypeEnums.
+0.36
+ 02/08
+ Corrected buildingStoreyIdRef attribute in Space element.
+ Added HydronicLoopEquipmentId element to Space element.
+ Added airChangesSchedIdRef attribute to Zone element.
+ Add constraint to Surface element to have a minimum of four defined.
+ Corrected spelling error in PercentAreaDaylitControlled element in LightingControl element.
+ Added the following elements to allow USDA-FS to conduct urban/wildland interface fire modeling: BiomassDensity element to Vegetation element, WFTDTemp, WFTDRelHumidity, WFTDWindSpeed, WFTDWindDir, and WFTDPressure to Weather element, Fire to Material element and FireFace to Construction element.
+ Changed DocumentHistory/CreatedBy and DocumentHistory/ProgramInfo elements to be required.
+0.35
+ 8/06
+ Corrected spelling error in capacityTypeEnum.
+ Added SingleFamily to buildingTypeEnum.
+ Replaced sequence requirement with unbound choice.
+0.34
+ 8/19/03
+ Convert spaceTypeEnum facets to Pascal case and added DiningCafeteriaFastFood to buildingTypeEnum. Ensured all enumeration facets are in Pascal case.
+ 6/25/03
+ Added CartesianPoint element to Results element.
+ Set minNumber for ZipcodeOrPostalCode element under the Location element to 1.
+ Set Campus element id attribute use to required.
+ Set Building element id attribute use to required.
+ Corrected Surface element id attribute use to required.
+0.33
+ 1/15/02
+ Added PolyLoop element to RectangularGeometry for describing polygons
+ Changed CartesianPoint element to allow only two Coordinate elements for describing flat geometry
+ Added PeakDomesticHotWaterFlow element to Building
+ Created PeakDomesticHotWaterFlow element
+ Moved simple type elements into complex type elements - easier to find correct element
+ Added enumeration to conditionTypeEnum
+ 1/14/02
+ Made HydronicLoopId repeatable in AirLoopEquipment and HydronicLoopEquipment
+ Added Name and Description as optional elements to the Results element
+ 1/10/02
+ Created heatGainTypeEnum enumeration and assigned it to the PeopleHeatGain element
+ Created PeopleHeatGain element and added it to the Space element
+ Removed TotalPeopleHeatGain and PeopleLatentHeatGain elements
+ Added systemType attribute to the AirLoop element, and added systemTypeEnum enumeration
+ Removed Lighting element from gbXML root element
+ Replaced LightId in Campus and Building elements with Lighting elements that refrence LightingSystem elements directly
+ Changed InfiltrationFlow/@type to optional
+ Added an optional HydronicLoop/@primaryLoopId attribute
+0.32
+ 12/12/01
+ Changed xsd:any namespace="##any" to ##other for GeneralGeometry and Meter elements
+ 12/10/01
+ Removed gbXML/CreatorPersonInfo and gbXML/CreatorCadInfo
+ Created Surface/RectangularGeometry and Opening/RectangularGeometry and their children
+ Created gbXML/DocumentHistory and its children
+ Updated schema to version http://www.w3.org/2001/XMLSchema
+ Changed enumerations for spaceTypeEnum to remove spaces and slashes
+ Changed Results/@timeIncrement to type xsd:duration as required for the 2001 schema specification
+0.31
+ 8/1/01
+ Added HydronicLoopId to AirLoopEquipment element
+ 7/26/01
+ Added Control element to equipment elements
+ Added FlowControl element to HydronicLoop element
+ Added PressureControl element to AirLoop element
+ Added TemperatureControl element to both loop elements
+ Added enumerations to tempTypeEnum
+ 7/25/01
+ Added xmlns to schema element
+ Added conditioningTypeEnum
+ Changed enumerations for efficiencyTypeEnum
+ Changed enumerations for resourceTypeEnum
+ Added stadardsTypeEnum
+ Added DependentValue element
+ Added IndependentValue element
+ Removed XValue element
+ Removed YValue element
+ Added RefrigerantType to AirLoopEquipment element
+ Changed structure of Data element
+ Added attributes to DeltaP element
+ Added conditionType attribute to DeltaT element
+ Made Name and Description elements optional in the DependentVariable element
+ Added minValue and maxValue attributes to the DependentVariable element
+ Changed structure of the Efficiency element
+ Allowed up to 2 IndependentVariable elements in the Equation element
+ Added fluidType attribute to the HydronicLoop element
+ Changed structure of HydronicLoopEquipment element
+ Made Name in IndependentVariable element optional
+ Changed structure of MinFlow element
+ Added id attribute to the Performance element
+ Changed structure of PointData element
+ 7/9/01
+ Added hydronicLoopType to HydronicLoopId
+ Added HydronicLoopId to HydronicLoopEquipment
+ 7/3/01
+ Added ShadeControl to Opening
+ Added ShadeSchedule, SolarOnOpening, HorizontalSolar, AirTempature, ZoneCoolingLoad, and Glare to ShadeControl
+ Added attributes, enumerations, and documentation for these new elements
+ Removed frameIdRef, blindIdRef, GlazeId, GapId from Opening - they are redundant and already contained in WindowType
+0.30
+ 6/28/01
+ Changed Results element
+ Removed MaterialType - it did not add information
+0.29
+ 4/30/01
+ Added StreetAddress element to Building - removed Location.
+ Changed SIResults element to useSIUnitsForResults.
+ Made several attributes at the gbXML level required instead of defaulting to SI.
+ Campus/@buildingType removed - Building/@buildingType required.
+ Changed SpaceId element to AdjacentSpaceId.
+ Moved CADObjectId after PlanarGeometry in the Opening element.
+ Made PlanarGeometry/@id optional.
+ Removed shadeTypeEnum (no longer used).
+ 4/27/01
+ Added annotation to several elements and attributes.
+ Added Enum to the end of enumerations to clarify distinction between 'type', meaning simple type (used for enumerations) and 'type', used in classifying an object (example: buildingType, surfaceType).
+0.28
+ 4/12/01
+ Added uValueUnit.
+ Made exposedToSun default = true.
+ 4/10/01
+ Changed sequence of gbXML, Campus, Building, Surface, and Location children.
+ Added more of a description for Location.
+ Made Building/@id, Surface/@id optional.
+ Moved Surface to be child of Campus.
+ Added enumerations to conditionType.
+ Changed ShadingSurface element to ExposedToSun boolean attribute.
+ Renamed SpaceRef to SpaceId, @spaceRef to @spaceIdRef
+ Removed Name and Description from PlanarGeometry.
+ Added explicit right-hand-rule documentation to the PolyLoop element.
+ Constrained PolyLoop to at least 3 CartesianPoints.
+ Constrained CartesianPoint to exactly 3 Coordinates.
+ Added @lengthUnit, @areaUnit, @volumeUnit, and @temperatureUnit to the gbXML element.
+ Changed documentation for Latitude and Longitude.
+ 4/6/01
+ Added targetNamespace.
+ Removed gbXML/@version.
+ Made gbXML/@id optional.
+ Removed GeoPraxisEAM from gbXML/@engine.
+ Renamed gbXML/SI to gbXML/SIResults and added documentation.
+ Removed @unit from Latitude and Longitude and made simple type - must be in decimal degrees.
+ Added global enumerations to be called out elsewhere.
+0.27
+ 2/13/01
+ Removed buildingType attribute from Space.
+ Added spaceType attribute to Space.
+ Changed FloorArea to Area.
+ Changed CADObjectIdRef attribute to CADObjectId element to allow for multiples.
+ Changed to surface-centric model.
+ Changed Geometry to PlanarGeometry, ShellGeometry, and GeneralGeometry
+ 2/12/01
+ Changing from X3D elements to ifcXML elements.
+ Removed X3D element.
+ Placed in alphabetical order.
+ Seperated complex types from simple type elements.
+ Changed back to sequence type - all had unusable restrictions.
+0.26
+ 2/7/01
+ Replaced sequence types with type all.
+ Removed empty sequence elements.
+
+
+
+ ACCA has given permission to gbxml authors to use this trademark ACCA and Manual J in the gbXML schema. Users of the gbXML schema are restricted from using the ACCA trademarks for any other purposes without express permission from ACCA.
+
+
+ "ASHRAE" is a registered service mark of the American Society of Heating, Refrigerating and Air-Conditioning Engineers, Inc. All rights reserved.
+
+
+ Enumerations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use to specify the most predominant building use type.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enumeration value to be used when there is no building type information available.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Coefficient of Performance
+
+
+
+
+ Energy Efficiency Ratio
+
+
+
+
+ Seasonal Energy Efficiency Ratio
+
+
+
+
+ Annual Fuel Utilization Efficiency
+
+
+
+
+ Heating Seasonal Performance Factor
+
+
+
+
+
+
+ Thermal Efficiency
+
+
+
+
+ Motor Efficiency
+
+
+
+
+ Fan Efficiency
+
+
+
+
+ Mechanical Efficiency
+
+
+
+
+ Boiler Efficiency
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Used with the floorCategory attribute.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Used with the floorSlabPerimeterHeatLossCoefficientUnitType attribute.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Used with the hOutsideUnitType attribute.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Opening in a surface with a tilt between 45° and 149.99° with a non-operable glazed opening in it.
+
+
+
+
+ Opening in a surface with a tilt between 45° and 149.99° with a operable glazed opening in it.
+
+
+
+
+ Opening in a surface with a tilt between 0° and 44.99° with a non-operable glazed opening in it.
+
+
+
+
+ Opening in a surface with a tilt between 0° and 44.99° with a operable glazed opening in it.
+
+
+
+
+ Opening in a surface with a tilt between 45° and 149.99° with a sliding door in it.
+
+
+
+
+ Opening in a surface with a tilt between 45° and 149.99° with a non-sliding door in it.
+
+
+
+
+ Opening in a surface with a tilt between 0° and 180° with nothing in it.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Used with the roofASHRAENumber attribute. Each annotation for the values is only one example of many possible constructions for that ASHRAE roof number. The user should select the one that best matches the thermal characteristics of the roof, not necessarily the one closest to the example description.
+
+
+
+
+ Undefined
+
+
+
+
+ Steel sheet with 1 or 2 inches insulation
+
+
+
+
+ One inch wood with 1 inch insulation
+
+
+
+
+ Four inch light weight concrete
+
+
+
+
+ Two inch heavy weight concrete
+
+
+
+
+ One inch wood with 2 inch insulation
+
+
+
+
+ Six inch light weight concrete
+
+
+
+
+ 2.5 inch wood with 1 inch insulation
+
+
+
+
+ Eight inch light weight concrete
+
+
+
+
+ 4 inch hvy wt concrete with 1-2 inch insulation
+
+
+
+
+ 2.5 inch wood with 2 inches of insulation
+
+
+
+
+ Roof Terrace System
+
+
+
+
+ 6 inch hvy wt concrete with 1-2 inch insulation
+
+
+
+
+ 4 inch wood with 1-2 inches of insulation
+
+
+
+
+
+
+ Used with the roofCLTDIndex attribute.
+
+
+
+
+ Under attic or knee wall, U-value = 0.408 - 0.018, Unvented Attic, No Radiant Barrier, Any Roofing Material, Any Roof Color
+
+
+
+
+ Under attic or knee wall, U-value = 0.408 - 0.018, Vented Attic, No Radiant Barrier, Dark Asphalt Shingles or Dark Metal, Tar and Gravel or Membrane
+
+
+
+
+ Under attic or knee wall, U-value = 0.408 - 0.018, Vented Attic, No Radiant Barrier, White or Light Color Shingles, Any Wood Shake Light Metal, Tar and Gravel or Membrane
+
+
+
+
+ Under attic or knee wall, U-value = 0.408 - 0.02, Vented Attic, No Radiant Barrier, Dark Tile, Slate or Concrete
+
+
+
+
+ Under attic or knee wall, U-value = 0.408 - 0.02, Vented Attic, No Radiant Barrier, Light Tile, Slate or Concrete
+
+
+
+
+ Under attic or knee wall, U-value = 0.408 - 0.02, Vented Attic, No Radiant Barrier, White Tile, Slate or Concrete, White Metal or White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.287 - 0.134, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.118 - 0.091, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.074 - 0.063, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.054, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.048, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.043 - 0.039, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.035, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.032 - 0.027, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.287 - 0.134, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.118 - 0.091, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.074 - 0.063, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.054, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.048, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.043 - 0.039, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.035, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.032 - 0.027, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ On exposed beams, U-value = 0.287 - 0.134, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.118 - 0.091, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.074 - 0.063, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.054, White or Light Color Tile Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.048, White or Light Color Tile Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.043 - 0.039, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.035, White or Light Color Tile Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ On exposed beams, U-value = 0.032 - 0.027, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ Below roof joists, U-value = 0.241 - 0.109, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.09 - 0.076, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.069, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.051 - 0.047, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.034, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.029, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.241 - 0.109, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.09 - 0.076, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.069, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.051 - 0.047, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.034, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.029, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel
+
+
+
+
+ Below roof joists, U-value = 0.241 - 0.109, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ Below roof joists, U-value = 0.09 - 0.076, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ Below roof joists, U-value = 0.069, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ Below roof joists, U-value = 0.051 - 0.034, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+ Below roof joists, U-value = 0.029, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane
+
+
+
+
+
+
+ Used with the roofColor attribute. Only enter Light if the construction is a roof and if it's in a rural location.
+
+
+
+
+ Dark colored or light colored in an industrial area
+
+
+
+
+ Permanently light colored and in a rural area
+
+
+
+
+
+
+ Used with the roofCTSType attribute. Each annotation for the values is only one example of many possible constructions for that CTS type. The user should select the one that best matches the thermal characteristics of the roof, not necessarily the one closest to the example description.
+
+
+
+
+ Metal Roof, R-19 Batt Insulation, Gyp Board
+
+
+
+
+ Metal Roof, R-19 Batt Insulation, Suspended Acoustical Ceiling
+
+
+
+
+ Metal Roof, R-19 Batt Insulation
+
+
+
+
+ Asphalt Shingles, Wood Sheathing, R-19 Batt Insulation, Gyp Board
+
+
+
+
+ Slate or Tile, Wood Sheathing, R-19 Batt Insulation, Gyp Board
+
+
+
+
+ Wood Shingles, Wood Sheathing, R-19 Batt Insulation, Gyp Board
+
+
+
+
+ Membrane, Sheathing, R-10 Insulation Board, Wood Deck
+
+
+
+
+ Membrane, Sheathing, R-10 Insulation Board, Wood Deck Suspended Acoustical Ceiling
+
+
+
+
+ Membrane, Sheathing, R-10 Insulation Board, Metal Deck
+
+
+
+
+ Membrane, Sheathing, R-10 Insulation Board, Metal Deck Suspended Acoustical Ceiling
+
+
+
+
+ Membrane, Sheathing, R-15 Insulation Board, Metal Deck
+
+
+
+
+ Membrane, Sheathing, R-10 plus R-15 Insulation Boards, Metal Deck
+
+
+
+
+ 2" Concrete Roof Ballast, Membrane, Sheathing, R-15 Insulation Board, Metal Deck
+
+
+
+
+ Membrane, Sheathing, R-15 Insulation Board, 4" LW Concrete
+
+
+
+
+ Membrane, Sheathing, R-15 Insulation Board, 6" LW Concrete
+
+
+
+
+ Membrane, Sheathing, R-15 Insulation Board, 8" LW Concrete
+
+
+
+
+ Membrane, Sheathing, R-15 Insulation Board, 6" HW Concrete
+
+
+
+
+ Membrane, Sheathing, R-15 Insulation Board, 8" HW Concrete
+
+
+
+
+ Membrane, 6" HW Concrete, R-19 Batt Insulation, Suspended Acoustical Ceiling
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Department of Energy
+
+
+
+
+ Air-Conditioning and Refrigeration Institute
+
+
+
+
+ American National Standards Institute
+
+
+
+
+ National Electrical Manufacturers Association
+
+
+
+
+
+
+
+
+ A five-digit station identifier assigned by the World Meteorological Organization (WMO), used for international weather data exchange and station documentation.
+
+
+
+
+ Weather-Bureau-Army-Navy station id. A five-digit station identifier used at National Climatic Data Center (NCDC) for digital data storage and general station identification purposes.
+
+
+
+
+ A 4-letter indicator for geographical locations throughout the world, managed by the International Civil Aviation Organization (ICAO).
+
+
+
+
+ A 3- to 5-character alpha-numeric identifier assigned by the US National Weather Service (NWS), used for site identification in the NWS communications systems (e.g. AFOS, ROSA, SHEF, etc.).
+
+
+
+
+ An alpha-numeric identifier of up to 4-characters managed by the USDT Federal Aviation Administration (FAA), used for site identification of airports, weather stations and other sites vital to navigation.
+
+
+
+
+ A 6-digit number identifying a station in the NWS Cooperative Network.
+
+
+
+
+ A custom code identifying a virtual station for a particular grid location on the planet that was modeled by a simulation program such as MM5, WRF, or other weather simulation programs.
+
+
+
+
+
+
+
+
+ Surface adjacent to two conditioned or unconditioned spaces with a tilt between 45° and 149.99°.
+
+
+
+
+ Surface adjacent to one conditioned or unconditioned space and the outside with a tilt between 45° and 149.99°.
+
+
+
+
+ Surface adjacent to one conditioned or unconditioned space and the outside with a tilt between 0° and 44.99°.
+
+
+
+
+ Surface adjacent to two conditioned or unconditioned spaces with a tilt between 150° and 180°.
+
+
+
+
+ Surface not adjacent to any spaces with tilt between 0° and 180°.
+
+
+
+
+ Surface adjacent to one conditioned or unconditioned space and earth (soil) with a tilt between 45° and 149.99°.
+
+
+
+
+ Surface adjacent to one conditioned or unconditioned space and earth (soil) below grade with a tilt between 150° and 180°.
+
+
+
+
+ Surface adjacent to two conditioned or unconditioned spaces with a tilt between 0° and 44.99°.
+
+
+
+
+ Air membrane between two conditioned or unconditioned spaces with a tilt between 0° and 180°.
+
+
+
+
+ Surface adjacent to one conditioned or unconditioned space and earth (soil) with a tilt between 0° and 44.99°.
+
+
+
+
+ Surface adjacent to one conditioned or unconditioned space and the outside with a tilt between 150° and 180°.
+
+
+
+
+ Surface adjacent to one conditioned or unconditioned space and earth (soil) at grade with a tilt between 150° and 180°.
+
+
+
+
+ Freestanding column in space specified by its top surface having the same ifcGUID.
+
+
+
+
+ Embedded column in wall specified by a surface which is coplanar with (one of) the embedding wall(s).
+
+
+
+
+
+
+
+
+ Variable Temperature
+
+
+
+
+ Packaged Single-zone
+
+
+
+
+ Ceiling Induction
+
+
+
+
+ Constant-volume Reheat Fan
+
+
+
+
+ Variable-volume Fan
+
+
+
+
+ Powered Induction Unit
+
+
+
+
+ Packaged Variable Air Volume
+
+
+
+
+ Packaged Variable-Volume Variable-Temperature
+
+
+
+
+ Ceiling Bypass
+
+
+
+
+ Evaporative Cooling
+
+
+
+
+ Multizone Fan
+
+
+
+
+ Packaged Multizone
+
+
+
+
+ Dual-duct Fan
+
+
+
+
+ Fan Coil
+
+
+
+
+ Induction Unit
+
+
+
+
+ Packaged Terminal Air Conditioner
+
+
+
+
+ Water Loop Heat Pump
+
+
+
+
+ Residential with cycling furnace and cycling air-conditioner
+
+
+
+
+ Residential Variable-Volume Variable-Temperature
+
+
+
+
+ Floor Panel Heating
+
+
+
+
+ Heating and Ventilating
+
+
+
+
+ Unit Heater
+
+
+
+
+ Unit Ventilator
+
+
+
+
+ Central Heating Radiators
+
+
+
+
+ Central Heating Convectors
+
+
+
+
+ Central Heating Radiant Floor
+
+
+
+
+ Central Heating Hot Air
+
+
+
+
+ Other Room Heater
+
+
+
+
+ Radiant Heater No Flue
+
+
+
+
+ Radiant Heater Flue
+
+
+
+
+ Radiant Heater Multiburner
+
+
+
+
+ Forced Convection Heater Flue
+
+
+
+
+ Forced Convection Heater No Flue
+
+
+
+
+ VAV Single Duct
+
+
+
+
+ VAV Dual Duct
+
+
+
+
+ VAV Reheat Fan
+
+
+
+
+ VAV Indoor Packaged Cabinet
+
+
+
+
+ Constant Volume Fixed OA
+
+
+
+
+ Constant Volume Variable OA
+
+
+
+
+ Constant Volume Terminal Reheat
+
+
+
+
+ Multizone Hot Deck Cold Deck
+
+
+
+
+ Constant Volume Dual Duct
+
+
+
+
+ Radiant Cooled Ceilings
+
+
+
+
+ Active Chilled Beams
+
+
+
+
+ Variable Refrigerant Flow
+
+
+
+
+ Split Systems With Natural Ventilation
+
+
+
+
+ Split Systems With Mechanical Ventilation
+
+
+
+
+ Split Systems With Mechanical Ventilation With Cooling
+
+
+
+
+ Exhaust Air Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Used with the wallASHRAEGroup attribute. Each annotation for the values is only one example of many possible constructions for that ASHRAE wall group. The user should select the one that best matches the thermal characteristics of the wall, not necessarily the one closest to the example description.
+
+
+
+
+ 4-in. face brick, insulation + 8-in. com. brick
+
+
+
+
+ 4-in. face brick, 2-in. insul., 4-in. com. brick
+
+
+
+
+ 4-in. face brick, air space + 4-in. face brick
+
+
+
+
+ 4-in. face brick + 4-in. common brick
+
+
+
+
+ 4-in. face brick + 4-in. block
+
+
+
+
+ 4-in. block + air space or insulation
+
+
+
+
+ Metal curtain wall + 1 to 3-in. insulation
+
+
+
+
+
+
+ Used with the wallColor attribute. Only enter Light or Medium if the construction is a wall and if it's in a rural location.
+
+
+
+
+ Dark colored or light colored in an industrial area
+
+
+
+
+ Permanently medium colored and in a rural area
+
+
+
+
+ Permanently light colored and in a rural area
+
+
+
+
+
+
+ Used with the wallCTSType attribute. Each annotation for the values is only one example of many possible constructions for that CTS type. The user should select the one that best matches the thermal characteristics of the wall, not necessarily the one closest to the example description.
+
+
+
+
+ Spandrel Glass, R-10 Insulation Board, Gyp Board
+
+
+
+
+ Metal Wall Panel, R-10 Insulation Board, Gyp Board
+
+
+
+
+ 1" Stone, R-10 Insulation Board, Gyp Board
+
+
+
+
+ Metal Wall Panel, Sheathing, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ 1" Stone, Sheathing, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ Wood Siding, Sheathing, R-11 Batt Insulation, 1/2"
+ Wood
+
+
+
+
+ 1" Stucco, Sheathing, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ EIFS Finish, R-5 Insulation Board, Sheathing, Gyp Board
+
+
+
+
+ EIFS Finish, R-5 Insulation Board, Sheathing, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ EIFS Finish, R-5 Insulation Board, Sheathing, 8" LW CMU, Gyp Board
+
+
+
+
+ Brick, R-5 Insulation Board, Sheathing, Gyp Board
+
+
+
+
+ Brick, Sheathing, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ Brick, R-5 Insulation Board, Sheathing, R-11 Batt Insulation Gyp Board
+
+
+
+
+ Brick, R-5 Insulation Board, 8" LW CMU
+
+
+
+
+ Brick, 8" LW CMU, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ Brick, R-5 Insulation Board, 8" HW CMU, Gyp Board
+
+
+
+
+ Brick, R-5 Insulation Board, Brick
+
+
+
+
+ Brick, R-5 Insulation Board, 8" LW Concrete, Gyp Board
+
+
+
+
+ Brick, R-5 Insulation Board, 12" HW Concrete, Gyp Board
+
+
+
+
+ Brick, 8" HW Concrete, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ 8" LW CMU, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ 8" LW CMU w Fill Insulation, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ 1" Stucco, 8" HW CMU, R-11 Batt Insulation, Gyp Board
+
+
+
+
+ 8" LW CMU w Fill Insulation
+
+
+
+
+ 8" LW CMU w Fill Insulation, Gyp Board
+
+
+
+
+ 12" LW CMU w Fill Insulation, Gyp Board
+
+
+
+
+ 4" LW Concrete. R-5 Board Insulation, Gyp Board
+
+
+
+
+ 4" LW Concrete. R-11 Batt Insulation, Gyp Board
+
+
+
+
+ 4" LW Concrete. R-10 Board Insulation, 4" LW Concrete
+
+
+
+
+ EIFS Finish, R-5 Insulation Board, 8" LW Concrete, Gyp Board
+
+
+
+
+ 8" LW Concrete. R-11 Batt Insulation, Gyp Board
+
+
+
+
+ EIFS Finish, R-10 Insulation Board, 8" HW Concrete, Gyp Board
+
+
+
+
+ 8" HW Concrete. R-11 Batt Insulation, Gyp Board
+
+
+
+
+ 12" HW Concrete. R-19 Batt Insulation, Gyp Board
+
+
+
+
+ 12" HW Concrete
+
+
+
+
+
+
+ Used with the wallGroupManualJ attribute.
+
+
+
+
+ Fastest heat transfer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Medium heat transfer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Slowest heat transfer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Analysis engine used
+
+
+
+
+
+
+
+
+
+
+
+ This attribute specifies the default temperature unit for the entire gbXML document, wherever the temperatureUnit simple type is used.
+
+
+
+
+ This attribute specifies the default length unit for the entire gbXML document, wherever the lengthUnit simple type is used.
+
+
+
+
+ This attribute specifies the default area unit for the entire gbXML document, wherever the areaUnit simple type is used.
+
+
+
+
+ This attribute specifies the default volume unit for the entire gbXML document, wherever the volumeUnit simple type is used.
+
+
+
+
+ Results will be given in SI or IP units. True = SI units which is the implied default. If False, results will be in english units.
+
+
+
+
+
+
+
+
+ Absorptance of the outside surface
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for a space that is bounded by this surface. First AdjacentSpaceId entered will determine how the referenced construction layers are ordered with the first construction layer being in contact with the outside or 2nd space listed and the last layer in contact with the first space listed. The outward normal of the surface, as defined by the right hand rule of the coordinates in the planar geometry element, is always pointing away from the first AdjacentSpaceID listed.
+
+
+
+
+ With interior horizontal surfaces, this attribute can distinguish between ceiling and floor surfaces to avoid double-counting of floor areas, etc. May be required in future schema versions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The AirLoop element represents the equipment serving one path of air
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ A piece of equipment serving an air-loop. This is generalized to be able to contain any type of air loop equipment. The air loop equipment are ordered as they exist on the airloop. A blow-through system should have fan listed before the coils. A draw-through system should have the fan listed after the coils.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ ID pointing at an air loop equipment object
+
+
+
+
+
+
+
+
+ ID pointing to an air loop
+
+
+
+
+
+
+ Minimum air temperature before shades are closed.
+
+
+
+
+
+
+
+
+
+
+
+
+ Cooling and Heating Reset Temperature Type
+
+
+
+
+
+
+
+
+
+
+
+
+ Reflectance of solar radiation
+
+
+
+
+
+
+
+
+
+
+
+ Alternative energy source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ Specifies the area of the space or building. This value should be equal to the area enclosed by the physical boundaries of the space, as defined by the intersection of the horizontal plane at the highest floor height and the volumetric model's vertical interior surface planes. Building area should be the sum of space areas whose PeopleNumber element values are greater than zero.
+
+
+
+
+
+
+
+
+
+
+
+
+ Polygon azimuth. The direction of the outward normal for the polygon (surface or opening) defined in RectangularGeometry element. Azimuth is measured in degrees clockwise from North, where North = 0 degrees. Examples: East = 90 deg, South = 180 deg, West = 270 deg. If CADModelAzimuth is defined, the Azimuth value is relative to the CADModelAzimuth value rather then North.
+
+
+
+
+
+
+
+
+
+
+ Type of ballast used
+
+
+
+
+ Month and day year schedule begins
+
+
+
+
+ Date of holiday modeled
+
+
+
+
+ Biomass of vegetation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Leakage value obtained from blower door test.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this element to define the shell of the building.
+
+
+
+
+ This element establishes the logical relation of a given part of the building envelope such that its PlanarGeometry is part of an exterior surface of the building.
+
+
+
+
+
+
+
+
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC) file.
+
+
+
+
+
+
+ Captures Building Storey Structure
+
+
+
+
+
+
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC) file.
+
+
+
+
+
+
+
+
+ ID used by a CAD/BIM program to reference its internal materials library
+
+
+
+
+
+
+ The number of degrees (0 to 360) of the angle of positive Y axis from north. (Value of the of Azimuth of Model's North relative to Cardinal North)
+
+
+
+
+ The CADModelId Element is used to map a CAD model or BIM to its corresponding gbXML file. Allows the CAD/BIM tool referenced by the programIdRef to correlate the gbXML file to its CAD/BIM model.
+
+
+
+
+
+
+ ID reference to unique CAD/BIM program defined in DocumentHistory/ProgramInfo element.
+
+
+
+
+
+
+
+
+ The CADObjectId Element is used to map unique CAD object identifiers to gbXML elements. Allows CAD/BIM tools to read results from a gbXML file and map them to their CAD objects.
+
+
+
+
+
+
+ ID reference to unique CAD/BIM program defined in DocumentHistory/ProgramInfo element.
+
+
+
+
+
+
+
+
+ The Campus element should be used as the base for all physical objects. On a campus, place one or more buildings.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for the weather data used for a heating design day
+
+
+
+
+ ID for the weather data used for a cooling design day
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC) file.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is the x, y, and z distances from the origin. This element must have three Coordinate elements when representing 3-d space, which represent x, y and z in order. This element must have two Coordinate elements when representing 2-d space.
+
+ IfcCartesianPoint
+
+
+
+
+
+
+
+
+
+
+ Cooling degree days. CDD is calculated as the number of degrees a mean daily temperature is above a value (specified as the Temperature element), for each day. For example, if the mean temperature in a region rises to 77 degrees for three days during a year, the rest of the time staying below 75, and the Temperature element is set at 75, then CDD = 6.
+
+
+
+
+
+
+
+
+
+
+ Cooling degree day value
+
+
+
+
+
+ This is an element from ifcXML that describes a collection of faces that make up a closed shell.
+
+ IfcClosedShell
+
+
+
+
+
+
+
+
+
+
+ Parameters required by CLTD load calculation method, as described in the 1989 ASHRAE Handbook, Fundamentals volume, pages 26.32 and following. Ignore this element and all elements under it if you are not planning to use that method.
+
+
+
+
+ Specifies the number 1 to 13 to use for a roof. See Table 29 page 26.34, 1989 ASHRAE Handbook, Fundamentals volume.
+
+
+
+
+ Specifies the wall group code A to G to use for a wall. See Table 31, page 26.36, 1989 ASHRAE Handbook, Fundamentals volume.
+
+
+
+
+ Specifies the effective roof color, which depends on the actual color and whether the location is industrial or rural. See page 26.34, 1989 ASHRAE Handbook, Fundamentals volume.
+
+
+
+
+ Specifies whether or not a roof has a suspended ceiling under it. See table 29, page 26.34, 1989 ASHRAE Handbook, Fundamentals volume.
+
+
+
+
+ Specifies the effective wall color, which depends on the actual color and whether the location is industrial or rural. See page 26.36, 1989 ASHRAE Handbook, Fundamentals volume.
+
+
+
+
+
+
+ The coefficient of utilization is the ratio of luminous flux on a work plane to the luminous flux emitted by the lamps alone.
+
+
+
+
+
+
+
+
+
+ Room cavity ratio is a measure of the room cavity proportions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Conductivity as a function of temperature
+
+
+
+
+
+
+
+
+
+
+
+ A Construction is a combination of layers, such as a wall or a roof
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reference to layers that comprise this construction. Multiple LayerId's order is important and specifies the layering of the layer's referenced materials. The first Surface/AdjacentSpaceId entered will determine how the referenced construction layers are ordered with the first construction layer being in contact with the outside or 2nd Surface/AdjacentSpaceId listed and the last layer in contact with the first Surface/AdjacentSpaceId listed.
+
+
+
+
+ This element is for purposes of modeling BIPV (building integrated photovoltaics).
+
+
+
+
+
+
+
+ Use this attribute to reference objects in the DOE2 library
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ The Control element should be used for describing how this equipment is controlled.
+
+
+
+
+
+
+
+
+
+
+
+ This is the an x, y, or z length measurement from the origin.
+
+ IfcLengthMeasure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Denotes the time this file has been created, as well as the person and program used to create this file.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Number of operation cycles per week.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for operation schedules
+
+
+
+
+
+
+
+
+
+ Allows for including daylight savings time
+
+
+
+
+ Set of values that define the profile of one 24 hour period divided equally to the number of values entered.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Day of the month that the cooling design day occurs on
+
+
+
+
+ Day of the month that the heating design day occurs on
+
+
+
+
+ Flag for daylight savings on the cooling design day
+
+
+
+
+ Flag for daylight savings for the heating design day
+
+
+
+
+ Cooling design day dry bulb temperature
+
+
+
+
+
+
+
+
+
+
+
+ Heating design day dry bulb temperature
+
+
+
+
+
+
+
+
+
+
+
+ Cooling design day dry bulb temperature range
+
+
+
+
+
+
+
+
+
+
+
+ Heating design day dry bulb temperature range
+
+
+
+
+
+
+
+
+
+
+
+ Ground temperature on the cooling design day
+
+
+
+
+
+
+
+
+
+
+
+ Ground temperature for the heating design day
+
+
+
+
+
+
+
+
+
+
+
+ Cooling design day hour of high temperature
+
+
+
+
+ Heating design day hour of high temperature
+
+
+
+
+ Cooling design day hour of low temperature
+
+
+
+
+ Heating design day hour of low temperature
+
+
+
+
+ Month the cooling design day lands on. 1=Jan 12=Dec
+
+
+
+
+ Month that the heating design day occurs on. 1=Jan 12=Dec
+
+
+
+
+ Cooling design day atmospheric pressure
+
+
+
+
+
+
+
+
+
+
+
+ Heating design day atmospheric pressure
+
+
+
+
+
+
+
+
+
+
+
+ Flag for rain on the cooling design day. 0=no rain 1=rain
+
+
+
+
+ Heating design day rain flag. 0=no rain, 1=rain
+
+
+
+
+ Cooling design day sky clearness
+
+
+
+
+
+
+
+
+
+
+
+ Heating design day sky clearness
+
+
+
+
+
+
+
+
+
+
+
+ Flag for snow on the cooling design day. 0=not snowing 1=snowing
+
+
+
+
+ Heating design day snow flag. 0=not snowing 1=snowing
+
+
+
+
+ Cooling design day wet bulb temperature
+
+
+
+
+
+
+
+
+
+
+
+ Heating design day wet bulb temperature
+
+
+
+
+
+
+
+
+
+
+
+ Cooing design day wind direction
+
+
+
+
+
+
+
+
+
+
+
+ Heating design day wind direction
+
+
+
+
+
+
+
+
+
+
+
+ Cooling design day wind speed
+
+
+
+
+
+
+
+
+
+
+
+ Heating design day wind speed
+
+
+
+
+
+
+
+
+
+
+
+ Difference in pressure
+
+
+
+
+
+
+
+
+
+ Use this attribute for conditioning units with both heating and cooling.
+
+
+
+
+ Use this attribute to point to a performance curve if one is provided
+
+
+
+
+
+
+
+
+ Difference in temperature
+
+
+
+
+
+
+
+ Use this attribute for conditioning units with both heating and cooling.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Density as a function of temperature
+
+
+
+
+
+
+
+
+
+
+
+ Value of a dependent variable for this data point
+
+
+
+
+
+
+
+
+
+
+
+
+ Use minValue and maxValue to define constraints on the curve.
+
+
+
+
+
+
+
+
+ Design temperature for cooling
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Design temperature for heating
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contains details about people and programs that created and modified this file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use the standardsType attribute when the efficiency is measured at standard conditions.
+
+
+
+
+
+ Use this attribute for conditioning units with both heating and cooling.
+
+
+
+
+ Use this attribute to point to a performance curve if one is provided
+
+
+
+
+
+
+
+
+ Electric load
+
+
+
+
+
+
+
+
+
+
+
+ Height above sea level
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Infra-red emissivity
+
+
+
+
+
+
+
+
+
+
+
+
+ Month and day year schedule ends
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for a resource meter
+
+
+
+
+
+
+
+
+ Minimum enthalpy setpoint for air-side economizer.
+
+
+
+
+
+
+
+
+
+
+
+ The Equation element allows data for n-dimensional algebraic data to be entered. The Expression element should contain an dependent variable followed by an = sign and an equation containing independent variables. The independent and dependent variables are then defined by their respective tags. The only mathematical operations allowed are ^ (power), + (addition), - (subtraction), / (division), and * (multiplication). Example: z=x+2*y^2 would have an DependentVariable with a name = z, and two IndependentVariable(s) with names of x and y. Descriptions would be included for each variable, along with unit and dataType information identifying the variable and its role.
+
+
+
+
+
+
+
+
+
+
+
+ Amount of power used by equipment in a given area
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+ External equipment. This is generalized to be able to contain any type of external equipment.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for the schedule of transmittance of a shading surface
+
+
+
+
+
+ ID pointing to a hydronic loop
+
+
+
+
+
+
+
+ ID pointing to an air loop
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties of a material under fire conditions.
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties of a construction under fire conditions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the heat loss from a floor in terms of the amount of heat lost per length of exposed perimeter. Used with both commercial and residential load calculation methods.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ Use this element to describe how the fluid flow is controlled. The temperatures specified in this element should be measured just upstream of the chiller.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this attribute to reference objects in the DOE2 library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Space between window panes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this attribute to reference objects in the DOE2 library
+
+
+
+
+
+
+
+
+ ID for a gap between window panes
+
+
+
+
+
+
+ This element has been left open for use with other geometry definitions, such as X3D or BLISXML.
+
+
+
+
+
+
+
+
+
+ Minimum amount of glare to trigger the shades to close
+
+
+
+
+
+
+
+
+
+
+
+ Properties of one layer of a window
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this attribute to reference objects in the DOE2 library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID indicating the type of glaze used
+
+
+
+
+
+
+ Monthly ground temperatures, 12 values
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Heating degree days. HDD is calculated as the number of degrees a mean daily temperature is below a value (specified as the Temperature element), for each day. For example, if the mean temperature in a region drops to 64 degrees for four days during a year, the rest of the time staying above 65, and the Temperature element is set at 65, then HDD = 4.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Amount of horizontal solar radiation striking the opening before a shade is closed.
+
+
+
+
+
+
+
+
+
+
+
+ h (Outside) is the combined coefficient of heat transfer by long-wave radiation and convection at outer surface, Btu/h-sf-F. See 2001 HoF Chapter 25 Table 1.
+
+
+
+
+
+
+ Used by the hOutsideUnitType attribute.
+
+
+
+
+
+
+
+
+ The HydronicLoop element represents the equipment serving one path of water, or other liquid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Only use this attribute for secondary loops to reference the primary loop.
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ A piece of equipment serving a hydronic loop (most commonly a water loop). This is generalized to be able to contain any type of hydronic loop equipment.
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this element to point to another loop. For instance if this is a chiller and is a child of a chilled water loop, use this element to point at a cooling water loop.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ ID pointing at a hydronic loop equipment object
+
+
+
+
+
+
+
+
+ ID pointing to a hydronic loop
+
+
+
+
+ Type of hydronic loop
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is an X3D element to map a texture to this material. From X3D specification: The ImageTexture node defines a texture map by specifying an image file and general parameters for mapping to geometry. Texture maps are defined in a 2D coordinate system (s, t) that ranges from [0.0, 1.0] in both directions. The bottom edge of the image corresponds to the S-axis of the texture map, and left edge of the image corresponds to the T-axis of the texture map. The lower-left pixel of the image corresponds to s=0, t=0, and the top-right pixel of the image corresponds to s=1, t=1.
+
+
+
+
+
+ Specifies location of the image. From X3D specification: The texture is read from the URL specified by the url field. When the url field contains no values, texturing is disabled. Browsers shall support the JPEG and PNG image file formats. In addition, browsers may support other image formats (e.g. CGM) which can be rendered into a 2D image. Support for the GIF format is also recommended (including transparency).
+
+
+
+
+ From X3D specification: If repeatS is TRUE, the texture map is repeated outside the [0.0, 1.0] texture coordinate range in the S direction so that it fills the shape. If repeatS is FALSE, the texture coordinates are clamped in the S direction to lie within the [0.0, 1.0] range.
+
+
+
+
+ From X3D specification: If repeatT is TRUE, the texture map is repeated outside the [0.0, 1.0] texture coordinate range in the T direction so that it fills the shape. If repeatT is FALSE, the texture coordinates are clamped in the T direction to lie within the [0.0, 1.0] range.
+
+
+
+
+
+
+ Value of the independent variable for this data point
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for the schedule of transmittance of a shading surface
+
+
+
+
+
+
+ Flow of air through building envelope
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thermal resistance of the internal air film in a layer
+
+
+
+
+
+
+
+
+
+
+
+ Interior equipment. This is generalized to be able to contain any type of internal equipment.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for the schedule of transmittance of a shading surface
+
+
+
+
+
+ ID pointing to a hydronic loop
+
+
+
+
+
+
+
+ ID pointing to an air loop
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ ID pointing at an interior equipment object
+
+
+
+
+
+
+ Type of lamp used
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Degrees north of the equator, in decimal degrees. Locations south of the equator are negative.
+
+
+
+
+ A Layer is a combination of one of more materials
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this attribute to reference objects in the DOE2 library
+
+
+
+
+
+
+
+
+ ID identifying a layer in this construction. Multiple layers in Constructions are in order from outside to inside.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Building storey Local Placement Z coordinate.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for the schedule of transmittance of a shading surface
+
+
+
+
+
+
+
+
+
+
+ Identifier pointing at a light object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID for a resource meter
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+ Illuminance level that the lights are maintained if daylighting controls present (lightControlTypeEnum not equal to on off).
+
+
+
+
+ Location where Illuminance value is specified.
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ Amount of power used by lighting in a given area
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The Location element describes the location of the global origin for this campus. This element can be used in a general sense by using the Name and Description elements for a physical address or landmark, or Location can be made precise by specifying the Elevation, Longitude, and Latitude of the origin.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Degrees east of Greenwich, in decimal degrees. Locations west of Greenwich are negative.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type of luminaire used
+
+
+
+
+ Parameters required by the ACCA Manual J Eighth Edition load calculation method. Ignore this element and all elements under it if you are not planning to use that method.
+
+
+
+
+ Specifies the group code for the wall, which determines how quickly the wall delivers heat into the space. See Table 4C, page T4C-1 ACCA Manual J Eighth Edition.
+
+
+
+
+ Specifies the array of CLTD values to use for the roof, which determines how quickly the roof delivers heat into the space. See Table 4A page T4A-18 and following, ACCA Manual J Eighth Edition.
+
+
+
+
+ Specifies whether or not to use a higher heating temperature difference value in calculating the heating loss for a floor (25 degrees F higher value is used in formula if floor is radiant). See Figure A5-5, page A5-8, ACCA Manual J Eighth Edition.
+
+
+
+
+ Specifies the u-value of the crawl space wall that is associated with the floor, which affects both the heating and cooling load. See Figure A5-5, page A5-8, and Figure A5-17, page A5-16, ACCA Manual J Eighth Edition.
+
+
+
+
+ Specifies whether or not the crawl space wall associated with this floor is well sealed from the outdoor air, which affects both the heating and cooling loads. See Figure A5-5, page A5-8, and Figure A5-17 page A5-16, ACCA Manual J Eighth Edition.
+
+
+
+
+ Specifies the type of floor being considered, which affects both the heating and the cooling loads. See Table 4A, pages T4A-27 and following, ACCA Manual J Eighth Edition.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this attribute to reference objects in the DOE2 library
+
+
+
+
+
+
+
+
+ ID identifying a material in this layer. Multiple materials in layers are in order from outside to inside.
+
+
+
+
+ Percentage (1-100%) of this layer that this material is made from.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Description of a resource measurement
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ ID for a resource meter
+
+
+
+
+
+
+
+ Minimum flow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fraction of light illuminance used at minimum setting.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fraction of power used at minimum setting.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Denotes the time this file has been modified, as well as the person and program used to modify this file.
+
+
+
+
+
+
+
+
+
+ Indicates if the motor is located in the path of the air stream.
+
+
+
+
+
+ Natural ventilation does not occur above this temperature.
+
+
+
+
+
+
+
+
+
+
+
+ Natural ventilation does not occur below this temperature.
+
+
+
+
+
+
+
+
+
+
+
+ Occupancy dependence of natural ventilation. If true, then natural ventilation only occurs when people are present.
+
+
+
+
+
+ Outside air flow per area
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ Outside air flow per person
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ Indicates which object or objects the results apply to, if any
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Identifier pointing to a construction
+
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC) file.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Schedule of operation for a piece of equipment. For heating and cooling equipment (such as a boiler or chiller) this is the availability schedule, the schedule of temperatures that, when reached, the piece of equipment will be available.
+
+
+
+
+
+
+ Use this element to report overall domestic hot water use for the domestic hot water loop referenced with the hydronicLoopIdRef attribute. The schedule referenced by waterUseScheduleIdRef defines a hot water use fraction schedule, which when combined with the value of PeakDomesticHotWaterFlow fully describe the hot water use of this building.
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ Occupancy of the space
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ Amount of heat added to the space by people
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ Percent of space area whose lights are controlled by a daylight sensor. Only applicable when LightPowerPerArea is used at the space level and not Lighting Systems.
+
+
+
+
+
+
+
+
+
+
+
+ Percent of original building shell used in renovation
+
+
+
+
+
+
+
+
+
+
+
+ Used to represent part-load performance and other performance metrics
+
+
+
+
+
+
+
+
+
+
+
+
+ The rate water vapor is allowed through a surface
+
+
+
+
+
+
+
+
+
+
+
+ Contains information about people that created and modified this file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This element has been left open for use with other photometry definitions. Photometric data is required for various forms of lighting analysis. This tag provides a way for the photometric data to be passed. Since this can be done in a variety of ways (iesna LM-63, cibse TM14, ELUMDAT, etc.) a specific format is not being specified.
+
+
+
+
+ This element specifies the position and the x, y and z axis of the light source. This element must have four Coordinate elements which represent the position and the x, y and z axis in order. The first CartesianPoint element specifies the position of the light source. The second, third and fourth CartesianPoint elements specifies the displacement points for the positive x, positive y and positive z axis.
+
+
+
+
+
+
+
+
+
+ List of points defining a loop. There are no repeated points in the list. All data are global, with the assumption that positive Z is up, and if CADModelAzimuth is undefined or zero, positive X is East and positive Y is North. If CADModelAzimuth is defined it is the angle of positive Y to North, positive X is the vectorial product of Y and Z. If geometry is to be precise, use Longitude, Latitude and Elevation in the Location element to define the origin. Otherwise the origin is an arbitrary point. Use PlanarGeometry to define a three dimensional polygon that lies on a plane, and has no self-intersection.
+
+
+
+
+
+
+
+
+
+
+
+
+ The PointData element allows for graph or tabular information to be entered. The data type and units of the independent and dependent variables are defined in their respective elements. Each Data element represent a data point, with each Value element representing the value of a variable - starting with the independent variable, then each dependent variable listed in the order defined.
+
+
+
+
+
+
+
+
+
+
+
+ This is a list of coordinates that make up a polygon in three-dimensional space. All coordinates must lie on the same plane. The right-hand rule applies for defining the outward normal of a surface: For every surface, points must be defined in order, such that the direction of (the average cross-product between (any point, the centroid of the surface, and the next point)) points in the direction of the outward normal, which is a vector pointing away from the first AdjacentSpaceID listed.
+
+ IfcPolyLoop
+
+
+
+
+
+
+
+
+
+
+ the ratio of the total amount of void space in a material (due to poses, small channels, and so on) to the bulk volume occupied by the material.
+
+
+
+
+
+
+
+
+
+
+
+ Maximum consumption of energy (power input)
+
+
+
+
+
+
+
+
+
+ ID for a resource meter
+
+
+
+
+
+
+
+
+
+ Prandtl number as a function of temperature
+
+
+
+
+
+
+
+
+
+
+
+ Use this element to describe how the air pressure is controlled. The temperatures specified in this element should be measured just upstream of the air handlers.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contains information about the originating or modifying file or service that created or modified this file
+
+
+
+
+
+
+
+
+
+
+
+ Contains information about programs that created and modified this file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Geometry data in a form typically used in simulation engines. For surfaces, specify the location of the bottom-left corner with the CartesianPoint element when facing it from the outside. Also for surfaces, Tilt and Azimuth must be specified. If CADModelAzimuth is defined, the Azimuth value is relative to the CADModelAzimuth value rather then North. For openings, the third Coordinate should be zero or left missing. For openings, these Coordinates represent the distance of the bottom-left of the opening to the bottom-left corner of the parent surface. Azimuth and Tilt should not be specified for opening. There is an optional PolyLoop element, which may be used for describing the polygon shape of the surface.
+
+
+
+
+
+
+
+
+
+
+ This is a two-dimensional polygon, with the origin at the point specified with RectangularGeometry/CartesianPoint.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that generated the results using the id of the ProgramInfo element.
+
+
+
+
+ Please specify how the values were obtained.
+
+
+
+
+ Use the startTime attribute to define the start of the first Value element.
+
+
+
+
+ This specifies the duration of time between each Value element. This is required if more than one Value element exists in a this Results element.
+
+
+
+
+
+
+ Roughness of the outside surface
+
+
+
+
+
+
+
+ Parameters required by RTS load calculation method, as described in pages 29.25 and following of the 2001 ASHRAE Handbook, Fundamentals volume. Ignore this element and all elements under it if you are not planning to use that method.
+
+
+
+
+
+
+
+ Specifies which Conduction Time Series to use for the roof. See Table 21, page 29.30, 2001 ASHRAE Handbook, Fundamentals volume. Only used if the construction is a roof and you are using the RTS calculation method.
+
+
+
+
+ Specifies which Conduction Time Series to use for the wall. See Table 20, page 29.28, 2001 ASHRAE Handbook, Fundamentals volume. Only used if the construction is a wall and you are using the RTS calculation method.
+
+
+
+
+
+
+ Resistance of material
+
+
+
+
+
+
+
+
+
+
+
+
+ The ShadeControl element is a bit complex, as shading control is handled differently in different simulation engines. Each child of ShadeControl represents a criteria to help determine if the shades will be open or closed. The resulting shade action should be a union of these. Example: You have included a ShadeSchedule, which is a 1 on weekdays and a 0 on weekends, and a SolarOnOpening. The shade will be drawn when the solar radiation on this opening is greater than SolarOnOpening and it is a weekday.
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ Use this element to define schedules for a shade.
+
+
+
+
+
+
+
+ List of year schedules that make up an entire calendar year.
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ Value for one block of time. Divides a day evenly into number of ScheduleValue elements defined in DaySchedule. Example: If 12 ScheduleValue elements are defined, each will represent two hours
+
+
+
+
+ Distance from outside surface of window to outside surface of wall
+
+
+
+
+
+
+
+
+
+
+
+ Shading Coefficient: The ratio of total solar transmittance for the specified glazing system to the total solar transmittance for the standard reference glazing (1/8" clear).
+
+
+
+
+
+
+
+
+
+
+
+ All data are global, with the assumption that positive Z is up, and if CADModelAzimuth is undefined or zero, positive X is East and positive Y is North. If CADModelAzimuth is defined it is the angle of positive Y to North, positive X is the vectorial product of Y and Z. If geometry is to be precise, use Longitude Latitude, and Elevation in the Location element to define the origin. Otherwise the origin is an arbitrary point. ShellGeometry is used to define a union of closed shells, where there is no intersection of any two of the given shells.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ When element is a child of WindowType: The center of glass solar heat gain coefficient. When element is a child of Opening: The overall solar heat gain coefficient for the window assembly.
+
+
+
+
+
+
+
+
+
+
+
+
+ Amount of solar radiation striking the opening before a shade is closed.
+
+
+
+
+
+
+
+
+
+
+
+ A space represents a volume enclosed by surfaces.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Planar polygon that represents the perimeter of space and whose area is equal to the floor area of the space.
+
+
+
+
+ Planar polygons that represent the interior surfaces bounding the space and whose volume is equal to the volume of the space.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ spaceType represents how a space is used.
+
+ IfcPolyLoop, an IESNA and ASHRAE project for determining lighting power density for individual spaces.
+
+
+
+
+
+ ID for the schedule of transmittance of a shading surface
+
+
+
+
+ ID of the schedule for lights contained in this space
+
+
+
+
+ ID for schedule of equipment use
+
+
+
+
+ ID for schedule of people in this space
+
+
+
+
+
+ ID for BuildingStorey this space is on.
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC) file.
+
+
+
+
+
+
+ This element establishes the logical relation of a given part of the space ShellGeometry such that its PlanarGeometry is part of an interior surface bounding the space.
+
+
+
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC)
+ file.
+
+
+
+
+ If this attribute is set to true, the boundary is important in heat flow calculation.
+
+
+
+
+ Connects the space boundary to a surface representing a building element (or representing the open air).
+
+
+
+
+ If surface referenced by SpaceBoundary is adjacent to two spaces, then this references the corresponding SpaceBoundary of the opposite space.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ First AdjacentSpaceId entered will determine how the referenced construction layers are ordered with the first construction layer being in contact with the outside or 2nd space listed and the last layer in contact with the first space listed.
+
+
+
+
+
+
+
+
+
+
+
+ Identifier pointing to a construction
+
+
+
+
+ ID for the schedule of transmittance of a shading surface
+
+
+
+
+ This attribute specifies whether or not direct beam radiation from the sun will ever hit this surface. Only relevant to exterior surface types.
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC) file.
+
+
+
+
+
+
+ Temperature
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+ Use this element to describe how the temperature is controlled. The temperatures specified in this element should be measured just upstream of the most critical piece of equipment (air handlers for a chilled water and hot water loops the chiller for the cooling water loop).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The number of degrees from up that the outside of the surface is tilted in relation to the bottom-left corner.
+
+
+
+
+
+
+
+
+
+
+ Time or period that results represent. Example: if timeType = Month and TimeIncrement = 1 the Value would be for the month of January or if timeType = Hour and TimeIncrement = 4 the 81st the Value would be for January 14 at noon.
+
+
+
+
+
+
+
+
+
+
+
+ Transmittance of shading surface
+
+
+
+
+
+
+
+
+
+
+
+
+ Public transportation
+
+
+
+
+
+
+
+
+
+
+
+ ID for the schedule of transmittance of a shading surface
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ User/project defined Code for Space or Zone.
+
+
+
+
+
+ We have left the UtilityRate element open to allow for use with billing schemas.
+
+
+
+
+
+ Overall conductance
+
+
+
+
+
+
+
+
+
+
+
+ Contains the actual numerical result value. If series result type each Value element contains the one value and is in sequential order for the series.
+
+
+
+
+ Plants, trees, etc. on a campus
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refers to a building-level surface.
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Viscosity as a function of temperature
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the volume of the space. This value should be equal to the volume enclosed by the actual physical boundaries of the space, as defined by the volumetric model's interior surfaces bounding that space.
+
+
+
+
+
+
+
+
+
+
+
+ Waste water heat recovery efficiency
+
+
+
+
+
+
+
+ ID pointing to an air loop
+
+
+
+
+ ID pointing to a hydronic loop
+
+
+
+
+
+
+
+
+ This includes blowdown (draining a cooling tower to clean), drift (water loss from water sprayed), and evaporation in cooling towers.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Amount of water used for water using equipment per cycle of operation.
+
+
+
+
+
+
+
+
+
+
+
+ The amount of heat from this equipment rejected to this space. For condensors exterior to building, this value will be 0.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+ Set of day schedules all assigned to a unique particular period of the week using the day type attribute. Do not schedule conflicting day types to the same week schedule.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Wildfire threat design atomospheric pressure.
+
+
+
+
+
+
+
+
+
+
+
+ Wildfire threat design relative humidity.
+
+
+
+
+
+
+
+
+
+
+
+ Wildfire threat design dry bulb temperature.
+
+
+
+
+
+
+
+
+
+
+
+ Wildfire threat design wind direction
+
+
+
+
+
+
+
+
+
+
+
+ Wildfire threat design wind speed.
+
+
+
+
+
+
+
+
+
+
+
+ Wind speed for wind turbine.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ One WindowType should be created for each type of window. Create a Blind, Frame, and Cost for each OpeningType, and then add as many Glaze and Gaps as exist in the window. Place these Glaze and Gap elements in order from outside to inside. For instance, a two pane window will have Glaze Gap Glaze, where the first Glaze represents the outside surface.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This element is for purposes of modeling BIPV (building integrated photovoltaics).
+
+
+
+
+
+
+ Use this attribute to reference objects in the DOE2 library
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Year of simulation to use
+
+
+
+
+
+
+
+
+
+
+
+ Set of week schedules all assigned for a particular time period during the year defined by the begin and end date elements. These must not span more than one calendar year.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID of heating schedule
+
+
+
+
+ Design temperature for cooling
+
+
+
+
+ Outside air schedule ID
+
+
+
+
+ Air changes schedule ID
+
+
+
+
+ ID of the fan schedule for this zone
+
+
+
+
+ Global Unique ID from Industry Foundation Class (IFC) file.
+
+
+
+
+ Please specify the program that added this element.
+
+
+
+
+
+
+ Minimum cooling load that triggers the shades to close
+
+
+
+
+
+
+
+
+
+
diff --git a/XMLValidatorWeb/Images/TmpImage.gif b/XMLValidatorWeb/Images/TmpImage.gif
new file mode 100644
index 0000000000000000000000000000000000000000..0ca7ada960568fff04400cda966fbdcb106abfa2
GIT binary patch
literal 6820
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
literal 0
HcmV?d00001
diff --git a/XMLValidatorWeb/Images/header01.jpg b/XMLValidatorWeb/Images/header01.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2e379caf0a4ff0c98afa9f3d347c2d08d68c4dd1
GIT binary patch
literal 51337
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