/// <summary>
        /// Add floor placement point
        /// </summary>
        /// <param name="row">COBieCoordinateRow holding the data</param>
        private void AddFloorPlacement(COBieCoordinateRow row)
        {
            IfcBuildingStorey ifcBuildingStorey = null;

            if (ValidateString(row.ExtIdentifier))
            {
                IfcGloballyUniqueId id = new IfcGloballyUniqueId(row.ExtIdentifier);
                ifcBuildingStorey = Model.FederatedInstances.Where <IfcBuildingStorey>(bs => bs.GlobalId == id).FirstOrDefault();
            }

            if ((ifcBuildingStorey == null) && (ValidateString(row.RowName)))
            {
                ifcBuildingStorey = Model.FederatedInstances.Where <IfcBuildingStorey>(bs => bs.Name == row.RowName).FirstOrDefault();
            }

            if (ifcBuildingStorey != null)
            {
                var placementRelToIfcProduct      = ifcBuildingStorey.GetContainingStructuralElement();
                IfcLocalPlacement objectPlacement = CalcObjectPlacement(row, placementRelToIfcProduct);
                if (objectPlacement != null)
                {
                    //using statement will set the Model.OwnerHistoryAddObject to IfcRoot.OwnerHistory as OwnerHistoryAddObject is used upon any property changes,
                    //then swaps the original OwnerHistoryAddObject back in the dispose, so set any properties within the using statement
                    using (COBieXBimEditScope context = new COBieXBimEditScope(Model, ifcBuildingStorey.OwnerHistory))
                    {
                        ifcBuildingStorey.ObjectPlacement = objectPlacement;
                    }
                }
            }
        }
        private bool GetPointFromRow(COBieCoordinateRow row, out XbimPoint3D point)
        {
            double x, y, z;

            if ((double.TryParse(row.CoordinateXAxis, out x)) &&
                (double.TryParse(row.CoordinateYAxis, out y)) &&
                (double.TryParse(row.CoordinateZAxis, out z))
                )
            {
                point = new XbimPoint3D(x, y, z);
                return(true);
            }
            point = new XbimPoint3D();
            return(false);
        }
        /// <summary>
        /// Calculate the ObjectPlacment for an IfcProduct from row data and the parent object
        /// </summary>
        /// <param name="row">COBieCoordinateRow holding the data</param>
        /// <param name="placementRelToIfcProduct">IfcProduct that the ObjectPlacment relates too, i.e. the parent of the ifcProduct ObjectPlacment we are calculating</param>
        /// <returns></returns>
        private IfcLocalPlacement CalcObjectPlacement(COBieCoordinateRow row, IfcProduct placementRelToIfcProduct)
        {
            XbimPoint3D locationPt;
            bool        havePoint = GetPointFromRow(row, out locationPt);

            if (havePoint)
            {
                if ((placementRelToIfcProduct != null) && (placementRelToIfcProduct.ObjectPlacement is IfcLocalPlacement))
                {
                    //TEST, change the building position to see if the same point comes out in Excel sheet, it should be, and in test was.
                    //((IfcAxis2Placement3D)((IfcLocalPlacement)placementRelToIfcProduct.ObjectPlacement).RelativePlacement).SetNewLocation(10.0, 10.0, 0.0);
                    IfcLocalPlacement placementRelTo = (IfcLocalPlacement)placementRelToIfcProduct.ObjectPlacement;
                    XbimMatrix3D      matrix3D       = ConvertMatrix3D(placementRelTo);

                    //we want to take off the translations and rotations caused by IfcLocalPlacement of the parent objects as we will add these to the new IfcLocalPlacement for this floor
                    matrix3D.Invert();                           //so invert matrix to remove the translations to give the origin for the next IfcLocalPlacement
                    locationPt = matrix3D.Transform(locationPt); //get the point with relation to the last IfcLocalPlacement i.e the parent element

                    //Get the WCS matrix values
                    double rotX, rotY, rotZ;
                    if (!(double.TryParse(row.YawRotation, out rotX) && (double.NaN.CompareTo(rotX) != 0)))
                    {
                        rotX = 0.0;
                    }

                    if (!(double.TryParse(row.ElevationalRotation, out rotY) && (double.NaN.CompareTo(rotY) != 0)))
                    {
                        rotY = 0.0;
                    }

                    if (double.TryParse(row.ClockwiseRotation, out rotZ) && (double.NaN.CompareTo(rotZ) != 0))
                    {
                        rotZ = rotZ * -1; //convert back from clockwise to anti clockwise
                    }
                    else
                    {
                        rotZ = 0.0;
                    }

                    //apply the WCS rotation from COBie Coordinates stored values
                    XbimMatrix3D matrixNewRot3D = new XbimMatrix3D();
                    if (rotX != 0.0)
                    {
                        matrixNewRot3D.RotateAroundXAxis(TransformedBoundingBox.DegreesToRadians(rotX));
                    }
                    if (rotY != 0.0)
                    {
                        matrixNewRot3D.RotateAroundYAxis(TransformedBoundingBox.DegreesToRadians(rotY));
                    }
                    if (rotZ != 0.0)
                    {
                        matrixNewRot3D.RotateAroundZAxis(TransformedBoundingBox.DegreesToRadians(rotZ));
                    }

                    //remove any displacement from the matrix which moved/rotated us to the object space
                    matrix3D.OffsetX = 0.0F;
                    matrix3D.OffsetY = 0.0F;
                    matrix3D.OffsetZ = 0.0F;

                    //remove the matrix that got use to the object space from the WCS location of this object
                    XbimMatrix3D matrixRot3D = matrixNewRot3D * matrix3D;

                    //get the rotation vectors to place in the new IfcAxis2Placement3D for the new IfcLocalPlacement for this object
                    XbimVector3D ucsAxisX = matrixRot3D.Transform(new XbimVector3D(1, 0, 0));
                    XbimVector3D ucsAxisZ = matrixRot3D.Transform(new XbimVector3D(0, 0, 1));
                    ucsAxisX = ucsAxisX.Normalized();
                    ucsAxisZ = ucsAxisZ.Normalized();

                    //create the new IfcAxis2Placement3D
                    IfcAxis2Placement3D relativePlacemant = Model.Instances.New <IfcAxis2Placement3D>();
                    relativePlacemant.SetNewDirectionOf_XZ(ucsAxisX.X, ucsAxisX.Y, ucsAxisX.Z, ucsAxisZ.X, ucsAxisZ.Y, ucsAxisZ.Z);
                    relativePlacemant.SetNewLocation(locationPt.X, locationPt.Y, locationPt.Z);

                    //Set up IfcLocalPlacement
                    IfcLocalPlacement objectPlacement = Model.Instances.New <IfcLocalPlacement>();
                    objectPlacement.PlacementRelTo    = placementRelTo;
                    objectPlacement.RelativePlacement = relativePlacemant;

                    return(objectPlacement);
                }
            }
            return(null);
        }
        /// <summary>
        /// Create and setup Bounding Box's
        /// </summary>
        /// <param name="cOBieSheet">COBieSheet of COBieCoordinateRow to read data from</param>
        public void SerialiseCoordinate(COBieSheet <COBieCoordinateRow> cOBieSheet)
        {
            using (XbimReadWriteTransaction trans = Model.BeginTransaction("Add Coordinate"))
            {
                try
                {
                    int count = 1;
                    ProgressIndicator.ReportMessage("Starting Coordinates...");
                    ProgressIndicator.Initialise("Creating Coordinates", cOBieSheet.RowCount);
                    var rows = cOBieSheet.Rows.OrderBy(a => a.SheetName == "Component").ThenBy(a => a.SheetName == "Space").ThenBy(a => a.SheetName == "Floor"); //order into Floor,Space,Component, needed to build object placements

                    for (int i = 0; i < cOBieSheet.RowCount; i++)
                    {
                        COBieCoordinateRow row     = rows.ElementAt(i);// cOBieSheet[i];
                        COBieCoordinateRow rowNext = null;
                        BumpTransaction(trans, count);
                        count++;

                        //do floor placement point
                        if ((ValidateString(row.Category)) &&
                            (row.Category.ToLower() == "point")
                            )
                        {
                            ProgressIndicator.IncrementAndUpdate();

                            AddFloorPlacement(row);
                            continue; //work done, next loop please
                        }
                        //do bounding box items
                        if ((ValidateString(row.Category)) &&
                            (row.Category.Contains("box-"))
                            )
                        {
                            i++;                             //set to get next row

                            if (i < cOBieSheet.RowCount)     //get next row if still in range
                            {
                                rowNext = rows.ElementAt(i); //cOBieSheet[i];
                            }
                            if ((rowNext != null) &&
                                (ValidateString(rowNext.Category)) &&
                                (rowNext.Category.Contains("box-")) &&
                                (ValidateString(row.SheetName)) &&
                                //(ValidateString(row.RowName)) &&
                                (ValidateString(rowNext.SheetName)) &&
                                //(ValidateString(rowNext.RowName)) &&
                                (row.SheetName == rowNext.SheetName) &&
                                (row.RowName == rowNext.RowName)
                                )
                            {
                                ProgressIndicator.IncrementAndUpdate();

                                AddBoundingBoxAsExtrudedAreaSolid(row, rowNext);

                                ProgressIndicator.IncrementAndUpdate(); //two row processed here

//#if DEBUG
//                                Console.WriteLine("{0} : {1} == {2} : {3} ", row.SheetName, row.RowName, rowNext.SheetName, rowNext.RowName);
//#endif
                            }
                            else
                            {
#if DEBUG
                                if (rowNext == null)
                                {
                                    Console.WriteLine("Failed to find pair {0} : {1} != {2} : {3} ", row.SheetName, row.RowName, "Null", "Null");
                                }
                                else
                                {
                                    Console.WriteLine("Failed to find pair {0} : {1} != {2} : {3} ", row.SheetName, row.RowName, rowNext.SheetName, rowNext.RowName);
                                }
#endif
                                i--; //set back in case next is point, as two box points failed
                            }
                        }
                    }
                    ProgressIndicator.Finalise();

                    trans.Commit();
                }
                catch (Exception)
                {
                    //TODO: Catch with logger?
                    throw;
                }
            }
        }
        /// <summary>
        /// Add a Bounding Box extrusion onto the ifcProduct
        /// </summary>
        /// <param name="row">COBieCoordinateRow holding the data for one corner</param>
        /// <param name="rowNext">COBieCoordinateRow holding the data for the other corner</param>
        /// <param name="placementRelToIfcProduct">Product which is parent of ifcProduct passed product to add extrusion onto</param>
        /// <param name="ifcProduct">IfcProduct to add the extrusion onto</param>
        private void AddExtrudedRectangle(COBieCoordinateRow row, COBieCoordinateRow rowNext, IfcProduct ifcProduct, IfcProduct placementRelToIfcProduct)
        {
            if (ifcProduct != null)
            {
                COBieCoordinateRow lowerLeftRow, upperRightRow;
                if (row.Category.ToLower() == "box-lowerleft")
                {
                    lowerLeftRow  = row;
                    upperRightRow = rowNext;
                }
                else
                {
                    lowerLeftRow  = rowNext;
                    upperRightRow = row;
                }
                IfcLocalPlacement objectPlacement = CalcObjectPlacement(lowerLeftRow, placementRelToIfcProduct);
                if (objectPlacement != null)
                {
                    //set the object placement for the space
                    ifcProduct.ObjectPlacement = objectPlacement;

                    //get matrix to the space placement
                    XbimMatrix3D matrix3D = ConvertMatrix3D(objectPlacement);
                    //invert matrix so we can convert row points back to the object space
                    matrix3D.Invert();
                    //lets get the points from the two rows
                    XbimPoint3D lowpt, highpt;
                    if ((GetPointFromRow(upperRightRow, out highpt)) &&
                        (GetPointFromRow(lowerLeftRow, out lowpt))
                        )
                    {
                        //transform the points back to object space
                        lowpt  = matrix3D.Transform(lowpt);
                        highpt = matrix3D.Transform(highpt);
                        //in object space so we can use Rect3D as this will be aligned with coordinates systems X and Y
                        XbimRect3D bBox = new XbimRect3D();
                        bBox.Location = lowpt;
                        bBox.Union(highpt);
                        if ((double.NaN.CompareTo(bBox.SizeX) != 0) && (double.NaN.CompareTo(bBox.SizeY) != 0))
                        {
                            XbimPoint3D ctrPt = new XbimPoint3D(bBox.X + (bBox.SizeX / 2.0), bBox.Y + (bBox.SizeY / 2.0), bBox.Z + (bBox.SizeZ / 2.0));

                            //Create IfcRectangleProfileDef
                            IfcCartesianPoint      IfcCartesianPointCtr   = Model.Instances.New <IfcCartesianPoint>(cp => { cp.X = ctrPt.X; cp.Y = ctrPt.Y; cp.Z = 0.0; }); //centre point of 2D box
                            IfcDirection           IfcDirectionXDir       = Model.Instances.New <IfcDirection>(d => { d.X = 1.0; d.Y = 0; d.Z = 0.0; });                    //default to X direction
                            IfcAxis2Placement2D    ifcAxis2Placement2DCtr = Model.Instances.New <IfcAxis2Placement2D>(a2p => { a2p.Location = IfcCartesianPointCtr; a2p.RefDirection = IfcDirectionXDir; });
                            IfcRectangleProfileDef ifcRectangleProfileDef = Model.Instances.New <IfcRectangleProfileDef>(rpd => { rpd.ProfileType = IfcProfileTypeEnum.AREA; rpd.ProfileName = row.RowName; rpd.Position = ifcAxis2Placement2DCtr; rpd.XDim = bBox.SizeX; rpd.YDim = bBox.SizeY; });

                            //Create IfcExtrudedAreaSolid
                            IfcDirection         IfcDirectionAxis            = Model.Instances.New <IfcDirection>(d => { d.X = 0.0; d.Y = 0; d.Z = 1.0; });            //default to Z direction
                            IfcDirection         IfcDirectionRefDir          = Model.Instances.New <IfcDirection>(d => { d.X = 1.0; d.Y = 0; d.Z = 0.0; });            //default to X direction
                            IfcCartesianPoint    IfcCartesianPointPosition   = Model.Instances.New <IfcCartesianPoint>(cp => { cp.X = 0.0; cp.Y = 0.0; cp.Z = 0.0; }); //centre point of 2D box
                            IfcAxis2Placement3D  ifcAxis2Placement3DPosition = Model.Instances.New <IfcAxis2Placement3D>(a2p3D => { a2p3D.Location = IfcCartesianPointPosition; a2p3D.Axis = IfcDirectionAxis; a2p3D.RefDirection = IfcDirectionRefDir; });
                            IfcDirection         IfcDirectionExtDir          = Model.Instances.New <IfcDirection>(d => { d.X = 0.0; d.Y = 0; d.Z = 1.0; });            //default to Z direction
                            IfcExtrudedAreaSolid ifcExtrudedAreaSolid        = Model.Instances.New <IfcExtrudedAreaSolid>(eas => { eas.SweptArea = ifcRectangleProfileDef; eas.Position = ifcAxis2Placement3DPosition; eas.ExtrudedDirection = IfcDirectionExtDir; eas.Depth = bBox.SizeZ; });
                            var project = Model.FederatedInstances.OfType <IfcProject>().FirstOrDefault();
                            //Create IfcShapeRepresentation
                            IfcShapeRepresentation ifcShapeRepresentation = Model.Instances.New <IfcShapeRepresentation>(sr =>
                            {
                                sr.ContextOfItems           = project.ModelContext;
                                sr.RepresentationIdentifier = "Body"; sr.RepresentationType = "SweptSolid";
                            });
                            ifcShapeRepresentation.Items.Add(ifcExtrudedAreaSolid);

                            //create IfcProductDefinitionShape
                            IfcProductDefinitionShape ifcProductDefinitionShape = Model.Instances.New <IfcProductDefinitionShape>(pds => { pds.Name = row.Name; pds.Description = row.SheetName; });
                            ifcProductDefinitionShape.Representations.Add(ifcShapeRepresentation);

                            //Link to the IfcProduct
                            ifcProduct.Representation = ifcProductDefinitionShape;
                        }
                        else
                        {
#if DEBUG
                            Console.WriteLine("Failed to calculate box size for {0}", row.Name);
#endif
                        }
                    }
                }
                else
                {
#if DEBUG
                    Console.WriteLine("Failed to add Object placement for {0}", row.Name);
#endif
                }
            }
        }
        /// <summary>
        /// Add space placement
        /// </summary>
        /// <param name="row">COBieCoordinateRow holding the data for one corner</param>
        /// <param name="rowNext">COBieCoordinateRow holding the data for the other corner</param>
        private void AddBoundingBoxAsExtrudedAreaSolid(COBieCoordinateRow row, COBieCoordinateRow rowNext)
        {
            if (row.SheetName.ToLower() == "floor")
            {
                IfcBuildingStorey ifcBuildingStorey = null;
                if (ValidateString(row.ExtIdentifier))
                {
                    IfcGloballyUniqueId id = new IfcGloballyUniqueId(row.ExtIdentifier);
                    ifcBuildingStorey = Model.FederatedInstances.Where <IfcBuildingStorey>(bs => bs.GlobalId == id).FirstOrDefault();
                }

                if ((ifcBuildingStorey == null) && (ValidateString(row.RowName)))
                {
                    ifcBuildingStorey = Model.FederatedInstances.Where <IfcBuildingStorey>(bs => bs.Name == row.RowName).FirstOrDefault();
                }

                if (ifcBuildingStorey != null)
                {
                    //using statement will set the Model.OwnerHistoryAddObject to IfcRoot.OwnerHistory as OwnerHistoryAddObject is used upon any property changes,
                    //then swaps the original OwnerHistoryAddObject back in the dispose, so set any properties within the using statement
                    using (COBieXBimEditScope context = new COBieXBimEditScope(Model, ifcBuildingStorey.OwnerHistory))
                    {
                        var placementRelToIfcProduct = ifcBuildingStorey.GetContainingStructuralElement();
                        AddExtrudedRectangle(row, rowNext, ifcBuildingStorey, placementRelToIfcProduct);
                    }
                }
            }
            if (row.SheetName.ToLower() == "space")
            {
                IfcSpace ifcSpace = null;
                if (ValidateString(row.ExtIdentifier))
                {
                    IfcGloballyUniqueId id = new IfcGloballyUniqueId(row.ExtIdentifier);
                    ifcSpace = Model.FederatedInstances.Where <IfcSpace>(bs => bs.GlobalId == id).FirstOrDefault();
                }
                if ((ifcSpace == null) && (ValidateString(row.RowName)))
                {
                    ifcSpace = Model.FederatedInstances.Where <IfcSpace>(bs => bs.Name == row.RowName).FirstOrDefault();
                }
                if ((ifcSpace == null) && (ValidateString(row.RowName)))
                {
                    IEnumerable <IfcSpace> ifcSpaces = Model.FederatedInstances.Where <IfcSpace>(bs => bs.Description == row.RowName);
                    //check we have one, if >1 then no match
                    if ((ifcSpaces.Any()) && (ifcSpaces.Count() == 1))
                    {
                        ifcSpace = ifcSpaces.FirstOrDefault();
                    }
                }

                if (ifcSpace != null)
                {
                    if (ifcSpace.Representation != null) //check it has no graphics attached, if it has then skip
                    {
                        return;
                    }
                    //using statement will set the Model.OwnerHistoryAddObject to IfcRoot.OwnerHistory as OwnerHistoryAddObject is used upon any property changes,
                    //then swaps the original OwnerHistoryAddObject back in the dispose, so set any properties within the using statement
                    using (COBieXBimEditScope context = new COBieXBimEditScope(Model, ifcSpace.OwnerHistory))
                    {
                        var placementRelToIfcProduct = ifcSpace.GetContainingStructuralElement();
                        AddExtrudedRectangle(row, rowNext, ifcSpace, placementRelToIfcProduct);
                    }
                }
            }

            if (row.SheetName.ToLower() == "component")
            {
                IfcElement ifcElement = null;
                if (ValidateString(row.ExtIdentifier))
                {
                    IfcGloballyUniqueId id = new IfcGloballyUniqueId(row.ExtIdentifier);
                    ifcElement = Model.FederatedInstances.Where <IfcElement>(bs => bs.GlobalId == id).FirstOrDefault();
                }
                if ((ifcElement == null) && (ValidateString(row.RowName)))
                {
                    ifcElement = Model.FederatedInstances.Where <IfcElement>(bs => bs.Name == row.RowName).FirstOrDefault();
                }

                if ((ifcElement == null) && (ValidateString(row.RowName)))
                {
                    IEnumerable <IfcElement> ifcElements = Model.FederatedInstances.Where <IfcElement>(bs => bs.Description == row.RowName);
                    //check we have one, if >1 then no match
                    if ((ifcElements.Any()) && (ifcElements.Count() == 1))
                    {
                        ifcElement = ifcElements.FirstOrDefault();
                    }
                }

                if (ifcElement != null)
                {
                    if (ifcElement.Representation != null) //check it has no graphics attached, if it has then skip
                    {
                        return;
                    }

                    //using statement will set the Model.OwnerHistoryAddObject to IfcRoot.OwnerHistory as OwnerHistoryAddObject is used upon any property changes,
                    //then swaps the original OwnerHistoryAddObject back in the dispose, so set any properties within the using statement
                    using (COBieXBimEditScope context = new COBieXBimEditScope(Model, ifcElement.OwnerHistory))
                    {
                        IfcProduct placementRelToIfcProduct = ifcElement.ContainedInStructure as IfcProduct;
                        IfcRelContainedInSpatialStructure ifcRelContainedInSpatialStructure = Model.FederatedInstances.OfType <IfcRelContainedInSpatialStructure>().Where(rciss => rciss.RelatedElements.Contains(ifcElement)).FirstOrDefault();
                        if ((ifcRelContainedInSpatialStructure != null) &&
                            (ifcRelContainedInSpatialStructure.RelatingStructure != null)
                            )
                        {
                            placementRelToIfcProduct = ifcRelContainedInSpatialStructure.RelatingStructure;
                            AddExtrudedRectangle(row, rowNext, ifcElement, placementRelToIfcProduct);
                        }
                        else
                        {
#if DEBUG
                            Console.WriteLine("COBieXBimCoordinate.AddBoundingBoxAsExtrudedAreaSolid: Cannot find Parent object placement");
#endif
                        }
                    }
                }
                else
                {
#if DEBUG
                    Console.WriteLine("COBieXBimCoordinate.AddBoundingBoxAsExtrudedAreaSolid: Cannot find object to relate points too");
#endif
                }
            }
        }