public static CartesianPoint makegbCartesianPt(Vector.MemorySafe_CartCoord pt)
        {
            CartesianPoint cp = new CartesianPoint();

            cp.Coordinate = new string[3];

            cp.Coordinate[0] = gb.FormatDoubleToString(pt.X);
            cp.Coordinate[1] = gb.FormatDoubleToString(pt.Y);
            cp.Coordinate[2] = gb.FormatDoubleToString(pt.Z);
            return(cp);
        }
        public static LLRet GetLLForFloor(List <Vector.MemorySafe_CartCoord> surfacecoords)
        {
            LLRet ll = new LLRet();

            ll.indices = new List <int>();
            int            surfindex = -1;
            CartesianPoint cp        = new CartesianPoint();

            Vector.CartCoord llsurf = new Vector.CartCoord();

            Vector.MemorySafe_CartVect RHRVector = Vector.GetMemRHR(surfacecoords);
            if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == -1)
            {
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X  = surfacecoords[sccount].X;
                        llsurf.Y  = surfacecoords[sccount].Y;
                        llsurf.Z  = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most low(smallest Y), then most left (largest X)
                    if (surfacecoords[sccount].Y <= llsurf.Y)
                    {
                        if (surfacecoords[sccount].X > llsurf.X)
                        {
                            llsurf.X  = surfacecoords[sccount].X;
                            llsurf.Y  = surfacecoords[sccount].Y;
                            llsurf.Z  = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }
            }
            else
            {
                //special procedure for this type of floor
            }

            Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(llsurf.X, llsurf.Y, llsurf.Z);
            cp = makegbCartesianPt(LLeft);

            ll.cp = cp;
            ll.indices.Add(surfindex);
            return(ll);
        }
Exemple #3
0
        public static MemorySafe_Surface convert2MemorySafeSurface(Surface surface)
        {
            List <Vector.MemorySafe_CartCoord> surfaceCoords = new List <Vector.MemorySafe_CartCoord>();

            foreach (Vector.CartCoord coord in surface.SurfaceCoords)
            {
                Vector.MemorySafe_CartCoord surfaceCoord = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, coord.Z);
                surfaceCoords.Add(surfaceCoord);
            }

            MemorySafe_Surface memSurface = new MemorySafe_Surface(surface.name, surface.multiplier, surface.surfaceType, surface.constructionName,
                                                                   surface.outsideBoundary, surface.zoneName, surface.outsideBoundaryCondition, surface.sunExposureVar, surface.windExposureVar,
                                                                   surface.viewFactor, surface.numVertices, surfaceCoords, surface.tilt, surface.azimuth);

            return(memSurface);
        }
Exemple #4
0
        public static MemorySafe_OpeningDefinitions convert2MemorySafeOpening(OpeningDefinitions opening)
        {
            List <Vector.MemorySafe_CartCoord> surfaceCoords = new List <Vector.MemorySafe_CartCoord>();

            foreach (Vector.CartCoord coord in opening.coordinateList)
            {
                Vector.MemorySafe_CartCoord surfaceCoord = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, coord.Z);
                surfaceCoords.Add(surfaceCoord);
            }
            Vector.MemorySafe_CartVect memSafeRHR = Vector.convertToMemorySafeVector(opening.rHRVector);

            MemorySafe_OpeningDefinitions memOpening = new MemorySafe_OpeningDefinitions(opening.nameId,
                                                                                         opening.openingType, opening.parentSurfaceNameId,
                                                                                         opening.parentAzimuth, opening.parentTilt, opening.outsideBoundaryConditionObj, opening.viewFactortoGround,
                                                                                         opening.shadeControlSch, surfaceCoords, opening.Azimuth, opening.Tilt, memSafeRHR,
                                                                                         opening.constructionName, opening.frameAndDividerName, opening.multiplier, opening.numVertices,
                                                                                         opening.area);

            return(memOpening);
        }
        private static double GetSurfaceArea(SurfaceDefinitions surface, double areaConversion)
        {
            
            logger.Debug("STARTING SUBROUTINE: GetSurfaceArea.");
            logger.Debug("PROGAMMER'S NOTE: PolyLoop coordinates will be used to calculate the area.");
            double area = -1;
            //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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                foreach (Vector.MemorySafe_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
                    //create new
                    Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z);
                    coordList.Add(c2);

                }
                area = GetAreaFrom2DPolyLoop(coordList);
                if (area == -999)
                {
                    logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined.");
                    logger.Debug("The coordinates should be 2D and could not be translated to 2D");
                    logger.Fatal("ATTENTION: Attempting to calculate surface area.  Test may be inaccurate and requires gbXML.org support");
                }
            }
            //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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                foreach (Vector.MemorySafe_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
                    Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z);
                    coordList.Add(c2);

                }
                area = GetAreaFrom2DPolyLoop(coordList);
                if (area == -999)
                {
                    logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined.");
                    logger.Debug("The coordinates should be 2D and could not be translated to 2D");
                    logger.Fatal("ATTENTION: Attempting to calculate surface area.  Test may be inaccurate and requires gbXML.org support");

                }
            }
            else if (surface.PlRHRVector.X == 0 && surface.PlRHRVector.Y == 0 && Math.Abs(surface.PlRHRVector.Z) == 1)
            {
                List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                foreach (Vector.MemorySafe_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
                    Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0);
                    coordList.Add(c2);

                }
                area = GetAreaFrom2DPolyLoop(coordList);
                if (area == -999)
                {
                    logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined.");
                    logger.Debug("The coordinates should be 2D and could not be translated to 2D");
                    logger.Fatal("ATTENTION: Attempting to calculate surface area.  Test may be inaccurate and requires gbXML.org support");

                }
                
               
                        
            }
            //the surface is not aligned with one of the reference frame axes, which requires a bit more work to determine the right answer.
            else
            {
                logger.Debug("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 globalReferenceX = new Vector.CartVect();
                globalReferenceX.X = 1;
                globalReferenceX.Y = 0;
                globalReferenceX.Z = 0;
                Vector.MemorySafe_CartVect localY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(surface.PlRHRVector, globalReferenceX));


                //new X axis is the localY cross the surface normal vector
                Vector.MemorySafe_CartVect localX = Vector.UnitVector(Vector.CrossProduct(localY, surface.PlRHRVector));

                //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<Vector.MemorySafe_CartCoord> translatedCoordinates = new List<Vector.MemorySafe_CartCoord>();
                Vector.MemorySafe_CartCoord newOrigin = new Vector.MemorySafe_CartCoord(0, 0, 0);
                translatedCoordinates.Add(newOrigin);
                for (int j = 1; j < surface.PlCoords.Count; j++)
                {
                    //randomly assigns the first polyLoop coordinate as the origin
                    Vector.MemorySafe_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;

                    //x coordinate is distance vector dot the new local X axis
                    double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
                    //y coordinate is distance vector dot the new local Y axis
                    double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
                    double tZ = 0;
                    Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX, tY, tZ);
                    translatedCoordinates.Add(translatedPt);

                }
                area = GetAreaFrom2DPolyLoop(translatedCoordinates);
                if (area == -999)
                {
                    logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined.");
                    logger.Debug("The coordinates should be 2D and could not be translated to 2D");
                    logger.Fatal("ATTENTION: Attempting to calculate surface area.  Test may be inaccurate and requires gbXML.org support");
                }
            }
            logger.Debug("ENDING SUBROUTINE: GetSurfaceArea");
            logger.Debug("Area:" + Math.Abs(area).ToString());
            if (area != -1 || area != -999)
            {
                return Math.Abs(area * areaConversion);
            }
            else return area;
        }
        private DOEgbXMLReportingObj GetPossibleSurfaceMatches(SurfaceDefinitions surface, List<SurfaceDefinitions> TestSurfaces, DOEgbXMLReportingObj report, Conversions.lengthUnitEnum standardLengthUnits, Conversions.lengthUnitEnum testLengthUnits, double testlengthConversion, double standardlengthConversion, Conversions.areaUnitEnum standardAreaUnits, Conversions.areaUnitEnum testAreaUnits, double testareaConversion, double standardareaConversion)
        {
            //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 += "</br>";
            //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 += "</br>";
            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 += "</br>";
            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 += "</br>";
            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("</br>");
                //initialize the return list
                //alternate between these two to filter out bad matches
                List<SurfaceDefinitions> possiblesList1 = new List<SurfaceDefinitions>();
                List<SurfaceDefinitions> possiblesList2 = new List<SurfaceDefinitions>();

                bool adjSpaceIdMatch = false;
                bool isLowTiltObject = false;
                bool isHighTiltObject = false;
                bool interiorWallFlipped = false;
                bool issurfaceRegular = false;
                bool istestSurfaceRegular = 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
                for(int ts = 0; ts<TestSurfaces.Count;ts++)
                {
                    SurfaceDefinitions testSurface = TestSurfaces[ts];
                    //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; }

                        //has to have the same order of adjacent space id strings to qualify.  This method assumes the strings are identical
                        if(surface.AdjSpaceId.Count == 1)
                        {
                            if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; }
                        }
                        if(surface.AdjSpaceId.Count == 2)
                        {
                            if(surface.SurfaceType == "Ceiling" && testSurface.SurfaceType == "InteriorFloor")
                            {
                                if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0])
                                {
                                    adjSpaceIdMatch = true;
                                }
                            }
                            else if (surface.SurfaceType == "InteriorFloor"  && testSurface.SurfaceType == "Ceiling")
                            {
                                if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0])
                                {
                                    adjSpaceIdMatch = true;
                                }
                            }
                            else if (surface.SurfaceType == "InteriorWall" && testSurface.SurfaceType == "InteriorWall")
                            {
                                if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[1])
                                {
                                    adjSpaceIdMatch = true;
                                }
                                if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0])
                                {
                                    adjSpaceIdMatch = true;
                                    interiorWallFlipped = true;
                                }
                            }
                            else
                            {
                                if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[1])
                                {
                                    adjSpaceIdMatch = true;
                                }
                            }
                        }
                        //if adjacent space Ids match and the surface types match, note this 
                        if (adjSpaceIdMatch)
                        {
                            if(!IsHighTiltSurface(surface) && !IsLowTiltSurface(surface))
                            {
                                if(surface.SurfaceType == testSurface.SurfaceType)
                                {
                                    report.MessageList.Add("AdjancentSpaceId(s) and surfaceType Match.");
                                    report.MessageList.Add("Surface id: " + testSurface.SurfaceId + " is a candidate.");
                                    report.MessageList.Add("</br>");
                                    possiblesList1.Add(testSurface);
                                }
                            }
                            else
                            {
                                if(IsLowTiltSurface(surface)) isLowTiltObject = true;
                                if (IsHighTiltSurface(surface)) isHighTiltObject = true;
                                if(surface.SurfaceType == testSurface.SurfaceType)
                                {
                                    report.MessageList.Add("AdjancentSpaceId(s) and surfaceType Match.");
                                    report.MessageList.Add("Surface id: " + testSurface.SurfaceId + " is a candidate.");
                                    report.MessageList.Add("</br>");
                                    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("<br/>");
                }
                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("<br/>");
                }
                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 = 0;
                        double azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth);
                        if(isLowTiltObject)
                        {
                            if(IsLowTiltSurface(testSurface)) //they are the same, both have small tils
                            {
                                tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt);
                            }
                            else //they are 180 degrees different, and the test surface is a high tilt while the standard is low tilt
                            {
                                if (testSurface.SurfaceType == "InteriorFloor")
                                {
                                    tiltDifference = Math.Abs(Math.Abs(testSurface.Tilt - 180) - surface.Tilt);
                                }
                                else
                                {
                                    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("</br>");
                                    continue;
                                }
                            }

                            //no azimuth tests
                            if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) //azimuth no longer matters for these surfaces
                            {
                                if(surface.Tilt != 0)
                                {
                                    if(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("</br>");
                                        continue;
                                    }
                                }
                                else
                                {
                                    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("</br>");
                                    continue;
                                }
                                
                            }
                            //if the tilt and azimuth is within tolerance
                            else
                            {
                                //add to the free List
                                if (surface.Tilt == 0)
                                {
                                    possiblesList2.Add(testSurface);
                                    if (tiltDifference == 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("</br>");
                                    }
                                    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("</br>");
                                    }
                                }
                                else
                                {
                                    //check the azimuth
                                    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("</br>");
                                        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("</br>");
                                        }
                                        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("</br>");
                                        }
                                    }
                                }
                            }
                        }
                        else if (isHighTiltObject)
                        {
                            if(IsHighTiltSurface(testSurface)) //both high tilt interior surfaces
                            {
                                tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt);
                            }
                            else //standard is high tilt, test is low tilt
                            {
                                if(testSurface.SurfaceType == "Ceiling")
                                {
                                    tiltDifference = Math.Abs(Math.Abs(testSurface.Tilt - 180) - surface.Tilt);
                                }
                                else
                                {
                                    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("</br>");
                                    continue;
                                }
                            }

                            //no azimuth tests
                            if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) //azimuth no longer matters for these surfaces
                            {
                                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("</br>");
                                continue;
                            }
                            //if the tilt and azimuth is within tolerance
                            else
                            {
                                //add to the free List
                                possiblesList2.Add(testSurface);
                                if (tiltDifference == 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("</br>");
                                }
                                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("</br>");
                                }
                            }
                        }
                        else
                        {
                            azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth);
                            if (interiorWallFlipped) //both high tilt interior surfaces
                            {
                                
                                azimuthDifference = Math.Abs(Math.Abs(testSurface.Azimuth - surface.Azimuth) - 180); //180 is needed because they should be separated by 180
                            }
                            tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt);
                            
                            //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("</br>");
                                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("</br>");
                                }
                                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("</br>");
                                }
                            }
                        }
                        
                    }
                }
                // 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("</br>");
                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("<br/>");
                        //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.");
                        issurfaceRegular = IsSurfaceRegular(surface);
                        foreach (SurfaceDefinitions regSurface in possiblesList2)
                        {
                            //ensures likewise that all the test surface candidates are regular, 
                            //TODO:  if they are not, then the entire set is assumed to be irregular (this could be improved)
                            istestSurfaceRegular = IsSurfaceRegular(regSurface);
                            if (istestSurfaceRegular == false) break;
                        }
                        if (issurfaceRegular && istestSurfaceRegular)
                        {
                            //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
                                //TODO:  consider removing or giving a feature to allow this to be overridded.
                                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((testlengthConversion * testsurface.Width) - surface.Width * standardlengthConversion);
                                if(widthDiff > DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance)
                                {
                                    widthDiff = Math.Abs((testlengthConversion * testsurface.Height) - surface.Width * standardlengthConversion);
                                    if(widthDiff < DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance)
                                    {
                                        //we will swap them
                                        double heightDiff = Math.Abs((testlengthConversion * testsurface.Width) - surface.Height * standardlengthConversion);
                                        if (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 + " have has the width and height swapped, but the width and height exactly match 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 + " have been swapped, but are within the width and height tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance + standardLengthUnits + " and " + DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance + standardLengthUnits + ", respectively.");
                                                //go ahead and now check the polyloop coordinates, and then the insertion point
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    //we won't swap them
                                    double heightDiff = Math.Abs((testlengthConversion * testsurface.Height) - surface.Height * standardlengthConversion);
                                    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 + standardLengthUnits + " and " + DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance + standardLengthUnits + ", 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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                                foreach (Vector.MemorySafe_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
                                    //create new
                                    Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z);
                                    coordList.Add(c2);

                                }
                                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<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>();
                                        foreach (Vector.MemorySafe_CartCoord coord in testSurface.PlCoords)
                                        {
                                            Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z);
                                            testCoordList.Add(c2);
                                        }
                                        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");
                                        }
                                        //convert from the test units to the standard units

                                        double difference = Math.Abs((area*standardareaConversion) - (testSurfacesArea * testareaConversion));
                                        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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                                foreach (Vector.MemorySafe_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
                                    Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z);
                                    coordList.Add(c2);

                                }
                                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<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>();
                                        foreach (Vector.MemorySafe_CartCoord coord in testSurface.PlCoords)
                                        {
                                            Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z);
                                            testCoordList.Add(c2);
                                        }
                                        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");
                                        }
                                        //convert the testSurfaceArea
                                        double difference = Math.Abs((area*standardareaConversion) - (testSurfacesArea * testareaConversion));
                                        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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                                foreach (Vector.MemorySafe_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
                                    Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0);
                                    coordList.Add(c2);

                                }
                                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<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>();
                                        foreach (Vector.MemorySafe_CartCoord coord in testSurface.PlCoords)
                                        {
                                            
                                            Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0);
                                            testCoordList.Add(c2);
                                        }
                                        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");
                                        }
                                        //provide area conversion
                                        double difference = Math.Abs((area*standardareaConversion) - (testSurfacesArea * testareaConversion));
                                        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 globalReferenceX = new Vector.CartVect();
                                globalReferenceX.X = 1;
                                globalReferenceX.Y = 0;
                                globalReferenceX.Z = 0;
                                Vector.MemorySafe_CartVect localY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(surface.PlRHRVector, globalReferenceX));
                                

                                //new X axis is the localY cross the surface normal vector
                                Vector.MemorySafe_CartVect localX = Vector.UnitVector(Vector.CrossProduct(localY, surface.PlRHRVector));

                                //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<Vector.MemorySafe_CartCoord> translatedCoordinates = new List<Vector.MemorySafe_CartCoord>();
                                Vector.MemorySafe_CartCoord newOrigin = new Vector.MemorySafe_CartCoord(0,0,0);
                                translatedCoordinates.Add(newOrigin);
                                for (int j = 1; j < surface.PlCoords.Count; j++)
                                {
                                    //randomly assigns the first polyLoop coordinate as the origin
                                    Vector.MemorySafe_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;
                                    
                                    //x coordinate is distance vector dot the new local X axis
                                    double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
                                    //y coordinate is distance vector dot the new local Y axis
                                    double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
                                    double tZ = 0;
                                    Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX,tY,tZ);
                                    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 testglobalReferenceX = new Vector.CartVect();
                                    globalReferenceX.X = 1;
                                    globalReferenceX.Y = 0;
                                    globalReferenceX.Z = 0;
                                    Vector.MemorySafe_CartVect testlocalY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(surface.PlRHRVector, testglobalReferenceX));

                                    //new X axis is the localY cross the surface normal vector
                                    Vector.MemorySafe_CartVect testlocalX = Vector.UnitVector(Vector.CrossProduct(testlocalY, surface.PlRHRVector));

                                    //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<Vector.MemorySafe_CartCoord> testtranslatedCoordinates = new List<Vector.MemorySafe_CartCoord>();
                                    Vector.MemorySafe_CartCoord newOriginTest = new Vector.MemorySafe_CartCoord(0,0,0);
                                    testtranslatedCoordinates.Add(newOriginTest);
                                    for (int j = 1; j < surface.PlCoords.Count; j++)
                                    {
                                        //randomly assigns the first polyLoop coordinate as the origin
                                        Vector.MemorySafe_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;
                                        
                                        //x coordinate is distance vector dot the new local X axis
                                        double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
                                        //y coordinate is distance vector dot the new local Y axis
                                        double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
                                        double tZ = 0;
                                        Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX,tY,tZ);
                                        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");
                                    }
                                    //convert to the standard units
                                    double difference = Math.Abs((area*standardareaConversion) - (testarea * testareaConversion));
                                    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("</br>");
                    report.MessageList.Add("Starting PolyLoop coordinate comparisons.......");
                    report.MessageList.Add("</br>");
                    if (possiblesList1.Count > 0)
                    {

                        foreach (SurfaceDefinitions testSurface in possiblesList1)
                        {
                            //check the polyLoop coordinates
                            foreach (Vector.MemorySafe_CartCoord standardPolyLoopCoord in surface.PlCoords)
                            {
                                report = GetPolyLoopCoordMatch(standardPolyLoopCoord, testSurface, report, surface.SurfaceId, testlengthConversion, standardlengthConversion);
                                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("</br>");
                    if(!isHighTiltObject && !isLowTiltObject && issurfaceRegular) //no point in doing this if thing is not square and regular
                    {
                        report.MessageList.Add("Starting Insertion Point Coordinate comparisons.......");
                        report.MessageList.Add("</br>");
                        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 * testlengthConversion) - (surface.InsertionPoint.X*standardlengthConversion));
                                double insPtYDiff = Math.Abs((testSurface.InsertionPoint.Y * testlengthConversion) - (surface.InsertionPoint.Y*standardlengthConversion));
                                double insPtZDiff = Math.Abs((testSurface.InsertionPoint.Z * testlengthConversion) - (surface.InsertionPoint.Z*standardlengthConversion));
                                if(interiorWallFlipped)
                                {
                                    report.MessageList.Add("The azimuths are flipped.  Looking to see if the test surface has properly defined the insertion point it has.");
                                    report.MessageList.Add("</br>");
                                    //find the complimenting insertion point
                                    for(int pt = 0; pt<testSurface.PlCoords.Count; pt++)
                                    {
                                        if(Math.Abs((surface.InsertionPoint.Z*standardlengthConversion) - (testSurface.PlCoords[pt].Z * testlengthConversion)) < DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance)
                                        {
                                            //this is a potential candidate
                                            if(Math.Abs((surface.InsertionPoint.X*standardlengthConversion) - testSurface.PlCoords[pt].X * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance)
                                            {
                                                if(Math.Abs((surface.InsertionPoint.Y*standardlengthConversion) - testSurface.PlCoords[pt].Y * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance)
                                                {
                                                    //a match
                                                    insPtXDiff = Math.Abs((testSurface.PlCoords[pt].X * testlengthConversion) - (surface.InsertionPoint.X*standardlengthConversion));
                                                    insPtYDiff = Math.Abs((testSurface.PlCoords[pt].Y * testlengthConversion) - (surface.InsertionPoint.Y*standardlengthConversion));
                                                    insPtZDiff = Math.Abs((testSurface.PlCoords[pt].Z * testlengthConversion) - (surface.InsertionPoint.Z*standardlengthConversion));
                                                }
                                                else
                                                {
                                                    //didn't find a candidate
                                                }
                                            }
                                            else
                                            {
                                                if (Math.Abs((surface.InsertionPoint.Y*standardlengthConversion) - testSurface.PlCoords[pt].Y * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance)
                                                {
                                                    //didn't find a candidate
                                                }
                                                else
                                                {
                                                    //didn't find a candidate
                                                }
                                            }
                                        }
                                    }
                                }
                                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<string> testFileSurfIds = new List<string>();
                            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<string> testFileSurfIds = new List<string>();
                            //foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); }
                            //report.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds);
                            return report;
                        }
                        return report;
                    }
                    else
                    {
                        //we do not conduct insertion point tests for horizontal surfaces
                        if (possiblesList2.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<string> testFileSurfIds = new List<string>();
                            foreach (SurfaceDefinitions surf in possiblesList2) { testFileSurfIds.Add(surf.SurfaceId); }

                            globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds);
                            return report;
                        }
                        else if (possiblesList2.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 (possiblesList2.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<string> testFileSurfIds = new List<string>();
                            //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 DOEgbXMLReportingObj GetPossibleOpeningMatches(OpeningDefinitions standardOpening, List<OpeningDefinitions> 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<OpeningDefinitions> possibleMatches = new List<OpeningDefinitions>();
            List<OpeningDefinitions> possibleMatches2 = new List<OpeningDefinitions>();
            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("</br>");
                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("</br>");
                        }
                    }

                    if (matchedParentAz && matchedParentTilt)
                    {
                        possibleMatches.Add(testOpening);
                        report.MessageList.Add("Successful Match Candidate Identified.");
                        report.MessageList.Add("</br>");
                    }
                    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("</br>");
                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.MemorySafe_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("</br>");
                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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                        foreach (Vector.MemorySafe_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
                            Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z);
                            coordList.Add(c2);

                        }
                        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<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>();
                            foreach (Vector.MemorySafe_CartCoord coord in testOpening.PlCoords)
                            {
                                Vector.MemorySafe_CartCoord o2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z);
                                testCoordList.Add(o2);
                            }
                            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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                        foreach (Vector.MemorySafe_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
                            Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z);
                            coordList.Add(c2);

                        }
                        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<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>();
                            foreach (Vector.MemorySafe_CartCoord coord in testOpening.PlCoords)
                            {
                                Vector.MemorySafe_CartCoord o2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z);
                                testCoordList.Add(o2);
                            }
                            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<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>();
                        foreach (Vector.MemorySafe_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
                            Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0);
                            coordList.Add(c2);

                        }
                        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<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>();
                            foreach (Vector.MemorySafe_CartCoord coord in testOpening.PlCoords)
                            {
                                Vector.MemorySafe_CartCoord c02 = new Vector.MemorySafe_CartCoord(coord.X, 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;
                        }

                    }
                    //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 globalReferenceX = new Vector.CartVect();
                        globalReferenceX.X = 1;
                        globalReferenceX.Y = 0;
                        globalReferenceX.Z = 0;
                        Vector.MemorySafe_CartVect localY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(standardOpening.PlRHRVector, globalReferenceX));
                        localY = Vector.UnitVector(localY);

                        //new X axis is the localY cross the surface normal vector
                        Vector.MemorySafe_CartVect localX = Vector.UnitVector(Vector.CrossProduct(localY, standardOpening.PlRHRVector));

                        //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<Vector.MemorySafe_CartCoord> translatedCoordinates = new List<Vector.MemorySafe_CartCoord>();
                        Vector.MemorySafe_CartCoord newOrigin = new Vector.MemorySafe_CartCoord(0,0,0);
                        translatedCoordinates.Add(newOrigin);
                        for (int j = 1; j < standardOpening.PlCoords.Count; j++)
                        {
                            //randomly assigns the first polyLoop coordinate as the origin
                            Vector.MemorySafe_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;
                            //x coordinate is distance vector dot the new local X axis
                            double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
                            //y coordinate is distance vector dot the new local Y axis
                            double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
                            double tZ = 0;
                            Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX,tY,tZ);
                            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 testglobalReferenceX = new Vector.CartVect();
                        globalReferenceX.X = 1;
                        globalReferenceX.Y = 0;
                        globalReferenceX.Z = 0;
                        Vector.MemorySafe_CartVect testlocalY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(testOpening.PlRHRVector, testglobalReferenceX));

                        //new X axis is the localY cross the surface normal vector
                        Vector.MemorySafe_CartVect testlocalX = Vector.UnitVector(Vector.CrossProduct(testlocalY, testOpening.PlRHRVector));

                        //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<Vector.MemorySafe_CartCoord> testtranslatedCoordinates = new List<Vector.MemorySafe_CartCoord>();
                        Vector.MemorySafe_CartCoord newOriginTest = new Vector.MemorySafe_CartCoord(0,0,0);
                        testtranslatedCoordinates.Add(newOriginTest);
                        for (int j = 1; j < testOpening.PlCoords.Count; j++)
                        {
                            //randomly assigns the first polyLoop coordinate as the origin
                            Vector.MemorySafe_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;
                            
                            //x coordinate is distance vector dot the new local X axis
                            double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z;
                            //y coordinate is distance vector dot the new local Y axis
                            double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z;
                            double tZ = 0;
                            Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX,tY,tZ);
                            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("</br>");
                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<OpeningDefinitions>(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("</br>");
                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<string> openingMatch = new List<string>();
                            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<string> 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<string> openingMatch = new List<string>();
                                                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;
        }
        public static DOEgbXMLPhase2Report SurfaceCCTest(Dictionary<string,List<SurfaceDefinitions>> enclosure, DOEgbXMLPhase2Report 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 17 2014
            report.testSummary = "This test ensures that each Surface has PolyLoop coordinate descriptions that wind in a counter clockwise order.";
            
            report.TestPassedDict = new Dictionary<string, bool>();
            try
            {
                
                foreach (KeyValuePair<string,List<SurfaceDefinitions>> kp in enclosure)
                {
                    List<string> ml = new List<string>();
                    

                    //this fakespacecount is a dummy because NamedSurfaceCCTest requires an integer.
                    int fakespacecount = 0;
                    Dictionary<string,List<Vector.MemorySafe_CartCoord>> sbcc = new Dictionary<string,List<Vector.MemorySafe_CartCoord>>();
                    foreach (SurfaceDefinitions s in kp.Value)
                    {
                        List<Vector.MemorySafe_CartCoord> pl = new List<Vector.MemorySafe_CartCoord>();
                        //different conditions if interior or exterior
                        if (s.AdjSpaceId.Count() == 1)
                        {
                            foreach (Vector.MemorySafe_CartCoord p in s.PlCoords)
                            {
                                Vector.MemorySafe_CartCoord msp = new Vector.MemorySafe_CartCoord(p.X, p.Y, p.Z);
                                pl.Add(msp);
                            }
                            sbcc[s.SurfaceId] = pl;
                            continue;
                        }
                        //implied that the count is equal to 2
                        else
                        {
                            for (int i = 0; i < s.AdjSpaceId.Count(); i++)
                            {
                                if (s.AdjSpaceId[i] == s.AdjSpaceId[i + 1])
                                {
                                    //slab on grade
                                    //treat normally
                                    foreach (Vector.MemorySafe_CartCoord p in s.PlCoords)
                                    {
                                        Vector.MemorySafe_CartCoord msp = new Vector.MemorySafe_CartCoord(p.X, p.Y, p.Z);
                                        pl.Add(msp);
                                    }
                                    sbcc[s.SurfaceId] = pl;
                                    break;
                                }
                                else
                                {
                                    //some other sort of typical interior surface.  outward normal points away from first, toward second.
                                    //if the adj id value of first is equal to space id, leave alone
                                    //otherwise reverse
                                    if (s.AdjSpaceId[i] == kp.Key)
                                    {
                                        foreach (Vector.MemorySafe_CartCoord p in s.PlCoords)
                                        {
                                            Vector.MemorySafe_CartCoord msp = new Vector.MemorySafe_CartCoord(p.X, p.Y, p.Z);
                                            pl.Add(msp);
                                        }
                                        sbcc[s.SurfaceId] = pl;
                                        break;
                                    }
                                    else
                                    {
                                        s.PlCoords.Reverse();
                                        foreach (Vector.MemorySafe_CartCoord p in s.PlCoords)
                                        {
                                            Vector.MemorySafe_CartCoord msp = new Vector.MemorySafe_CartCoord(p.X, p.Y, p.Z);
                                            pl.Add(msp);
                                        }
                                        sbcc[s.SurfaceId] = pl;
                                        s.PlCoords.Reverse();
                                        break;

                                    }
                                }
                            }
                        }
                    }
                    
                    Vector.MemorySafe_CartCoord sbcentroid = Vector.FindVolumetricCentroid(sbcc);
                    Dictionary<string, bool> surfres = Vector.NamedSurfacesCCWound(sbcentroid, sbcc,fakespacecount,false);

                    
                    foreach (KeyValuePair<string, bool> surfkp in surfres)
                    {
                        //since I have already checked to see if the names of the ids are unique, there is no reason to re-check something that has been checked.
                        //I could alternatively stry and store things at the Space level, but this doesn't really make sense, since this is specifically a Surface test
                        if(report.TestPassedDict.ContainsKey(surfkp.Key)) continue;
                        if (surfkp.Value == true)
                        {
                            ml.Add("PASS: Surface Boundary with id " + surfkp.Key + " is wound in a counterclockwise order.");
                        }
                        else
                        {
                            ml.Add("FAIL: Surface Boundary with id " + surfkp.Key + " is wound in a clockwise order.");
                        }
                    }
                    report.MessageList[kp.Key] = ml;

                }
        
            }
            catch (Exception e)
            {
                report.longMsg = ("SORRY, we have run into an unexpected issue:" + e.ToString());
                report.passOrFail = false;
                return report;
            }
            //if we have made it this far, that is good.
            if (report.TestPassedDict.ContainsValue(false))
            {
                report.longMsg = "TEST FAILED: Surfaces have been detected with clockwise winding orders.  We suggest reviewing if these errors have occurred on interior ";
                report.longMsg += " or exterior surfaces.  If interior surfaces, likely this will not be a problem unless the order of insulation materials for your interior";
                report.longMsg += " surface is important.  Exterior surfaces pointing with incorrect orientation is a problem.  In either case, we suggest you contact your BIM authoring tool ";
                report.longMsg += " to let them know there is an error.";
                report.passOrFail = false;
                return report;
            }
            else
            {
                report.longMsg = "TEST PASSED: All Surfaces have counter-clockwise winding orders.";
                report.passOrFail = true;
                return report;
            }
        }
        public static LLRet GetLLForRoof(List<Vector.MemorySafe_CartCoord> surfacecoords)
        {
            LLRet ll = new LLRet();
            ll.indices = new List<int>();
            int surfindex = -1;
            CartesianPoint cp = new CartesianPoint();

            Vector.CartCoord llsurf = new Vector.CartCoord();

            Vector.MemorySafe_CartVect RHRVector = Vector.GetMemRHR(surfacecoords);
            if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == 1)
            {

                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X = surfacecoords[sccount].X;
                        llsurf.Y = surfacecoords[sccount].Y;
                        llsurf.Z = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;

                    }
                    //get lower left...most low(largest Y), then most left (smallest X)
                    if (surfacecoords[sccount].Y >= llsurf.Y)
                    {
                        if (surfacecoords[sccount].X < llsurf.X)
                        {
                            llsurf.X = surfacecoords[sccount].X;
                            llsurf.Y = surfacecoords[sccount].Y;
                            llsurf.Z = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }
            }
            else
            {
                //special procedure for this type of roof
            }
            Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(llsurf.X, llsurf.Y, llsurf.Z);
            cp = makegbCartesianPt(LLeft);
            ll.cp = cp;
            ll.indices.Add(surfindex);
            return ll;
        }
        //Reminder to factor in CADAzimuth if appropriate
        public static LLRet GetLLForOpening(List<Vector.MemorySafe_CartCoord> surfacecoords, List<Vector.MemorySafe_CartCoord> openingcoords)
        {
            LLRet ll = new LLRet();
            ll.indices = new List<int>();
            int surfindex=-1;
            int opindex=-1;
            CartesianPoint cp = new CartesianPoint();

            //we want to verify that this is indeed correct
            //west-facing

            Vector.MemorySafe_CartVect RHRVector = Vector.GetMemRHR(surfacecoords);
            if (Math.Abs(RHRVector.X) == -1 && RHRVector.Y == 0 && RHRVector.Z == 0)
            {

                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X = surfacecoords[sccount].X;
                        llsurf.Y = surfacecoords[sccount].Y;
                        llsurf.Z = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most lowest(smallest Z), then most left (largest Y)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if(surfacecoords[sccount].Y > llsurf.Y)
                        {
                            llsurf.X = surfacecoords[sccount].X;
                            llsurf.Y = surfacecoords[sccount].Y;
                            llsurf.Z = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex = occount;
                        continue;
                    }
                    //get lower left...most low(lowest Z), then most left (largest Y)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if(openingcoords[occount].Y > llopening.Y)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.Y - llopening.Y);
                double diffY = Math.Abs(llopening.Z - llsurf.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0);
                cp = makegbCartesianPt(LLeft);
            }
            //north-facing
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 1 && RHRVector.Z == 0)
            {

                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X = surfacecoords[sccount].X;
                        llsurf.Y = surfacecoords[sccount].Y;
                        llsurf.Z = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (largest X)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if(surfacecoords[sccount].X > llsurf.X)
                        {
                            llsurf.X = surfacecoords[sccount].X;
                            llsurf.Y = surfacecoords[sccount].Y;
                            llsurf.Z = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex = occount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (largest X)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if(openingcoords[occount].X > llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Z - llopening.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0);
                cp= makegbCartesianPt(LLeft);
            }
            //south-facing
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == -1 && RHRVector.Z == 0)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X = surfacecoords[sccount].X;
                        llsurf.Y = surfacecoords[sccount].Y;
                        llsurf.Z = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most low(smaller Z), then most left (smallest X)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if(surfacecoords[sccount].X < llsurf.X)
                        {
                            llsurf.X = surfacecoords[sccount].X;
                            llsurf.Y = surfacecoords[sccount].Y;
                            llsurf.Z = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex = occount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (smallest X)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if(openingcoords[occount].X < llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Z - llopening.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0);
                cp = makegbCartesianPt(LLeft);
            }

            //east-facing
            else if (Math.Abs(RHRVector.X) == 1 && RHRVector.Y == 0 && RHRVector.Z == 0)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X = surfacecoords[sccount].X;
                        llsurf.Y = surfacecoords[sccount].Y;
                        llsurf.Z = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most low(smaller Z), then most left (smallest Y)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if(surfacecoords[sccount].Y < llsurf.Y)
                        {
                            llsurf.X = surfacecoords[sccount].X;
                            llsurf.Y = surfacecoords[sccount].Y;
                            llsurf.Z = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex = occount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (smallest Y)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if(openingcoords[occount].Y < llopening.Y)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.Y - llopening.Y);
                double diffY = Math.Abs(llsurf.Z - llopening.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0);
                cp = makegbCartesianPt(LLeft);
            }

            //floors
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == -1)
            {

                Vector.CartCoord llsurf = new Vector.CartCoord();
                LLRet llroof = GetLLForFloor(surfacecoords);
                llsurf.X = Convert.ToDouble(llroof.cp.Coordinate[0]);
                llsurf.Y = Convert.ToDouble(llroof.cp.Coordinate[1]);
                llsurf.Z = Convert.ToDouble(llroof.cp.Coordinate[2]);
                surfindex = llroof.indices[0];

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex = occount;

                        continue;
                    }
                    //get lower left...most low(smallest Y), then most left (largest X)
                    if (openingcoords[occount].Y <= llopening.Y)
                    {
                        if (openingcoords[occount].X > llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex = occount;

                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Y - llopening.Y);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }
            //flat roof
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == 1)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                LLRet llroof = GetLLForRoof(surfacecoords);
                llsurf.X = Convert.ToDouble(llroof.cp.Coordinate[0]);
                llsurf.Y = Convert.ToDouble(llroof.cp.Coordinate[1]);
                llsurf.Z = Convert.ToDouble(llroof.cp.Coordinate[2]);
                surfindex = llroof.indices[0];

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex = occount;
                        continue;
                    }
                    //get lower left...most low(largest Y), then most left (smallest X)
                    if (openingcoords[occount].Y >= llopening.Y)
                    {
                        if (openingcoords[occount].X < llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex = occount;

                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Y - llopening.Y);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }
            //plane does not reside on a primary axis
            else
            {
                //I will deal with this later
                //have to factor in what is a "roof" or "floor" or "wall" based on the default tilt settings
            }
            ll.cp = cp;
            ll.indices.Add(surfindex);
            ll.indices.Add(opindex);
            return ll;
        }
        //Reminder to factor in CADAzimuth if appropriate
        public static LLRet GetLLForOpening(List <Vector.MemorySafe_CartCoord> surfacecoords, List <Vector.MemorySafe_CartCoord> openingcoords)
        {
            LLRet ll = new LLRet();

            ll.indices = new List <int>();
            int            surfindex = -1;
            int            opindex   = -1;
            CartesianPoint cp        = new CartesianPoint();

            //we want to verify that this is indeed correct
            //west-facing

            Vector.MemorySafe_CartVect RHRVector = Vector.GetMemRHR(surfacecoords);
            if (Math.Abs(RHRVector.X) == -1 && RHRVector.Y == 0 && RHRVector.Z == 0)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X  = surfacecoords[sccount].X;
                        llsurf.Y  = surfacecoords[sccount].Y;
                        llsurf.Z  = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most lowest(smallest Z), then most left (largest Y)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if (surfacecoords[sccount].Y > llsurf.Y)
                        {
                            llsurf.X  = surfacecoords[sccount].X;
                            llsurf.Y  = surfacecoords[sccount].Y;
                            llsurf.Z  = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex     = occount;
                        continue;
                    }
                    //get lower left...most low(lowest Z), then most left (largest Y)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if (openingcoords[occount].Y > llopening.Y)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex     = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.Y - llopening.Y);
                double diffY = Math.Abs(llopening.Z - llsurf.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }
            //north-facing
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 1 && RHRVector.Z == 0)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X  = surfacecoords[sccount].X;
                        llsurf.Y  = surfacecoords[sccount].Y;
                        llsurf.Z  = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (largest X)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if (surfacecoords[sccount].X > llsurf.X)
                        {
                            llsurf.X  = surfacecoords[sccount].X;
                            llsurf.Y  = surfacecoords[sccount].Y;
                            llsurf.Z  = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex     = occount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (largest X)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if (openingcoords[occount].X > llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex     = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Z - llopening.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }
            //south-facing
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == -1 && RHRVector.Z == 0)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X  = surfacecoords[sccount].X;
                        llsurf.Y  = surfacecoords[sccount].Y;
                        llsurf.Z  = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most low(smaller Z), then most left (smallest X)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if (surfacecoords[sccount].X < llsurf.X)
                        {
                            llsurf.X  = surfacecoords[sccount].X;
                            llsurf.Y  = surfacecoords[sccount].Y;
                            llsurf.Z  = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex     = occount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (smallest X)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if (openingcoords[occount].X < llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex     = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Z - llopening.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }

            //east-facing
            else if (Math.Abs(RHRVector.X) == 1 && RHRVector.Y == 0 && RHRVector.Z == 0)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                for (int sccount = 0; sccount < surfacecoords.Count; sccount++)
                {
                    if (sccount == 0)
                    {
                        llsurf.X  = surfacecoords[sccount].X;
                        llsurf.Y  = surfacecoords[sccount].Y;
                        llsurf.Z  = surfacecoords[sccount].Z;
                        surfindex = sccount;
                        continue;
                    }
                    //get lower left...most low(smaller Z), then most left (smallest Y)
                    if (surfacecoords[sccount].Z <= llsurf.Z)
                    {
                        if (surfacecoords[sccount].Y < llsurf.Y)
                        {
                            llsurf.X  = surfacecoords[sccount].X;
                            llsurf.Y  = surfacecoords[sccount].Y;
                            llsurf.Z  = surfacecoords[sccount].Z;
                            surfindex = sccount;
                        }
                    }
                }

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex     = occount;
                        continue;
                    }
                    //get lower left...most low(smallest Z), then most left (smallest Y)
                    if (openingcoords[occount].Z <= llopening.Z)
                    {
                        if (openingcoords[occount].Y < llopening.Y)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex     = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.Y - llopening.Y);
                double diffY = Math.Abs(llsurf.Z - llopening.Z);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }

            //floors
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == -1)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                LLRet            llroof = GetLLForFloor(surfacecoords);
                llsurf.X  = Convert.ToDouble(llroof.cp.Coordinate[0]);
                llsurf.Y  = Convert.ToDouble(llroof.cp.Coordinate[1]);
                llsurf.Z  = Convert.ToDouble(llroof.cp.Coordinate[2]);
                surfindex = llroof.indices[0];

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex     = occount;

                        continue;
                    }
                    //get lower left...most low(smallest Y), then most left (largest X)
                    if (openingcoords[occount].Y <= llopening.Y)
                    {
                        if (openingcoords[occount].X > llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex     = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Y - llopening.Y);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }
            //flat roof
            else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == 1)
            {
                Vector.CartCoord llsurf = new Vector.CartCoord();
                LLRet            llroof = GetLLForRoof(surfacecoords);
                llsurf.X  = Convert.ToDouble(llroof.cp.Coordinate[0]);
                llsurf.Y  = Convert.ToDouble(llroof.cp.Coordinate[1]);
                llsurf.Z  = Convert.ToDouble(llroof.cp.Coordinate[2]);
                surfindex = llroof.indices[0];

                Vector.CartCoord llopening = new Vector.CartCoord();
                for (int occount = 0; occount < openingcoords.Count; occount++)
                {
                    if (occount == 0)
                    {
                        llopening.X = openingcoords[occount].X;
                        llopening.Y = openingcoords[occount].Y;
                        llopening.Z = openingcoords[occount].Z;
                        opindex     = occount;
                        continue;
                    }
                    //get lower left...most low(largest Y), then most left (smallest X)
                    if (openingcoords[occount].Y >= llopening.Y)
                    {
                        if (openingcoords[occount].X < llopening.X)
                        {
                            llopening.X = openingcoords[occount].X;
                            llopening.Y = openingcoords[occount].Y;
                            llopening.Z = openingcoords[occount].Z;
                            opindex     = occount;
                        }
                    }
                }
                double diffX = Math.Abs(llsurf.X - llopening.X);
                double diffY = Math.Abs(llsurf.Y - llopening.Y);
                Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0);
                cp = makegbCartesianPt(LLeft);
            }
            //plane does not reside on a primary axis
            else
            {
                //I will deal with this later
                //have to factor in what is a "roof" or "floor" or "wall" based on the default tilt settings
            }
            ll.cp = cp;
            ll.indices.Add(surfindex);
            ll.indices.Add(opindex);
            return(ll);
        }