Repository: NREL/OpenStudio (language: python)

Issue:
Hotfix GLTF extras broke running tests in Debug
Pull request overview
---------------------

GLTF extras broke (#4571) running ctest in Debug (400 tests segfaulting)

This is an absolute minimal fix to have the tests passing, but I think we should refactor: 
* avoid all static storage objects
* change the data layout and API in the classes that are in GltfForwardTranslator
    * just use `T` (eg double) instead of std::tuple<std::string, tinygltf::Value(T)> 
    * provide a protected toGltfValue that will create the std::map<std::string, tinygltf::Value>
* Move those to separate files (like the wrappers are)
* Remove the wrappers (which are superflous now)

### Pull Request Author

<!--- Add to this list or remove from it as applicable.  This is a simple templated set of guidelines. -->

 - [ ] Model API Changes / Additions
 - [ ] Any new or modified fields have been implemented in the EnergyPlus ForwardTranslator (and ReverseTranslator as appropriate)
 - [ ] Model API methods are tested (in `src/model/test`)
 - [ ] EnergyPlus ForwardTranslator Tests (in `src/energyplus/Test`)
 - [ ] If a new object or method, added a test in NREL/OpenStudio-resources: Add Link
 - [ ] If needed, added VersionTranslation rules for the objects (`src/osversion/VersionTranslator.cpp`)
 - [ ] Verified that C# bindings built fine on Windows, partial classes used as needed, etc.
 - [ ] All new and existing tests passes
 - [ ] If methods have been deprecated, update rest of code to use the new methods

**Labels:**

 - [ ] If change to an IDD file, add the label `IDDChange`
 - [ ] If breaking existing API, add the label `APIChange`
 - [ ] If deemed ready, add label `Pull Request - Ready for CI` so that CI builds your PR

### Review Checklist

This will not be exhaustively relevant to every PR.
 - [ ] Perform a Code Review on GitHub
 - [ ] Code Style, strip trailing whitespace, etc.
 - [ ] All related changes have been implemented: model changes, model tests, FT changes, FT tests, VersionTranslation, OS App
 - [ ] Labeling is ok
 - [ ] If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
 - [ ] If feature, test running new feature, try creative ways to break it
 - [ ] CI status: all green or justified

GLTF: Next steps
Enhancement Request
--------------

#4605 is a refactored that preserve the existing behavior.  This is a running list of changes or enhancements for the GLTF facilities we provide that are in addition.

## Detailed Description

**Changes we should implement**:

* [ ] Improper use of json `object` in the `extras` (instead of an Array):
   *  on the GLTF Nodes, airLoopHVACHandles, airLoopHVACMaterialNames, airLooppHVACNames are individual json `object` with a key that is a string representation of an integer. Instead we should make a Json Array of objects
   <details><summary>**See Diff**</summary>

    ```diff
    "extras": {
    -  "airLoopHVACHandles": {
    -    "0": "00611a5f-76dc-46bb-962e-dd46ade0a5cc",
    -    "1": "8ec55b5d-de0f-4f30-b572-7d963b121c06"
    -  },
    -  "airLoopHVACMaterialNames": {
    -    "0": "AirLoopHVAC_Air Loop HVAC 1",
    -    "1": "AirLoopHVAC_Air Loop HVAC 2"
    -  },
    -  "airLoopHVACNames": {
    -    "0": "Air Loop HVAC 1",
    -    "1": "Air Loop HVAC 2"
    -  },
    +  "airLoopHVACs": [
    +    {
    +      "Handle": "00611a5f-76dc-46bb-962e-dd46ade0a5cc",
    +      "MaterialName": "AirLoopHVAC_Air Loop HVAC 1",
    +      "Name": "Air Loop HVAC 1"
    +    },
    +    {
    +      "Handle": "8ec55b5d-de0f-4f30-b572-7d963b121c06",
    +      "MaterialName": "AirLoopHVAC_Air Loop HVAC 2",
    +      "Name": "Air Loop HVAC 2"
    +    }
    +  ],
       "airWall": false,
       "boundaryMaterialName": "",
       [.. etc..]
    }
    ```
    </details>

   * on the GLTF Scene, modelObjectMetaData is also using a std::to_string(i) indexed object instead of an array as well
    <details><summary>**Example**</summary>


    ```json
        "modelObjectMetaData": {
          "0": {
            "color": "#F5B3DE",
            "handle": "0154d9bd-9cd4-4702-be7d-d27ec3be041f",
            "iddObjectType": "OS:BuildingStory",
            "multiplier": 0,
            "name": "Building Story 1",
            "nominal_floorCeiling_Height": 0.0,
            "nominal_z_coordinate": 0.0,
            "open_to_below": false
          },
          "1": {
            "color": "",
            "handle": "b7954df7-87eb-4f80-87df-2896df12479c",
            "iddObjectType": "OS:Space",
            "multiplier": 0,
            "name": "Space 1",
            "nominal_floorCeiling_Height": 0.0,
            "nominal_z_coordinate": 0.0,
            "open_to_below": false
          },
    }
    ```
    </details>

* [ ] `openstudio::model::Model&` is passed by const, but Rendering Colors are created **and assigned to ModelObjects**. While this is not terribly scary, it is incorrect. https://github.com/NREL/OpenStudio/blob/68b0787df780df813c49ba0c6cc709769b7d8771/src/gltf/GltfMaterialData.cpp#L227-L228

* [ ] Loads of .GLTF files have been commited to the resources/utilities/Geometry folder, yet we're doing nothing with them.

* The protected members toExtras() should probably return directly a tinygltf::Value or tinygltf::Node instead of a std::map<std::string, tinygltf::Value) (you then need to just wrap into a tinygltf::Value object at the point of use)

* [ ] Extras bear a bunch of xxxMaterialName (eg: `buildingStoryMaterialName`), yet these are **not** present in the tingygltf `materials` key

* [ ] Braces are **sometimes** removed from the "handle" fields (eg: `buildingStoryHandle`) and sometimes not (eg: the 'handle' field of the modelObjectMetaData). 1) I don't think it's necessary. 2) I think it should be consistent.

* [ ] Should maybe expose the 

**Enhancement requests**:

* [ ] Write a GltfReverseTranslator? (is this needed/wanted?)
* [ ] Schema validation

* [ ] During the refactor in #4605, I removed some of the callback params `std::function<void(double)> updatePercentage`. Either put that back, or completely remove that.


## Possible Implementation
<!--- Not mandatory, but if you can, suggest an idea for implementing the feature -->



Discussion / hints:
CI Results for f32a6a114ed178c8400b1550930f6228e9a2254d:

* Ubuntu 18.04:
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Ubuntu-18.04.deb](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha%2Bf32a6a114e-Ubuntu-18.04.deb)
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Ubuntu-18.04.tar.gz](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha%2Bf32a6a114e-Ubuntu-18.04.tar.gz)

* Ubuntu 20.04:
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Ubuntu-20.04.deb](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha%2Bf32a6a114e-Ubuntu-20.04.deb)
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Ubuntu-20.04.tar.gz](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha%2Bf32a6a114e-Ubuntu-20.04.tar.gz)
    * [perf_all.csv](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/f32a6a114ed178c8400b1550930f6228e9a2254d/perf_all.csv)
    * [perf_comparison.png](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/f32a6a114ed178c8400b1550930f6228e9a2254d/perf_comparison.png)
    * [perf_means.csv](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/f32a6a114ed178c8400b1550930f6228e9a2254d/perf_means.csv)

* Darwin:
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Darwin-x86_64.dmg](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha+f32a6a114e-Darwin-x86_64.dmg)
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Darwin-x86_64.tar.gz](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha+f32a6a114e-Darwin-x86_64.tar.gz)

* Windows:
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Windows.exe](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha+f32a6a114e-Windows.exe)
    * [OpenStudio-3.4.1-alpha+f32a6a114e-Windows.tar.gz](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/OpenStudio-3.4.1-alpha+f32a6a114e-Windows.tar.gz)

* Code Coverage:
    * [OpenStudio-f32a6a114ed178c8400b1550930f6228e9a2254d.gcov.html](http://openstudio-ci-builds.s3-website-us-west-2.amazonaws.com/PR-4597/gcov/html/OpenStudio-f32a6a114ed178c8400b1550930f6228e9a2254d.gcov.html)
@jmarrec Thanks for the quick fix on this! I looked at the CI runner for code coverage and it's been set ignore the ctest failures as it was only looking at the code coverage. I changed this so it'll fail now if any of the debug tests fail. It looks like a couple of debug tests routinely fail so I added these to filter list.  Going forward we should be able to catch these. 


Fix patch:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bc5902ec4d5..9549a4e4611 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1007,6 +1007,7 @@ set(project_directories
   epjson
   radiance
   gbxml
+  gltf
   airflow
   isomodel
   osversion
diff --git a/ProjectMacros.cmake b/ProjectMacros.cmake
index b541fbcf9d7..49bdb3a6ac2 100644
--- a/ProjectMacros.cmake
+++ b/ProjectMacros.cmake
@@ -546,6 +546,7 @@ macro(MAKE_SWIG_TARGET NAME SIMPLENAME KEY_I_FILE I_FILES PARENT_TARGET PARENT_S
       OpenStudioAirflow
       OpenStudioEnergyPlus
       OpenStudioGBXML
+      OpenStudioGltf
       OpenStudioISOModel
       OpenStudioRadiance
       OpenStudioSDD
diff --git a/csharp/CMakeLists.txt b/csharp/CMakeLists.txt
index c602a63b5f9..24e2ee08e37 100644
--- a/csharp/CMakeLists.txt
+++ b/csharp/CMakeLists.txt
@@ -109,6 +109,7 @@ set(translator_wrappers
   csharp_OpenStudioAirflow_wrap.cxx
   csharp_OpenStudioEnergyPlus_wrap.cxx
   csharp_OpenStudioGBXML_wrap.cxx
+  csharp_OpenStudioGltf_wrap.cxx
   csharp_OpenStudioISOModel_wrap.cxx
   csharp_OpenStudioRadiance_wrap.cxx
   csharp_OpenStudioSDD_wrap.cxx
@@ -137,6 +138,7 @@ set(utilities_wrappers
   csharp_OpenStudioEnergyPlus_wrap.cxx
   csharp_OpenStudioRadiance_wrap.cxx
   csharp_OpenStudioGBXML_wrap.cxx
+  csharp_OpenStudioGltf_wrap.cxx
   csharp_OpenStudioAirflow_wrap.cxx
   csharp_OpenStudioISOModel_wrap.cxx
   csharp_OpenStudioSDD_wrap.cxx
diff --git a/python/openstudio.py b/python/openstudio.py
index bf78d219deb..633377dad8a 100644
--- a/python/openstudio.py
+++ b/python/openstudio.py
@@ -6,6 +6,7 @@
     from . import openstudioenergyplus as energyplus
     from . import openstudioepjson as epjson
     from . import openstudiogbxml as gbxml
+    from . import openstudiogltf as gltf
     from . import openstudioisomodel as isomodel
     from . import openstudiomeasure as measure
 
@@ -46,6 +47,7 @@
     import openstudioenergyplus as energyplus
     import openstudioepjson as epjson
     import openstudiogbxml as gbxml
+    import openstudiogltf as gltf
     import openstudioisomodel as isomodel
     import openstudiomeasure as measure
 
diff --git a/ruby/CMakeLists.txt b/ruby/CMakeLists.txt
index e509962f565..951372199d4 100644
--- a/ruby/CMakeLists.txt
+++ b/ruby/CMakeLists.txt
@@ -100,6 +100,7 @@ else()
     openstudio_sdd
     openstudio_isomodel
     openstudio_gbxml
+    openstudio_gltf
     openstudio_radiance
   )
 endif()
diff --git a/ruby/init_openstudio.cpp b/ruby/init_openstudio.cpp
index 39ff112cd31..a02c6900f50 100644
--- a/ruby/init_openstudio.cpp
+++ b/ruby/init_openstudio.cpp
@@ -32,7 +32,8 @@
 #include <stdexcept>
 #include <iostream>
 
-extern "C" {
+extern "C"
+{
   void Init_openstudioairflow(void);
   void Init_openstudiomodelcore(void);
   void Init_openstudiomodelsimulation(void);
@@ -43,7 +44,8 @@ extern "C" {
   void Init_openstudioosversion(void);
   void Init_openstudioutilitiesdata(void);
   void Init_openstudioutilitiessql(void);
-  void Init_openstudiogbxml(void); 
+  void Init_openstudiogbxml(void);
+  void Init_openstudiogltf(void);
   void Init_openstudiomodelgenerators(void);
   void Init_openstudioradiance(void);
   void Init_openstudioutilitiestime(void);
@@ -71,8 +73,7 @@ extern "C" {
   ////void Init_openstudiomodeleditor(void); # happens separately in openstudio.so only, for SketchUp plug-in
 }
 
-void init_openstudio_internal_basic()
-{
+void init_openstudio_internal_basic() {
   rb_provide("openstudio");
   rb_provide("openstudio.so");
 
@@ -114,8 +115,7 @@ void init_openstudio_internal_basic()
   rb_provide("openstudioutilities.so");
 }
 
-void init_openstudio_internal_extended()
-{
+void init_openstudio_internal_extended() {
   Init_openstudiomodel();
   rb_provide("openstudiomodel");
   rb_provide("openstudiomodel.so");
@@ -156,7 +156,6 @@ void init_openstudio_internal_extended()
   rb_provide("openstudiomodelgenerators");
   rb_provide("openstudiomodelgenerators.so");
 
-
   Init_openstudioenergyplus();
   rb_provide("openstudioenergyplus");
   rb_provide("openstudioenergyplus.so");
@@ -169,6 +168,9 @@ void init_openstudio_internal_extended()
   Init_openstudiogbxml();
   rb_provide("openstudiogbxml");
   rb_provide("openstudiogbxml.so");
+  Init_openstudiogltf();
+  rb_provide("openstudiogltf");
+  rb_provide("openstudiogltf.so");
   Init_openstudioairflow();
   rb_provide("openstudioairflow");
   rb_provide("openstudioairflow.so");
@@ -185,7 +187,6 @@ void init_openstudio_internal_extended()
   rb_provide("openstudiosdd");
   rb_provide("openstudiosdd.so");
 
-
   //Init_openstudiomodeleditor(); # happens separately in openstudio.so only, for SketchUp plug-in
   //rb_provide("openstudiomodeleditor");
   //rb_provide("openstudiomodeleditor.so");
@@ -364,7 +365,6 @@ end # module OpenStudio
   evalString(ruby_typedef_script);
 }
 
-
 void init_openstudio_internal() {
   init_openstudio_internal_basic();
   init_openstudio_internal_extended();
@@ -372,40 +372,33 @@ void init_openstudio_internal() {
 
 class RubyException : public std::runtime_error
 {
-  public:
-
-    RubyException(const std::string& msg, const std::string& location)
-      : std::runtime_error(msg), m_location(location)
-    {}
-
-    virtual ~RubyException() throw() {}
+ public:
+  RubyException(const std::string& msg, const std::string& location) : std::runtime_error(msg), m_location(location) {}
 
-    std::string location() const {return m_location;}
+  virtual ~RubyException() throw() {}
 
-  private:
-
-    std::string m_location;
+  std::string location() const {
+    return m_location;
+  }
 
+ private:
+  std::string m_location;
 };
 
-static VALUE evaluateSimpleImpl(VALUE arg)
-{
+static VALUE evaluateSimpleImpl(VALUE arg) {
   return rb_eval_string(StringValuePtr(arg));
 }
 
-void evalString(const std::string &t_str)
-{
+void evalString(const std::string& t_str) {
 
   VALUE val = rb_str_new2(t_str.c_str());
   int error;
 
-  rb_protect(evaluateSimpleImpl,val,&error);
+  rb_protect(evaluateSimpleImpl, val, &error);
 
-
-  if (error != 0)
-  {
+  if (error != 0) {
     VALUE errval = rb_eval_string("$!.to_s");
-    char *str = StringValuePtr(errval);
+    char* str = StringValuePtr(errval);
     std::string err(str);
 
     VALUE locval = rb_eval_string("$@.to_s");
@@ -416,5 +409,3 @@ void evalString(const std::string &t_str)
   }
 }
 
-
-
diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt
index 8037a6744ad..cd437c27712 100644
--- a/src/cli/CMakeLists.txt
+++ b/src/cli/CMakeLists.txt
@@ -297,6 +297,7 @@ target_link_libraries(openstudio
  openstudio_sdd
  openstudio_isomodel
  openstudio_gbxml
+ openstudio_gltf
  openstudio_radiance
  ${ruby_extension_libs}
 )
diff --git a/src/cli/openstudio_cli.rb b/src/cli/openstudio_cli.rb
index de35475088b..40f801a5c45 100644
--- a/src/cli/openstudio_cli.rb
+++ b/src/cli/openstudio_cli.rb
@@ -59,6 +59,7 @@
 OpenStudio.autoload(:EnergyPlus, ":/openstudio_init_extended.rb")
 OpenStudio.autoload(:EPJSON, ":/openstudio_init_extended.rb")
 OpenStudio.autoload(:GbXML, ":/openstudio_init_extended.rb")
+OpenStudio.autoload(:Gltf, ":/openstudio_init_extended.rb")
 OpenStudio.autoload(:ISOModel, ":/openstudio_init_extended.rb")
 OpenStudio.autoload(:Measure, ":/openstudio_init_extended.rb")
 OpenStudio.autoload(:Ruleset, ":/openstudio_init_extended.rb")
diff --git a/src/cli/openstudio_init_extended.rb b/src/cli/openstudio_init_extended.rb
index f09f26e761d..ad8e587f1a7 100644
--- a/src/cli/openstudio_init_extended.rb
+++ b/src/cli/openstudio_init_extended.rb
@@ -7,9 +7,10 @@
 ::OpenStudio.module_eval { remove_const(:EnergyPlus) }
 ::OpenStudio.module_eval { remove_const(:EPJSON) }
 ::OpenStudio.module_eval { remove_const(:GbXML) }
+::OpenStudio.module_eval { remove_const(:Gltf) }
 ::OpenStudio.module_eval { remove_const(:ISOModel) }
 ::OpenStudio.module_eval { remove_const(:Measure) }
-::OpenStudio.module_eval { remove_const(:Ruleset) } 
+::OpenStudio.module_eval { remove_const(:Ruleset) }
 ::OpenStudio.module_eval { remove_const(:Model) }
 ::OpenStudio.module_eval { remove_const(:OSVersion) }
 ::OpenStudio.module_eval { remove_const(:Radiance) }
diff --git a/src/gltf/CMakeLists.txt b/src/gltf/CMakeLists.txt
new file mode 100644
index 00000000000..2f9caae0464
--- /dev/null
+++ b/src/gltf/CMakeLists.txt
@@ -0,0 +1,65 @@
+set(target_name openstudio_gltf)
+
+set(${target_name}_src
+        mainpage.hpp
+        GltfForwardTranslator.hpp
+        GltfForwardTranslator.cpp
+        GltfBoundingBox.hpp
+        GltfBoundingBox.cpp
+        GltfModelObjectMetaData.hpp
+        GltfModelObjectMetaData.cpp
+        GltfUserData.hpp
+        GltfUserData.cpp
+        GltfMetaData.hpp
+        GltfMetaData.cpp
+        GltfMaterialData.hpp
+        GltfMaterialData.cpp
+        GltfUtils.hpp
+        GltfUtils.cpp
+        ${CMAKE_CURRENT_BINARY_DIR}/../OpenStudio.hxx
+        )
+
+set(${target_name}_test_src
+        test/GltfFixture.hpp
+        test/GltfFixture.cpp
+        test/GltfForwardTranslator_GTest.cpp
+        )
+
+set(${target_name}_swig_src
+        Gltf.i
+        )
+
+add_library(${target_name}
+        OBJECT
+        ${${target_name}_src}
+        )
+
+set(${target_name}_depends
+  ${openstudio_model_depends}
+)
+set(${target_name}_depends ${${target_name}_depends} PARENT_SCOPE)
+
+target_compile_definitions(${target_name} PRIVATE openstudio_gltf_EXPORTS SHARED_OS_LIBS)
+target_link_libraries(${target_name} PUBLIC ${${target_name}_depends})
+target_link_libraries(${target_name} PRIVATE CONAN_PKG::tinygltf)
+
+add_dependencies(${target_name} GenerateIddFactoryRun)
+
+set(${target_name}_test_depends
+        openstudiolib
+        )
+
+CREATE_SRC_GROUPS("${${target_name}_src}")
+CREATE_SRC_GROUPS("${${target_name}_test_src}")
+CREATE_SRC_GROUPS("${${target_name}_swig_src}")
+
+if (BUILD_TESTING)
+
+  CREATE_TEST_TARGETS(${target_name} "${${target_name}_test_src}" "${${target_name}_test_depends}")
+  # TODO
+  #add_dependencies(${target_name}_tests
+  #  openstudio_gltf_resources
+  #)
+endif ()
+
+MAKE_SWIG_TARGET(OpenStudioGltf Gltf "${CMAKE_CURRENT_SOURCE_DIR}/Gltf.i" "${${target_name}_swig_src}" ${target_name} OpenStudioModel)
diff --git a/src/gltf/Gltf.i b/src/gltf/Gltf.i
new file mode 100644
index 00000000000..fddf3ddf86a
--- /dev/null
+++ b/src/gltf/Gltf.i
@@ -0,0 +1,78 @@
+#ifndef GLTF_I
+#define GLTF_I
+
+#ifdef SWIGPYTHON
+%module openstudiogltf
+#endif
+
+#define UTILITIES_API
+#define MODEL_API
+#define GLTF_API
+
+%include <utilities/core/CommonInclude.i>
+%import <utilities/core/CommonImport.i>
+%import <utilities/Utilities.i>
+
+%ignore openstudio::gltf::detail;
+
+#if defined(SWIGCSHARP) || defined(SWIGJAVA)
+%import <model/Model.i>
+#else
+%import(module="openstudiomodel") <model/Model.hpp>
+%import(module="openstudiomodel") <model/ModelObject.hpp>
+#endif
+
+// ignore specific overload of GltfForwardTranslator::modelToGLTF to avoid dealing with std::function<void(double)>updatePercentage
+%ignore openstudio::gltf::GltfForwardTranslator::modelToGLTF(const model::Model& model, std::function<void(double)> updatePercentage, const path& outputPath);
+
+%{
+  #include <utilities/core/Path.hpp>
+  #include <gltf/GltfBoundingBox.hpp>
+//  #include <gltf/GltfMaterialData.hpp>
+  #include <gltf/GltfModelObjectMetaData.hpp>
+  #include <gltf/GltfMetaData.hpp>
+  #include <gltf/GltfUserData.hpp>
+  #include <gltf/GltfForwardTranslator.hpp>
+
+  using namespace openstudio::gltf;
+  using namespace openstudio;
+%}
+
+%include <gltf/GltfBoundingBox.hpp>
+//%include <gltf/GltfMaterialData.hpp>
+%include <gltf/GltfModelObjectMetaData.hpp>
+%include <gltf/GltfMetaData.hpp>
+%include <gltf/GltfUserData.hpp>
+%include <gltf/GltfForwardTranslator.hpp>
+
+// create an instantiation of the vector classes
+%template(GltfUserDataVector) std::vector<openstudio::gltf::GltfUserData>;
+%template(GltfModelObjectMetaDataVector) std::vector<openstudio::gltf::GltfModelObjectMetaData>;
+// %template(GltfMaterialDataVector) std::vector<openstudio::gltf::GltfMaterialDataVector>;
+
+%template(OptionalGltfUserData) boost::optional<openstudio::gltf::GltfUserData>;
+
+#if defined SWIGRUBY
+  // This isn't super clean and there might be a better way with typemaps in SWIG rather than using a String in between,
+  // but still helpful I think: we redefine toJSON that will return a native ruby hash. 'json' is part of ruby stdlib since at least ruby 2.5.5
+  %init %{
+    rb_eval_string("OpenStudio::Gltf::GltfForwardTranslator.class_eval { define_method(:modelToGLTFJSON) { |model| json_str = self.modelToGLTFString(model); require 'json'; JSON.load(json_str);  }; }");
+ %}
+#endif
+
+#if defined SWIGPYTHON
+
+  // Let's use monkey-patching via unbound functions
+  %pythoncode %{
+# Manually added: Lazy-load the json module (python std lib) and return a dict via modelToGLTFString
+def _modelToGLTFJSON(self, *args) -> dict:
+    import json
+    return json.loads(self.modelToGLTFString(*args))
+
+GltfForwardTranslator.modelToGLTFJSON = _modelToGLTFJSON
+  %}
+#endif
+
+#endif // GLTF_I
+
+
diff --git a/src/gltf/GltfAPI.hpp b/src/gltf/GltfAPI.hpp
new file mode 100644
index 00000000000..a22432d5907
--- /dev/null
+++ b/src/gltf/GltfAPI.hpp
@@ -0,0 +1,43 @@
+/***********************************************************************************************************************
+*  OpenStudio(R, Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef GLTF_GLTFAPI_HPP
+#define GLTF_GLTFAPI_HPP
+
+#if (_WIN32 || _MSC_VER) && SHARED_OS_LIBS
+#  if defined(openstudio_gltf_EXPORTS) || defined(openstudio_EXPORTS)
+#    define GLTF_API __declspec(dllexport)
+#  else
+#    define GLTF_API __declspec(dllimport)
+#  endif
+#else
+#  define GLTF_API
+#endif
+
+#endif
diff --git a/src/gltf/GltfBoundingBox.cpp b/src/gltf/GltfBoundingBox.cpp
new file mode 100644
index 00000000000..ef4314ec38d
--- /dev/null
+++ b/src/gltf/GltfBoundingBox.cpp
@@ -0,0 +1,237 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "GltfBoundingBox.hpp"
+#include "../model/PlanarSurfaceGroup.hpp"
+
+#include "../utilities/geometry/BoundingBox.hpp"
+#include "../utilities/geometry/Point3d.hpp"
+#include "../utilities/geometry/Transformation.hpp"
+
+#include <boost/optional.hpp>
+#include <tiny_gltf.h>
+
+#include <map>
+#include <string>
+
+namespace openstudio {
+namespace gltf {
+
+  GltfBoundingBox::GltfBoundingBox() = default;
+
+  GltfBoundingBox::GltfBoundingBox(const std::vector<model::PlanarSurfaceGroup>& planarSurfaceGroups) {
+
+    // Bounding Box
+    BoundingBox boundingBox;
+    boundingBox.addPoint(Point3d(0, 0, 0));
+    boundingBox.addPoint(Point3d(1, 1, 1));
+    for (const auto& group : planarSurfaceGroups) {
+      boundingBox.add(group.transformation() * group.boundingBox());
+    }
+
+    double lookAtX = 0;  // (boundingBox.minX().get() + boundingBox.maxX().get()) / 2.0
+    double lookAtY = 0;  // (boundingBox.minY().get() + boundingBox.maxY().get()) / 2.0
+    double lookAtZ = 0;  // (boundingBox.minZ().get() + boundingBox.maxZ().get()) / 2.0
+    double lookAtR =
+      sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2) + std::pow(boundingBox.maxZ().get() / 2.0, 2));
+    lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2)
+                                     + std::pow(boundingBox.maxZ().get() / 2.0, 2)));
+    lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
+                                     + std::pow(boundingBox.maxZ().get() / 2.0, 2)));
+    lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2)
+                                     + std::pow(boundingBox.minZ().get() / 2.0, 2)));
+    lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
+                                     + std::pow(boundingBox.maxZ().get() / 2.0, 2)));
+    lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2)
+                                     + std::pow(boundingBox.minZ().get() / 2.0, 2)));
+    lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
+                                     + std::pow(boundingBox.minZ().get() / 2.0, 2)));
+    lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
+                                     + std::pow(boundingBox.minZ().get() / 2.0, 2)));
+
+    m_lookAtR = lookAtR;
+    m_lookAtX = lookAtX;
+    m_lookAtY = lookAtY;
+    m_lookAtZ = lookAtZ;
+    m_maxX = boundingBox.maxX().get();
+    m_maxY = boundingBox.maxY().get();
+    m_maxZ = boundingBox.maxZ().get();
+    m_minX = boundingBox.minX().get();
+    m_minY = boundingBox.minY().get();
+    m_minZ = boundingBox.minZ().get();
+  }
+
+  double GltfBoundingBox::lookAtR() const {
+    return m_lookAtR;
+  }
+  void GltfBoundingBox::setLookAtR(double lookAtR) {
+    m_lookAtR = lookAtR;
+  };
+
+  double GltfBoundingBox::lookAtX() const {
+    return m_lookAtX;
+  }
+  void GltfBoundingBox::setLookAtX(double lookAtX) {
+    m_lookAtX = lookAtX;
+  };
+
+  double GltfBoundingBox::lookAtY() const {
+    return m_lookAtY;
+  }
+  void GltfBoundingBox::setLookAtY(double lookAtY) {
+    m_lookAtY = lookAtY;
+  };
+
+  double GltfBoundingBox::lookAtZ() const {
+    return m_lookAtZ;
+  }
+  void GltfBoundingBox::setLookAtZ(double lookAtZ) {
+    m_lookAtZ = lookAtZ;
+  };
+
+  double GltfBoundingBox::maxX() const {
+    return m_maxX;
+  }
+  void GltfBoundingBox::setMaxX(double maxX) {
+    m_maxX = maxX;
+  };
+
+  double GltfBoundingBox::maxY() const {
+    return m_maxY;
+  }
+  void GltfBoundingBox::setMaxY(double maxY) {
+    m_maxY = maxY;
+  };
+
+  double GltfBoundingBox::maxZ() const {
+    return m_maxZ;
+  }
+  void GltfBoundingBox::setMaxZ(double maxZ) {
+    m_maxZ = maxZ;
+  };
+
+  double GltfBoundingBox::minX() const {
+    return m_minX;
+  }
+  void GltfBoundingBox::setMinX(double minX) {
+    m_minX = minX;
+  };
+
+  double GltfBoundingBox::minY() const {
+    return m_minY;
+  }
+  void GltfBoundingBox::setMinY(double minY) {
+    m_minY = minY;
+  };
+
+  double GltfBoundingBox::minZ() const {
+    return m_minZ;
+  }
+  void GltfBoundingBox::setMinZ(double minZ) {
+    m_minZ = minZ;
+  };
+
+  std::map<std::string, tinygltf::Value> GltfBoundingBox::toExtras() const {
+    return {
+      {"lookAtR", tinygltf::Value(m_lookAtR)}, {"lookAtX", tinygltf::Value(m_lookAtX)}, {"lookAtY", tinygltf::Value(m_lookAtY)},
+      {"lookAtZ", tinygltf::Value(m_lookAtZ)}, {"maxX", tinygltf::Value(m_maxX)},       {"maxY", tinygltf::Value(m_maxY)},
+      {"maxZ", tinygltf::Value(m_maxZ)},       {"minX", tinygltf::Value(m_minX)},       {"minY", tinygltf::Value(m_minY)},
+      {"minZ", tinygltf::Value(m_minZ)},
+    };
+  }
+
+  GltfBoundingBox::GltfBoundingBox(const tinygltf::Value& boundingBoxObj) {
+
+    if (!boundingBoxObj.IsObject()) {
+      LOG_AND_THROW("boundingBoxObj is not a tinygltf Object.");
+    }
+
+    for (const auto& key : {"lookAtR", "lookAtX", "lookAtY", "lookAtZ", "maxX", "maxY", "maxZ", "minX", "minY", "minZ"}) {
+      if (!boundingBoxObj.Has(key)) {
+        LOG(Debug, "boundingBoxObj is missing the key " << key);
+      }
+    }
+
+    auto tryGetDoubleFromkey = [&boundingBoxObj](const std::string& key) -> boost::optional<double> {
+      if (boundingBoxObj.Has(key)) {
+        auto val = boundingBoxObj.Get(key);
+        if (val.IsReal()) {
+          return val.Get<double>();
+        } else {
+          LOG(Warn, "boundingBoxObj has the key '" << key << "' but it is not a double");
+        }
+      } else {
+        LOG(Debug, "boundingBoxObj is missing the key '" << key << "'");
+      }
+      return boost::none;
+    };
+
+    if (auto d_ = tryGetDoubleFromkey("lookAtR")) {
+      m_lookAtR = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("lookAtX")) {
+      m_lookAtX = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("lookAtY")) {
+      m_lookAtY = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("lookAtZ")) {
+      m_lookAtZ = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("maxX")) {
+      m_maxX = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("maxY")) {
+      m_maxY = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("maxZ")) {
+      m_maxZ = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("minX")) {
+      m_minX = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("minY")) {
+      m_minY = d_.get();
+    }
+
+    if (auto d_ = tryGetDoubleFromkey("minZ")) {
+      m_minZ = d_.get();
+    }
+  }
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/model/GltfMetaDataWrapper.hpp b/src/gltf/GltfBoundingBox.hpp
similarity index 58%
rename from src/model/GltfMetaDataWrapper.hpp
rename to src/gltf/GltfBoundingBox.hpp
index 0046d6e4904..a4075262177 100644
--- a/src/model/GltfMetaDataWrapper.hpp
+++ b/src/gltf/GltfBoundingBox.hpp
@@ -26,59 +26,85 @@
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ***********************************************************************************************************************/
-#ifndef MODEL_GLTFMETADATAWRAPPER_HPP
-#define MODEL_GLTFMETADATAWRAPPER_HPP
+#ifndef GLTF_GLTFBOUNDINGBOX_HPP
+#define GLTF_GLTFBOUNDINGBOX_HPP
 
-#include "ModelAPI.hpp"
-#include "Model.hpp"
-#include "GltfBoundingBoxWrapper.hpp"
-#include "GltfModelObjectMetadataWrapper.hpp"
+#include "GltfAPI.hpp"
+
+#include "../utilities/core/Logger.hpp"
+
+#include <vector>
+
+namespace tinygltf {
+class Value;
+}
 
 namespace openstudio {
-//class GltfMetaDta;
 namespace model {
+  class PlanarSurfaceGroup;
+}  // namespace model
+
+namespace gltf {
+
+  class GltfMetaData;
 
-  class MODEL_API GltfMetaDataWrapper
+  /** GltfBoundingBox is an Interface between the PlanarSurfaceGroups of a Model and a glTF Scene's extras to set the boundingbox **/
+  class GLTF_API GltfBoundingBox
   {
    public:
-    GltfMetaDataWrapper();
-
-    void setBuildingStoryNames(const std::vector<std::string>& storyNames);
-    void setGenerator(const std::string& value);
-    void setType(const std::string& value);
-    void setVersion(const std::string& value);
-    void setNorthAxis(const double& value);
-
-    void setglTFBoundingBoxWrapper(const GltfBoundingBoxWrapper& gbx);
-    void addModelObjectMetadata(GltfModelObjectMetadataWrapper& gmow);
-
-    std::vector<std::string> getBuildingStoryNames() const;
-    std::string getGenerator() const;
-    std::string getType() const;
-    std::string getVersion() const;
-    double getNorthAxis() const;
-
-    GltfBoundingBoxWrapper getglTFBoundingBoxWrapper();
-    std::vector<GltfModelObjectMetadataWrapper> getglTFModelObjectMetadataWrapper();
-
-    void storyCountIncrement();
-    void thermalZoneCountIncrement();
-    void spaceCountIncrement();
-    void spaceTypeCountIncrement();
-    void constructionSetCountIncrement();
-    void airLoopCountIncrement();
-
-    int getStoryCount() const;
-    int getThermalZoneCount() const;
-    int getSpaceCount() const;
-    int getSpaceTypeCount() const;
-    int getConstructionSetCount() const;
-    int getAirLoopCount() const;
-  };
+    GltfBoundingBox();
+    GltfBoundingBox(const std::vector<model::PlanarSurfaceGroup>& planarSurfaceGroups);
 
-  // vector of GltfModelObjectMetadataWrapper
-  typedef std::vector<GltfModelObjectMetadataWrapper> GltfModelObjectMetadataWrapperVector;
-}  // namespace model
+    double lookAtR() const;
+    void setLookAtR(double lookAtR);
+
+    double lookAtX() const;
+    void setLookAtX(double lookAtX);
+
+    double lookAtY() const;
+    void setLookAtY(double lookAtY);
+
+    double lookAtZ() const;
+    void setLookAtZ(double lookAtZ);
+
+    double maxX() const;
+    void setMaxX(double maxX);
+
+    double maxY() const;
+    void setMaxY(double maxY);
+
+    double maxZ() const;
+    void setMaxZ(double maxZ);
+
+    double minX() const;
+    void setMinX(double minX);
+
+    double minY() const;
+    void setMinY(double minY);
+
+    double minZ() const;
+    void setMinZ(double minZ);
+
+   protected:
+    std::map<std::string, tinygltf::Value> toExtras() const;
+    GltfBoundingBox(const tinygltf::Value& boundingBoxObj);
+    friend class GltfMetaData;
+
+   private:
+    REGISTER_LOGGER("openstudio.gltf.GltfBoundingBox");
+
+    double m_lookAtR = 0.0;
+    double m_lookAtX = 0.0;
+    double m_lookAtY = 0.0;
+    double m_lookAtZ = 0.0;
+    double m_maxX = 0.0;
+    double m_maxY = 0.0;
+    double m_maxZ = 0.0;
+    double m_minX = 0.0;
+    double m_minY = 0.0;
+    double m_minZ = 0.0;
+  };
+}  // namespace gltf
 }  // namespace openstudio
 
-#endif  //MODEL_GLTFMETADATAWRAPPER_HPP
+#endif  //GLTF_GLTFBOUNDINGBOX_HPP
diff --git a/src/gltf/GltfForwardTranslator.cpp b/src/gltf/GltfForwardTranslator.cpp
new file mode 100644
index 00000000000..b279ec8d32b
--- /dev/null
+++ b/src/gltf/GltfForwardTranslator.cpp
@@ -0,0 +1,563 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "GltfForwardTranslator.hpp"
+#include "GltfUtils.hpp"
+#include "GltfMetaData.hpp"
+#include "GltfUserData.hpp"
+#include "GltfModelObjectMetaData.hpp"
+#include "GltfBoundingBox.hpp"
+#include "GltfMaterialData.hpp"
+
+#include "../model/Model.hpp"
+
+#include "../model/RenderingColor.hpp"
+#include "../model/ConstructionBase.hpp"
+#include "../model/ConstructionBase_Impl.hpp"
+#include "../model/ConstructionAirBoundary.hpp"
+#include "../model/ConstructionAirBoundary_Impl.hpp"
+#include "../model/AirLoopHVAC.hpp"
+#include "../model/AirLoopHVAC_Impl.hpp"
+#include "../model/ThermalZone.hpp"
+#include "../model/ThermalZone_Impl.hpp"
+#include "../model/SpaceType.hpp"
+#include "../model/SpaceType_Impl.hpp"
+#include "../model/Building.hpp"
+#include "../model/Building_Impl.hpp"
+#include "../model/BuildingStory.hpp"
+#include "../model/BuildingStory_Impl.hpp"
+#include "../model/BuildingUnit.hpp"
+#include "../model/BuildingUnit_Impl.hpp"
+#include "../model/Surface.hpp"
+#include "../model/Surface_Impl.hpp"
+#include "../model/SubSurface.hpp"
+#include "../model/SubSurface_Impl.hpp"
+#include "../model/ShadingSurface.hpp"
+#include "../model/ShadingSurface_Impl.hpp"
+#include "../model/InteriorPartitionSurface.hpp"
+#include "../model/InteriorPartitionSurface_Impl.hpp"
+#include "../model/PlanarSurfaceGroup.hpp"
+#include "../model/PlanarSurfaceGroup_Impl.hpp"
+#include "../model/PlanarSurface.hpp"
+#include "../model/PlanarSurface_Impl.hpp"
+#include "../model/Space.hpp"
+#include "../model/Space_Impl.hpp"
+#include "../model/DefaultConstructionSet.hpp"
+#include "../model/DefaultConstructionSet_Impl.hpp"
+#include "../model/ShadingSurfaceGroup.hpp"
+#include "../model/InteriorPartitionSurfaceGroup.hpp"
+
+#include "../utilities/core/Assert.hpp"
+#include "../utilities/core/Compare.hpp"
+#include "../utilities/geometry/Point3d.hpp"
+#include "../utilities/geometry/Plane.hpp"
+#include "../utilities/geometry/BoundingBox.hpp"
+#include "../utilities/geometry/Transformation.hpp"
+#include "../utilities/geometry/Geometry.hpp"
+#include "../utilities/geometry/Polygon3d.hpp"
+
+#define TINYGLTF_IMPLEMENTATION
+#define STB_IMAGE_IMPLEMENTATION
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+
+#include <tiny_gltf.h>
+
+#include <algorithm>
+#include <iterator>
+#include <numeric>
+#include <type_traits>
+
+namespace openstudio {
+namespace gltf {
+
+  GltfForwardTranslator::GltfForwardTranslator() {
+    m_logSink.setLogLevel(Warn);
+    m_logSink.setThreadId(std::this_thread::get_id());
+  }
+
+  std::vector<LogMessage> GltfForwardTranslator::warnings() const {
+    std::vector<LogMessage> result;
+    for (const auto& logMessage : m_logSink.logMessages()) {
+      if (logMessage.logLevel() == Warn) {
+        result.push_back(logMessage);
+      }
+    }
+    return result;
+  }
+
+  std::vector<LogMessage> GltfForwardTranslator::errors() const {
+    std::vector<LogMessage> result;
+    for (const auto& logMessage : m_logSink.logMessages()) {
+      if (logMessage.logLevel() > Warn) {
+        result.push_back(logMessage);
+      }
+    }
+    return result;
+  }
+
+  // Initializes our two main Buffer Views
+  // one for the indices & other for Coordinates and Normals
+  void initBufferViews(tinygltf::BufferView& indicesBv, tinygltf::BufferView& coordinatesBv) {
+    indicesBv.buffer = 0;
+    // defining bytestride is not required in this case
+    indicesBv.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
+
+    // The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
+    // at position 8 in the buffer and are of type ARRAY_BUFFER
+    coordinatesBv.buffer = 0;
+    coordinatesBv.target = TINYGLTF_TARGET_ARRAY_BUFFER;
+    coordinatesBv.byteStride = 12;
+  }
+
+  // Finds the vertex Index from all Vertices of a planar Surface
+  // param : point3d
+  // param : allPoints
+  // param : tol
+  // returns :  index of the Vertex
+  size_t getOrCreateVertexIndexT(const Point3d& point3d, std::vector<Point3d>& allPoints, double tol = 0.001) {
+    size_t n = allPoints.size();
+    for (size_t i = 0; i < n; ++i) {
+      if (openstudio::getDistance(point3d, allPoints[i]) < tol) {
+        return i;
+      }
+    }
+    allPoints.push_back(point3d);
+    return (allPoints.size() - 1);
+  }
+
+  template <typename T>
+  std::vector<T> getObjectsAndSort(const model::Model& model) {
+    std::vector<T> objects;
+    if constexpr (std::is_same_v<T, model::PlanarSurface> || std::is_same_v<T, model::PlanarSurfaceGroup>) {
+      objects = model.getModelObjects<T>();
+    } else {
+      objects = model.getConcreteModelObjects<T>();
+    }
+    std::sort(objects.begin(), objects.end(), WorkspaceObjectNameLess());
+    return objects;
+  }
+
+  boost::optional<tinygltf::Model> GltfForwardTranslator::toGltfModel(const model::Model& model, std::function<void(double)> updatePercentage) {
+    // MAIN PIPELINE TO TRANSLATE OPENSTUDIO MODEL -> GLTF MODEL
+
+    bool triangulateSurfaces = true;  //we're always triangulating the surfaces to get the best possible output.
+
+    // TODO: cleanup
+    tinygltf::Model gltfModel;
+    std::string err;
+    std::string warning;
+    path p;
+
+    std::vector<tinygltf::Accessor>& accessors = gltfModel.accessors;
+    std::vector<tinygltf::Material>& materials = gltfModel.materials;
+    std::vector<tinygltf::Mesh>& meshes = gltfModel.meshes;
+    std::vector<tinygltf::Node>& nodes = gltfModel.nodes;
+
+    tinygltf::Scene& scene = gltfModel.scenes.emplace_back();
+    tinygltf::Buffer& buffer = gltfModel.buffers.emplace_back();
+
+    // Note: Can't emplace_back twice and store refs (before a reserve at least),
+    // because the first ref would be invalidated by the second emplace_back, so just resize and get refs after that
+    gltfModel.bufferViews.resize(2);
+    tinygltf::BufferView& indicesBv = gltfModel.bufferViews.front();
+    tinygltf::BufferView& coordinatesBv = gltfModel.bufferViews.back();
+    std::vector<unsigned char> indicesBuffer;
+    std::vector<unsigned char> coordinatesBuffer;
+
+    // Start Region INIT
+
+    // Define the asset. The version is required
+    gltfModel.asset.version = "2.0";
+    gltfModel.asset.generator = "OpenStudio";
+
+    // Init the scene
+    // aware of all other nodes, meshes, materials, BufferViews, Accessors tightly
+    // tied up in a Hierarchy using indices pointing one to other.
+    scene.nodes = {0};
+
+    // I'm going to be emplacing back elements in nodes a bunch later, which is going to invalidate the references, so limit scope
+    {
+      tinygltf::Node& topNode = nodes.emplace_back();
+      topNode.name = "Z_UP";
+      topNode.matrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+    }
+
+    initBufferViews(indicesBv, coordinatesBv);
+
+    // End Region INIT
+
+    /*
+
+    This comprises of the other nodes that GLTF provides
+    for further addition of complex details, textures, lights, etc.
+
+    std::vector<tinygltf::Scene> scenes;
+    std::vector<tinygltf::Buffer> buffers;
+    std::vector<tinygltf::Animation> animations;
+    std::vector<tinygltf::Texture> textures;
+    std::vector<tinygltf::Image> images;
+    std::vector<tinygltf::Skin> skins;
+    std::vector<tinygltf::Sampler> samplers;
+    std::vector<tinygltf::Camera> cameras;
+    std::vector<tinygltf::Light> lights;
+
+    */
+
+    // get number of things to translate
+    // make it deterministic by sorting!
+    auto planarSurfaces = getObjectsAndSort<model::PlanarSurface>(model);
+    auto planarSurfaceGroups = getObjectsAndSort<model::PlanarSurfaceGroup>(model);
+    auto buildingStories = getObjectsAndSort<model::BuildingStory>(model);
+    auto buildingUnits = getObjectsAndSort<model::BuildingUnit>(model);
+    auto thermalZones = getObjectsAndSort<model::ThermalZone>(model);
+    auto airLoopHVACs = getObjectsAndSort<model::AirLoopHVAC>(model);
+    auto spaceTypes = getObjectsAndSort<model::SpaceType>(model);
+    auto defaultConstructionSets = getObjectsAndSort<model::DefaultConstructionSet>(model);
+    double n = 0;
+
+    size_t N = planarSurfaces.size() + planarSurfaceGroups.size() + buildingStories.size() + buildingUnits.size() + thermalZones.size()
+               + airLoopHVACs.size() + spaceTypes.size() + defaultConstructionSets.size() + 1;
+
+    updatePercentage(0.0);
+
+    // Start Region CREATE MATERIALS
+    // add model specific materials
+    // End Region CREATE MATERIALS
+
+    TransformationVector transformStack{Transformation{}};
+
+    std::vector<double> matrixDefaultTransformation{1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0};
+
+    // We prepare a vector of Materials
+    std::vector<GltfMaterialData> allMaterials = GltfMaterialData::buildMaterials(model);
+
+    // TODO: make it deterministic by sorting!
+    // std::sort(objects.begin(), objects.end(), WorkspaceObjectNameLess());
+
+    for (const auto& planarSurface : planarSurfaces) {
+      // Start Region MAIN LOOP
+      //
+      // TODO: MOVE THAT ENTIRE LOGIC TO THE GltfUserData file? (and rename to GltfPlanarSurfaceData and make it export a Node directly)
+      std::string planarSurfaceName = planarSurface.nameString();
+      // Construct in place
+      tinygltf::Node& node = nodes.emplace_back();
+      node.name = planarSurfaceName;
+
+      // Now the geometry
+      Transformation buildingTransformation;
+      if (boost::optional<model::PlanarSurfaceGroup> planarSurfaceGroup_ = planarSurface.planarSurfaceGroup()) {
+        buildingTransformation = planarSurfaceGroup_->buildingTransformation();
+      }
+      // get the vertices
+      Point3dVector vertices = planarSurface.vertices();
+      Transformation& t = transformStack.emplace_back(Transformation::alignFace(vertices));
+      Transformation tInv = t.inverse();
+      Point3dVector faceVertices = reverse(tInv * vertices);
+      std::vector<double> matrix = openstudio::toStandardVector(buildingTransformation.vector());
+
+      // Adding a check to avoid warning "NODE_MATRIX_DEFAULT"  <Do not specify default transform matrix>.
+      // This is the identity_matrix<4>
+      if (matrixDefaultTransformation != matrix) {
+        node.matrix = matrix;
+      } else {
+        node.matrix = {};
+      }
+      node.mesh = meshes.size();
+
+      // EXTRAS
+
+      // TODO: Based on flag add UserData to nodes..
+      // Initializes all userdata attributes as per the planar Surface
+      GltfUserData glTFUserData(planarSurface);
+
+      tinygltf::Mesh& targetMesh = meshes.emplace_back();
+      targetMesh.name = planarSurfaceName;
+
+      auto matName = glTFUserData.surfaceTypeMaterialName();
+      size_t materialIndex = 0;
+      auto it = std::find_if(materials.cbegin(), materials.cend(), [&matName](const auto& mat) { return mat.name == matName; });
+      if (it != materials.cend()) {
+        materialIndex = std::distance(materials.cbegin(), it);
+      } else {
+        auto it2 = std::find_if(allMaterials.cbegin(), allMaterials.cend(), [&matName](const auto& mat) { return mat.materialName() == matName; });
+        if (it2 == allMaterials.cend()) {
+          it2 = allMaterials.cbegin();  // This is always the "Undefined" material
+        }
+        materialIndex = materials.size();
+        // add to gltfModel
+        materials.emplace_back(it2->toGltf());
+      }
+
+      // get vertices of all sub surfaces
+      Point3dVectorVector faceSubVertices;
+      if (auto surface_ = planarSurface.optionalCast<model::Surface>()) {
+        for (const auto& subSurface : surface_->subSurfaces()) {
+          faceSubVertices.push_back(reverse(tInv * subSurface.vertices()));
+        }
+      }
+
+      Point3dVectorVector finalFaceVertices;
+      if (triangulateSurfaces) {
+        finalFaceVertices = computeTriangulation(faceVertices, faceSubVertices);
+        if (finalFaceVertices.empty()) {
+          LOG_FREE(Error, "modelToGLTF",
+                   "Failed to triangulate surface " << planarSurfaceName << " with " << faceSubVertices.size() << " sub surfaces");
+        }
+      } else {
+        finalFaceVertices.push_back(faceVertices);
+      }
+
+      Point3dVector allVertices;
+      Point3dVector triangleVertices;
+      std::vector<size_t> faceIndices;
+      for (const auto& finalFaceVerts : finalFaceVertices) {
+        Point3dVector finalVerts = t * finalFaceVerts;
+        triangleVertices.insert(triangleVertices.end(), finalVerts.begin(), finalVerts.end());
+        auto it = finalVerts.rbegin();
+        auto itend = finalVerts.rend();
+        for (; it != itend; ++it) {
+          faceIndices.push_back(getOrCreateVertexIndexT(*it, allVertices));
+        }
+      }
+
+      Vector3d outwardNormal = planarSurface.outwardNormal();
+      Vector3dVector normalVectors(allVertices.size(), outwardNormal);
+
+      detail::ShapeComponentIds shapeComponentIds(faceIndices, allVertices, normalVectors, indicesBuffer, coordinatesBuffer, accessors);
+
+      tinygltf::Primitive& thisPrimitive = targetMesh.primitives.emplace_back();
+      thisPrimitive.attributes["NORMAL"] = shapeComponentIds.normalsAccessorId;
+      thisPrimitive.attributes["POSITION"] = shapeComponentIds.verticesAccessorId;
+      thisPrimitive.indices = shapeComponentIds.indicesAccessorId;
+      thisPrimitive.material = static_cast<int>(materialIndex);
+      thisPrimitive.mode = TINYGLTF_MODE_TRIANGLES;
+
+      // TODO: Based on a flag override UserData attribute
+      // Addition of UserData as Extras to the node
+      node.extras = tinygltf::Value(glTFUserData.toExtras());
+
+      n += 1;
+      updatePercentage(100.0 * n / N);
+      // End Region MAIN
+    }
+    // Start Region BUILD SCENE | ELEMENT
+
+    if (coordinatesBuffer.empty()) {
+      return boost::none;
+    }
+
+    // Write the buffer data
+    // TODO: why use a single buffer for two buffersView instead of one buffer for each?
+    // no *.bin file is involved | everything is integrated in the mail output gltf file only.
+    // Having a separate input file for the GLTF is old now everything resides in the main GLTF file only... as a binary buffer data.
+    auto padding = indicesBuffer.size() % 4;
+    for (unsigned int i = 0; i < padding; i++) {
+      indicesBuffer.push_back(0x00);  // padding bytes
+    }
+
+    std::vector<unsigned char> allBuffer = indicesBuffer;  //std::move(_indicesBuffer);
+    allBuffer.insert(allBuffer.end(), coordinatesBuffer.begin(), coordinatesBuffer.end());
+
+    buffer.data = allBuffer;
+
+    indicesBv.byteLength = indicesBuffer.size();
+    indicesBv.byteOffset = 0;
+
+    coordinatesBv.byteLength = coordinatesBuffer.size();
+    coordinatesBv.byteOffset = indicesBuffer.size();
+    // End Region BUILD SCENE | ELEMENT
+
+    // Other tie ups
+
+    // Declare all nodes as a child of topNode
+    auto& topNodeChildren = nodes.front().children;
+    topNodeChildren.resize(nodes.size() - 1);
+    std::iota(topNodeChildren.begin(), topNodeChildren.end(), 1);
+
+    // SCENE EXTRAS | this will be having all the metadata
+    scene.extras = tinygltf::Value(GltfMetaData(model).toExtras());
+
+    return gltfModel;
+  }
+
+  std::string GltfForwardTranslator::modelToGLTFString(const model::Model& model) {
+    boost::optional<tinygltf::Model> gltfModel_ = toGltfModel(model, [](double percentage) {});
+    if (!gltfModel_) {
+      LOG(Error, "Failed to prepare GLTF model");
+      return "";
+    }
+
+    auto gltfModel = gltfModel_.get();
+
+    // Save it to a file
+    // glTF Parser/Serialier context
+    tinygltf::TinyGLTF ctx;
+    // Uncomment this to use extras_as_string [std::string] instead of extras [tinygltf::Value]
+    ctx.SetStoreOriginalJSONForExtrasAndExtensions(true);
+
+    std::stringstream ss;
+    bool ret = ctx.WriteGltfSceneToStream(&gltfModel, ss,
+                                          true,    // pretty print
+                                          false);  // write binary
+    if (!ret) {
+      LOG(Error, "Writing GLTF failed");
+    }
+    return ss.str();
+  }
+
+  // Exports a gltf against a Model
+  // returns : exports a GLTF file against a Model
+  bool GltfForwardTranslator::modelToGLTF(const model::Model& model, const path& outputPath) {
+    return modelToGLTF(
+      model, [](double percentage) {}, outputPath);
+  }
+
+  bool GltfForwardTranslator::modelToGLTF(const model::Model& model, std::function<void(double)> updatePercentage, const path& outputPath) {
+
+    boost::optional<tinygltf::Model> gltfModel_ = toGltfModel(model, [](double percentage) {});
+    if (!gltfModel_) {
+      LOG(Error, "Failed to prepare GLTF model");
+      return "";
+    }
+
+    // Save it to a file
+    auto gltfModel = gltfModel_.get();
+
+    // glTF Parser/Serialier context
+    tinygltf::TinyGLTF ctx;
+    // Uncomment this to use extras_as_string [std::string] instead of extras [tinygltf::Value]
+    ctx.SetStoreOriginalJSONForExtrasAndExtensions(true);
+    bool ret = ctx.WriteGltfSceneToFile(&gltfModel, toString(outputPath),
+                                        true,    // embedImages
+                                        true,    // embedBuffers
+                                        true,    // pretty print
+                                        false);  // write binary
+
+    updatePercentage(100.0);
+
+    return ret;
+  }
+
+  // TODO: either rename, or properly populate the model...
+  // To populate a GLTF Model from an existing GLTF file.
+  // also exports a gltf file with a .bin file (non embeded version).
+  bool GltfForwardTranslator::loadGLTF(const path& inputPath, const path& inputNonEmbededPath) {
+    tinygltf::TinyGLTF loader;
+    tinygltf::Model gltf_Model;
+    std::string err;
+    std::string warning;
+    std::string fileName = toString(inputPath);
+    bool ret = loader.LoadASCIIFromFile(&gltf_Model, &err, &warning, fileName);
+    if (!err.empty()) {
+      LOG(Error, "Error loading GLTF " << err);
+      //ret = false;
+    }
+    if (!warning.empty()) {
+      LOG(Warn, "Error loading GLTF " << warning);
+    }
+
+    if (!ret) {
+      LOG(Error, "Failed to parse glTF");
+    } else {
+      std::string output_filename = toString(inputNonEmbededPath);
+      std::string embedded_filename = output_filename.substr(0, output_filename.size() - 5) + "-Embedded.gltf";
+      bool a = loader.WriteGltfSceneToFile(&gltf_Model, output_filename);
+      OS_ASSERT(a);
+      // Embedd buffers and (images if present)
+#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
+      bool b = loader.WriteGltfSceneToFile(&gltf_Model, embedded_filename, true, true);
+      OS_ASSERT(b);
+#endif
+    }
+    return ret;
+  }
+
+  bool GltfForwardTranslator::loadGLTF(const path& inputPath) {
+    tinygltf::TinyGLTF loader;
+    tinygltf::Model gltf_Model;
+    std::string err;
+    std::string warning;
+    std::string fileName = toString(inputPath);
+    bool ret = loader.LoadASCIIFromFile(&gltf_Model, &err, &warning, fileName);
+    if (!err.empty()) {
+      LOG(Error, "Error loading GLTF: " << err);
+      //ret = false;
+    }
+    if (!warning.empty()) {
+      LOG(Warn, "Warning loading GLTF: " << warning);
+    }
+
+    if (!ret) {
+      LOG(Error, "Failed to parse glTF");
+    } else {
+      // TODO: get the materials too?
+
+      // USERDATA INITIALIZATION FROM EACH NODE's EXTRAS
+      m_userDataCollection.clear();
+      bool isTopNode = true;
+      for (const auto& node : gltf_Model.nodes) {
+        if (isTopNode) {
+          isTopNode = false;
+          continue;
+        }
+        m_userDataCollection.emplace_back(GltfUserData(node.extras));
+      }
+
+      // METADATA INITIALIZATION FROM SCENE's EXTRAS
+      if (gltf_Model.scenes.size() > 1) {
+        LOG(Warn, "Found more than one scene object, using the first found, occurred in GLTF File '" << toString(inputPath) << "'");
+      } else if (gltf_Model.scenes.empty()) {
+        LOG_AND_THROW("Could not find a scene object in the GTLF file '" << toString(inputPath) << "'");
+      }
+      m_gltfMetaData = GltfMetaData(gltf_Model.scenes[0].extras);
+    }
+    return ret;
+  }
+
+  std::vector<GltfUserData> GltfForwardTranslator::getUserDataCollection() const {
+    return m_userDataCollection;
+  }
+
+  boost::optional<GltfUserData> GltfForwardTranslator::getUserDataBySurfaceName(const std::string& surfaceName) const {
+    boost::optional<GltfUserData> result;
+
+    auto it =
+      std::find_if(m_userDataCollection.begin(), m_userDataCollection.end(), [&surfaceName](const auto& obj) { return obj.name() == surfaceName; });
+    if (it != m_userDataCollection.end()) {
+      result = *it;
+    }
+    return result;
+  }
+
+  GltfMetaData GltfForwardTranslator::getMetaData() const {
+    return m_gltfMetaData;
+  }
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/model/GltfForwardTranslator.hpp b/src/gltf/GltfForwardTranslator.hpp
similarity index 64%
rename from src/model/GltfForwardTranslator.hpp
rename to src/gltf/GltfForwardTranslator.hpp
index 9a0ec6a3434..a8ab8a0d2bb 100644
--- a/src/model/GltfForwardTranslator.hpp
+++ b/src/gltf/GltfForwardTranslator.hpp
@@ -26,65 +26,82 @@
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ***********************************************************************************************************************/
-#ifndef MODEL_GLTFFORWARDTRANSLATOR_HPP
-#define MODEL_GLTFFORWARDTRANSLATOR_HPP
+#ifndef GLTF_GLTFFORWARDTRANSLATOR_HPP
+#define GLTF_GLTFFORWARDTRANSLATOR_HPP
 
-#include "ModelAPI.hpp"
-#include "Model.hpp"
+#include "GltfAPI.hpp"
+
+#include "GltfMetaData.hpp"
+#include "GltfUserData.hpp"
+
+#include "../utilities/core/Path.hpp"
 #include "../utilities/core/Logger.hpp"
 #include "../utilities/core/StringStreamLogSink.hpp"
-#include "GltfMetaDataWrapper.hpp"
-#include "GltfUserDataWrapper.hpp"
+
+namespace tinygltf {
+class Model;
+}
 
 namespace openstudio {
 namespace model {
+  class Model;
+}
+
+namespace gltf {
+
+  // TODO: update this docstring, it's always been out of sync
 
-  /* GltfForwardTranslator converts an OpenStudio Model to GLTF format. There are two variations of the GLTF format,
+  /** GltfForwardTranslator converts an OpenStudio Model to GLTF format. There are two variations of the GLTF format,
     *   a triangulated one which is suitable for rendering with GLTF and non-triangulated one that preserves all vertices in a
     *   surface for conversion to OpenStudio Model format.
     *
     *   The FloorplanJS in the Utilities/Geometry project converts a FloorspaceJS JSON file to GLTF format, code should be shared between these two classes as much as possible.
     */
-  class MODEL_API GltfForwardTranslator
+  class GLTF_API GltfForwardTranslator
   {
    public:
     GltfForwardTranslator();
 
-    //  Convert an OpenStudio Model to Gltf format
-    bool modelToGLTF(const Model& model, const path& outputPath);
-    bool modelToGLTF(const Model& model, std::function<void(double)> updatePercentage, const path& outputpath);
+    /** Convert an OpenStudio Model to Gltf format */
+    bool modelToGLTF(const model::Model& model, const path& outputPath);
+    bool modelToGLTF(const model::Model& model, std::function<void(double)> updatePercentage, const path& outputpath);
 
-    // To export a Minimal GLTF file (Triangle with 3 Points) using raw buffer data.
-    bool createTriangleGLTF(const path& outputPath);
-    // To export a Minimal GLTF file (Triangle with 3 Points) using generated
-    // raw buffer data from Point3DVector
-    bool createTriangleGLTFFromPoint3DVector(const path& outputPath);
+    /** Convert an OpenStudio Model to Gltf format but as a JSON string */
+    std::string modelToGLTFString(const model::Model& model);
 
-    //load minimal gltf
+    /** @name QA / QC convenience methods */
+    //@{
+    /** load minimal gltf for QA/QC */
     bool loadGLTF(const path& inputPath, const path& inputNonEmbededpath);
+    /** load minimal gltf for QA/QC */
     bool loadGLTF(const path& inputPath);
 
-    GltfMetaDataWrapper getMetaData();
-    std::vector<GltfUserDataWrapper> getUserDataCollection();
-    GltfUserDataWrapper getUserDataBySurfaceName(const std::string& surfaceName);
+    GltfMetaData getMetaData() const;
+    std::vector<GltfUserData> getUserDataCollection() const;
+    boost::optional<GltfUserData> getUserDataBySurfaceName(const std::string& surfaceName) const;
 
-    // Get warning messages generated by the last translation.
+    /** Get warning messages generated by the last translation. */
     std::vector<LogMessage> warnings() const;
 
-    // Get error messages generated by the last translation.
+    /** Get error messages generated by the last translation. */
     std::vector<LogMessage> errors() const;
+    //@}
 
    private:
-    // tinygltf::Model gltf_Model;
-    REGISTER_LOGGER("openstudio.model.GltfForwardTranslator");
+    boost::optional<tinygltf::Model> toGltfModel(const model::Model& model, std::function<void(double)> updatePercentage);
+
+    REGISTER_LOGGER("openstudio.gltf.GltfForwardTranslator");
 
     StringStreamLogSink m_logSink;
-  };
 
-  // vector of GltfUserDataWrapper
-  typedef std::vector<GltfUserDataWrapper> GltfUserDataWrapperVector;
+    GltfMetaData m_gltfMetaData;
+    std::vector<GltfUserData> m_userDataCollection;
+
+    // TODO: make this a member?
+    // std::vector<GltfMaterialData> allMaterials;
+  };
 
-}  // namespace model
+}  // namespace gltf
 }  // namespace openstudio
 
-#endif  //MODEL_GLTFFORWARDTRANSLATOR_HPP
+#endif  // GLTF_GLTFFORWARDTRANSLATOR_HPP
diff --git a/src/gltf/GltfMaterialData.cpp b/src/gltf/GltfMaterialData.cpp
new file mode 100644
index 00000000000..12e09a409a9
--- /dev/null
+++ b/src/gltf/GltfMaterialData.cpp
@@ -0,0 +1,295 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "GltfMaterialData.hpp"
+#include "GltfUtils.hpp"
+
+#include "../model/Model.hpp"
+
+#include "../model/RenderingColor.hpp"
+#include "../model/ConstructionBase.hpp"
+#include "../model/ConstructionBase_Impl.hpp"
+#include "../model/ConstructionAirBoundary.hpp"
+#include "../model/ConstructionAirBoundary_Impl.hpp"
+#include "../model/BuildingStory.hpp"
+#include "../model/BuildingStory_Impl.hpp"
+#include "../model/BuildingUnit.hpp"
+#include "../model/BuildingUnit_Impl.hpp"
+#include "../model/ThermalZone.hpp"
+#include "../model/ThermalZone_Impl.hpp"
+#include "../model/AirLoopHVAC.hpp"
+#include "../model/AirLoopHVAC_Impl.hpp"
+#include "../model/SpaceType.hpp"
+#include "../model/SpaceType_Impl.hpp"
+
+#include <tiny_gltf.h>
+
+#include <map>
+#include <string>
+#include <string_view>
+#include <iostream>
+
+namespace openstudio {
+namespace gltf {
+
+  GltfMaterialData::GltfMaterialData(std::string_view materialName, const model::RenderingColor& color, bool isDoubleSided)
+    : m_materialName(materialName),
+      m_r(color.renderingRedValue()),
+      m_g(color.renderingGreenValue()),
+      m_b(color.renderingBlueValue()),
+      m_a(color.renderingAlphaValue() / 255.0),
+      m_isDoubleSided(isDoubleSided) {}
+
+  std::string GltfMaterialData::materialName() const {
+    return std::string{m_materialName};
+  }
+  void GltfMaterialData::setMaterialName(const std::string& materialName) {
+    m_materialName = materialName;
+  };
+
+  int GltfMaterialData::r() const {
+    return m_r;
+  }
+  void GltfMaterialData::setR(int r) {
+    m_r = r;
+  };
+
+  int GltfMaterialData::g() const {
+    return m_g;
+  }
+  void GltfMaterialData::setG(int g) {
+    m_g = g;
+  };
+
+  int GltfMaterialData::b() const {
+    return m_b;
+  }
+  void GltfMaterialData::setB(int b) {
+    m_b = b;
+  };
+
+  double GltfMaterialData::a() const {
+    return m_a;
+  }
+  void GltfMaterialData::setA(double a) {
+    m_a = a;
+  };
+
+  bool GltfMaterialData::isDoubleSided() const {
+    return m_isDoubleSided;
+  }
+  void GltfMaterialData::setIsDoubleSided(bool isDoubleSided) {
+    m_isDoubleSided = isDoubleSided;
+  };
+
+  tinygltf::Material GltfMaterialData::toGltf() const {
+    tinygltf::Material m;
+    m.name = m_materialName;
+    tinygltf::PbrMetallicRoughness pbr;
+    // this contains the red, green, blue and alpha components of the main color of the material
+    pbr.baseColorFactor = {(static_cast<float>(m_r) / 255.0f), (static_cast<float>(m_g) / 255.0f), (static_cast<float>(m_b) / 255.0f),
+                           static_cast<float>(m_a)};
+    // this indicates that the material should have very minimum reflection characteristics
+    // between that of a metal and non-metal material.
+    pbr.metallicFactor = 0.0;
+    // this makes the material to not be perfectly mirror-like, but instead scatter the
+    // reflected light a bit.
+    pbr.roughnessFactor = 1.0;
+    m.pbrMetallicRoughness = pbr;
+    // emissive texture describes the parts of the object surface that emit light with a certain color
+    m.emissiveFactor = {0.01, 0.01, 0.00};
+    // occlusion texture can be used to simulate the effect of objects self-shadowing each other.
+    // m.occlusionTexture = "";
+    // normal map is a texture applied to modulate the surface normal in a way that makes
+    // it possible to simulate finer geometric details without the cost of a higher mesh.
+    // m.normalTexture = "";
+    m.alphaMode = (m_a < 1.0f) ? "BLEND" : "OPAQUE";
+    // alphaCutoff should not be 1.0f else MATERIAL_ALPHA_CUTOFF_INVALID_MODE
+    // Alpha cutoff is supported only for 'MASK' alpha mode
+    m.alphaCutoff = 0.5f;
+    m.doubleSided = m_isDoubleSided;
+    return m;
+  }
+
+  // Creates a collection of raw (values: R,G,B,A & isDoubleSided) for all pre-defined GLTF material
+  static constexpr std::array<GltfMaterialData, 56> standardGltfMaterialDatas{{
+    {"Undefined", 255, 255, 255, 1, true},
+
+    {"NormalMaterial", 255, 255, 255, 1, true},
+    {"NormalMaterial_Ext", 255, 255, 255, 1},
+    {"NormalMaterial_Int", 255, 0, 0, 1},
+
+    {"Floor", 140, 140, 140, 1, true},
+    {"Floor_Ext", 128, 128, 128, 1},
+    {"Floor_Int", 191, 191, 191, 1},
+
+    {"Wall", 150, 131, 75, 1, true},
+    {"Wall_Ext", 204, 178, 102, 1},
+    {"Wall_Int", 235, 226, 197, 1},
+
+    {"RoofCeiling", 112, 56, 57, 1, true},
+    {"RoofCeiling_Ext", 153, 76, 76, 1},
+    {"RoofCeiling_Int", 202, 149, 149, 1},
+
+    {"Window", 102, 178, 204, 0.6, true},
+    {"Window_Ext", 102, 178, 204, 0.6},
+    {"Window_Int", 192, 226, 235, 0.6},
+
+    {"Door", 111, 98, 56, 1, true},
+    {"Door_Ext", 153, 133, 76, 1},
+    {"Door_Int", 202, 188, 149, 1},
+
+    {"SiteShading", 55, 90, 109, 1, true},
+    {"SiteShading_Ext", 75, 124, 149, 1},
+    {"SiteShading_Int", 187, 209, 220, 1},
+
+    {"BuildingShading", 83, 56, 111, 1, true},
+    {"BuildingShading_Ext", 113, 76, 153, 1},
+    {"BuildingShading_Int", 216, 203, 229, 1},
+
+    {"SpaceShading", 55, 81, 130, 1, true},
+    {"SpaceShading_Ext", 76, 110, 178, 1},
+    {"SpaceShading_Int", 183, 197, 224, 1},
+
+    {"InteriorPartitionSurface", 117, 138, 105, 1, true},
+    {"InteriorPartitionSurface_Ext", 158, 188, 143, 1},
+    {"InteriorPartitionSurface_Int", 213, 226, 207, 1},
+
+    // start textures for boundary conditions
+    {"Boundary_Surface", 0, 153, 0, 1, true},
+    {"Boundary_Adiabatic", 255, 0, 0, 1, true},
+    {"Boundary_Space", 255, 0, 0, 1, true},
+    {"Boundary_Outdoors", 163, 204, 204, 1, true},
+    {"Boundary_Outdoors_Sun", 40, 204, 204, 1, true},
+    {"Boundary_Outdoors_Wind", 9, 159, 162, 1, true},
+    {"Boundary_Outdoors_SunWind", 68, 119, 161, 1, true},
+    {"Boundary_Ground", 204, 183, 122, 1, true},
+    {"Boundary_Foundation", 117, 30, 122, 1, true},
+    {"Boundary_Groundfcfactormethod", 153, 122, 30, 1, true},
+    {"Boundary_Groundslabpreprocessoraverage", 255, 191, 0, 1, true},
+    {"Boundary_Groundslabpreprocessorcore", 255, 182, 50, 1, true},
+    {"Boundary_Groundslabpreprocessorperimeter", 255, 178, 101, 1, true},
+    {"Boundary_Groundbasementpreprocessoraveragewall", 204, 51, 0, 1, true},
+    {"Boundary_Groundbasementpreprocessoraveragefloor", 204, 81, 40, 1, true},
+    {"Boundary_Groundbasementpreprocessorupperwall", 204, 112, 81, 1, true},
+    {"Boundary_Groundbasementpreprocessorlowerwall", 204, 173, 163, 1, true},
+    {"Boundary_Othersidecoefficients", 63, 63, 63, 1, true},
+    {"Boundary_Othersideconditionsmodel", 153, 0, 76, 1, true},
+
+    // special rendering materials
+    {"SpaceType_Plenum", 192, 192, 192, 0.1, true},
+    {"ThermalZone_Plenum", 192, 192, 192, 0.1, true},
+
+    // special rendering materials, these are components or textures in SketchUp
+    {"DaylightingControl", 102, 178, 204, 0.1, true},
+    {"AirWall", 102, 178, 204, 0.1, true},
+    {"SolarCollector", 255, 255, 255, 1, true},
+    {"Photovoltaic", 255, 255, 255, 0.1, true},
+  }};
+
+  // Static
+  std::vector<GltfMaterialData> GltfMaterialData::buildMaterials(const model::Model& model) {
+
+    // We start by putting all standard materials: NOTE: "Undefined" will always be the first one
+    std::vector<GltfMaterialData> allMaterials(standardGltfMaterialDatas.begin(), standardGltfMaterialDatas.end());
+
+    std::set<std::string> allMaterialNamesSet;
+
+    auto getOrCreateRenderingColor = [&model](auto& object) {
+      auto color_ = object.renderingColor();
+      if (!color_) {
+        color_ = model::RenderingColor(model);
+        // TODO: Uh Oh, taking model as const but mutating objects by adding rendering colors to them...
+        object.setRenderingColor(color_.get());
+      }
+      return color_.get();
+    };
+
+    auto getOrCreateMaterial = [&allMaterials, &allMaterialNamesSet](auto& object, const model::RenderingColor& color) {
+      std::string materialName = getObjectGLTFMaterialName(object);
+      auto [it, hasInserted] = allMaterialNamesSet.insert(materialName);
+      if (hasInserted) {
+        // instead of creating the material whose node might get not used inshort to avoid
+        // warning "UNUSED_OBJECT". we'll add the material to our allMaterial collection
+        // and whie processing the surface if required we'll create and the node.
+        // createMaterial(materials, color, materialName, true);
+        allMaterials.emplace_back(materialName, color, true);
+      } else {
+        LOG_FREE(Debug, "GltfForwardTranslator", "buildMaterials, Key " << materialName << " found in materialList: " << *it);
+      }
+    };
+
+    // make construction materials
+    for (auto& construction : model.getModelObjects<model::ConstructionBase>()) {
+      // If it's ConstructionAirBoundary, we'll later use the standard material "AirWall"
+      if (!construction.optionalCast<model::ConstructionAirBoundary>()) {
+        getOrCreateMaterial(construction, getOrCreateRenderingColor(construction));
+      }
+    }
+
+    // make thermal zone materials
+    for (auto& thermalZone : model.getConcreteModelObjects<model::ThermalZone>()) {
+      getOrCreateMaterial(thermalZone, getOrCreateRenderingColor(thermalZone));
+    }
+
+    // make space type materials
+    for (auto& spaceType : model.getConcreteModelObjects<model::SpaceType>()) {
+      getOrCreateMaterial(spaceType, getOrCreateRenderingColor(spaceType));
+    }
+
+    // make building story materials
+    for (auto& buildingStory : model.getConcreteModelObjects<model::BuildingStory>()) {
+      getOrCreateMaterial(buildingStory, getOrCreateRenderingColor(buildingStory));
+    }
+
+    // make building unit materials
+    for (auto& buildingUnit : model.getConcreteModelObjects<model::BuildingUnit>()) {
+      getOrCreateMaterial(buildingUnit, getOrCreateRenderingColor(buildingUnit));
+    }
+
+    // make air loop HVAC materials (AirLoopHVAC doesn't have a renderingColor() method)
+    for (auto& airLoopHVAC : model.getConcreteModelObjects<model::AirLoopHVAC>()) {
+      getOrCreateMaterial(airLoopHVAC, model::RenderingColor(model));
+    }
+
+    return allMaterials;
+  }
+
+  std::ostream& operator<<(std::ostream& out, const GltfMaterialData& gltfMaterialData) {
+    out << "GltfMaterialData(r=" << gltfMaterialData.r() << ", g=" << gltfMaterialData.g() << ", b=" << gltfMaterialData.b()
+        << ", a=" << gltfMaterialData.a();
+    if (gltfMaterialData.isDoubleSided()) {
+      out << ", Double Sided";
+    }
+    out << ")";
+    return out;
+  }
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/gltf/GltfMaterialData.hpp b/src/gltf/GltfMaterialData.hpp
new file mode 100644
index 00000000000..130d7269852
--- /dev/null
+++ b/src/gltf/GltfMaterialData.hpp
@@ -0,0 +1,115 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+#ifndef GLTF_GLTFMATERIALDATA_HPP
+#define GLTF_GLTFMATERIALDATA_HPP
+
+#include "GltfAPI.hpp"
+
+#include <array>
+#include <string_view>
+#include <vector>
+
+namespace tinygltf {
+struct Material;
+}
+
+namespace openstudio {
+
+namespace model {
+  class Model;
+  class RenderingColor;
+}  // namespace model
+
+namespace gltf {
+
+  class GltfForwardTranslator;
+
+  /** GltfMaterialData is an Interface class between a `RenderingColor` and a `tinygltf::Material` **/
+  class GLTF_API GltfMaterialData
+  {
+   public:
+    /** @name Interface with Model and ModelObjects */
+    //@{
+
+    /** Standard constructor */
+    constexpr GltfMaterialData(std::string_view materialName, int r, int g, int b, double a, bool isDoubleSided = false)
+      : m_materialName(materialName), m_r(r), m_g(g), m_b(b), m_a(a), m_isDoubleSided(isDoubleSided){};
+
+    static std::vector<GltfMaterialData> buildMaterials(const model::Model& model);
+    //@}
+
+    GltfMaterialData(std::string_view materialName, const model::RenderingColor& color, bool isDoubleSided = false);
+
+    /** @name Getters and Setters */
+    //@{
+    std::string materialName() const;
+    void setMaterialName(const std::string& materialName);
+
+    int r() const;
+    void setR(int r);
+
+    int g() const;
+    void setG(int g);
+
+    int b() const;
+    void setB(int b);
+
+    double a() const;
+    void setA(double a);
+
+    bool isDoubleSided() const;
+    void setIsDoubleSided(bool isDoubleSided);
+
+   protected:
+    /** @name Protected */
+    //@{
+
+    /** Creates a GLTF material on the basis of raw Material Values, i.e, R, G, B, A & isDoubleSided */
+    tinygltf::Material toGltf() const;
+    friend class GltfForwardTranslator;
+
+    //@}
+
+   private:
+    std::string_view m_materialName;
+    int m_r;     // [0, 255]
+    int m_g;     // [0, 255]
+    int m_b;     // [0, 255]
+    double m_a;  // [0, 1]     -> TODO: make that 0, 255 (int) like RenderingColor does
+    bool m_isDoubleSided = false;
+  };
+
+  /** \relates GltfMaterialData */
+  GLTF_API std::ostream& operator<<(std::ostream& out, const GltfMaterialData& gltfMaterialData);
+
+  using GltfMaterialDataVector = std::vector<GltfMaterialData>;
+
+}  // namespace gltf
+}  // namespace openstudio
+#endif  // GLTF_GLTFMATERIALDATA_HPP
diff --git a/src/gltf/GltfMetaData.cpp b/src/gltf/GltfMetaData.cpp
new file mode 100644
index 00000000000..a3d3d2b8aee
--- /dev/null
+++ b/src/gltf/GltfMetaData.cpp
@@ -0,0 +1,421 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "GltfMetaData.hpp"
+
+#include "../model/Model.hpp"
+
+#include "../model/Building.hpp"
+#include "../model/Building_Impl.hpp"
+
+#include "../model/PlanarSurface.hpp"
+#include "../model/PlanarSurfaceGroup.hpp"
+#include "../model/BuildingStory.hpp"
+#include "../model/BuildingStory_Impl.hpp"
+#include "../model/BuildingUnit.hpp"
+#include "../model/BuildingUnit_Impl.hpp"
+#include "../model/ThermalZone.hpp"
+#include "../model/ThermalZone_Impl.hpp"
+#include "../model/AirLoopHVAC.hpp"
+#include "../model/AirLoopHVAC_Impl.hpp"
+#include "../model/SpaceType.hpp"
+#include "../model/SpaceType_Impl.hpp"
+#include "../model/DefaultConstructionSet.hpp"
+#include "../model/DefaultConstructionSet_Impl.hpp"
+#include "../model/Space.hpp"
+#include "../model/Space_Impl.hpp"
+
+#include <OpenStudio.hxx>
+
+#include <tiny_gltf.h>
+
+#include <map>
+#include <string>
+
+namespace openstudio {
+namespace gltf {
+
+  GltfMetaData::GltfMetaData() = default;
+
+  GltfMetaData::GltfMetaData(const model::Model& model) {
+
+    // Generator
+    setGenerator("OpenStudio");
+    // type  | ??
+    setType("Object");
+    // Version
+    setVersion(openStudioVersion());
+    // North Axis
+    setNorthAxis(model);
+
+    m_glTFBoundingBox = GltfBoundingBox(model.getModelObjects<model::PlanarSurfaceGroup>());
+
+    // Building Story Names
+    auto buildingStories = model.getConcreteModelObjects<model::BuildingStory>();
+    for (const auto& buildingStory : buildingStories) {
+      m_glTFModelObjectMetaDataVector.emplace_back(buildingStory);
+      m_buildingStoryNames.emplace_back(buildingStory.nameString());
+      ++m_buildingStoryCount;
+      // TODO: I am matching what the initial implementation was doing, I guess the idea is to have spaces follow the story they belong to
+      for (const auto& space : buildingStory.spaces()) {
+        m_glTFModelObjectMetaDataVector.emplace_back(space);
+        ++m_spaceCount;
+      }
+    }
+
+    for (const auto& buildingUnit : model.getConcreteModelObjects<model::BuildingUnit>()) {
+      m_glTFModelObjectMetaDataVector.emplace_back(buildingUnit);
+      ++m_buildingUnitCount;
+    }
+
+    for (const auto& thermalZone : model.getConcreteModelObjects<model::ThermalZone>()) {
+      m_glTFModelObjectMetaDataVector.emplace_back(thermalZone);
+      ++m_thermalZoneCount;
+    }
+
+    for (const auto& buildingUnit : model.getConcreteModelObjects<model::SpaceType>()) {
+      m_glTFModelObjectMetaDataVector.emplace_back(buildingUnit);
+      ++m_spaceTypeCount;
+    }
+
+    for (const auto& buildingUnit : model.getConcreteModelObjects<model::DefaultConstructionSet>()) {
+      m_glTFModelObjectMetaDataVector.emplace_back(buildingUnit);
+      ++m_constructionSetCount;
+    }
+
+    for (const auto& buildingUnit : model.getConcreteModelObjects<model::AirLoopHVAC>()) {
+      m_glTFModelObjectMetaDataVector.emplace_back(buildingUnit);
+      ++m_airLoopCount;
+    }
+  }
+
+  std::vector<GltfModelObjectMetaData> GltfMetaData::glTFModelObjectMetaDataVector() const {
+    return m_glTFModelObjectMetaDataVector;
+  }
+  void GltfMetaData::setGlTFModelObjectMetaDataVector(const std::vector<GltfModelObjectMetaData>& glTFModelObjectMetaDataVector) {
+    m_glTFModelObjectMetaDataVector = glTFModelObjectMetaDataVector;
+  };
+
+  GltfBoundingBox GltfMetaData::glTFBoundingBox() const {
+    return m_glTFBoundingBox;
+  }
+  void GltfMetaData::setGlTFBoundingBox(const GltfBoundingBox& glTFBoundingBox) {
+    m_glTFBoundingBox = glTFBoundingBox;
+  };
+
+  std::vector<std::string> GltfMetaData::buildingStoryNames() const {
+    return m_buildingStoryNames;
+  }
+  void GltfMetaData::setBuildingStoryNames(const std::vector<std::string>& buildingStoryNames) {
+    m_buildingStoryNames = buildingStoryNames;
+  };
+
+  void GltfMetaData::setBuildingStoryNames(const std::vector<model::BuildingStory>& buildingStories) {
+    m_buildingStoryNames.clear();
+    m_buildingStoryCount = 0;
+    for (const auto& buildingStory : buildingStories) {
+      m_buildingStoryNames.emplace_back(buildingStory.nameString());
+      ++m_buildingStoryCount;
+    }
+  }
+
+  std::string GltfMetaData::generator() const {
+    return m_generator;
+  }
+  void GltfMetaData::setGenerator(const std::string& generator) {
+    m_generator = generator;
+  };
+
+  std::string GltfMetaData::type() const {
+    return m_type;
+  }
+  void GltfMetaData::setType(const std::string& type) {
+    m_type = type;
+  };
+
+  std::string GltfMetaData::version() const {
+    return m_version;
+  }
+  void GltfMetaData::setVersion(const std::string& version) {
+    m_version = version;
+  };
+
+  double GltfMetaData::northAxis() const {
+    return m_northAxis;
+  }
+  void GltfMetaData::setNorthAxis(double northAxis) {
+    m_northAxis = northAxis;
+  };
+
+  void GltfMetaData::setNorthAxis(const model::Model& model) {
+    m_northAxis = 0.0;
+    if (auto building_ = model.getOptionalUniqueModelObject<model::Building>()) {
+      m_northAxis = -building_->northAxis();
+    }
+  }
+
+  int GltfMetaData::thermalZoneCount() const {
+    return m_thermalZoneCount;
+  }
+  void GltfMetaData::setThermalZoneCount(int thermalZoneCount) {
+    m_thermalZoneCount = thermalZoneCount;
+  };
+
+  int GltfMetaData::spaceCount() const {
+    return m_spaceCount;
+  }
+  void GltfMetaData::setSpaceCount(int spaceCount) {
+    m_spaceCount = spaceCount;
+  };
+
+  int GltfMetaData::spaceTypeCount() const {
+    return m_spaceTypeCount;
+  }
+  void GltfMetaData::setSpaceTypeCount(int spaceTypeCount) {
+    m_spaceTypeCount = spaceTypeCount;
+  };
+
+  int GltfMetaData::constructionSetCount() const {
+    return m_constructionSetCount;
+  }
+  void GltfMetaData::setConstructionSetCount(int constructionSetCount) {
+    m_constructionSetCount = constructionSetCount;
+  };
+
+  int GltfMetaData::airLoopCount() const {
+    return m_airLoopCount;
+  }
+  void GltfMetaData::setAirLoopCount(int airLoopCount) {
+    m_airLoopCount = airLoopCount;
+  };
+
+  int GltfMetaData::buildingStoryCount() const {
+    return m_buildingStoryCount;
+  }
+  void GltfMetaData::setBuildingStoryCount(int buildingStoryCount) {
+    m_buildingStoryCount = buildingStoryCount;
+  };
+
+  std::map<std::string, tinygltf::Value> GltfMetaData::toExtras() const {
+
+    // TODO: use an array instead of a map<std::string(int), std::string>
+    std::map<std::string, tinygltf::Value> modelObjectMetaDataVector;
+    for (size_t i = 0; i < m_glTFModelObjectMetaDataVector.size(); ++i) {
+      modelObjectMetaDataVector.emplace(std::make_pair(std::to_string(i), tinygltf::Value(m_glTFModelObjectMetaDataVector[i].toExtras())));
+    }
+
+    std::map<std::string, tinygltf::Value> buildingStoryNamesObject;
+    for (size_t i = 0; i < m_buildingStoryNames.size(); ++i) {
+      buildingStoryNamesObject.emplace(std::make_pair(std::to_string(i), tinygltf::Value(m_buildingStoryNames[i])));
+    }
+
+    return {
+      {"modelObjectMetaData", tinygltf::Value(modelObjectMetaDataVector)},
+      {"boundingbox", tinygltf::Value(m_glTFBoundingBox.toExtras())},
+      {"buildingStoryNames", tinygltf::Value(buildingStoryNamesObject)},
+      {"generator", tinygltf::Value(m_generator)},
+      {"type", tinygltf::Value(m_type)},
+      {"version", tinygltf::Value(m_version)},
+      {"northAxis", tinygltf::Value(m_northAxis)},
+      // {"thermalZoneCount", tinygltf::Value(m_thermalZoneCount)},
+      // {"spaceCount", tinygltf::Value(m_spaceCount)},
+      // {"spaceTypeCount", tinygltf::Value(m_spaceTypeCount)},
+      // {"constructionSetCount", tinygltf::Value(m_constructionSetCount)},
+      // {"airLoopCount", tinygltf::Value(m_airLoopCount)},
+      // {"buildingStoryCount", tinygltf::Value(m_buildingStoryCount)},
+    };
+  }
+
+  GltfMetaData::GltfMetaData(const tinygltf::Value& metaDataObj) {
+
+    if (metaDataObj.Has("modelObjectMetaData")) {
+      auto val = metaDataObj.Get("modelObjectMetaData");
+      if (val.IsObject()) {
+        for (const auto& vv : val.Get<std::map<std::string, tinygltf::Value>>()) {
+          if (vv.second.IsObject()) {
+            // Constructs in place via GltfModelObjectMetaData(const tinygltf::Value&) ctor
+            m_glTFModelObjectMetaDataVector.emplace_back(GltfModelObjectMetaData(vv.second));
+
+            std::string iddObjectTypeStr = m_glTFModelObjectMetaDataVector.back().iddObjectType();
+            if (iddObjectTypeStr == "OS:BuildingStory") {
+              m_buildingStoryCount++;
+            } else if (iddObjectTypeStr == "OS:Space") {
+              m_spaceCount++;
+            } else if (iddObjectTypeStr == "OS:ThermalZone") {
+              m_thermalZoneCount++;
+            } else if (iddObjectTypeStr == "OS:SpaceType") {
+              m_spaceTypeCount++;
+            } else if (iddObjectTypeStr == "OS:DefaultConstructionSet") {
+              m_constructionSetCount++;
+            } else if (iddObjectTypeStr == "OS:AirLoopHVAC") {
+              m_airLoopCount++;
+            } else if (iddObjectTypeStr == "OS:BuildingUnit") {
+              m_buildingUnitCount++;
+            }
+
+          } else {
+            LOG(Warn, "metaDataObj has the key 'modelObjectMetaData', it is an Object, but at least one of the subobjects is not an Object");
+          }
+        }
+      } else {
+        LOG(Warn, "metaDataObj has the key 'modelObjectMetaData' but it is not an Object");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'airWall'");
+    }
+
+    if (metaDataObj.Has("boundingbox")) {
+      auto val = metaDataObj.Get("boundingbox");
+      // TODO: do I check here, or do I actually let the GltfBoundingBox ctor throw?
+      if (val.IsObject()) {
+        m_glTFBoundingBox = GltfBoundingBox(val);
+      } else {
+        LOG(Debug, "metaDataObj has the key 'boundingbox' but it is not a an Object");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'boundingbox'");
+    }
+
+    if (metaDataObj.Has("buildingStoryNames")) {
+      auto val = metaDataObj.Get("buildingStoryNames");
+      if (val.IsObject()) {
+        for (const auto& vv : val.Get<std::map<std::string, tinygltf::Value>>()) {
+          if (vv.second.IsString()) {
+            m_buildingStoryNames.emplace_back(vv.second.Get<std::string>());
+          } else {
+            LOG(Warn, "metaDataObj has the key 'buildingStoryNames', it is an Object, but at least one of the subobjects is not a std::string");
+          }
+        }
+      } else {
+        LOG(Warn, "metaDataObj has the key 'buildingStoryNames' but it is not an Object");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'airWall'");
+    }
+
+    if (metaDataObj.Has("generator")) {
+      auto val = metaDataObj.Get("generator");
+      if (val.IsString()) {
+        m_generator = val.Get<std::string>();
+      } else {
+        LOG(Debug, "metaDataObj has the key 'generator' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'generator'");
+    }
+
+    if (metaDataObj.Has("type")) {
+      auto val = metaDataObj.Get("type");
+      if (val.IsString()) {
+        m_type = val.Get<std::string>();
+      } else {
+        LOG(Debug, "metaDataObj has the key 'type' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'type'");
+    }
+
+    if (metaDataObj.Has("version")) {
+      auto val = metaDataObj.Get("version");
+      if (val.IsString()) {
+        m_version = val.Get<std::string>();
+      } else {
+        LOG(Debug, "metaDataObj has the key 'version' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'version'");
+    }
+
+    if (metaDataObj.Has("northAxis")) {
+      auto val = metaDataObj.Get("northAxis");
+      if (val.IsReal()) {
+        m_northAxis = val.Get<double>();
+      } else {
+        LOG(Debug, "metaDataObj has the key 'northAxis' but it is not a double");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'northAxis'");
+    }
+
+    if (metaDataObj.Has("storyCount")) {
+      auto val = metaDataObj.Get("storyCount");
+      if (val.IsInt()) {
+        m_buildingStoryCount = val.Get<int>();
+      } else {
+        LOG(Debug, "metaDataObj has the key 'storyCount' but it is not a int");
+      }
+    } else {
+      LOG(Debug, "metaDataObj is missing the key 'storyCount'");
+    }
+
+    // auto tryGetIntFromkey = [&metaDataObj](const std::string& key) -> boost::optional<double> {
+    //   if (metaDataObj.Has(key)) {
+    //     auto val = metaDataObj.Get(key);
+    //     if (val.IsReal()) {
+    //       return val.Get<int>();
+    //     } else {
+    //       LOG(Warn, "metaDataObj has the key '" << key << "' but it is not an integer");
+    //     }
+    //   } else {
+    //     LOG(Debug, "metaDataObj is missing the key '" << key << "'");
+    //   }
+    //   return boost::none;
+    // };
+
+    // if (auto i_ = tryGetIntFromkey("buildingStoryCount")) {
+    //   m_buildingStoryCount = i_.get();
+    // }
+
+    // if (auto i_ = tryGetIntFromkey("thermalZoneCount")) {
+    //   m_thermalZoneCount = i_.get();
+    // }
+
+    // if (auto i_ = tryGetIntFromkey("spaceCount")) {
+    //   m_spaceCount = i_.get();
+    // }
+
+    // if (auto i_ = tryGetIntFromkey("spaceTypeCount")) {
+    //   m_spaceTypeCount = i_.get();
+    // }
+
+    // if (auto i_ = tryGetIntFromkey("constructionSetCount")) {
+    //   m_constructionSetCount = i_.get();
+    // }
+
+    // if (auto i_ = tryGetIntFromkey("airLoopCount")) {
+    //   m_airLoopCount = i_.get();
+    // }
+
+    // if (auto i_ = tryGetIntFromkey("buildingStoryCount")) {
+    //   m_buildingStoryCount = i_.get();
+    // }
+  }
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/gltf/GltfMetaData.hpp b/src/gltf/GltfMetaData.hpp
new file mode 100644
index 00000000000..06e7f2e98cb
--- /dev/null
+++ b/src/gltf/GltfMetaData.hpp
@@ -0,0 +1,144 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+#ifndef GLTF_GLTFMETADATA_HPP
+#define GLTF_GLTFMETADATA_HPP
+
+#include "GltfAPI.hpp"
+
+#include "GltfModelObjectMetaData.hpp"
+#include "GltfBoundingBox.hpp"
+
+#include "../utilities/core/Logger.hpp"
+
+namespace tinygltf {
+class Value;
+}
+
+namespace openstudio {
+namespace model {
+  class Model;
+  class PlanarSurfaceGroup;
+  class BuildingStory;
+
+}  // namespace model
+
+namespace gltf {
+
+  /** GltfMetadata is an Interface between an OpenStudio Model and a glTF Scene's `extras` **/
+  class GLTF_API GltfMetaData
+  {
+   public:
+    GltfMetaData();  // default ctor
+
+    /** @name Interface with Model */
+    //@{
+    /** Interface with the Model **/
+    GltfMetaData(const model::Model& model);
+    //@}
+
+    /** @name Getters and Setters */
+    //@{
+
+    std::vector<GltfModelObjectMetaData> glTFModelObjectMetaDataVector() const;
+    void setGlTFModelObjectMetaDataVector(const std::vector<GltfModelObjectMetaData>& glTFModelObjectMetaDataVector);
+
+    GltfBoundingBox glTFBoundingBox() const;
+    void setGlTFBoundingBox(const GltfBoundingBox& glTFBoundingBox);
+
+    std::vector<std::string> buildingStoryNames() const;
+    void setBuildingStoryNames(const std::vector<std::string>& buildingStoryNames);
+    // Convenience function. TODO: keep?
+    void setBuildingStoryNames(const std::vector<model::BuildingStory>& buildingStories);
+
+    std::string generator() const;
+    void setGenerator(const std::string& generator);
+
+    std::string type() const;
+    void setType(const std::string& type);
+
+    std::string version() const;
+    void setVersion(const std::string& version);
+
+    double northAxis() const;
+    void setNorthAxis(double northAxis);
+    void setNorthAxis(const model::Model& model);
+
+    // Counting
+    // TODO: Remove setters
+    int thermalZoneCount() const;
+    void setThermalZoneCount(int thermalZoneCount);
+
+    int spaceCount() const;
+    void setSpaceCount(int spaceCount);
+
+    int spaceTypeCount() const;
+    void setSpaceTypeCount(int spaceTypeCount);
+
+    int constructionSetCount() const;
+    void setConstructionSetCount(int constructionSetCount);
+
+    int airLoopCount() const;
+    void setAirLoopCount(int airLoopCount);
+
+    int buildingStoryCount() const;
+    void setBuildingStoryCount(int buildingStoryCount);
+
+    //@}
+
+   protected:
+    /** @name Protected */
+    //@{
+    std::map<std::string, tinygltf::Value> toExtras() const;
+    GltfMetaData(const tinygltf::Value& metaDataObj);
+
+    //@}
+    friend class GltfForwardTranslator;
+
+   private:
+    REGISTER_LOGGER("openstudio.gltf.GltfMetaData");
+
+    std::vector<GltfModelObjectMetaData> m_glTFModelObjectMetaDataVector;
+    GltfBoundingBox m_glTFBoundingBox;
+    std::vector<std::string> m_buildingStoryNames;
+    std::string m_generator;
+    std::string m_type;
+    std::string m_version;
+    double m_northAxis = 0.0;
+    int m_buildingStoryCount = 0;  // TODO: this is pointless, we have m_buildingStoryNames.size()
+    int m_thermalZoneCount = 0;
+    int m_spaceCount = 0;
+    int m_spaceTypeCount = 0;
+    int m_constructionSetCount = 0;
+    int m_airLoopCount = 0;
+    int m_buildingUnitCount = 0;
+  };
+}  // namespace gltf
+}  // namespace openstudio
+
+#endif  //GLTF_GLTFMETADATA_HPP
diff --git a/src/gltf/GltfModelObjectMetaData.cpp b/src/gltf/GltfModelObjectMetaData.cpp
new file mode 100644
index 00000000000..e0666ecb024
--- /dev/null
+++ b/src/gltf/GltfModelObjectMetaData.cpp
@@ -0,0 +1,290 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "GltfModelObjectMetaData.hpp"
+
+#include "../model/AirLoopHVAC.hpp"
+#include "../model/BuildingUnit.hpp"
+#include "../model/SpaceType.hpp"
+#include "../model/BuildingStory.hpp"
+#include "../model/ThermalZone.hpp"
+#include "../model/DefaultConstructionSet.hpp"
+#include "../model/Space.hpp"
+#include "../model/RenderingColor.hpp"
+
+#include "utilities/core/UUID.hpp"
+
+#include <tiny_gltf.h>
+
+#include <string>
+#include <map>
+
+namespace openstudio {
+namespace gltf {
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData() = default;
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const model::AirLoopHVAC& airLoopHVAC)
+    : m_handle(openstudio::removeBraces(airLoopHVAC.handle())),
+      m_iddObjectType(model::AirLoopHVAC::iddObjectType().valueDescription()),
+      m_name(airLoopHVAC.nameString()) {}
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const model::BuildingUnit& buildingUnit)
+    : m_handle(openstudio::removeBraces(buildingUnit.handle())),
+      m_iddObjectType(model::BuildingUnit::iddObjectType().valueDescription()),
+      m_name(buildingUnit.nameString()) {
+
+    if (buildingUnit.renderingColor()) {
+      m_color = buildingUnit.renderingColor()->colorString();
+    }
+  }
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const model::SpaceType& spaceType)
+    : m_handle(openstudio::removeBraces(spaceType.handle())),
+      m_iddObjectType(model::SpaceType::iddObjectType().valueDescription()),
+      m_name(spaceType.nameString()) {
+
+    if (spaceType.renderingColor()) {
+      m_color = spaceType.renderingColor()->colorString();
+    }
+  }
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const model::BuildingStory& buildingStory)
+    : m_handle(openstudio::removeBraces(buildingStory.handle())),
+      m_iddObjectType(model::BuildingStory::iddObjectType().valueDescription()),
+      m_name(buildingStory.nameString()) {
+
+    if (buildingStory.renderingColor()) {
+      m_color = buildingStory.renderingColor()->colorString();
+    }
+    if (buildingStory.nominalZCoordinate()) {
+      m_nominalZCoordinate = buildingStory.nominalZCoordinate().get();
+    }
+    // TBD: Do we have to include this ?
+    if (buildingStory.nominalFloortoCeilingHeight()) {
+      m_nominalFloortoCeilingHeight = buildingStory.nominalFloortoCeilingHeight().get();
+    }
+
+    // TODO: How to calculate this ?
+    m_opentoBelow = false;
+
+    if (buildingStory.nominalFloortoFloorHeight()) {
+      // TODO: DLM how to translate this?
+    }
+  }
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const model::ThermalZone& thermalZone)
+    : m_handle(openstudio::removeBraces(thermalZone.handle())),
+      m_iddObjectType(model::ThermalZone::iddObjectType().valueDescription()),
+      m_name(thermalZone.nameString()) {
+
+    if (thermalZone.renderingColor()) {
+      m_color = thermalZone.renderingColor()->colorString();
+    }
+
+    // TODO: How to calculate this ?
+    m_opentoBelow = false;
+
+    m_multiplier = thermalZone.multiplier();
+  }
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const model::DefaultConstructionSet& defaultConstructionSet)
+    : m_handle(openstudio::removeBraces(defaultConstructionSet.handle())),
+      m_iddObjectType(model::DefaultConstructionSet::iddObjectType().valueDescription()),
+      m_name(defaultConstructionSet.nameString()) {}
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const model::Space& space)
+    : m_handle(openstudio::removeBraces(space.handle())),
+      m_iddObjectType(model::Space::iddObjectType().valueDescription()),
+      m_name(space.nameString()) {
+
+    // TODO: the original implementation doesn't use the space multiplier (well: it does come from the attached thermal Zone so...)
+  }
+
+  std::string GltfModelObjectMetaData::color() const {
+    return m_color;
+  }
+  void GltfModelObjectMetaData::setColor(const std::string& color) {
+    m_color = color;
+  };
+
+  std::string GltfModelObjectMetaData::handle() const {
+    return m_handle;
+  }
+  void GltfModelObjectMetaData::setHandle(const std::string& handle) {
+    m_handle = handle;
+  };
+
+  std::string GltfModelObjectMetaData::iddObjectType() const {
+    return m_iddObjectType;
+  }
+  void GltfModelObjectMetaData::setIddObjectType(const std::string& iddObjectType) {
+    m_iddObjectType = iddObjectType;
+  };
+
+  std::string GltfModelObjectMetaData::name() const {
+    return m_name;
+  }
+  void GltfModelObjectMetaData::setName(const std::string& name) {
+    m_name = name;
+  };
+
+  bool GltfModelObjectMetaData::isOpentoBelow() const {
+    return m_opentoBelow;
+  }
+  void GltfModelObjectMetaData::setOpentoBelow(bool opentoBelow) {
+    m_opentoBelow = opentoBelow;
+  };
+
+  double GltfModelObjectMetaData::nominalZCoordinate() const {
+    return m_nominalZCoordinate;
+  }
+  void GltfModelObjectMetaData::setNominalZCoordinate(double nominalZCoordinate) {
+    m_nominalZCoordinate = nominalZCoordinate;
+  };
+
+  double GltfModelObjectMetaData::nominalFloortoCeilingHeight() const {
+    return m_nominalFloortoCeilingHeight;
+  }
+  void GltfModelObjectMetaData::setNominalFloortoCeilingHeight(double nominalFloortoCeilingHeight) {
+    m_nominalFloortoCeilingHeight = nominalFloortoCeilingHeight;
+  };
+
+  int GltfModelObjectMetaData::multiplier() const {
+    return m_multiplier;
+  }
+  void GltfModelObjectMetaData::setMultiplier(int multiplier) {
+    m_multiplier = multiplier;
+  };
+
+  std::map<std::string, tinygltf::Value> GltfModelObjectMetaData::toExtras() const {
+    return {
+      {"color", tinygltf::Value(m_color)},
+      {"handle", tinygltf::Value(m_handle)},
+      {"iddObjectType", tinygltf::Value(m_iddObjectType)},
+      {"name", tinygltf::Value(m_name)},
+      {"open_to_below", tinygltf::Value(m_opentoBelow)},
+      {"nominal_z_coordinate", tinygltf::Value(m_nominalZCoordinate)},
+      {"nominal_floorCeiling_Height", tinygltf::Value(m_nominalFloortoCeilingHeight)},
+      {"multiplier", tinygltf::Value(m_multiplier)},
+    };
+  }
+
+  GltfModelObjectMetaData::GltfModelObjectMetaData(const tinygltf::Value& modelObjectMetaDataObj) {
+
+    if (modelObjectMetaDataObj.Has("color")) {
+      auto val = modelObjectMetaDataObj.Get("color");
+      if (val.IsString()) {
+        m_color = val.Get<std::string>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'color' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'color'");
+    }
+
+    if (modelObjectMetaDataObj.Has("handle")) {
+      auto val = modelObjectMetaDataObj.Get("handle");
+      if (val.IsString()) {
+        m_handle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'handle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'handle'");
+    }
+
+    if (modelObjectMetaDataObj.Has("iddObjectType")) {
+      auto val = modelObjectMetaDataObj.Get("iddObjectType");
+      if (val.IsString()) {
+        m_iddObjectType = val.Get<std::string>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'iddObjectType' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'iddObjectType'");
+    }
+
+    if (modelObjectMetaDataObj.Has("name")) {
+      auto val = modelObjectMetaDataObj.Get("name");
+      if (val.IsString()) {
+        m_name = val.Get<std::string>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'name' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'name'");
+    }
+
+    if (modelObjectMetaDataObj.Has("opentoBelow")) {
+      auto val = modelObjectMetaDataObj.Get("opentoBelow");
+      if (val.IsBool()) {
+        m_opentoBelow = val.Get<bool>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'opentoBelow' but it is not a bool");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'opentoBelow'");
+    }
+
+    if (modelObjectMetaDataObj.Has("nominalZCoordinate")) {
+      auto val = modelObjectMetaDataObj.Get("nominalZCoordinate");
+      if (val.IsReal()) {
+        m_nominalZCoordinate = val.Get<double>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'nominalZCoordinate' but it is not a double");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'nominalZCoordinate'");
+    }
+
+    if (modelObjectMetaDataObj.Has("nominalFloortoCeilingHeight")) {
+      auto val = modelObjectMetaDataObj.Get("nominalFloortoCeilingHeight");
+      if (val.IsReal()) {
+        m_nominalFloortoCeilingHeight = val.Get<double>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'nominalFloortoCeilingHeight' but it is not a double");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'nominalFloortoCeilingHeight'");
+    }
+
+    if (modelObjectMetaDataObj.Has("multiplier")) {
+      auto val = modelObjectMetaDataObj.Get("multiplier");
+      if (val.IsInt()) {
+        m_multiplier = val.Get<int>();
+      } else {
+        LOG(Warn, "modelObjectMetaDataObj has the key 'multiplier' but it is not a int");
+      }
+    } else {
+      LOG(Debug, "modelObjectMetaDataObj is missing the key 'multiplier'");
+    }
+  }
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/gltf/GltfModelObjectMetaData.hpp b/src/gltf/GltfModelObjectMetaData.hpp
new file mode 100644
index 00000000000..cc7fd0cd0eb
--- /dev/null
+++ b/src/gltf/GltfModelObjectMetaData.hpp
@@ -0,0 +1,139 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+#ifndef GLTF_GLTFMODELOBJECTMETADATA_HPP
+#define GLTF_GLTFMODELOBJECTMETADATA_HPP
+
+#include "GltfAPI.hpp"
+
+#include "../utilities/core/Logger.hpp"
+
+namespace tinygltf {
+class Value;
+}
+
+namespace openstudio {
+namespace model {
+
+  class AirLoopHVAC;
+  class BuildingUnit;
+  class SpaceType;
+  class BuildingStory;
+  class ThermalZone;
+  class DefaultConstructionSet;
+  class Space;
+}  // namespace model
+
+namespace gltf {
+
+  class GltfMetaData;
+
+  /** GltfModelObjectMetaData is an Interface class between select ModelObjects and glTF values
+   *
+   *  It is capable of storing attributes such as name, iddObjectType, color, handle from ModelObjects:
+   *  ThermalZone, SpaceType, AirLoopHVAC, BuildingStory, BuildingUnit, DefaultConstructionSet
+   **/
+  class GLTF_API GltfModelObjectMetaData
+  {
+   public:
+    /** Default constructor **/
+    GltfModelObjectMetaData();
+
+    /** @name Interface with ModelObjects */
+    //@{
+    explicit GltfModelObjectMetaData(const model::AirLoopHVAC& airLoopHVAC);
+    explicit GltfModelObjectMetaData(const model::BuildingUnit& buildingUnit);
+    explicit GltfModelObjectMetaData(const model::SpaceType& spaceType);
+    explicit GltfModelObjectMetaData(const model::BuildingStory& buildingStory);
+    explicit GltfModelObjectMetaData(const model::ThermalZone& thermalZone);
+    explicit GltfModelObjectMetaData(const model::DefaultConstructionSet& defaultConstructionSet);
+    explicit GltfModelObjectMetaData(const model::Space& space);
+    //@}
+
+    /** @name Getters and Setters */
+    //@{
+
+    std::string color() const;
+    void setColor(const std::string& color);
+
+    std::string handle() const;
+    void setHandle(const std::string& handle);
+
+    std::string iddObjectType() const;
+    void setIddObjectType(const std::string& iddObjectType);
+
+    std::string name() const;
+    void setName(const std::string& name);
+
+    bool isOpentoBelow() const;
+    void setOpentoBelow(bool opentoBelow);
+
+    double nominalZCoordinate() const;
+    void setNominalZCoordinate(double nominalZCoordinate);
+
+    double nominalFloortoCeilingHeight() const;
+    void setNominalFloortoCeilingHeight(double nominalFloortoCeilingHeight);
+
+    int multiplier() const;
+    void setMultiplier(int multiplier);
+
+    //@}
+
+   protected:
+    /** @name Protected */
+    //@{
+
+    /** Interface with an existing GLTF file **/
+    explicit GltfModelObjectMetaData(const tinygltf::Value& modelObjectMetaDataObj);
+
+    /** Export to tinygltf **/
+    std::map<std::string, tinygltf::Value> toExtras() const;
+
+    //@}
+
+    friend class GltfMetaData;
+
+   private:
+    REGISTER_LOGGER("openstudio.gltf.GltfModelObjectMetaData");
+
+    std::string m_color;
+    std::string m_handle;
+    std::string m_iddObjectType;
+    std::string m_name;
+    bool m_opentoBelow = false;
+    double m_nominalZCoordinate = 0.0;
+    double m_nominalFloortoCeilingHeight = 0.0;
+    int m_multiplier = 0;
+  };
+
+  using GltfModelObjectMetaDataVector = std::vector<GltfModelObjectMetaData>;
+
+}  // namespace gltf
+}  // namespace openstudio
+
+#endif  // GLTF_GLTFMODELOBJECTMETADATA_HPP
diff --git a/src/gltf/GltfUserData.cpp b/src/gltf/GltfUserData.cpp
new file mode 100644
index 00000000000..41dea07c2dd
--- /dev/null
+++ b/src/gltf/GltfUserData.cpp
@@ -0,0 +1,1096 @@
+
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "GltfUserData.hpp"
+#include "GltfUtils.hpp"
+
+#include "../model/Model.hpp"
+
+#include "../model/PlanarSurface.hpp"
+
+#include "../model/PlanarSurfaceGroup.hpp"
+#include "../model/Surface.hpp"
+#include "../model/Surface_Impl.hpp"
+#include "../model/SubSurface.hpp"
+#include "../model/SubSurface_Impl.hpp"
+#include "../model/ShadingSurface.hpp"
+#include "../model/ShadingSurface_Impl.hpp"
+#include "../model/InteriorPartitionSurface.hpp"
+#include "../model/InteriorPartitionSurface_Impl.hpp"
+#include "../model/DefaultConstructionSet.hpp"
+#include "../model/ShadingSurfaceGroup.hpp"
+#include "../model/InteriorPartitionSurfaceGroup.hpp"
+#include "../model/ConstructionBase.hpp"
+#include "../model/ConstructionAirBoundary.hpp"
+#include "../model/ConstructionAirBoundary_Impl.hpp"
+#include "../model/Construction.hpp"
+#include "../model/Space.hpp"
+#include "../model/ThermalZone.hpp"
+#include "../model/AirLoopHVAC.hpp"
+#include "../model/SpaceType.hpp"
+#include "../model/BuildingStory.hpp"
+#include "../model/BuildingUnit.hpp"
+
+#include "../utilities/core/UUID.hpp"
+#include "../utilities/geometry/Transformation.hpp"
+#include "../utilities/geometry/Geometry.hpp"
+
+#include <tiny_gltf.h>
+
+#include <string>
+#include <map>
+
+namespace openstudio {
+namespace gltf {
+
+  GltfUserData::GltfUserData() = default;
+
+  std::string GltfUserData::surfaceTypeMaterialName() const {
+    {
+      if (istringEqual(m_surfaceType, "FixedWindow") || istringEqual(m_surfaceType, "OperableWindow") || istringEqual(m_surfaceType, "GlassDoor")
+          || istringEqual(m_surfaceType, "Skylight") || istringEqual(m_surfaceType, "TubularDaylightDome")
+          || istringEqual(m_surfaceType, "TubularDaylightDiffuser")) {
+        return "Window";
+      } else if (istringEqual(m_surfaceType, "Door") || istringEqual(m_surfaceType, "OverheadDoor")) {
+        return "Door";
+      }
+      return m_surfaceType;
+    }
+  }
+
+  std::string GltfUserData::boundaryMaterialName() const {
+    std::string result;
+    if (m_outsideBoundaryCondition.empty()) {
+      return result;
+    }
+
+    if (istringEqual(m_outsideBoundaryCondition, "Outdoors")) {
+      if (istringEqual(m_sunExposure, "SunExposed") && istringEqual(m_windExposure, "WindExposed")) {
+        result = "Boundary_Outdoors_SunWind";
+      } else if (istringEqual(m_sunExposure, "SunExposed")) {
+        result = "Boundary_Outdoors_Sun";
+      } else if (istringEqual(m_windExposure, "WindExposed")) {
+        result = "Boundary_Outdoors_Wind";
+      } else {
+        result = "Boundary_Outdoors";
+      }
+    } else {
+      result = "Boundary_" + m_outsideBoundaryCondition;
+    }
+    return result;
+  }
+
+  GltfUserData::GltfUserData(const model::PlanarSurface& planarSurface) {
+    std::string name = planarSurface.nameString();
+
+    m_handle = openstudio::removeBraces(planarSurface.handle());
+    m_name = planarSurface.nameString();
+
+    if (auto surface = planarSurface.optionalCast<model::Surface>()) {
+      m_surfaceName = surface->nameString();
+      m_surfaceHandle = openstudio::removeBraces(surface->handle());
+      m_surfaceType = surface->surfaceType();
+      m_sunExposure = surface->sunExposure();
+      m_windExposure = surface->windExposure();
+      m_outsideBoundaryCondition = surface->outsideBoundaryCondition();
+
+      boost::optional<model::Surface> adjacentSurface = surface->adjacentSurface();
+      if (adjacentSurface) {
+        m_outsideBoundaryConditionObjectName = adjacentSurface->nameString();
+        m_outsideBoundaryConditionObjectHandle = openstudio::removeBraces(adjacentSurface->handle());
+      }
+    } else if (auto shadingSurface = planarSurface.optionalCast<model::ShadingSurface>()) {
+
+      m_shadingHandle = openstudio::removeBraces(shadingSurface->handle());
+      m_shadingName = shadingSurface->nameString();
+
+      std::string shadingSurfaceType = "Building";
+      if (shadingSurface->shadingSurfaceGroup()) {
+        shadingSurfaceType = shadingSurface->shadingSurfaceGroup()->shadingSurfaceType();
+      }
+      std::string surfaceType = shadingSurfaceType + "Shading";
+      m_surfaceType = surfaceType;
+      m_sunExposure = "SunExposed";
+      m_windExposure = "WindExposed";
+      // m_outsideBoundaryCondition.clear();
+      // m_outsideBoundaryConditionObjectName.clear();
+      // m_outsideBoundaryConditionObjectHandle.clear();
+    } else if (auto interiorPartitionSurface = planarSurface.optionalCast<model::InteriorPartitionSurface>()) {
+      m_surfaceType = "InteriorPartitionSurface";
+      m_sunExposure = "NoSun";
+      m_windExposure = "NoWind";
+      // m_outsideBoundaryCondition.clear();
+      // m_outsideBoundaryConditionObjectName.clear();
+      // m_outsideBoundaryConditionObjectHandle.clear();
+    }
+
+    else if (auto subSurface = planarSurface.optionalCast<model::SubSurface>()) {
+      m_subSurfaceHandle = openstudio::removeBraces(subSurface->handle());
+      m_subSurfaceName = subSurface->nameString();
+      m_surfaceType = subSurface->subSurfaceType();
+
+      boost::optional<model::Surface> parentSurface = subSurface->surface();
+      if (parentSurface) {
+        m_outsideBoundaryCondition = parentSurface->outsideBoundaryCondition();
+        m_sunExposure = parentSurface->sunExposure();
+        m_windExposure = parentSurface->windExposure();
+        m_surfaceName = parentSurface->nameString();
+        m_surfaceHandle = openstudio::removeBraces(parentSurface->handle());
+      }
+
+      boost::optional<model::SubSurface> adjacentSubSurface = subSurface->adjacentSubSurface();
+      if (adjacentSubSurface) {
+        m_outsideBoundaryConditionObjectName = adjacentSubSurface->nameString();
+        m_outsideBoundaryConditionObjectHandle = openstudio::removeBraces(adjacentSubSurface->handle());
+      }
+    }
+
+    if (boost::optional<model::ConstructionBase> construction = planarSurface.construction()) {
+
+      m_constructionSetHandle = openstudio::removeBraces(construction->handle());
+      m_constructionName = construction->nameString();
+      // If this is a ConstructionAirBoundary, then set to the standard material "AirWall"
+      if (construction->optionalCast<model::ConstructionAirBoundary>()) {
+        m_constructionMaterialName = "AirWall";
+      } else if (construction->iddObjectType() == model::Construction::iddObjectType()) {
+        m_constructionMaterialName = "Construction_" + construction->nameString();
+      } else {
+        OS_ASSERT(false);  // Shouldn't happen
+        m_constructionMaterialName = getObjectGLTFMaterialName(construction.get());
+      }
+    }
+
+    if (auto space = planarSurface.space()) {
+      m_spaceHandle = openstudio::removeBraces(space->handle());
+      m_spaceName = space->nameString();
+      if (auto thermalZone = space->thermalZone()) {
+        m_thermalZoneHandle = openstudio::removeBraces(thermalZone->handle());
+        m_thermalZoneName = thermalZone->nameString();
+        m_thermalZoneMaterialName = "ThermalZone_" + thermalZone->nameString();
+        std::vector<model::AirLoopHVAC> airLoopHVACs = thermalZone->airLoopHVACs();
+        int count = 0;
+        for (const auto& airLoopHVAC : thermalZone->airLoopHVACs()) {
+          m_airLoopHVACHandles.emplace_back(openstudio::removeBraces(airLoopHVAC.handle()));
+
+          m_airLoopHVACNames.emplace_back(airLoopHVAC.nameString());
+
+          m_airLoopHVACMaterialNames.emplace_back(getObjectGLTFMaterialName(airLoopHVAC));
+
+          count++;
+        }
+      }
+
+      if (auto spaceType = space->spaceType()) {
+        m_spaceTypeHandle = openstudio::removeBraces(spaceType->handle());
+        m_spaceTypeName = spaceType->nameString();
+        m_spaceTypeMaterialName = getObjectGLTFMaterialName(spaceType.get());
+      }
+
+      if (auto buildingStory = space->buildingStory()) {
+        m_buildingStoryHandle = openstudio::removeBraces(buildingStory->handle());
+        m_buildingStoryName = buildingStory->nameString();
+        m_buildingStoryMaterialName = getObjectGLTFMaterialName(buildingStory.get());
+      }
+
+      if (auto buildingUnit = space->buildingUnit()) {
+        m_buildingUnitHandle = openstudio::removeBraces(buildingUnit->handle());
+        m_buildingUnitName = buildingUnit->nameString();
+        m_buildingUnitMaterialName = getObjectGLTFMaterialName(buildingUnit.get());
+      }
+    }
+
+    // check if the adjacent surface is truly adjacent
+    m_coincidentWithOutsideObject = false;
+
+    if (!m_outsideBoundaryConditionObjectHandle.empty()) {
+
+      Transformation buildingTransformation;
+      if (boost::optional<model::PlanarSurfaceGroup> planarSurfaceGroup_ = planarSurface.planarSurfaceGroup()) {
+        buildingTransformation = planarSurfaceGroup_->buildingTransformation();
+      }
+      // get the vertices
+      Point3dVector vertices = planarSurface.vertices();
+
+      auto adjacentHandle = toUUID(m_outsideBoundaryConditionObjectHandle);
+      auto adjacentPlanarSurface = planarSurface.model().getModelObject<model::PlanarSurface>(adjacentHandle);
+      OS_ASSERT(adjacentPlanarSurface);
+
+      Transformation otherBuildingTransformation;
+      if (adjacentPlanarSurface->planarSurfaceGroup()) {
+        otherBuildingTransformation = adjacentPlanarSurface->planarSurfaceGroup()->buildingTransformation();
+      }
+
+      Point3dVector otherVertices = otherBuildingTransformation * adjacentPlanarSurface->vertices();
+      m_coincidentWithOutsideObject = circularEqual(buildingTransformation * vertices, reverse(otherVertices));
+    }
+  }
+
+  std::string GltfUserData::handle() const {
+    return m_handle;
+  }
+  void GltfUserData::setHandle(const std::string& handle) {
+    m_handle = handle;
+  }
+
+  std::string GltfUserData::name() const {
+    return m_name;
+  }
+  void GltfUserData::setName(const std::string& name) {
+    m_name = name;
+  }
+
+  std::string GltfUserData::surfaceType() const {
+    return m_surfaceType;
+  }
+  void GltfUserData::setSurfaceType(const std::string& surfaceType) {
+    m_surfaceType = surfaceType;
+  }
+
+  std::string GltfUserData::constructionName() const {
+    return m_constructionName;
+  }
+  void GltfUserData::setConstructionName(const std::string& constructionName) {
+    m_constructionName = constructionName;
+  }
+
+  std::string GltfUserData::constructionHandle() const {
+    return m_constructionHandle;
+  }
+  void GltfUserData::setConstructionHandle(const std::string& constructionHandle) {
+    m_constructionHandle = constructionHandle;
+  }
+
+  std::string GltfUserData::constructionMaterialName() const {
+    return m_constructionMaterialName;
+  }
+  void GltfUserData::setConstructionMaterialName(const std::string& constructionMaterialName) {
+    m_constructionMaterialName = constructionMaterialName;
+  }
+
+  std::string GltfUserData::surfaceName() const {
+    return m_surfaceName;
+  }
+  void GltfUserData::setSurfaceName(const std::string& surfaceName) {
+    m_surfaceName = surfaceName;
+  }
+
+  std::string GltfUserData::surfaceHandle() const {
+    return m_surfaceHandle;
+  }
+  void GltfUserData::setSurfaceHandle(const std::string& surfaceHandle) {
+    m_surfaceHandle = surfaceHandle;
+  }
+
+  std::string GltfUserData::subSurfaceName() const {
+    return m_subSurfaceName;
+  }
+  void GltfUserData::setSubSurfaceName(const std::string& subSurfaceName) {
+    m_subSurfaceName = subSurfaceName;
+  }
+
+  std::string GltfUserData::subSurfaceHandle() const {
+    return m_subSurfaceHandle;
+  }
+  void GltfUserData::setSubSurfaceHandle(const std::string& subSurfaceHandle) {
+    m_subSurfaceHandle = subSurfaceHandle;
+  }
+
+  std::string GltfUserData::spaceName() const {
+    return m_spaceName;
+  }
+  void GltfUserData::setSpaceName(const std::string& spaceName) {
+    m_spaceName = spaceName;
+  }
+
+  std::string GltfUserData::spaceHandle() const {
+    return m_spaceHandle;
+  }
+  void GltfUserData::setSpaceHandle(const std::string& spaceHandle) {
+    m_spaceHandle = spaceHandle;
+  }
+
+  std::string GltfUserData::shadingName() const {
+    return m_shadingName;
+  }
+  void GltfUserData::setShadingName(const std::string& shadingName) {
+    m_shadingName = shadingName;
+  }
+
+  std::string GltfUserData::shadingHandle() const {
+    return m_shadingHandle;
+  }
+  void GltfUserData::setShadingHandle(const std::string& shadingHandle) {
+    m_shadingHandle = shadingHandle;
+  }
+
+  std::string GltfUserData::thermalZoneName() const {
+    return m_thermalZoneName;
+  }
+  void GltfUserData::setThermalZoneName(const std::string& thermalZoneName) {
+    m_thermalZoneName = thermalZoneName;
+  }
+
+  std::string GltfUserData::thermalZoneHandle() const {
+    return m_thermalZoneHandle;
+  }
+  void GltfUserData::setThermalZoneHandle(const std::string& thermalZoneHandle) {
+    m_thermalZoneHandle = thermalZoneHandle;
+  }
+
+  std::string GltfUserData::thermalZoneMaterialName() const {
+    return m_thermalZoneMaterialName;
+  }
+  void GltfUserData::setThermalZoneMaterialName(const std::string& thermalZoneMaterialName) {
+    m_thermalZoneMaterialName = thermalZoneMaterialName;
+  }
+
+  std::string GltfUserData::spaceTypeName() const {
+    return m_spaceTypeName;
+  }
+  void GltfUserData::setSpaceTypeName(const std::string& spaceTypeName) {
+    m_spaceTypeName = spaceTypeName;
+  }
+
+  std::string GltfUserData::spaceTypeHandle() const {
+    return m_spaceTypeHandle;
+  }
+  void GltfUserData::setSpaceTypeHandle(const std::string& spaceTypeHandle) {
+    m_spaceTypeHandle = spaceTypeHandle;
+  }
+
+  std::string GltfUserData::spaceTypeMaterialName() const {
+    return m_spaceTypeMaterialName;
+  }
+  void GltfUserData::setSpaceTypeMaterialName(const std::string& spaceTypeMaterialName) {
+    m_spaceTypeMaterialName = spaceTypeMaterialName;
+  }
+
+  std::string GltfUserData::buildingStoryName() const {
+    return m_buildingStoryName;
+  }
+  void GltfUserData::setBuildingStoryName(const std::string& buildingStoryName) {
+    m_buildingStoryName = buildingStoryName;
+  }
+
+  std::string GltfUserData::buildingStoryHandle() const {
+    return m_buildingStoryHandle;
+  }
+  void GltfUserData::setBuildingStoryHandle(const std::string& buildingStoryHandle) {
+    m_buildingStoryHandle = buildingStoryHandle;
+  }
+
+  std::string GltfUserData::buildingStoryMaterialName() const {
+    return m_buildingStoryMaterialName;
+  }
+  void GltfUserData::setBuildingStoryMaterialName(const std::string& buildingStoryMaterialName) {
+    m_buildingStoryMaterialName = buildingStoryMaterialName;
+  }
+
+  std::string GltfUserData::buildingUnitName() const {
+    return m_buildingUnitName;
+  }
+  void GltfUserData::setBuildingUnitName(const std::string& buildingUnitName) {
+    m_buildingUnitName = buildingUnitName;
+  }
+
+  std::string GltfUserData::buildingUnitHandle() const {
+    return m_buildingUnitHandle;
+  }
+  void GltfUserData::setBuildingUnitHandle(const std::string& buildingUnitHandle) {
+    m_buildingUnitHandle = buildingUnitHandle;
+  }
+
+  std::string GltfUserData::buildingUnitMaterialName() const {
+    return m_buildingUnitMaterialName;
+  }
+  void GltfUserData::setBuildingUnitMaterialName(const std::string& buildingUnitMaterialName) {
+    m_buildingUnitMaterialName = buildingUnitMaterialName;
+  }
+
+  std::string GltfUserData::constructionSetName() const {
+    return m_constructionSetName;
+  }
+  void GltfUserData::setConstructionSetName(const std::string& constructionSetName) {
+    m_constructionSetName = constructionSetName;
+  }
+
+  std::string GltfUserData::constructionSetHandle() const {
+    return m_constructionSetHandle;
+  }
+  void GltfUserData::setConstructionSetHandle(const std::string& constructionSetHandle) {
+    m_constructionSetHandle = constructionSetHandle;
+  }
+
+  std::string GltfUserData::constructionSetMaterialName() const {
+    return m_constructionSetMaterialName;
+  }
+  void GltfUserData::setConstructionSetMaterialName(const std::string& constructionSetMaterialName) {
+    m_constructionSetMaterialName = constructionSetMaterialName;
+  }
+
+  std::string GltfUserData::outsideBoundaryCondition() const {
+    return m_outsideBoundaryCondition;
+  }
+  void GltfUserData::setOutsideBoundaryCondition(const std::string& outsideBoundaryCondition) {
+    m_outsideBoundaryCondition = outsideBoundaryCondition;
+  }
+
+  std::string GltfUserData::outsideBoundaryConditionObjectName() const {
+    return m_outsideBoundaryConditionObjectName;
+  }
+  void GltfUserData::setOutsideBoundaryConditionObjectName(const std::string& outsideBoundaryConditionObjectName) {
+    m_outsideBoundaryConditionObjectName = outsideBoundaryConditionObjectName;
+  }
+
+  std::string GltfUserData::outsideBoundaryConditionObjectHandle() const {
+    return m_outsideBoundaryConditionObjectHandle;
+  }
+  void GltfUserData::setOutsideBoundaryConditionObjectHandle(const std::string& outsideBoundaryConditionObjectHandle) {
+    m_outsideBoundaryConditionObjectHandle = outsideBoundaryConditionObjectHandle;
+  }
+
+  bool GltfUserData::coincidentWithOutsideObject() const {
+    return m_coincidentWithOutsideObject;
+  }
+  void GltfUserData::setCoincidentWithOutsideObject(bool coincidentWithOutsideObject) {
+    m_coincidentWithOutsideObject = coincidentWithOutsideObject;
+  }
+
+  std::string GltfUserData::sunExposure() const {
+    return m_sunExposure;
+  }
+  void GltfUserData::setSunExposure(const std::string& sunExposure) {
+    m_sunExposure = sunExposure;
+  }
+
+  std::string GltfUserData::windExposure() const {
+    return m_windExposure;
+  }
+  void GltfUserData::setWindExposure(const std::string& windExposure) {
+    m_windExposure = windExposure;
+  }
+
+  double GltfUserData::illuminanceSetpoint() const {
+    return m_illuminanceSetpoint;
+  }
+  void GltfUserData::setIlluminanceSetpoint(double illuminanceSetpoint) {
+    m_illuminanceSetpoint = illuminanceSetpoint;
+  }
+
+  bool GltfUserData::airWall() const {
+    return m_airWall;
+  }
+  void GltfUserData::setAirWall(bool airWall) {
+    m_airWall = airWall;
+  }
+
+  std::vector<std::string> GltfUserData::airLoopHVACNames() const {
+    return m_airLoopHVACNames;
+  }
+
+  void GltfUserData::setAirLoopHVACNames(const std::vector<std::string>& airLoopHVACNames) {
+    m_airLoopHVACNames = airLoopHVACNames;
+  }
+
+  void GltfUserData::addAirLoopHVACName(std::string airLoopHVACName) {
+    m_airLoopHVACNames.emplace_back(std::move(airLoopHVACName));
+  }
+
+  std::vector<std::string> GltfUserData::airLoopHVACHandles() const {
+    return m_airLoopHVACHandles;
+  }
+
+  void GltfUserData::setAirLoopHVACHandles(const std::vector<std::string>& airLoopHVACHandles) {
+    m_airLoopHVACHandles = airLoopHVACHandles;
+  }
+
+  void GltfUserData::addAirLoopHVACHandle(std::string airLoopHVACHandle) {
+    m_airLoopHVACHandles.emplace_back(std::move(airLoopHVACHandle));
+  }
+
+  std::vector<std::string> GltfUserData::airLoopHVACMaterialNames() const {
+    return m_airLoopHVACMaterialNames;
+  }
+
+  void GltfUserData::setAirLoopHVACMaterialNames(const std::vector<std::string>& airLoopHVACMaterialNames) {
+    m_airLoopHVACMaterialNames = airLoopHVACMaterialNames;
+  }
+
+  void GltfUserData::addAirLoopHVACMaterialName(std::string airLoopHVACMaterialName) {
+    m_airLoopHVACMaterialNames.emplace_back(std::move(airLoopHVACMaterialName));
+  }
+
+  std::map<std::string, tinygltf::Value> GltfUserData::toExtras() const {
+    // TODO: probably make the airloopHVAC stuff a single object with multiple properties
+    // But in any case, we want Arrays not a useless map<std::string(int), std::string>
+
+    std::map<std::string, tinygltf::Value> airLoopHVACNamesObject;
+    std::map<std::string, tinygltf::Value> airLoopHVACHandlesObject;
+    std::map<std::string, tinygltf::Value> airLoopHVACMaterialNamesObject;
+    for (size_t i = 0; i < m_airLoopHVACNames.size(); ++i) {
+      airLoopHVACNamesObject.emplace(std::make_pair(std::to_string(i), tinygltf::Value(m_airLoopHVACNames[i])));
+      airLoopHVACHandlesObject.emplace(std::make_pair(std::to_string(i), tinygltf::Value(m_airLoopHVACHandles[i])));
+      airLoopHVACMaterialNamesObject.emplace(std::make_pair(std::to_string(i), tinygltf::Value(m_airLoopHVACMaterialNames[i])));
+    }
+
+    return {
+      {"handle", tinygltf::Value(m_handle)},
+      {"name", tinygltf::Value(m_name)},
+      {"surfaceType", tinygltf::Value(m_surfaceType)},
+      {"surfaceTypeMaterialName", tinygltf::Value(this->surfaceTypeMaterialName())},
+      {"constructionName", tinygltf::Value(m_constructionName)},
+      {"constructionHandle", tinygltf::Value(m_constructionHandle)},
+      {"constructionMaterialName", tinygltf::Value(m_constructionMaterialName)},
+      {"surfaceName", tinygltf::Value(m_surfaceName)},
+      {"surfaceHandle", tinygltf::Value(m_surfaceHandle)},
+      {"subSurfaceName", tinygltf::Value(m_subSurfaceName)},
+      {"subSurfaceHandle", tinygltf::Value(m_subSurfaceHandle)},
+      {"spaceName", tinygltf::Value(m_spaceName)},
+      {"spaceHandle", tinygltf::Value(m_spaceHandle)},
+      {"shadingName", tinygltf::Value(m_shadingName)},
+      {"shadingHandle", tinygltf::Value(m_shadingHandle)},
+      {"thermalZoneName", tinygltf::Value(m_thermalZoneName)},
+      {"thermalZoneHandle", tinygltf::Value(m_thermalZoneHandle)},
+      {"thermalZoneMaterialName", tinygltf::Value(m_thermalZoneMaterialName)},
+      {"spaceTypeName", tinygltf::Value(m_spaceTypeName)},
+      {"spaceTypeHandle", tinygltf::Value(m_spaceTypeHandle)},
+      {"spaceTypeMaterialName", tinygltf::Value(m_spaceTypeMaterialName)},
+      {"buildingStoryName", tinygltf::Value(m_buildingStoryName)},
+      {"buildingStoryHandle", tinygltf::Value(m_buildingStoryHandle)},
+      {"buildingStoryMaterialName", tinygltf::Value(m_buildingStoryMaterialName)},
+      {"buildingUnitName", tinygltf::Value(m_buildingUnitName)},
+      {"buildingUnitHandle", tinygltf::Value(m_buildingUnitHandle)},
+      {"buildingUnitMaterialName", tinygltf::Value(m_buildingUnitMaterialName)},
+      {"constructionSetName", tinygltf::Value(m_constructionSetName)},
+      {"constructionSetHandle", tinygltf::Value(m_constructionSetHandle)},
+      {"constructionSetMaterialName", tinygltf::Value(m_constructionSetMaterialName)},
+      {"outsideBoundaryCondition", tinygltf::Value(m_outsideBoundaryCondition)},
+      {"outsideBoundaryConditionObjectName", tinygltf::Value(m_outsideBoundaryConditionObjectName)},
+      {"outsideBoundaryConditionObjectHandle", tinygltf::Value(m_outsideBoundaryConditionObjectHandle)},
+      {"boundaryMaterialName", tinygltf::Value(this->boundaryMaterialName())},
+      {"coincidentWithOutsideObject", tinygltf::Value(m_coincidentWithOutsideObject)},
+      {"sunExposure", tinygltf::Value(m_sunExposure)},
+      {"windExposure", tinygltf::Value(m_windExposure)},
+      {"illuminanceSetpoint", tinygltf::Value(m_illuminanceSetpoint)},
+      {"airWall", tinygltf::Value(m_airWall)},
+      {"airLoopHVACNames", tinygltf::Value(airLoopHVACNamesObject)},
+      {"airLoopHVACHandles", tinygltf::Value(airLoopHVACHandlesObject)},
+      {"airLoopHVACMaterialNames", tinygltf::Value(airLoopHVACMaterialNamesObject)},
+    };
+  }
+
+  GltfUserData::GltfUserData(const tinygltf::Value& userDataObj) {
+
+    if (userDataObj.Has("handle")) {
+      auto val = userDataObj.Get("handle");
+      if (val.IsString()) {
+        m_handle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'handle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'handle'");
+    }
+
+    if (userDataObj.Has("name")) {
+      auto val = userDataObj.Get("name");
+      if (val.IsString()) {
+        m_name = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'name' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'name'");
+    }
+
+    if (userDataObj.Has("surfaceType")) {
+      auto val = userDataObj.Get("surfaceType");
+      if (val.IsString()) {
+        m_surfaceType = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'surfaceType' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'surfaceType'");
+    }
+
+    //    if (userDataObj.Has("surfaceTypeMaterialName")) {
+    //      auto val = userDataObj.Get("surfaceTypeMaterialName");
+    //      if (val.IsString()) {
+    //        m_surfaceTypeMaterialName = val.Get<std::string>();
+    //      } else {
+    //        LOG(Warn, "userDataObj has the key 'surfaceTypeMaterialName' but it is not a std::string");
+    //      }
+    //    } else {
+    //      LOG(Debug, "userDataObj is missing the key 'surfaceTypeMaterialName'");
+    //    }
+
+    if (userDataObj.Has("constructionName")) {
+      auto val = userDataObj.Get("constructionName");
+      if (val.IsString()) {
+        m_constructionName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'constructionName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'constructionName'");
+    }
+
+    if (userDataObj.Has("constructionHandle")) {
+      auto val = userDataObj.Get("constructionHandle");
+      if (val.IsString()) {
+        m_constructionHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'constructionHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'constructionHandle'");
+    }
+
+    if (userDataObj.Has("constructionMaterialName")) {
+      auto val = userDataObj.Get("constructionMaterialName");
+      if (val.IsString()) {
+        m_constructionMaterialName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'constructionMaterialName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'constructionMaterialName'");
+    }
+
+    if (userDataObj.Has("surfaceName")) {
+      auto val = userDataObj.Get("surfaceName");
+      if (val.IsString()) {
+        m_surfaceName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'surfaceName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'surfaceName'");
+    }
+
+    if (userDataObj.Has("surfaceHandle")) {
+      auto val = userDataObj.Get("surfaceHandle");
+      if (val.IsString()) {
+        m_surfaceHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'surfaceHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'surfaceHandle'");
+    }
+
+    if (userDataObj.Has("subSurfaceName")) {
+      auto val = userDataObj.Get("subSurfaceName");
+      if (val.IsString()) {
+        m_subSurfaceName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'subSurfaceName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'subSurfaceName'");
+    }
+
+    if (userDataObj.Has("subSurfaceHandle")) {
+      auto val = userDataObj.Get("subSurfaceHandle");
+      if (val.IsString()) {
+        m_subSurfaceHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'subSurfaceHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'subSurfaceHandle'");
+    }
+
+    if (userDataObj.Has("spaceName")) {
+      auto val = userDataObj.Get("spaceName");
+      if (val.IsString()) {
+        m_spaceName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'spaceName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'spaceName'");
+    }
+
+    if (userDataObj.Has("spaceHandle")) {
+      auto val = userDataObj.Get("spaceHandle");
+      if (val.IsString()) {
+        m_spaceHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'spaceHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'spaceHandle'");
+    }
+
+    if (userDataObj.Has("shadingName")) {
+      auto val = userDataObj.Get("shadingName");
+      if (val.IsString()) {
+        m_shadingName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'shadingName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'shadingName'");
+    }
+
+    if (userDataObj.Has("shadingHandle")) {
+      auto val = userDataObj.Get("shadingHandle");
+      if (val.IsString()) {
+        m_shadingHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'shadingHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'shadingHandle'");
+    }
+
+    if (userDataObj.Has("thermalZoneName")) {
+      auto val = userDataObj.Get("thermalZoneName");
+      if (val.IsString()) {
+        m_thermalZoneName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'thermalZoneName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'thermalZoneName'");
+    }
+
+    if (userDataObj.Has("thermalZoneHandle")) {
+      auto val = userDataObj.Get("thermalZoneHandle");
+      if (val.IsString()) {
+        m_thermalZoneHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'thermalZoneHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'thermalZoneHandle'");
+    }
+
+    if (userDataObj.Has("thermalZoneMaterialName")) {
+      auto val = userDataObj.Get("thermalZoneMaterialName");
+      if (val.IsString()) {
+        m_thermalZoneMaterialName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'thermalZoneMaterialName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'thermalZoneMaterialName'");
+    }
+
+    if (userDataObj.Has("spaceTypeName")) {
+      auto val = userDataObj.Get("spaceTypeName");
+      if (val.IsString()) {
+        m_spaceTypeName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'spaceTypeName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'spaceTypeName'");
+    }
+
+    if (userDataObj.Has("spaceTypeHandle")) {
+      auto val = userDataObj.Get("spaceTypeHandle");
+      if (val.IsString()) {
+        m_spaceTypeHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'spaceTypeHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'spaceTypeHandle'");
+    }
+
+    if (userDataObj.Has("spaceTypeMaterialName")) {
+      auto val = userDataObj.Get("spaceTypeMaterialName");
+      if (val.IsString()) {
+        m_spaceTypeMaterialName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'spaceTypeMaterialName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'spaceTypeMaterialName'");
+    }
+
+    if (userDataObj.Has("buildingStoryName")) {
+      auto val = userDataObj.Get("buildingStoryName");
+      if (val.IsString()) {
+        m_buildingStoryName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'buildingStoryName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'buildingStoryName'");
+    }
+
+    if (userDataObj.Has("buildingStoryHandle")) {
+      auto val = userDataObj.Get("buildingStoryHandle");
+      if (val.IsString()) {
+        m_buildingStoryHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'buildingStoryHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'buildingStoryHandle'");
+    }
+
+    if (userDataObj.Has("buildingStoryMaterialName")) {
+      auto val = userDataObj.Get("buildingStoryMaterialName");
+      if (val.IsString()) {
+        m_buildingStoryMaterialName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'buildingStoryMaterialName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'buildingStoryMaterialName'");
+    }
+
+    if (userDataObj.Has("buildingUnitName")) {
+      auto val = userDataObj.Get("buildingUnitName");
+      if (val.IsString()) {
+        m_buildingUnitName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'buildingUnitName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'buildingUnitName'");
+    }
+
+    if (userDataObj.Has("buildingUnitHandle")) {
+      auto val = userDataObj.Get("buildingUnitHandle");
+      if (val.IsString()) {
+        m_buildingUnitHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'buildingUnitHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'buildingUnitHandle'");
+    }
+
+    if (userDataObj.Has("buildingUnitMaterialName")) {
+      auto val = userDataObj.Get("buildingUnitMaterialName");
+      if (val.IsString()) {
+        m_buildingUnitMaterialName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'buildingUnitMaterialName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'buildingUnitMaterialName'");
+    }
+
+    if (userDataObj.Has("constructionSetName")) {
+      auto val = userDataObj.Get("constructionSetName");
+      if (val.IsString()) {
+        m_constructionSetName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'constructionSetName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'constructionSetName'");
+    }
+
+    if (userDataObj.Has("constructionSetHandle")) {
+      auto val = userDataObj.Get("constructionSetHandle");
+      if (val.IsString()) {
+        m_constructionSetHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'constructionSetHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'constructionSetHandle'");
+    }
+
+    if (userDataObj.Has("constructionSetMaterialName")) {
+      auto val = userDataObj.Get("constructionSetMaterialName");
+      if (val.IsString()) {
+        m_constructionSetMaterialName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'constructionSetMaterialName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'constructionSetMaterialName'");
+    }
+
+    if (userDataObj.Has("outsideBoundaryCondition")) {
+      auto val = userDataObj.Get("outsideBoundaryCondition");
+      if (val.IsString()) {
+        m_outsideBoundaryCondition = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'outsideBoundaryCondition' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'outsideBoundaryCondition'");
+    }
+
+    if (userDataObj.Has("outsideBoundaryConditionObjectName")) {
+      auto val = userDataObj.Get("outsideBoundaryConditionObjectName");
+      if (val.IsString()) {
+        m_outsideBoundaryConditionObjectName = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'outsideBoundaryConditionObjectName' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'outsideBoundaryConditionObjectName'");
+    }
+
+    if (userDataObj.Has("outsideBoundaryConditionObjectHandle")) {
+      auto val = userDataObj.Get("outsideBoundaryConditionObjectHandle");
+      if (val.IsString()) {
+        m_outsideBoundaryConditionObjectHandle = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'outsideBoundaryConditionObjectHandle' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'outsideBoundaryConditionObjectHandle'");
+    }
+
+    //     if (userDataObj.Has("boundaryMaterialName")) {
+    //       auto val = userDataObj.Get("boundaryMaterialName");
+    //       if (val.IsString()) {
+    //         m_boundaryMaterialName = val.Get<std::string>();
+    //       } else {
+    //         LOG(Warn, "userDataObj has the key 'boundaryMaterialName' but it is not a std::string");
+    //       }
+    //     } else {
+    //       LOG(Debug, "userDataObj is missing the key 'boundaryMaterialName'");
+    //     }
+    //
+    if (userDataObj.Has("coincidentWithOutsideObject")) {
+      auto val = userDataObj.Get("coincidentWithOutsideObject");
+      if (val.IsBool()) {
+        m_coincidentWithOutsideObject = val.Get<bool>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'coincidentWithOutsideObject' but it is not a bool");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'coincidentWithOutsideObject'");
+    }
+
+    if (userDataObj.Has("sunExposure")) {
+      auto val = userDataObj.Get("sunExposure");
+      if (val.IsString()) {
+        m_sunExposure = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'sunExposure' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'sunExposure'");
+    }
+
+    if (userDataObj.Has("windExposure")) {
+      auto val = userDataObj.Get("windExposure");
+      if (val.IsString()) {
+        m_windExposure = val.Get<std::string>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'windExposure' but it is not a std::string");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'windExposure'");
+    }
+
+    if (userDataObj.Has("illuminanceSetpoint")) {
+      auto val = userDataObj.Get("illuminanceSetpoint");
+      if (val.IsReal()) {
+        m_illuminanceSetpoint = val.Get<double>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'illuminanceSetpoint' but it is not a double");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'illuminanceSetpoint'");
+    }
+
+    if (userDataObj.Has("airWall")) {
+      auto val = userDataObj.Get("airWall");
+      if (val.IsBool()) {
+        m_airWall = val.Get<bool>();
+      } else {
+        LOG(Warn, "userDataObj has the key 'airWall' but it is not a bool");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'airWall'");
+    }
+
+    if (userDataObj.Has("airLoopHVACNames")) {
+      auto val = userDataObj.Get("airLoopHVACNames");
+      if (val.IsObject()) {
+        std::vector<std::string> names;
+        for (const auto& vv : val.Get<std::map<std::string, tinygltf::Value>>()) {
+          if (vv.second.IsString()) {
+            m_airLoopHVACNames.emplace_back(vv.second.Get<std::string>());
+          } else {
+            LOG(Warn, "userDataObj has the key 'airLoopHVACNames', it is an Object, but at least one of the subobjects is not a std::string");
+          }
+        }
+      } else {
+        LOG(Warn, "userDataObj has the key 'airLoopHVACNames' but it is not an Object");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'airLoopHVACNames'");
+    }
+
+    if (userDataObj.Has("airLoopHVACHandles")) {
+      auto val = userDataObj.Get("airLoopHVACHandles");
+      if (val.IsObject()) {
+        std::vector<std::string> names;
+        for (const auto& vv : val.Get<std::map<std::string, tinygltf::Value>>()) {
+          if (vv.second.IsString()) {
+            m_airLoopHVACHandles.emplace_back(vv.second.Get<std::string>());
+          } else {
+            LOG(Warn, "userDataObj has the key 'airLoopHVACHandles', it is an Object, but at least one of the subobjects is not a std::string");
+          }
+        }
+      } else {
+        LOG(Warn, "userDataObj has the key 'airLoopHVACHandles' but it is not an Object");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'airLoopHVACHandles'");
+    }
+
+    if (userDataObj.Has("airLoopHVACMaterialNames")) {
+      auto val = userDataObj.Get("airLoopHVACMaterialNames");
+      if (val.IsObject()) {
+        std::vector<std::string> names;
+        for (const auto& vv : val.Get<std::map<std::string, tinygltf::Value>>()) {
+          if (vv.second.IsString()) {
+            m_airLoopHVACMaterialNames.emplace_back(vv.second.Get<std::string>());
+          } else {
+            LOG(Warn, "userDataObj has the key 'airLoopHVACMaterialNames', it is an Object, but at least one of the subobjects is not a std::string");
+          }
+        }
+      } else {
+        LOG(Warn, "userDataObj has the key 'airLoopHVACMaterialNames' but it is not an Object");
+      }
+    } else {
+      LOG(Debug, "userDataObj is missing the key 'airLoopHVACMaterialNames'");
+    }
+  }
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/gltf/GltfUserData.hpp b/src/gltf/GltfUserData.hpp
new file mode 100644
index 00000000000..5b197d353f2
--- /dev/null
+++ b/src/gltf/GltfUserData.hpp
@@ -0,0 +1,268 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+#ifndef GLTF_GLTFUSERDATA_HPP
+#define GLTF_GLTFUSERDATA_HPP
+
+#include "GltfAPI.hpp"
+
+#include "../utilities/core/Logger.hpp"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace tinygltf {
+class Value;
+}
+
+namespace openstudio {
+namespace model {
+
+  class PlanarSurface;
+}
+
+namespace gltf {
+  class GltfForwardTranslator;
+
+  // TODO: rename to GltfPlanarSurfaceData!
+  /** GltfUserData is an Interface class between a PlanarSurface and an glTF Node's `extras`.
+   *
+   *  It stores attributes such as surfaceType, its construction, the Space and SpaceType and ThermalZone it belongs to, etc.
+   **/
+  class GLTF_API GltfUserData
+  {
+   public:
+    GltfUserData();  // Default constructor (TODO: remove?)
+
+    /** @name Interface with Model and ModelObjects */
+    //@{
+    GltfUserData(const model::PlanarSurface& planarSurface);
+    //@}
+
+    /** @name Getters & Setters */
+    //@{
+
+    std::string handle() const;
+    void setHandle(const std::string& handle);
+
+    std::string name() const;
+    void setName(const std::string& name);
+
+    std::string surfaceType() const;
+    void setSurfaceType(const std::string& surfaceType);
+
+    std::string constructionName() const;
+    void setConstructionName(const std::string& constructionName);
+
+    std::string constructionHandle() const;
+    void setConstructionHandle(const std::string& constructionHandle);
+
+    std::string constructionMaterialName() const;
+    void setConstructionMaterialName(const std::string& constructionMaterialName);
+
+    std::string surfaceName() const;
+    void setSurfaceName(const std::string& surfaceName);
+
+    std::string surfaceHandle() const;
+    void setSurfaceHandle(const std::string& surfaceHandle);
+
+    std::string subSurfaceName() const;
+    void setSubSurfaceName(const std::string& subSurfaceName);
+
+    std::string subSurfaceHandle() const;
+    void setSubSurfaceHandle(const std::string& subSurfaceHandle);
+
+    std::string spaceName() const;
+    void setSpaceName(const std::string& spaceName);
+
+    std::string spaceHandle() const;
+    void setSpaceHandle(const std::string& spaceHandle);
+
+    std::string shadingName() const;
+    void setShadingName(const std::string& shadingName);
+
+    std::string shadingHandle() const;
+    void setShadingHandle(const std::string& shadingHandle);
+
+    std::string thermalZoneName() const;
+    void setThermalZoneName(const std::string& thermalZoneName);
+
+    std::string thermalZoneHandle() const;
+    void setThermalZoneHandle(const std::string& thermalZoneHandle);
+
+    std::string thermalZoneMaterialName() const;
+    void setThermalZoneMaterialName(const std::string& thermalZoneMaterialName);
+
+    std::string spaceTypeName() const;
+    void setSpaceTypeName(const std::string& spaceTypeName);
+
+    std::string spaceTypeHandle() const;
+    void setSpaceTypeHandle(const std::string& spaceTypeHandle);
+
+    std::string spaceTypeMaterialName() const;
+    void setSpaceTypeMaterialName(const std::string& spaceTypeMaterialName);
+
+    std::string buildingStoryName() const;
+    void setBuildingStoryName(const std::string& buildingStoryName);
+
+    std::string buildingStoryHandle() const;
+    void setBuildingStoryHandle(const std::string& buildingStoryHandle);
+
+    std::string buildingStoryMaterialName() const;
+    void setBuildingStoryMaterialName(const std::string& buildingStoryMaterialName);
+
+    std::string buildingUnitName() const;
+    void setBuildingUnitName(const std::string& buildingUnitName);
+
+    std::string buildingUnitHandle() const;
+    void setBuildingUnitHandle(const std::string& buildingUnitHandle);
+
+    std::string buildingUnitMaterialName() const;
+    void setBuildingUnitMaterialName(const std::string& buildingUnitMaterialName);
+
+    std::string constructionSetName() const;
+    void setConstructionSetName(const std::string& constructionSetName);
+
+    std::string constructionSetHandle() const;
+    void setConstructionSetHandle(const std::string& constructionSetHandle);
+
+    std::string constructionSetMaterialName() const;
+    void setConstructionSetMaterialName(const std::string& constructionSetMaterialName);
+
+    std::string outsideBoundaryCondition() const;
+    void setOutsideBoundaryCondition(const std::string& outsideBoundaryCondition);
+
+    std::string outsideBoundaryConditionObjectName() const;
+    void setOutsideBoundaryConditionObjectName(const std::string& outsideBoundaryConditionObjectName);
+
+    std::string outsideBoundaryConditionObjectHandle() const;
+    void setOutsideBoundaryConditionObjectHandle(const std::string& outsideBoundaryConditionObjectHandle);
+
+    bool coincidentWithOutsideObject() const;
+    void setCoincidentWithOutsideObject(bool coincidentWithOutsideObject);
+
+    std::string sunExposure() const;
+    void setSunExposure(const std::string& sunExposure);
+
+    std::string windExposure() const;
+    void setWindExposure(const std::string& windExposure);
+
+    double illuminanceSetpoint() const;
+    void setIlluminanceSetpoint(double illuminanceSetpoint);
+
+    bool airWall() const;
+    void setAirWall(bool airWall);
+
+    std::vector<std::string> airLoopHVACNames() const;
+    void setAirLoopHVACNames(const std::vector<std::string>& airLoopHVACNames);
+    void addAirLoopHVACName(std::string airLoopHVACName);
+
+    std::vector<std::string> airLoopHVACHandles() const;
+    void setAirLoopHVACHandles(const std::vector<std::string>& airLoopHVACHandles);
+    void addAirLoopHVACHandle(std::string airLoopHVACHandle);
+
+    std::vector<std::string> airLoopHVACMaterialNames() const;
+    void setAirLoopHVACMaterialNames(const std::vector<std::string>& airLoopHVACMaterialNames);
+    void addAirLoopHVACMaterialName(std::string airLoopHVACMaterialName);
+
+    //@}
+    /** @name Other */
+    //@{
+
+    // // Gets GLTF Material name on the basis of Surface Type
+    std::string surfaceTypeMaterialName() const;
+    // Gets GLTF Material name on the basis of Surface Outside Boundary Condition, Wind Exposure, Sun Exposure
+    std::string boundaryMaterialName() const;
+
+    //@}
+
+   protected:
+    /** @name Protected */
+    //@{
+    /** Interface with an existing GLTF file */
+    GltfUserData(const tinygltf::Value& userDataObj);
+
+    // TODO: change to return a tinygltf::Node instead
+    std::map<std::string, tinygltf::Value> toExtras() const;
+    //@}
+    friend class GltfForwardTranslator;
+
+   private:
+    REGISTER_LOGGER("openstudio.gltf.GltfUserData");
+
+    std::string m_handle;
+    std::string m_name;
+    std::string m_surfaceType;
+    std::string m_constructionName;
+    std::string m_constructionHandle;
+    std::string m_constructionMaterialName;
+    std::string m_surfaceName;
+    std::string m_surfaceHandle;
+    std::string m_subSurfaceName;
+    std::string m_subSurfaceHandle;
+    std::string m_spaceName;
+    std::string m_spaceHandle;
+    std::string m_shadingName;
+    std::string m_shadingHandle;
+    std::string m_thermalZoneName;
+    std::string m_thermalZoneHandle;
+    std::string m_thermalZoneMaterialName;
+    std::string m_spaceTypeName;
+    std::string m_spaceTypeHandle;
+    std::string m_spaceTypeMaterialName;
+    std::string m_buildingStoryName;
+    std::string m_buildingStoryHandle;
+    std::string m_buildingStoryMaterialName;
+    std::string m_buildingUnitName;
+    std::string m_buildingUnitHandle;
+    std::string m_buildingUnitMaterialName;
+    std::string m_constructionSetName;
+    std::string m_constructionSetHandle;
+    std::string m_constructionSetMaterialName;
+    std::string m_outsideBoundaryCondition;
+    std::string m_outsideBoundaryConditionObjectName;
+    std::string m_outsideBoundaryConditionObjectHandle;
+    bool m_coincidentWithOutsideObject = false;
+    std::string m_sunExposure;
+    std::string m_windExposure;
+    double m_illuminanceSetpoint = 0.0;
+    bool m_airWall = false;
+
+    // TODO: replace with a struct to avoid having to keep indices in line?
+    std::vector<std::string> m_airLoopHVACNames;
+    std::vector<std::string> m_airLoopHVACHandles;
+    std::vector<std::string> m_airLoopHVACMaterialNames;
+  };
+
+  using GltfUserDataVector = std::vector<GltfUserData>;
+
+}  // namespace gltf
+}  // namespace openstudio
+
+#endif  // GLTF_GLTFUSERDATA_HPP
diff --git a/src/gltf/GltfUtils.cpp b/src/gltf/GltfUtils.cpp
new file mode 100644
index 00000000000..a22cd4bcc9a
--- /dev/null
+++ b/src/gltf/GltfUtils.cpp
@@ -0,0 +1,456 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include "GltfUtils.hpp"
+
+#include "../model/ModelObject.hpp"
+
+#include "../utilities/core/Compare.hpp"
+#include "../utilities/geometry/Point3d.hpp"
+#include "../utilities/geometry/Vector3d.hpp"
+
+#include <tiny_gltf.h>
+
+#include <limits>
+#include <type_traits>
+#include <vector>
+
+namespace openstudio {
+
+namespace gltf {
+
+  namespace detail {
+    // Get Bytes from a value
+    // typeparam name :"T"
+    // param : value
+    // returns : collection of bytes
+    template <typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
+    std::vector<uint8_t> splitValueToBytes(T const& value) {
+      std::vector<uint8_t> bytes;
+      for (size_t i = 0; i < sizeof(value); ++i) {
+        uint8_t byte = value >> (i * 8);
+        bytes.insert(bytes.begin(), byte);
+      }
+      return bytes;
+    }
+
+    // Adds & Creates Face Indices buffers and Accessors
+    // This method infers the indicesbuffer and adds them to the glTF model accessor
+    // which expects two types of accessor input one from indicesbuffer and the second
+    // one form coordinates buffer. So here after appending the buffer content it is sending
+    // over the index so the containing node will be aware of which one to refer.
+    // A better overview here at https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/figures/gltfOverview-2.0.0b.png
+    // returns : index of the Face Indices
+    int addIndices(const std::vector<size_t>& faceIndices, std::vector<unsigned char>& indicesBuffer, std::vector<tinygltf::Accessor>& accessors) {
+      auto [min, max] = std::minmax_element(std::cbegin(faceIndices), std::cend(faceIndices));
+
+      // This but seems to be just figuring out the best way to back the indices in
+      // depenbding on the range of numbers
+      int ct = TINYGLTF_COMPONENT_TYPE_BYTE;
+      auto size = 0;
+
+      if (*max <= static_cast<size_t>(std::pow(2, 8))) {
+        ct = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
+        size = sizeof(std::byte);
+      } else if (*max <= static_cast<size_t>(std::pow(2, 16))) {
+        ct = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
+        size = sizeof(short);
+      } else {
+        ct = TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT;
+        size = sizeof(int);
+      }
+      // the offset position needs to be a multiple of the size
+      // (this is from a warning we received in beta testing)
+      // so we inject some padding when needed
+      auto padding = indicesBuffer.size() % size;
+      for (size_t i = 0; i < padding; ++i) {
+        indicesBuffer.push_back(0x00);
+      }
+
+      // To avoid Accessor offset Validation Issue
+      auto _padding = indicesBuffer.size() % 4;
+      for (size_t i = 0; i < _padding; ++i) {
+        indicesBuffer.push_back(0x00);
+      }
+
+      tinygltf::Accessor indAccessor;
+      indAccessor.bufferView = 0;
+      indAccessor.componentType = ct;
+      indAccessor.byteOffset = indicesBuffer.size();
+      indAccessor.normalized = false;
+      indAccessor.type = TINYGLTF_TYPE_SCALAR;
+      indAccessor.count = faceIndices.size();
+      indAccessor.minValues = {static_cast<double>(*min)};
+      indAccessor.maxValues = {static_cast<double>(*max)};
+
+      std::vector<unsigned char> indicesBufferData;
+      for (const auto index : faceIndices) {
+        std::vector<unsigned char> arrayOfByte;
+        if (ct == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
+          arrayOfByte.push_back((unsigned char)index);
+          // } else if (ct == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
+          //  arrayOfByte = splitValueToBytes(index);
+        } else {
+          arrayOfByte = splitValueToBytes(index);
+        }
+        indicesBufferData.insert(indicesBufferData.end(), arrayOfByte.begin(), arrayOfByte.end());
+      }
+
+      if (indicesBufferData.size() < 4) {
+        indicesBufferData.push_back(0x00);
+      }
+      indicesBuffer.insert(indicesBuffer.end(), indicesBufferData.begin(), indicesBufferData.end());
+
+      const auto thisIndex = accessors.size();
+      accessors.push_back(indAccessor);
+      return thisIndex;
+    }
+
+    // Creates Coordinates / Normal Buffers and Accessors.
+    // returns : index
+    int createBuffers(std::vector<float>& values, std::vector<unsigned char>& coordinatesBuffer, std::vector<tinygltf::Accessor>& accessors) {
+      // Fixes ACCESSOR_TOTAL_OFFSET_ALIGNMENT
+      // Accessor's total byteOffset XXXX isn't a multiple of componentType length 4.
+      auto _padding = coordinatesBuffer.size() % 4;
+      for (size_t i = 0; i < _padding; ++i) {
+        coordinatesBuffer.push_back((unsigned)0);
+      }
+      int startingBufferPosition = coordinatesBuffer.size();
+      std::vector<float> min(3, std::numeric_limits<float>::max());
+      std::vector<float> max(3, std::numeric_limits<float>::lowest());
+      int i = 0;
+      for (const auto& value : values) {
+        min[i] = std::min(value, min[i]);
+        max[i] = std::max(value, max[i]);
+        ++i;
+        if (i > 2) {
+          i = 0;
+        }
+        std::vector<unsigned char> v;
+        // TODO: ideally we should revisit this...
+        // cppcheck-suppress invalidPointerCast
+        const auto* ptr = reinterpret_cast<const unsigned char*>(&value);
+        for (size_t j = 0; j < sizeof(float); ++j) {
+          v.push_back(ptr[j]);
+        }
+        coordinatesBuffer.insert(coordinatesBuffer.end(), v.begin(), v.end());
+      }
+      // To Fix : offset 18 is not a multiple of Component Type length 4
+      auto padding = coordinatesBuffer.size() % 4;
+      for (size_t j = 0; j < padding; ++j) {
+        coordinatesBuffer.push_back((unsigned)0);
+      }
+      // convert min and max to double
+      std::vector<double> min_d;
+      std::vector<double> max_d;
+      for (const auto mn : min) {
+        min_d.push_back((double)mn);
+      }
+      for (const auto mx : max) {
+        max_d.push_back((double)mx);
+      }
+      tinygltf::Accessor coordAccessor;
+      coordAccessor.bufferView = 1;
+      coordAccessor.byteOffset = startingBufferPosition;
+      coordAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
+      coordAccessor.normalized = false;
+      coordAccessor.count = values.size() / 3;
+      coordAccessor.type = TINYGLTF_TYPE_VEC3;
+      coordAccessor.minValues = min_d;
+      coordAccessor.maxValues = max_d;
+
+      auto ret = accessors.size();
+      accessors.push_back(coordAccessor);
+      return ret;
+    }
+
+    // Adds Coordinate Buffers for all vertices of the surface
+    // returns : index for the Coordinates Buffer
+    int addCoordinates(const Point3dVector& allVertices, std::vector<unsigned char>& coordinatesBuffer, std::vector<tinygltf::Accessor>& accessors) {
+      std::vector<float> values(3 * allVertices.size());
+      size_t i = 0;
+      for (const auto& point : allVertices) {
+        values[i++] = static_cast<float>(point.x());
+        values[i++] = static_cast<float>(point.y());
+        values[i++] = static_cast<float>(point.z());
+      }
+      return createBuffers(values, coordinatesBuffer, accessors);
+    }
+
+    // Adds Normal Buffers for all normal Vectors
+    // returns : index for the Normals Buffer
+    int addNormals(const Vector3dVector& normalVectors, std::vector<unsigned char>& coordinatesBuffer, std::vector<tinygltf::Accessor>& accessors) {
+      std::vector<float> values(3 * normalVectors.size());
+      size_t i = 0;
+      for (const auto& vec : normalVectors) {
+        values[i++] = static_cast<float>(vec.x());
+        values[i++] = static_cast<float>(vec.y());
+        values[i++] = static_cast<float>(vec.z());
+      }
+      return createBuffers(values, coordinatesBuffer, accessors);
+    }
+
+    ShapeComponentIds::ShapeComponentIds(const std::vector<size_t>& faceIndices, const Point3dVector& allVertices,
+                                         const Vector3dVector& normalVectors, std::vector<unsigned char>& indicesBuffer,
+                                         std::vector<unsigned char>& coordinatesBuffer, std::vector<tinygltf::Accessor>& accessors) {
+
+      indicesAccessorId = addIndices(faceIndices, indicesBuffer, accessors);
+      verticesAccessorId = addCoordinates(allVertices, coordinatesBuffer, accessors);
+      normalsAccessorId = addNormals(normalVectors, coordinatesBuffer, accessors);
+    }
+  }  // namespace detail
+
+  // Gets GLTF Material name on the basis of idd Object Type and Name
+  // param : iddObjectType
+  // param : name
+  // returns : name of GLTF Material Name
+  std::string getObjectGLTFMaterialName(const std::string& iddObjectType, const std::string& name) {
+    std::string result;
+    if (istringEqual(iddObjectType, "OS:Construction")) {
+      result = "Construction_" + name;
+    } else if (istringEqual(iddObjectType, "OS:ThermalZone")) {
+      result = "ThermalZone_" + name;
+    } else if (istringEqual(iddObjectType, "OS:AirLoopHVAC")) {
+      result = "AirLoopHVAC_" + name;
+    } else if (istringEqual(iddObjectType, "OS:SpaceType")) {
+      result = "SpaceType_" + name;
+    } else if (istringEqual(iddObjectType, "OS:BuildingStory")) {
+      result = "BuildingStory_" + name;
+    } else if (istringEqual(iddObjectType, "OS:BuildingUnit")) {
+      result = "BuildingUnit_" + name;
+    } else if (istringEqual(iddObjectType, "OS:Construction:AirBoundary")) {
+      // TODO
+      // This shouldn't happen
+      // LOG_FREE(Error, "getObjectGLTFMaterialName", "Didn't expect it would be called for '" << iddObjectType << "' (name = '" << name << "')");
+      // result = "ConstructionAirBoundary_" + name;
+      result = "AirWall";
+    } else {
+      LOG_FREE(Error, "getObjectGLTFMaterialName", "Unknown iddObjectType '" << iddObjectType << "'");
+    }
+    return result;
+  }
+
+  // Gets GLTF Material Name on the basis of Model Object
+  // param : object
+  // returns : name of GLTF material Name
+  std::string getObjectGLTFMaterialName(const model::ModelObject& object) {
+    return getObjectGLTFMaterialName(object.iddObjectType().valueDescription(), object.nameString());
+  }
+
+  // To export a Minimal GLTF file (Triangle with 3 Points) using generated raw data from Point3DVector
+  bool createTriangleGLTFFromPoint3DVector(const path& outputPath) {
+    tinygltf::Model m;
+
+    //BPS: Buffer Views will not give the desired result if used emplace_back()
+    tinygltf::BufferView bufferView1;
+    tinygltf::BufferView bufferView2;
+
+    tinygltf::Scene& scene = m.scenes.emplace_back();
+    tinygltf::Mesh& mesh = m.meshes.emplace_back();
+    tinygltf::Node& node = m.nodes.emplace_back();
+    tinygltf::Buffer& buffer = m.buffers.emplace_back();
+    tinygltf::Asset& asset = m.asset;
+
+    // Create an array of size equivalent to vector
+    // unsigned char arr[42];
+    // The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
+    // start of the buffer.
+    bufferView1.buffer = 0;
+    bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
+
+    // The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
+    // at position 8 in the buffer and are of type ARRAY_BUFFER
+    bufferView2.buffer = 0;
+    bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
+
+    std::vector<size_t> faceIndices{0, 1, 2};
+    std::vector<unsigned char> _indicesBuffer;
+    std::vector<unsigned char> _coordinatesBuffer;
+    Point3dVector allVertices{
+      {0, 0, 0},
+      {1, 0, 0},
+      {0, 1, 0},
+    };
+
+    detail::ShapeComponentIds shapeComponentIds(faceIndices, allVertices, {}, _indicesBuffer, _coordinatesBuffer, m.accessors);
+
+    // Build the mesh primitive and add it to the mesh
+    // The index of the accessor for the vertex indices
+    tinygltf::Primitive& primitive = mesh.primitives.emplace_back();
+    primitive.indices = 0;
+    // The index of the accessor for positions
+    primitive.attributes["POSITION"] = shapeComponentIds.verticesAccessorId;
+    primitive.material = 0;
+    primitive.mode = TINYGLTF_MODE_TRIANGLES;
+
+    bufferView1.byteOffset = 0;
+    bufferView1.byteLength = _indicesBuffer.size();
+    bufferView2.byteOffset = _indicesBuffer.size();
+    bufferView2.byteLength = _coordinatesBuffer.size();
+
+    std::vector<unsigned char> _allBuffer = _indicesBuffer;  //std::move(_indicesBuffer);
+    _allBuffer.insert(_allBuffer.end(), _coordinatesBuffer.begin(), _coordinatesBuffer.end());
+
+    buffer.data = _allBuffer;
+
+    // Other tie ups
+    node.mesh = 0;
+    scene.nodes.push_back(0);  // Default scene
+
+    // Define the asset. The version is required
+    asset.version = "2.0";
+    asset.generator = "OpenStudio";
+
+    // Now all that remains is to tie back all the loose objects into the
+    // our single model.
+    m.bufferViews.emplace_back(std::move(bufferView1));
+    m.bufferViews.emplace_back(std::move(bufferView2));
+
+    // Create a simple material
+    tinygltf::Material mat;
+    mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
+    mat.pbrMetallicRoughness.metallicFactor = 1.0;
+    mat.pbrMetallicRoughness.roughnessFactor = 0.5;
+    mat.doubleSided = true;
+    m.materials.emplace_back(std::move(mat));
+
+    // Save it to a file
+    tinygltf::TinyGLTF gltf;
+    bool ret = gltf.WriteGltfSceneToFile(&m, toString(outputPath),
+                                         true,    // embedImages
+                                         true,    // embedBuffers
+                                         true,    // pretty print
+                                         false);  // write binary
+    return ret;
+  }
+
+  // To export a Minimal GLTF file (Triangle with 3 Points) using raw buffer data.
+  bool createTriangleGLTF(const path& outputPath) {
+    tinygltf::Model m;
+    tinygltf::Scene scene;
+    tinygltf::Mesh mesh;
+    tinygltf::Primitive primitive;
+    tinygltf::Node node;
+    tinygltf::Buffer buffer;
+    tinygltf::BufferView bufferView1;
+    tinygltf::BufferView bufferView2;
+    tinygltf::Accessor accessor1;
+    tinygltf::Accessor accessor2;
+    tinygltf::Asset asset;
+
+    // This is the raw data buffer.
+    buffer.data = {// 6 bytes of indices and two bytes of padding
+                   // 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+                   0x00, 0x01, 0x02, 0x00,
+                   // 36 bytes of floating point numbers
+                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00};
+
+    // Create an array of size equivalent to vector
+    // unsigned char arr[42]
+
+    // The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
+    // start of the buffer.
+    bufferView1.buffer = 0;
+    bufferView1.byteOffset = 0;
+    bufferView1.byteLength = 3;
+    bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
+
+    // The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
+    // at position 8 in the buffer and are of type ARRAY_BUFFER
+    bufferView2.buffer = 0;
+    bufferView2.byteOffset = 4;
+    bufferView2.byteLength = 36;
+    bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
+
+    // Describe the layout of bufferView1, the indices of the vertices
+    accessor1.bufferView = 0;
+    accessor1.byteOffset = 0;
+    accessor1.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;  // TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
+    accessor1.count = 3;
+    accessor1.type = TINYGLTF_TYPE_SCALAR;
+    accessor1.maxValues.push_back(2);
+    accessor1.minValues.push_back(0);
+
+    // Describe the layout of bufferView2, the vertices themself
+    accessor2.bufferView = 1;
+    accessor2.byteOffset = 0;
+    accessor2.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
+    accessor2.count = 3;
+    accessor2.type = TINYGLTF_TYPE_VEC3;
+    accessor2.maxValues = {1.0, 1.0, 0.0};
+    accessor2.minValues = {0.0, 0.0, 0.0};
+
+    // Build the mesh primitive and add it to the mesh
+    primitive.indices = 0;                 // The index of the accessor for the vertex indices
+    primitive.attributes["POSITION"] = 1;  // The index of the accessor for positions
+    primitive.material = 0;
+    // Other Modes in GLTF TINYGLTF_MODE_POINTS | TINYGLTF_MODE_LINE;
+    primitive.mode = TINYGLTF_MODE_TRIANGLES;
+    mesh.primitives.push_back(primitive);
+
+    // Other tie ups
+    node.mesh = 0;
+    scene.nodes.push_back(0);  // Default scene
+
+    // Define the asset. The version is required
+    asset.version = "2.0";
+    asset.generator = "OpenStudio";
+
+    // Now all that remains is to tie back all the loose objects into the
+    // our single model.
+    m.scenes.push_back(scene);
+    m.meshes.push_back(mesh);
+    m.nodes.push_back(node);
+    m.buffers.push_back(buffer);
+    m.bufferViews.push_back(bufferView1);
+    m.bufferViews.push_back(bufferView2);
+    m.accessors.push_back(accessor1);
+    m.accessors.push_back(accessor2);
+    m.asset = asset;
+
+    // Create a simple material
+    tinygltf::Material& mat = m.materials.emplace_back();
+    mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
+    mat.pbrMetallicRoughness.metallicFactor = 0.8;
+    mat.pbrMetallicRoughness.roughnessFactor = 0.5;
+    mat.doubleSided = true;
+
+    // Save it to a file
+    tinygltf::TinyGLTF gltf;
+    bool ret = gltf.WriteGltfSceneToFile(&m, toString(outputPath),
+                                         true,    // embedImages
+                                         true,    // embedBuffers
+                                         true,    // pretty print
+                                         false);  // write binary
+    return ret;
+  }
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/gltf/GltfUtils.hpp b/src/gltf/GltfUtils.hpp
new file mode 100644
index 00000000000..0e45207d7f0
--- /dev/null
+++ b/src/gltf/GltfUtils.hpp
@@ -0,0 +1,91 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+#ifndef GLTF_GLTFUTILS_HPP
+#define GLTF_GLTFUTILS_HPP
+
+#include "GltfAPI.hpp"
+
+#include "../utilities/core/Path.hpp"
+
+#include <string>
+#include <vector>
+
+namespace tinygltf {
+struct Accessor;
+}
+
+namespace openstudio {
+
+class Point3d;
+class Vector3d;
+
+namespace model {
+  class ModelObject;
+}
+
+namespace gltf {
+
+  // Gets GLTF Material name on the basis of idd Object Type and Name
+  GLTF_API std::string getObjectGLTFMaterialName(const std::string& iddObjectType, const std::string& name);
+
+  // Gets GLTF Material Name on the basis of Model Object
+  GLTF_API std::string getObjectGLTFMaterialName(const model::ModelObject& object);
+
+  // Export a Minimal GLTF file (Triangle with 3 Points) using raw buffer data.
+  GLTF_API bool createTriangleGLTF(const path& outputPath);
+
+  // Export a Minimal GLTF file (Triangle with 3 Points) using generated raw buffer data from Point3DVector
+  GLTF_API bool createTriangleGLTFFromPoint3DVector(const path& outputPath);
+
+  namespace detail {
+    // For Indices of Indices, Coordinates & Normal buffers against each Components
+    struct ShapeComponentIds
+    {
+      explicit ShapeComponentIds(const std::vector<size_t>& faceIndices, const std::vector<Point3d>& allVertices,
+                                 const std::vector<Vector3d>& normalVectors, std::vector<unsigned char>& indicesBuffer,
+                                 std::vector<unsigned char>& coordinatesBuffer, std::vector<tinygltf::Accessor>& accessors);
+
+      int indicesAccessorId;
+      int verticesAccessorId;
+      int normalsAccessorId;
+
+     private:
+      // int addIndices(const std::vector<size_t>& faceIndices, std::vector<unsigned char>& indicesBuffer, std::vector<tinygltf::Accessor>& accessors);
+      // int addCoordinates(const std::vector<Point3d>& allVertices, std::vector<unsigned char>& coordinatesBuffer,
+      //                    std::vector<tinygltf::Accessor>& accessors);
+      // int addNormals(const std::vector<Vector3d>& normalVectors, std::vector<unsigned char>& coordinatesBuffer,
+      //                std::vector<tinygltf::Accessor>& accessors);
+      // int createBuffers(std::vector<float>& values, std::vector<unsigned char>& coordinatesBuffer, std::vector<tinygltf::Accessor>& accessors);
+    };
+  }  // namespace detail
+
+}  // namespace gltf
+}  // namespace openstudio
+
+#endif  // GLTF_GLTFUTILS_HPP
diff --git a/src/gltf/mainpage.hpp b/src/gltf/mainpage.hpp
new file mode 100644
index 00000000000..bb57ca34662
--- /dev/null
+++ b/src/gltf/mainpage.hpp
@@ -0,0 +1,64 @@
+namespace openstudio {
+namespace gltf {
+
+  /** \mainpage OpenStudio Gltf
+ *
+ * \section overview_gltf Overview
+ *
+ * glTF (derivative short form of Graphics Language Transmission Format or GL Transmission Format)
+ * is a standard file format for three-dimensional scenes and models.
+ *
+ * An OpenStudio model can be ForwardTranslated to a glTF file for external viewing such as in-browser via WebGL.
+ * OpenStudio uses the glTF standard 2.0. Internally it uses the `tinygltf` library to write the glTF file.
+ *
+ * The following document aims to explains briefly how glTF and supporting OpenStudio class are laid out.
+ *
+ * The following classes form the foundation of the OpenStudio Gltf functionality:
+ *
+ * \li GltfForwardTranslator
+ * \li GltfUserData
+ * \li GltfMetaData
+ * \li GltfModelObjectMetaData
+ * \li GltfMaterialData
+ *
+ * The `GltfForwardTranslator` class is the orchestrator. The other classes are **interface** classes between the OpenStudio Model and the gltf Model.
+ * Their data members are there to represent the data that will eventually be stored in the gltf Model.
+ *
+ * \li They have one or several constructors that take in OpenStudio Model or ModelObject to populate the data members.
+ * \li They have a function that will export to a `tinygltf::Value::Object`
+ * \li They also have a constructor that does the reverse: populating the data members by reading a `tinygltf::Value` for inspection for eg
+ *
+ *
+ * \subsection gltf_geometry Geometry: PlanarSurfaces <=> glTF Node
+ *
+ * The geometry part of the glTF represents the surfaces of the OpenStudio Model.
+ *
+ * OpenStudio Model `PlanarSurface`s (such as `Surface`, `SubSurface`, `ShadingSurface`, etc) are glTF `Node`s. The Surface Vertices are packed in a
+ * base64 encoded buffer that the glTF `Node` will reference.
+ *
+ * The class `GltfUserData` is used to create node `extras`: we place some attribute on these nodes, such as the surface type, its construction,
+ * the Space and SpaceType and ThermalZone it belongs to. External viewers can use that information for displaying attributes or filtering.
+ *
+ * A glTF `Material` is also attached to these gltf `Node`s, with the help of the `GltfMaterialData` class, which interfaces between an OpenStudio
+ * RenderingColor and a `tinygltf::Material`
+ *
+ * \subsection gltf_metadata Scene MetaData
+ *
+ * A glTF `Scene` can also bear `extras`. We use the class `GltfMetaData` to do so. GltfMetaData holds:
+ *
+ * \li An array of `GltfModelObjectMetaData`
+ * \li a `GltfBoundingBox`
+ *
+ * GltfMetadata has a constructor that takes an OpenStudio Model. For there, it sets a few members like the northAxis, and will dispatch ModelObjects
+ * to its supporting classes:
+ *
+ * \li PlanarSurfaceGroups are dispatched to the GltfBoundingBox to calculate the glTF boundingbox
+ * \li ThermalZone, SpaceType, AirLoopHVAC, BuildingStory, BuildingUnit, DefaultConstructionSet objects are sent to the GltfModelObjectMetaData class
+ *     to store attributes such as the name, handle, iddObjectType, multiplier, etc
+ *
+ * It has a function that exports to a `tinygltf::Value::Object` and it has a constructor that can do the reverse: read from a `tinygltf::Value`.
+ * It dispatches to its supporting classes which are able to the do the same thing.
+ **/
+
+}  // namespace gltf
+}  // namespace openstudio
diff --git a/src/gltf/schemas/node.extras.schema.json b/src/gltf/schemas/node.extras.schema.json
new file mode 100644
index 00000000000..763a2bd47e8
--- /dev/null
+++ b/src/gltf/schemas/node.extras.schema.json
@@ -0,0 +1,210 @@
+{
+  "$schema": "https://json-schema.org/draft/2020-12/schema",
+  "$id": "node.extras.schema.json",
+  "title": "Node Extras",
+  "description": "OpenStudio-specific Node extra data",
+  "gltf_sectionDescription": "This places some OpenStudio Model specific data on the GLTF Nodes, such as information about the AirLoopHVAC, Construction, Building Story, Space Type etc.",
+  "type": "object",
+  "properties": {
+    "airLoopHVACHandles": {
+      "description": "**TODO: This should be an Array of AirLoopHVACInfo objects**",
+      "type": "object",
+      "properties": {
+        "0": {
+          "type": "string"
+        },
+        "1": {
+          "type": "string"
+        }
+      },
+      "required": []
+    },
+    "airLoopHVACMaterialNames": {
+      "description": "**TODO: This should be an Array of AirLoopHVACInfo objects**",
+      "type": "object",
+      "properties": {
+        "0": {
+          "type": "string"
+        },
+        "1": {
+          "type": "string"
+        }
+      },
+      "required": []
+    },
+    "airLoopHVACNames": {
+      "description": "**TODO: This should be an Array of AirLoopHVACInfo objects**",
+      "type": "object",
+      "properties": {
+        "0": {
+          "type": "string"
+        },
+        "1": {
+          "type": "string"
+        }
+      },
+      "required": []
+    },
+    "airWall": {
+      "type": "boolean"
+    },
+    "boundaryMaterialName": {
+      "type": "string"
+    },
+    "buildingStoryHandle": {
+      "type": "string"
+    },
+    "buildingStoryMaterialName": {
+      "type": "string"
+    },
+    "buildingStoryName": {
+      "type": "string"
+    },
+    "buildingUnitHandle": {
+      "type": "string"
+    },
+    "buildingUnitMaterialName": {
+      "type": "string"
+    },
+    "buildingUnitName": {
+      "type": "string"
+    },
+    "coincidentWithOutsideObject": {
+      "type": "boolean"
+    },
+    "constructionHandle": {
+      "type": "string"
+    },
+    "constructionMaterialName": {
+      "type": "string"
+    },
+    "constructionName": {
+      "type": "string"
+    },
+    "constructionSetHandle": {
+      "type": "string"
+    },
+    "constructionSetMaterialName": {
+      "type": "string"
+    },
+    "constructionSetName": {
+      "type": "string"
+    },
+    "handle": {
+      "type": "string"
+    },
+    "illuminanceSetpoint": {
+      "type": "number"
+    },
+    "name": {
+      "type": "string"
+    },
+    "outsideBoundaryCondition": {
+      "type": "string"
+    },
+    "outsideBoundaryConditionObjectHandle": {
+      "type": "string"
+    },
+    "outsideBoundaryConditionObjectName": {
+      "type": "string"
+    },
+    "shadingHandle": {
+      "type": "string"
+    },
+    "shadingName": {
+      "type": "string"
+    },
+    "spaceHandle": {
+      "type": "string"
+    },
+    "spaceName": {
+      "type": "string"
+    },
+    "spaceTypeHandle": {
+      "type": "string"
+    },
+    "spaceTypeMaterialName": {
+      "type": "string"
+    },
+    "spaceTypeName": {
+      "type": "string"
+    },
+    "subSurfaceHandle": {
+      "type": "string"
+    },
+    "subSurfaceName": {
+      "type": "string"
+    },
+    "sunExposure": {
+      "type": "string"
+    },
+    "surfaceHandle": {
+      "type": "string"
+    },
+    "surfaceName": {
+      "type": "string"
+    },
+    "surfaceType": {
+      "type": "string"
+    },
+    "surfaceTypeMaterialName": {
+      "type": "string"
+    },
+    "thermalZoneHandle": {
+      "type": "string"
+    },
+    "thermalZoneMaterialName": {
+      "type": "string"
+    },
+    "thermalZoneName": {
+      "type": "string"
+    },
+    "windExposure": {
+      "type": "string"
+    }
+  },
+  "required": [
+    "airLoopHVACHandles",
+    "airLoopHVACMaterialNames",
+    "airLoopHVACNames",
+    "airWall",
+    "boundaryMaterialName",
+    "buildingStoryHandle",
+    "buildingStoryMaterialName",
+    "buildingStoryName",
+    "buildingUnitHandle",
+    "buildingUnitMaterialName",
+    "buildingUnitName",
+    "coincidentWithOutsideObject",
+    "constructionHandle",
+    "constructionMaterialName",
+    "constructionName",
+    "constructionSetHandle",
+    "constructionSetMaterialName",
+    "constructionSetName",
+    "handle",
+    "illuminanceSetpoint",
+    "name",
+    "outsideBoundaryCondition",
+    "outsideBoundaryConditionObjectHandle",
+    "outsideBoundaryConditionObjectName",
+    "shadingHandle",
+    "shadingName",
+    "spaceHandle",
+    "spaceName",
+    "spaceTypeHandle",
+    "spaceTypeMaterialName",
+    "spaceTypeName",
+    "subSurfaceHandle",
+    "subSurfaceName",
+    "sunExposure",
+    "surfaceHandle",
+    "surfaceName",
+    "surfaceType",
+    "surfaceTypeMaterialName",
+    "thermalZoneHandle",
+    "thermalZoneMaterialName",
+    "thermalZoneName",
+    "windExposure"
+  ]
+}
diff --git a/src/gltf/schemas/scene.extras.schema.json b/src/gltf/schemas/scene.extras.schema.json
new file mode 100644
index 00000000000..938fe26957c
--- /dev/null
+++ b/src/gltf/schemas/scene.extras.schema.json
@@ -0,0 +1,183 @@
+{
+  "$schema": "https://json-schema.org/draft/2020-12/schema",
+  "$id": "scene.extras.schema.json",
+  "title": "Scene Extras",
+  "description": "OpenStudio-specific Scene extra data",
+  "gltf_sectionDescription": "This places some OpenStudio Model specific data on the GLTF Scene, such as the BoundingBox, Some ModelObjectMetadata, the OpenStudio Version used, etc",
+  "type": "object",
+  "properties": {
+    "boundingbox": {
+      "type": "object",
+      "description": "The Model's bounding box",
+      "properties": {
+        "lookAtR": {
+          "type": "number"
+        },
+        "lookAtX": {
+          "type": "number"
+        },
+        "lookAtY": {
+          "type": "number"
+        },
+        "lookAtZ": {
+          "type": "number"
+        },
+        "maxX": {
+          "type": "number"
+        },
+        "maxY": {
+          "type": "number"
+        },
+        "maxZ": {
+          "type": "number"
+        },
+        "minX": {
+          "type": "number"
+        },
+        "minY": {
+          "type": "number"
+        },
+        "minZ": {
+          "type": "number"
+        }
+      },
+      "required": [
+        "lookAtR",
+        "lookAtX",
+        "lookAtY",
+        "lookAtZ",
+        "maxX",
+        "maxY",
+        "maxZ",
+        "minX",
+        "minY",
+        "minZ"
+      ]
+    },
+    "buildingStoryNames": {
+      "type": "object",
+      "description": "The Names of the Building Story. **TODO: This should be an Array**",
+      "properties": {
+        "0": {
+          "type": "string"
+        },
+        "1": {
+          "type": "string"
+        }
+      },
+      "required": []
+    },
+    "generator": {
+      "type": "string",
+      "examples": ["OpenStudio"]
+    },
+    "modelObjectMetaData": {
+      "type": "object",
+      "description": "Stores information about some ModelObjects attributes such as name, iddObjectType, color, handle from ModelObjects: ThermalZone, SpaceType, AirLoopHVAC, BuildingStory, BuildingUnit, DefaultConstructionSet. **TODO: This should be an Array**",
+      "properties": {
+        "0": {
+          "type": "object",
+          "properties": {
+            "color": {
+              "type": "string"
+            },
+            "handle": {
+              "type": "string"
+            },
+            "iddObjectType": {
+              "type": "string"
+            },
+            "multiplier": {
+              "type": "integer"
+            },
+            "name": {
+              "type": "string"
+            },
+            "nominal_floorCeiling_Height": {
+              "type": "number"
+            },
+            "nominal_z_coordinate": {
+              "type": "number"
+            },
+            "open_to_below": {
+              "type": "boolean"
+            }
+          },
+          "required": [
+            "color",
+            "handle",
+            "iddObjectType",
+            "multiplier",
+            "name",
+            "nominal_floorCeiling_Height",
+            "nominal_z_coordinate",
+            "open_to_below"
+          ]
+        },
+        "1": {
+          "type": "object",
+          "properties": {
+            "color": {
+              "type": "string"
+            },
+            "handle": {
+              "type": "string"
+            },
+            "iddObjectType": {
+              "type": "string"
+            },
+            "multiplier": {
+              "type": "integer"
+            },
+            "name": {
+              "type": "string"
+            },
+            "nominal_floorCeiling_Height": {
+              "type": "number"
+            },
+            "nominal_z_coordinate": {
+              "type": "number"
+            },
+            "open_to_below": {
+              "type": "boolean"
+            }
+          },
+          "required": [
+            "color",
+            "handle",
+            "iddObjectType",
+            "multiplier",
+            "name",
+            "nominal_floorCeiling_Height",
+            "nominal_z_coordinate",
+            "open_to_below"
+          ]
+        }
+      },
+      "required": []
+    },
+    "northAxis": {
+      "type": "number",
+      "title": "The Building North Axis"
+    },
+    "type": {
+      "type": "string",
+      "default": "Object"
+    },
+    "version": {
+      "type": "string",
+      "title": "The OpenStudio version used to generate the GLTF file",
+      "examples": ["3.4.0"]
+    }
+  },
+  "required": [
+    "boundingbox",
+    "buildingStoryNames",
+    "generator",
+    "modelObjectMetaData",
+    "northAxis",
+    "type",
+    "version"
+  ]
+}
+}
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index be64669063a..e88b6de2f70 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -17,6 +17,7 @@ target_link_libraries(
  openstudio_sdd
  openstudio_isomodel
  openstudio_gbxml
+ openstudio_gltf
  openstudio_radiance
 )
 
@@ -28,6 +29,7 @@ target_link_libraries(
  CONAN_PKG::cpprestsdk
  CONAN_PKG::openssl
  CONAN_PKG::pugixml
+ # CONAN_PKG::tinygltf  # TODO: needed?
 )
 
 target_compile_definitions(openstudiolib INTERFACE "-DSHARED_OS_LIBS")
diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt
index 0ca31515a9a..360f01f7666 100644
--- a/src/model/CMakeLists.txt
+++ b/src/model/CMakeLists.txt
@@ -34,16 +34,6 @@ set(${target_name}_src
   ThreeJSForwardTranslator.cpp
   ThreeJSReverseTranslator.hpp
   ThreeJSReverseTranslator.cpp
-  GltfForwardTranslator.hpp
-  GltfForwardTranslator.cpp
-  GltfBoundingBoxWrapper.hpp
-  GltfBoundingBoxWrapper.cpp
-  GltfModelObjectMetadataWrapper.hpp
-  GltfModelObjectMetadataWrapper.cpp
-  GltfUserDataWrapper.hpp
-  GltfUserDataWrapper.cpp
-  GltfMetaDataWrapper.hpp
-  GltfMetaDataWrapper.cpp
   ModelMerger.hpp
   ModelMerger.cpp
 
@@ -2214,7 +2204,6 @@ set(${target_name}_test_src
   test/TemperingValve_GTest.cpp
   test/ThreeJSForwardTranslator_GTest.cpp
   test/ThreeJSReverseTranslator_GTest.cpp
-  test/GltfForwardTranslator_GTest.cpp
   test/UnitarySystemPerformanceMultispeed_GTest.cpp
   test/UtilityBill_GTest.cpp
   test/WaterHeaterMixed_GTest.cpp
diff --git a/src/model/GltfBoundingBoxWrapper.cpp b/src/model/GltfBoundingBoxWrapper.cpp
deleted file mode 100644
index 6266d9af32d..00000000000
--- a/src/model/GltfBoundingBoxWrapper.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/***********************************************************************************************************************
-*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
-*
-*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
-*  following conditions are met:
-*
-*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
-*  disclaimer.
-*
-*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
-*  disclaimer in the documentation and/or other materials provided with the distribution.
-*
-*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
-*  derived from this software without specific prior written permission from the respective party.
-*
-*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
-*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
-*  written permission from Alliance for Sustainable Energy, LLC.
-*
-*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
-*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-***********************************************************************************************************************/
-
-#include "GltfBoundingBoxWrapper.hpp"
-
-#include <tuple>
-
-namespace openstudio {
-namespace model {
-
-  void GltfBoundingBoxWrapper::setlookAtR(double value) {
-    std::string key = "lookAtR";
-    lookAtR = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setlookAtX(double value) {
-    std::string key = "lookAtX";
-    lookAtX = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setlookAtY(double value) {
-    std::string key = "lookAtY";
-    lookAtY = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setlookAtZ(double value) {
-    std::string key = "lookAtZ";
-    lookAtZ = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setmaxX(double value) {
-    std::string key = "maxX";
-    maxX = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setmaxY(double value) {
-    std::string key = "maxY";
-    maxY = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setmaxZ(double value) {
-    std::string key = "maxZ";
-    maxZ = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setminX(double value) {
-    std::string key = "minX";
-    minX = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setminY(double value) {
-    std::string key = "minY";
-    minY = std::make_tuple(key, value);
-  }
-
-  void GltfBoundingBoxWrapper::setminZ(double value) {
-    std::string key = "minZ";
-    minZ = std::make_tuple(key, value);
-  }
-
-  // Getters
-  double GltfBoundingBoxWrapper::getlookAtR() const {
-    return std::get<1>(lookAtR);
-  }
-
-  double GltfBoundingBoxWrapper::getlookAtX() const {
-    return std::get<1>(lookAtX);
-  }
-
-  double GltfBoundingBoxWrapper::getlookAtY() const {
-    return std::get<1>(lookAtY);
-  }
-
-  double GltfBoundingBoxWrapper::getlookAtZ() const {
-    return std::get<1>(lookAtZ);
-  }
-
-  double GltfBoundingBoxWrapper::getmaxX() const {
-    return std::get<1>(maxX);
-  }
-
-  double GltfBoundingBoxWrapper::getmaxY() const {
-    return std::get<1>(maxY);
-  }
-
-  double GltfBoundingBoxWrapper::getmaxZ() const {
-    return std::get<1>(maxZ);
-  }
-
-  double GltfBoundingBoxWrapper::getminX() const {
-    return std::get<1>(minX);
-  }
-
-  double GltfBoundingBoxWrapper::getminY() const {
-    return std::get<1>(minY);
-  }
-
-  double GltfBoundingBoxWrapper::getminZ() const {
-    return std::get<1>(minZ);
-  }
-
-}  // namespace model
-}  // namespace openstudio
diff --git a/src/model/GltfForwardTranslator.cpp b/src/model/GltfForwardTranslator.cpp
deleted file mode 100644
index a1bc6cd9f97..00000000000
--- a/src/model/GltfForwardTranslator.cpp
+++ /dev/null
@@ -1,3584 +0,0 @@
-/***********************************************************************************************************************
-*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
-*
-*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
-*  following conditions are met:
-*
-*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
-*  disclaimer.
-*
-*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
-*  disclaimer in the documentation and/or other materials provided with the distribution.
-*
-*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
-*  derived from this software without specific prior written permission from the respective party.
-*
-*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
-*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
-*  written permission from Alliance for Sustainable Energy, LLC.
-*
-*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
-*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-***********************************************************************************************************************/
-
-#include "GltfForwardTranslator.hpp"
-
-#include "RenderingColor.hpp"
-#include "ConstructionBase.hpp"
-#include "ConstructionBase_Impl.hpp"
-#include "ConstructionAirBoundary.hpp"
-#include "ConstructionAirBoundary_Impl.hpp"
-#include "AirLoopHVAC.hpp"
-#include "AirLoopHVAC_Impl.hpp"
-#include "ThermalZone.hpp"
-#include "ThermalZone_Impl.hpp"
-#include "SpaceType.hpp"
-#include "SpaceType_Impl.hpp"
-#include "Building.hpp"
-#include "Building_Impl.hpp"
-#include "BuildingStory.hpp"
-#include "BuildingStory_Impl.hpp"
-#include "BuildingUnit.hpp"
-#include "BuildingUnit_Impl.hpp"
-#include "Surface.hpp"
-#include "Surface_Impl.hpp"
-#include "SubSurface.hpp"
-#include "SubSurface_Impl.hpp"
-#include "ShadingSurface.hpp"
-#include "ShadingSurface_Impl.hpp"
-#include "InteriorPartitionSurface.hpp"
-#include "InteriorPartitionSurface_Impl.hpp"
-#include "PlanarSurfaceGroup.hpp"
-#include "PlanarSurfaceGroup_Impl.hpp"
-#include "Space.hpp"
-#include "Space_Impl.hpp"
-#include "DefaultConstructionSet.hpp"
-#include "DefaultConstructionSet_Impl.hpp"
-#include "ShadingSurfaceGroup.hpp"
-#include "InteriorPartitionSurfaceGroup.hpp"
-
-#include "../utilities/core/Assert.hpp"
-#include "../utilities/core/Compare.hpp"
-#include "../utilities/geometry/Point3d.hpp"
-#include "../utilities/geometry/Plane.hpp"
-#include "../utilities/geometry/BoundingBox.hpp"
-#include "../utilities/geometry/Transformation.hpp"
-#include "../utilities/geometry/Geometry.hpp"
-#include "../utilities/geometry/Polygon3d.hpp"
-
-#define TINYGLTF_IMPLEMENTATION
-#define STB_IMAGE_IMPLEMENTATION
-#define STB_IMAGE_WRITE_IMPLEMENTATION
-
-#include <tiny_gltf.h>
-
-#include <algorithm>
-#include <cmath>
-#include <iterator>
-#include <numeric>
-#include <stack>
-#include <limits.h>
-#include <tuple>
-
-namespace openstudio {
-namespace model {
-
-  // TODO: pick one in your usage.
-  namespace GLTF = tinygltf;
-
-  // For raw values for GLTF Materials
-  struct MaterialData
-  {
-    std::string materialName;
-    int r;     // [0, 255]
-    int g;     // [0, 255]
-    int b;     // [0, 255]
-    double a;  // [0, 1]
-    bool isDoubleSided = false;
-  };
-
-  // glTF Extras Bounding Box
-  struct GltfBoundingBox
-  {
-    // all members will take a value of type double
-    std::tuple<std::string, tinygltf::Value> lookAtR;
-    std::tuple<std::string, tinygltf::Value> lookAtX;
-    std::tuple<std::string, tinygltf::Value> lookAtY;
-    std::tuple<std::string, tinygltf::Value> lookAtZ;
-    std::tuple<std::string, tinygltf::Value> maxX;
-    std::tuple<std::string, tinygltf::Value> maxY;
-    std::tuple<std::string, tinygltf::Value> maxZ;
-    std::tuple<std::string, tinygltf::Value> minX;
-    std::tuple<std::string, tinygltf::Value> minY;
-    std::tuple<std::string, tinygltf::Value> minZ;
-
-    void setlookAtR(double value) {
-      std::string key = "lookAtR";
-      tinygltf::Value extraNodeValue(value);
-      lookAtR = make_tuple(key, extraNodeValue);
-    }
-
-    void setlookAtX(double value) {
-      std::string key = "lookAtX";
-      tinygltf::Value extraNodeValue(value);
-      lookAtX = make_tuple(key, extraNodeValue);
-    }
-
-    void setlookAtY(double value) {
-      std::string key = "lookAtY";
-      tinygltf::Value extraNodeValue(value);
-      lookAtY = make_tuple(key, extraNodeValue);
-    }
-
-    void setlookAtZ(double value) {
-      std::string key = "lookAtZ";
-      tinygltf::Value extraNodeValue(value);
-      lookAtZ = make_tuple(key, extraNodeValue);
-    }
-
-    void setmaxX(double value) {
-      std::string key = "maxX";
-      tinygltf::Value extraNodeValue(value);
-      maxX = make_tuple(key, extraNodeValue);
-    }
-
-    void setmaxY(double value) {
-      std::string key = "maxY";
-      tinygltf::Value extraNodeValue(value);
-      maxY = make_tuple(key, extraNodeValue);
-    }
-
-    void setmaxZ(double value) {
-      std::string key = "maxZ";
-      tinygltf::Value extraNodeValue(value);
-      maxZ = make_tuple(key, extraNodeValue);
-    }
-
-    void setminX(double value) {
-      std::string key = "minX";
-      tinygltf::Value extraNodeValue(value);
-      minX = make_tuple(key, extraNodeValue);
-    }
-
-    void setminY(double value) {
-      std::string key = "minY";
-      tinygltf::Value extraNodeValue(value);
-      minY = make_tuple(key, extraNodeValue);
-    }
-
-    void setminZ(double value) {
-      std::string key = "minZ";
-      tinygltf::Value extraNodeValue(value);
-      minZ = make_tuple(key, extraNodeValue);
-    }
-
-    // Getters
-    double getlookAtR() const {
-      tinygltf::Value v(std::get<1>(lookAtR));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getlookAtX() const {
-      tinygltf::Value v(std::get<1>(lookAtX));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getlookAtY() const {
-      tinygltf::Value v(std::get<1>(lookAtY));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getlookAtZ() const {
-      tinygltf::Value v(std::get<1>(lookAtZ));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getmaxX() const {
-      tinygltf::Value v(std::get<1>(maxX));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getmaxY() const {
-      tinygltf::Value v(std::get<1>(maxY));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getmaxZ() const {
-      tinygltf::Value v(std::get<1>(maxZ));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getminX() const {
-      tinygltf::Value v(std::get<1>(minX));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getminY() const {
-      tinygltf::Value v(std::get<1>(minY));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-
-    double getminZ() const {
-      tinygltf::Value v(std::get<1>(minZ));
-      double valueD = v.Get<double>();
-      return valueD;
-    }
-  };
-
-  class GltfModelObjectMetadata
-  {
-   public:
-    GltfModelObjectMetadata() {
-      // Initialize all attributes with defaults
-      initializeAttributesWithDefaults();
-    }
-
-    void setColor(std::string value) {
-      std::string key = "color";
-      tinygltf::Value extraNodeValue(value);
-      color = make_tuple(key, extraNodeValue);
-    }
-
-    void setHandle(std::string value) {
-      std::string key = "handle";
-      tinygltf::Value extraNodeValue(value);
-      handle = make_tuple(key, extraNodeValue);
-    }
-
-    void setIddObjectType(std::string value) {
-      std::string key = "iddObjectType";
-      tinygltf::Value extraNodeValue(value);
-      iddObjectType = make_tuple(key, extraNodeValue);
-    }
-
-    void setName(std::string value) {
-      std::string key = "name";
-      tinygltf::Value extraNodeValue(value);
-      name = make_tuple(key, extraNodeValue);
-    }
-
-    void setOpen_to_below(bool value) {
-      std::string key = "open_to_below";
-      tinygltf::Value extraNodeValue(value);
-      open_to_below = make_tuple(key, extraNodeValue);
-    }
-
-    void setNominal_z_coordinate(double value) {
-      std::string key = "nominal_z_coordinate";
-      tinygltf::Value extraNodeValue(value);
-      nominal_z_coordinate = make_tuple(key, extraNodeValue);
-    }
-
-    void setNominal_floorCeiling_Height(double value) {
-      std::string key = "nominal_floorCeiling_Height";
-      tinygltf::Value extraNodeValue(value);
-      nominal_floorCeiling_Height = make_tuple(key, extraNodeValue);
-    }
-
-    void setMultiplier(int value) {
-      std::string key = "multiplier";
-      tinygltf::Value extraNodeValue(value);
-      multiplier = make_tuple(key, extraNodeValue);
-    }
-
-    //
-
-    void setColor(tinygltf::Value value) {
-      std::string key = "color";
-      color = make_tuple(key, value);
-    }
-
-    void setHandle(tinygltf::Value value) {
-      std::string key = "handle";
-      handle = make_tuple(key, value);
-    }
-
-    void setIddObjectType(tinygltf::Value value) {
-      std::string key = "iddObjectType";
-      iddObjectType = make_tuple(key, value);
-    }
-
-    void setName(tinygltf::Value value) {
-      std::string key = "name";
-      name = make_tuple(key, value);
-    }
-
-    void setMultiplier(tinygltf::Value value) {
-      std::string key = "multiplier";
-      multiplier = make_tuple(key, value);
-    }
-
-    void setOpen_to_below(tinygltf::Value value) {
-      std::string key = "open_to_below";
-      open_to_below = make_tuple(key, value);
-    }
-
-    void setNominal_z_coordinate(tinygltf::Value value) {
-      std::string key = "nominal_z_coordinate";
-      nominal_z_coordinate = make_tuple(key, value);
-    }
-
-    void setNominal_floorCeiling_Height(tinygltf::Value value) {
-      std::string key = "nominal_floorCeiling_Height";
-      nominal_floorCeiling_Height = make_tuple(key, value);
-    }
-
-    std::map<std::string, tinygltf::Value> modelObjectMap;
-    void InitializeModelObjectMap() {
-      /*   tinygltf::Value extraNodeValue(toString(""));
-      modelObjectMap.insert({"multiplier", extraNodeValue});*/
-
-      //modelObjectMap.insert({std::get<0>(color), std::get<1>(color)});
-      /* modelObjectMap.insert({std::get<0>(handle), std::get<1>(handle)});
-      modelObjectMap.insert({std::get<0>(iddObjectType), std::get<1>(iddObjectType)});
-      modelObjectMap.insert({std::get<0>(name), std::get<1>(name)});
-      modelObjectMap.insert({std::get<0>(open_to_below), std::get<1>(open_to_below)});
-      modelObjectMap.insert({std::get<0>(nominal_z_coordinate), std::get<1>(nominal_z_coordinate)});
-      modelObjectMap.insert({std::get<0>(nominal_floorCeiling_Height), std::get<1>(nominal_floorCeiling_Height)});*/
-      //modelObjectMap.insert({std::get<0>(multiplier), std::get<1>(multiplier)});
-
-      /* auto insColor = modelObjectMap.insert(std::make_pair("color", 0));
-      insColor.first->second = std::get<1>(color);*/
-      /* auto insMultiplier = modelObjectMap.insert(std::make_pair("multiplier", 0));
-      insMultiplier.first->second = std::get<1>(multiplier);*/
-
-      modelObjectMap["color"] = std::get<1>(color);
-      modelObjectMap["handle"] = std::get<1>(handle);
-      modelObjectMap["iddObjectType"] = std::get<1>(iddObjectType);
-      modelObjectMap["name"] = std::get<1>(name);
-      modelObjectMap["open_to_below"] = std::get<1>(open_to_below);
-      modelObjectMap["nominal_z_coordinate"] = std::get<1>(nominal_z_coordinate);
-      modelObjectMap["nominal_floorCeiling_Height"] = std::get<1>(nominal_floorCeiling_Height);
-      modelObjectMap["multiplier"] = std::get<1>(multiplier);
-
-      /* if (!modelObjectMap.count("open_to_below")) {
-        tinygltf::Value extraNodeValue(false);
-        modelObjectMap.insert({"open_to_below", extraNodeValue});
-      }*/
-
-      /* if (!modelObjectMap.count("multiplier")) {
-        tinygltf::Value extraNodeValue(toString(""));
-        modelObjectMap.insert({"multiplier", extraNodeValue});
-      }*/
-    }
-
-    // getters
-
-    std::string getIddObjectType() const {
-      tinygltf::Value v(std::get<1>(iddObjectType));
-      std::string strVal = v.Get<std::string>().c_str();
-      return strVal;
-    }
-
-   private:
-    // string
-    std::tuple<std::string, tinygltf::Value> color;
-    std::tuple<std::string, tinygltf::Value> handle;
-    std::tuple<std::string, tinygltf::Value> iddObjectType;
-    std::tuple<std::string, tinygltf::Value> name;
-
-    // bool
-    std::tuple<std::string, tinygltf::Value> open_to_below;
-
-    // double
-    std::tuple<std::string, tinygltf::Value> nominal_z_coordinate;
-    std::tuple<std::string, tinygltf::Value> nominal_floorCeiling_Height;
-
-    // int
-    std::tuple<std::string, tinygltf::Value> multiplier;
-
-    void initializeAttributesWithDefaults() {
-      setColor("");
-      setHandle("");
-      setIddObjectType("");
-      setName("");
-      setOpen_to_below(false);
-      setNominal_z_coordinate(0.0);
-      setNominal_floorCeiling_Height(0.0);
-      setMultiplier(0);
-    }
-  };
-
-  // MetaData as glTF Extras
-  class GltfMetaData
-  {
-   public:
-    GltfMetaData() {
-      resetModelObjectMetaDataCount();
-    }
-
-    void resetModelObjectMetaDataCount() {
-      storyCount = 0;
-      thermalZoneCount = 0;
-      spaceCount = 0;
-      spaceTypeCount = 0;
-      constructionSetCount = 0;
-      airLoopCount = 0;
-    }
-
-    std::map<std::string, tinygltf::Value> metaData;
-
-    double getBoundingBoxlookAtR() {
-      return glTFBoundingBox.getlookAtR();
-    }
-
-    double getBoundingBoxlookAtX() {
-      return glTFBoundingBox.getlookAtX();
-    }
-
-    double getBoundingBoxlookAtY() {
-      return glTFBoundingBox.getlookAtY();
-    }
-
-    double getBoundingBoxlookAtZ() {
-      return glTFBoundingBox.getlookAtZ();
-    }
-
-    double getBoundingBoxmaxX() {
-      return glTFBoundingBox.getmaxX();
-    }
-
-    double getBoundingBoxmaxY() {
-      return glTFBoundingBox.getmaxY();
-    }
-
-    double getBoundingBoxmaxZ() {
-      return glTFBoundingBox.getmaxZ();
-    }
-
-    double getBoundingBoxminZ() {
-      return glTFBoundingBox.getminZ();
-    }
-
-    double getBoundingBoxminX() {
-      return glTFBoundingBox.getminX();
-    }
-
-    double getBoundingBoxminY() {
-      return glTFBoundingBox.getminY();
-    }
-
-    std::vector<GltfModelObjectMetadata> getModelObjectMetaDataCollection() {
-      return glTFModelObjectMetadataVector;
-    }
-
-    void setBoundingBox(tinygltf::Value value) {
-      auto boundingBoxObj = value.Get<std::map<std::string, tinygltf::Value>>();
-      for (auto const& x : boundingBoxObj) {
-        std::string key = x.first;
-        if (key == "lookAtR") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setlookAtR(vv);
-        } else if (key == "lookAtX") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setlookAtX(vv);
-        } else if (key == "lookAtY") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setlookAtY(vv);
-        } else if (key == "lookAtZ") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setlookAtZ(vv);
-        } else if (key == "maxX") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setmaxX(vv);
-        } else if (key == "maxY") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setmaxY(vv);
-        } else if (key == "maxZ") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setmaxZ(vv);
-        } else if (key == "minX") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setminX(vv);
-        } else if (key == "minY") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setminY(vv);
-        } else if (key == "minZ") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          glTFBoundingBox.setminZ(vv);
-        }
-      }
-    }
-
-    void setBoundingBox(const std::vector<PlanarSurfaceGroup>& planarSurfaceGroups, std::function<void(double)> updatePercentage, double& n,
-                        std::vector<PlanarSurface>::size_type& N) {
-      // Bounding Box
-      std::map<std::string, tinygltf::Value> boundingBoxObject;
-      BoundingBox boundingBox;
-      boundingBox.addPoint(Point3d(0, 0, 0));
-      boundingBox.addPoint(Point3d(1, 1, 1));
-      for (const auto& group : planarSurfaceGroups) {
-        boundingBox.add(group.transformation() * group.boundingBox());
-
-        n += 1;
-        updatePercentage(100.0 * n / N);
-      }
-
-      double lookAtX = 0;  // (boundingBox.minX().get() + boundingBox.maxX().get()) / 2.0
-      double lookAtY = 0;  // (boundingBox.minY().get() + boundingBox.maxY().get()) / 2.0
-      double lookAtZ = 0;  // (boundingBox.minZ().get() + boundingBox.maxZ().get()) / 2.0
-      double lookAtR =
-        sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2) + std::pow(boundingBox.maxZ().get() / 2.0, 2));
-      lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2)
-                                       + std::pow(boundingBox.maxZ().get() / 2.0, 2)));
-      lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
-                                       + std::pow(boundingBox.maxZ().get() / 2.0, 2)));
-      lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2)
-                                       + std::pow(boundingBox.minZ().get() / 2.0, 2)));
-      lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
-                                       + std::pow(boundingBox.maxZ().get() / 2.0, 2)));
-      lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.maxY().get() / 2.0, 2)
-                                       + std::pow(boundingBox.minZ().get() / 2.0, 2)));
-      lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.maxX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
-                                       + std::pow(boundingBox.minZ().get() / 2.0, 2)));
-      lookAtR = std::max(lookAtR, sqrt(std::pow(boundingBox.minX().get() / 2.0, 2) + std::pow(boundingBox.minY().get() / 2.0, 2)
-                                       + std::pow(boundingBox.minZ().get() / 2.0, 2)));
-
-      /*   std::map<std::string, tinygltf::Value> bbObj;*/
-      /*BoundingBoxglTF boundingBoxglTF;*/
-      glTFBoundingBox.setlookAtR(lookAtR);
-      glTFBoundingBox.setlookAtX(lookAtX);
-      glTFBoundingBox.setlookAtY(lookAtY);
-      glTFBoundingBox.setlookAtZ(lookAtZ);
-      glTFBoundingBox.setmaxX(boundingBox.maxX().get());
-      glTFBoundingBox.setmaxY(boundingBox.maxY().get());
-      glTFBoundingBox.setmaxZ(boundingBox.maxZ().get());
-      glTFBoundingBox.setminX(boundingBox.minX().get());
-      glTFBoundingBox.setminY(boundingBox.minY().get());
-      glTFBoundingBox.setminZ(boundingBox.minZ().get());
-
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.lookAtR), std::get<1>(glTFBoundingBox.lookAtR)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.lookAtX), std::get<1>(glTFBoundingBox.lookAtX)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.lookAtY), std::get<1>(glTFBoundingBox.lookAtY)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.lookAtZ), std::get<1>(glTFBoundingBox.lookAtZ)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.maxX), std::get<1>(glTFBoundingBox.maxX)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.maxY), std::get<1>(glTFBoundingBox.maxY)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.maxZ), std::get<1>(glTFBoundingBox.maxZ)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.minX), std::get<1>(glTFBoundingBox.minX)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.minY), std::get<1>(glTFBoundingBox.minY)});
-      boundingBoxObject.insert({std::get<0>(glTFBoundingBox.minZ), std::get<1>(glTFBoundingBox.minZ)});
-
-      tinygltf::Value bbObj(boundingBoxObject);
-      metaData.insert({"boundingbox", bbObj});
-    }
-
-    void setBuildingStoryNames(const std::vector<BuildingStory>& buildingStories, std::function<void(double)> updatePercentage, double& n,
-                               std::vector<PlanarSurface>::size_type& N) {
-      std::vector<std::string> buildingStoryNames;
-      for (const auto& buildingStory : buildingStories) {
-        buildingStoryNames.push_back(buildingStory.nameString());
-      }
-      std::sort(buildingStoryNames.begin(), buildingStoryNames.end(), IstringCompare());
-      std::map<std::string, tinygltf::Value> bObj;
-      int storyCount = 0;
-      for (const auto& buildingStoryName : buildingStoryNames) {
-        tinygltf::Value buildingStoryNameValue(buildingStoryName);
-        bObj.insert({std::to_string(storyCount), buildingStoryNameValue});
-        storyCount++;
-      }
-      tinygltf::Value buildingStoryNamesObj(bObj);
-      metaData.insert({"buildingStoryNames", buildingStoryNamesObj});
-    }
-
-    void setGenerator(std::string value) {
-      std::string key = "generator";
-      tinygltf::Value generatorExtraNodeValue(static_cast<std::string>(value));
-      generator = make_tuple(key, generatorExtraNodeValue);
-    }
-
-    void setType(std::string value) {
-      std::string key = "type";
-      tinygltf::Value typeExtraNodeValue(static_cast<std::string>(value));
-      type = make_tuple(key, typeExtraNodeValue);
-    }
-
-    void setVersion(std::string value) {
-      std::string key = "version";
-      tinygltf::Value versionExtraNodeValue(value);  // TODO:BPS what is this version and where to get it from..
-      version = make_tuple(key, versionExtraNodeValue);
-    }
-
-    void setNorthAxis(const Model& model) {
-      std::string key = "northAxis";
-      double northAxisValue = 0.0;
-      boost::optional<Building> building = model.getOptionalUniqueModelObject<Building>();
-      if (building) {
-        northAxisValue = -building->northAxis();
-      }
-      tinygltf::Value northAxisExtraNodeValue(northAxisValue);
-      northAxis = make_tuple(key, northAxisExtraNodeValue);
-    }
-
-    void setNorthAxis(double value) {
-      std::string key = "northAxis";
-      tinygltf::Value northAxisExtraNodeValue(value);
-      northAxis = make_tuple(key, northAxisExtraNodeValue);
-    }
-
-    void setModelObjectMetaDataForStories(const std::vector<BuildingStory>& buildingStories, std::function<void(double)> updatePercentage, double& n,
-                                          std::vector<PlanarSurface>::size_type& N) {
-      for (const auto& buildingStory : buildingStories) {
-        GltfModelObjectMetadata modelObjectMetadataglTF;
-        if (buildingStory.renderingColor()) {
-          modelObjectMetadataglTF.setColor(buildingStory.renderingColor()->colorString());
-        }
-        modelObjectMetadataglTF.setHandle(toString(buildingStory.handle()));
-        modelObjectMetadataglTF.setIddObjectType(buildingStory.iddObjectType().valueDescription());
-        modelObjectMetadataglTF.setName(buildingStory.nameString());
-        if (buildingStory.nominalZCoordinate()) {
-          modelObjectMetadataglTF.setNominal_z_coordinate(buildingStory.nominalZCoordinate().get());
-        }
-        // TBD: Do we have to include this ?
-        if (buildingStory.nominalFloortoCeilingHeight()) {
-          modelObjectMetadataglTF.setNominal_floorCeiling_Height(buildingStory.nominalFloortoCeilingHeight().get());
-        }
-        // TBD: How to calculate this ?
-        modelObjectMetadataglTF.setOpen_to_below(false);
-
-        if (buildingStory.nominalFloortoFloorHeight()) {
-          // DLM: how to translate this?
-        }
-
-        storyCount++;
-        glTFModelObjectMetadataVector.push_back(modelObjectMetadataglTF);
-
-        for (const auto& space : buildingStory.spaces()) {
-          GltfModelObjectMetadata modelObjectMetadataglTF;
-          // TBD: color is always empty for Space ?
-          modelObjectMetadataglTF.setColor(toString(""));
-          modelObjectMetadataglTF.setHandle(toString(space.handle()));
-          modelObjectMetadataglTF.setIddObjectType(space.iddObjectType().valueDescription());
-          modelObjectMetadataglTF.setName(space.nameString());
-          // TBD: open_to_below is always false for Space ?
-          modelObjectMetadataglTF.setOpen_to_below(false);
-
-          spaceCount++;
-          glTFModelObjectMetadataVector.push_back(modelObjectMetadataglTF);
-        }
-
-        n += 1;
-        updatePercentage(100.0 * n / N);
-      }
-    }
-
-    void setModelObjectMetaDataForBuildingUnits(const std::vector<BuildingUnit>& buildingUnits, std::function<void(double)> updatePercentage,
-                                                double& n, std::vector<PlanarSurface>::size_type& N) {
-      for (const auto& buildingUnit : buildingUnits) {
-        GltfModelObjectMetadata modelObjectMetadataglTF;
-        if (buildingUnit.renderingColor()) {
-          modelObjectMetadataglTF.setColor(buildingUnit.renderingColor()->colorString());
-        }
-        modelObjectMetadataglTF.setHandle(toString(buildingUnit.handle()));
-        modelObjectMetadataglTF.setIddObjectType(buildingUnit.iddObjectType().valueDescription());
-        modelObjectMetadataglTF.setName(buildingUnit.nameString());
-        // TBD: how to calculate open_to_below for building unit ??
-        modelObjectMetadataglTF.setOpen_to_below(false);
-
-        glTFModelObjectMetadataVector.push_back(modelObjectMetadataglTF);
-
-        n += 1;
-        updatePercentage(100.0 * n / N);
-      }
-    }
-
-    void setModelObjectMetaDataForThermalZones(const std::vector<ThermalZone>& thermalZones, std::function<void(double)> updatePercentage, double& n,
-                                               std::vector<PlanarSurface>::size_type& N) {
-      for (const auto& thermalZone : thermalZones) {
-        GltfModelObjectMetadata modelObjectMetadataglTF;
-        if (thermalZone.renderingColor()) {
-          modelObjectMetadataglTF.setColor(thermalZone.renderingColor()->colorString());
-        }
-        modelObjectMetadataglTF.setHandle(toString(thermalZone.handle()));
-        modelObjectMetadataglTF.setIddObjectType(thermalZone.iddObjectType().valueDescription());
-        modelObjectMetadataglTF.setName(thermalZone.nameString());
-        // TBD: how to calculate open_to_below for thermal Zone ??
-        modelObjectMetadataglTF.setOpen_to_below(false);
-
-        modelObjectMetadataglTF.setMultiplier(thermalZone.multiplier());
-
-        thermalZoneCount++;
-        glTFModelObjectMetadataVector.push_back(modelObjectMetadataglTF);
-
-        n += 1;
-        updatePercentage(100.0 * n / N);
-      }
-    }
-
-    void setModelObjectMetaDataForSpaceTypes(const std::vector<SpaceType>& spaceTypes, std::function<void(double)> updatePercentage, double& n,
-                                             std::vector<PlanarSurface>::size_type& N) {
-      for (const auto& spaceType : spaceTypes) {
-        GltfModelObjectMetadata modelObjectMetadataglTF;
-        if (spaceType.renderingColor()) {
-          modelObjectMetadataglTF.setColor(spaceType.renderingColor()->colorString());
-        }
-        modelObjectMetadataglTF.setHandle(toString(spaceType.handle()));
-        modelObjectMetadataglTF.setIddObjectType(spaceType.iddObjectType().valueDescription());
-        modelObjectMetadataglTF.setName(spaceType.nameString());
-        // TBD: how to calculate open_to_below for thermal Zone ??
-        modelObjectMetadataglTF.setOpen_to_below(false);
-
-        spaceTypeCount++;
-        glTFModelObjectMetadataVector.push_back(modelObjectMetadataglTF);
-
-        n += 1;
-        updatePercentage(100.0 * n / N);
-      }
-    }
-
-    void setModelObjectMetaDataFordefaultConstructionSets(const std::vector<DefaultConstructionSet>& defaultConstructionSets,
-                                                          std::function<void(double)> updatePercentage, double& n,
-                                                          std::vector<PlanarSurface>::size_type& N) {
-      for (const auto& defaultConstructionSet : defaultConstructionSets) {
-        GltfModelObjectMetadata modelObjectMetadataglTF;
-
-        modelObjectMetadataglTF.setColor(toString(""));
-        modelObjectMetadataglTF.setHandle(toString(defaultConstructionSet.handle()));
-        modelObjectMetadataglTF.setIddObjectType(defaultConstructionSet.iddObjectType().valueDescription());
-        modelObjectMetadataglTF.setName(defaultConstructionSet.nameString());
-        // TBD: how to calcualte open_to_below for defaultConstructionSet or remove this node ?
-        modelObjectMetadataglTF.setOpen_to_below(false);
-
-        constructionSetCount++;
-        glTFModelObjectMetadataVector.push_back(modelObjectMetadataglTF);
-
-        n += 1;
-        updatePercentage(100.0 * n / N);
-      }
-    }
-
-    void setModelObjectMetaDataForAirLoopHVACs(const std::vector<AirLoopHVAC>& airLoopHVACs, std::function<void(double)> updatePercentage, double& n,
-                                               std::vector<PlanarSurface>::size_type& N) {
-      for (const auto& airLoopHVAC : airLoopHVACs) {
-        GltfModelObjectMetadata modelObjectMetadataglTF;
-
-        modelObjectMetadataglTF.setColor(toString(""));
-        modelObjectMetadataglTF.setHandle(toString(airLoopHVAC.handle()));
-        modelObjectMetadataglTF.setIddObjectType(airLoopHVAC.iddObjectType().valueDescription());
-        modelObjectMetadataglTF.setName(airLoopHVAC.nameString());
-        //TBD:
-        modelObjectMetadataglTF.setOpen_to_below(false);
-
-        airLoopCount++;
-        glTFModelObjectMetadataVector.push_back(modelObjectMetadataglTF);
-
-        n += 1;
-        updatePercentage(100.0 * n / N);
-      }
-    }
-
-    void InitializeModelObject() {
-      int modelObjectKeyCount = 0;
-      std::map<std::string, tinygltf::Value> modelObj1;
-      for (GltfModelObjectMetadata modelObjectglTFMetaData : glTFModelObjectMetadataVector) {
-        modelObjectglTFMetaData.InitializeModelObjectMap();
-        tinygltf::Value alhObj(modelObjectglTFMetaData.modelObjectMap);
-        modelObj1.insert({std::to_string(modelObjectKeyCount), alhObj});
-        modelObjectKeyCount++;
-      }
-      tinygltf::Value mmObj(modelObj1);
-      metaData.insert({"modelObjectMetaData", mmObj});
-      metaData.insert({std::get<0>(generator), std::get<1>(generator)});
-      metaData.insert({std::get<0>(type), std::get<1>(type)});
-      metaData.insert({std::get<0>(version), std::get<1>(version)});
-      metaData.insert({std::get<0>(northAxis), std::get<1>(northAxis)});
-    }
-
-    void initializeFromSceneExtras(tinygltf::Scene scene) {
-      metaData = scene.extras.Get<std::map<std::string, tinygltf::Value>>();
-      // auto aaextra = gltf_Model.scenes[0].extras_json_string;
-
-      for (auto const& x : metaData) {
-        std::string key = x.first;
-        if (key == "generator") {
-          tinygltf::Value v(x.second);
-          auto vv = v.Get<std::string>().c_str();
-          setGenerator(vv);
-        } else if (key == "type") {
-          tinygltf::Value v(x.second);
-          auto vv = v.Get<std::string>().c_str();
-          setType(vv);
-        } else if (key == "northAxis") {
-          tinygltf::Value v(x.second);
-          double vv = v.Get<double>();
-          setNorthAxis(vv);
-        } else if (key == "version") {
-          tinygltf::Value v(x.second);
-          auto vv = v.Get<std::string>().c_str();
-          setVersion(vv);
-        } else if (key == "boundingbox") {
-          tinygltf::Value v(x.second);
-          setBoundingBox(v);
-        } else if (key == "modelObjectMetaData") {
-          tinygltf::Value v(x.second);
-          setModelObjectMetaData(v);
-        }
-      }
-    }
-
-    void setModelObjectMetaData(tinygltf::Value value) {
-      auto modelObjectMetatDataVector = value.Get<tinygltf::Value::Object>();
-      int countKey = 0;
-      for (auto const& x : modelObjectMetatDataVector) {
-        GltfModelObjectMetadata gltfModelObjectMetadata;
-        auto key = x.first;
-        tinygltf::Value v(x.second);
-        auto modelObjectMetaData1 = v.Get<tinygltf::Value::Object>();
-        for (auto const& y : modelObjectMetaData1) {
-          auto key1 = y.first;
-          tinygltf::Value v1(y.second);
-          if (key1 == "color") {
-            gltfModelObjectMetadata.setColor(y.second);
-          } else if (key1 == "handle") {
-            gltfModelObjectMetadata.setHandle(y.second);
-          } else if (key1 == "iddObjectType") {
-            gltfModelObjectMetadata.setIddObjectType(y.second);
-          } else if (key1 == "name") {
-            gltfModelObjectMetadata.setName(y.second);
-          } else if (key1 == "multiplier") {
-            gltfModelObjectMetadata.setMultiplier(y.second);
-          } else if (key1 == "open_to_below") {
-            gltfModelObjectMetadata.setOpen_to_below(y.second);
-          } else if (key1 == "nominal_z_coordinate") {
-            gltfModelObjectMetadata.setNominal_z_coordinate(y.second);
-          } else if (key1 == "nominal_floorCeiling_Height") {
-            gltfModelObjectMetadata.setNominal_floorCeiling_Height(y.second);
-          }
-        }
-        std::string iddObjectTypeStr = gltfModelObjectMetadata.getIddObjectType();
-        if (iddObjectTypeStr == "OS:BuildingStory") {
-          storyCount++;
-        } else if (iddObjectTypeStr == "OS:Space") {
-          spaceCount++;
-        } else if (iddObjectTypeStr == "OS:ThermalZone") {
-          thermalZoneCount++;
-        } else if (iddObjectTypeStr == "OS:SpaceType") {
-          spaceTypeCount++;
-        } else if (iddObjectTypeStr == "OS:DefaultConstructionSet") {
-          constructionSetCount++;
-        } else if (iddObjectTypeStr.compare("OS:AirLoopHVAC") == 0) {
-          airLoopCount++;
-        }
-        glTFModelObjectMetadataVector.push_back(gltfModelObjectMetadata);
-        countKey++;
-      }
-    }
-
-    std::string getGenerator() const {
-      tinygltf::Value v(std::get<1>(generator));
-      std::string generatorStr = v.Get<std::string>().c_str();
-      return generatorStr;
-    }
-
-    std::string getType() const {
-      tinygltf::Value v(std::get<1>(type));
-      std::string typeStr = v.Get<std::string>().c_str();
-      return typeStr;
-    }
-
-    std::string getVersion() const {
-      tinygltf::Value v(std::get<1>(version));
-      std::string versionStr = v.Get<std::string>().c_str();
-      return versionStr;
-    }
-
-    double getNorthAxis() const {
-      tinygltf::Value v(std::get<1>(northAxis));
-      double northAxisd = v.Get<double>();
-      return northAxisd;
-    }
-
-    int getStoryCount() {
-      return storyCount;
-    }
-
-    int getThermalZoneCount() {
-      return thermalZoneCount;
-    }
-
-    int getSpaceCount() {
-      return spaceCount;
-    }
-
-    int getSpaceTypeCount() {
-      return spaceTypeCount;
-    }
-
-    int getConstructionSetCount() {
-      return constructionSetCount;
-    }
-
-    int getAirLoopCount() {
-      return airLoopCount;
-    }
-
-   private:
-    std::vector<GltfModelObjectMetadata> glTFModelObjectMetadataVector;
-    GltfBoundingBox glTFBoundingBox;
-    std::vector<std::string> buildingStoryNames;
-
-    // string
-    std::tuple<std::string, tinygltf::Value> generator;
-    std::tuple<std::string, tinygltf::Value> type;
-    std::tuple<std::string, tinygltf::Value> version;
-    // double
-    std::tuple<std::string, tinygltf::Value> northAxis;
-
-    int storyCount;
-    int thermalZoneCount;
-    int spaceCount;
-    int spaceTypeCount;
-    int constructionSetCount;
-    int airLoopCount;
-  };
-
-  // UserData as glTF Extras
-  class GltfUserData
-  {
-   public:
-    GltfUserData() {
-      // Initialize all attributes with defaults
-      initializeAttributesWithDefaults();
-    }
-    // m_handle;
-    std::string handlekey = "handle";
-    void setHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      handle = make_tuple(handlekey, extraNodeValue);
-    }
-
-    void setHandle(tinygltf::Value value) {
-      handle = make_tuple(handlekey, value);
-    }
-
-    // m_name;
-    std::string namekey = "name";
-    void setName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      name = make_tuple(namekey, extraNodeValue);
-    }
-
-    void setName(tinygltf::Value value) {
-      name = make_tuple(namekey, value);
-    }
-
-    // m_surfaceType;
-    std::string surfaceTypekey = "surfaceType";
-    void setSurfaceType(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      surfaceType = make_tuple(surfaceTypekey, extraNodeValue);
-    }
-
-    void setSurfaceType(tinygltf::Value value) {
-      surfaceType = make_tuple(surfaceTypekey, value);
-    }
-
-    // m_surfaceTypeMaterialName;
-    std::string surfaceTypeMaterailNamekey = "surfaceTypeMaterailName";
-    void setSurfaceTypeMaterailName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      surfaceTypeMaterailName = make_tuple(surfaceTypeMaterailNamekey, extraNodeValue);
-    }
-
-    void setSurfaceTypeMaterailName(tinygltf::Value value) {
-      surfaceTypeMaterailName = make_tuple(surfaceTypeMaterailNamekey, value);
-    }
-
-    // m_constructionName;
-    std::string constructionNamekey = "constructionName";
-    void setConstructionName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      constructionName = make_tuple(constructionNamekey, extraNodeValue);
-    }
-
-    void setConstructionName(tinygltf::Value value) {
-      constructionName = make_tuple(constructionNamekey, value);
-    }
-
-    // m_constructionHandle;
-    std::string constructionHandlekey = "constructionHandle";
-    void setConstructionHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      constructionHandle = make_tuple(constructionHandlekey, extraNodeValue);
-    }
-
-    void setConstructionHandle(tinygltf::Value value) {
-      constructionHandle = make_tuple(constructionHandlekey, value);
-    }
-
-    // m_constructionMaterialName;
-    std::string constructionMaterialNamekey = "constructionMaterialName";
-    void setConstructionMaterialName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      constructionMaterialName = make_tuple(constructionMaterialNamekey, extraNodeValue);
-    }
-
-    void setConstructionMaterialName(tinygltf::Value value) {
-      constructionMaterialName = make_tuple(constructionMaterialNamekey, value);
-    }
-
-    // m_surfaceName;
-    std::string surfaceNamekey = "surfaceName";
-    void setSurfaceName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      surfaceName = make_tuple(surfaceNamekey, extraNodeValue);
-    }
-
-    void setSurfaceName(tinygltf::Value value) {
-      surfaceName = make_tuple(surfaceNamekey, value);
-    }
-
-    // m_surfaceHandle;
-    std::string surfaceHandlekey = "surfaceHandle";
-    void setSurfaceHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      surfaceHandle = make_tuple(surfaceHandlekey, extraNodeValue);
-    }
-
-    void setSurfaceHandle(tinygltf::Value value) {
-      surfaceHandle = make_tuple(surfaceHandlekey, value);
-    }
-
-    // m_subSurfaceName;
-    std::string subSurfaceNamekey = "subSurfaceName";
-    void setSubSurfaceName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      subSurfaceName = make_tuple(subSurfaceNamekey, extraNodeValue);
-    }
-
-    void setSubSurfaceName(tinygltf::Value value) {
-      subSurfaceName = make_tuple(subSurfaceNamekey, value);
-    }
-
-    // m_subSurfaceHandle;
-    std::string subSurfaceHandlekey = "subSurfaceHandle";
-    void setSubSurfaceHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      subSurfaceHandle = make_tuple(subSurfaceHandlekey, extraNodeValue);
-    }
-
-    void setSubSurfaceHandle(tinygltf::Value value) {
-      subSurfaceHandle = make_tuple(subSurfaceHandlekey, value);
-    }
-
-    // m_spaceName;
-    std::string spaceNamekey = "spaceName";
-    void setSpaceName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      spaceName = make_tuple(spaceNamekey, extraNodeValue);
-    }
-
-    void setSpaceName(tinygltf::Value value) {
-      spaceName = make_tuple(spaceNamekey, value);
-    }
-
-    // m_spaceHandle;
-    std::string spaceHandlekey = "spaceHandle";
-    void setSpaceHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      spaceHandle = make_tuple(spaceHandlekey, extraNodeValue);
-    }
-
-    void setSpaceHandle(tinygltf::Value value) {
-      spaceHandle = make_tuple(spaceHandlekey, value);
-    }
-
-    // m_shadingName
-    std::string shadingNamekey = "shadingName";
-    void setShadingName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      shadingName = make_tuple(shadingNamekey, extraNodeValue);
-    }
-
-    void setShadingName(tinygltf::Value value) {
-      shadingName = make_tuple(shadingNamekey, value);
-    }
-
-    // m_shadingHandle;
-    std::string shadingHandlekey = "shadingHandle";
-    void setShadingHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      shadingHandle = make_tuple(shadingHandlekey, extraNodeValue);
-    }
-
-    void setShadingHandle(tinygltf::Value value) {
-      shadingHandle = make_tuple(shadingHandlekey, value);
-    }
-
-    // m_thermalZoneName;
-    std::string thermalZoneNamekey = "thermalZoneName";
-    void setThermalZoneName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      thermalZoneName = make_tuple(thermalZoneNamekey, extraNodeValue);
-    }
-
-    void setThermalZoneName(tinygltf::Value value) {
-      thermalZoneName = make_tuple(thermalZoneNamekey, value);
-    }
-
-    // m_thermalZoneHandle;
-    std::string thermalZoneHandlekey = "thermalZoneHandle";
-    void setThermalZoneHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      thermalZoneHandle = make_tuple(thermalZoneHandlekey, extraNodeValue);
-    }
-
-    void setThermalZoneHandle(tinygltf::Value value) {
-      thermalZoneHandle = make_tuple(thermalZoneHandlekey, value);
-    }
-
-    // m_thermalZoneMaterialName;
-    std::string thermalZoneMaterialNamekey = "thermalZoneMaterialName";
-    void setThermalZoneMaterialName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      thermalZoneMaterialName = make_tuple(thermalZoneMaterialNamekey, extraNodeValue);
-    }
-
-    void setThermalZoneMaterialName(tinygltf::Value value) {
-      thermalZoneMaterialName = make_tuple(thermalZoneMaterialNamekey, value);
-    }
-
-    // m_spaceTypeName;
-    std::string spaceTypeNamekey = "spaceTypeName";
-    void setSpaceTypeName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      spaceTypeName = make_tuple(spaceTypeNamekey, extraNodeValue);
-    }
-
-    void setSpaceTypeName(tinygltf::Value value) {
-      spaceTypeName = make_tuple(spaceTypeNamekey, value);
-    }
-
-    // m_spaceTypeHandle;
-    std::string spaceTypeHandlekey = "spaceTypeHandle";
-    void setSpaceTypeHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      spaceTypeHandle = make_tuple(spaceTypeHandlekey, extraNodeValue);
-    }
-
-    void setSpaceTypeHandle(tinygltf::Value value) {
-      spaceTypeHandle = make_tuple(spaceTypeHandlekey, value);
-    }
-
-    // m_spaceTypeMaterialName;
-    std::string spaceTypeMaterialNamekey = "spaceTypeMaterialName";
-    void setSpaceTypeMaterialName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      spaceTypeMaterialName = make_tuple(spaceTypeMaterialNamekey, extraNodeValue);
-    }
-
-    void setSpaceTypeMaterialName(tinygltf::Value value) {
-      spaceTypeMaterialName = make_tuple(spaceTypeMaterialNamekey, value);
-    }
-
-    // m_buildingStoryName;
-    std::string buildingStoryNamekey = "buildingStoryName";
-    void setBuildingStoryName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      buildingStoryName = make_tuple(buildingStoryNamekey, extraNodeValue);
-    }
-
-    void setBuildingStoryName(tinygltf::Value value) {
-      buildingStoryName = make_tuple(buildingStoryNamekey, value);
-    }
-
-    // m_buildingStoryHandle;
-    std::string buildingStoryHandlekey = "buildingStoryHandle";
-    void setBuildingStoryHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      buildingStoryHandle = make_tuple(buildingStoryHandlekey, extraNodeValue);
-    }
-
-    void setBuildingStoryHandle(tinygltf::Value value) {
-      buildingStoryHandle = make_tuple(buildingStoryHandlekey, value);
-    }
-
-    // m_buildingStoryMaterialName;
-    std::string buildingStoryMaterialNamekey = "buildingStoryMaterialName";
-    void setBuildingStoryMaterialName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      buildingStoryMaterialName = make_tuple(buildingStoryMaterialNamekey, extraNodeValue);
-    }
-
-    void setBuildingStoryMaterialName(tinygltf::Value value) {
-      buildingStoryMaterialName = make_tuple(buildingStoryMaterialNamekey, value);
-    }
-
-    // m_buildingUnitName;
-    std::string buildingUnitNamekey = "buildingUnitName";
-    void setBuildingUnitName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      buildingUnitName = make_tuple(buildingUnitNamekey, extraNodeValue);
-    }
-
-    void setBuildingUnitName(tinygltf::Value value) {
-      buildingUnitName = make_tuple(buildingUnitNamekey, value);
-    }
-
-    // m_buildingUnitHandle;
-    std::string buildingUnitHandlekey = "buildingUnitHandle";
-    void setBuildingUnitHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      buildingUnitHandle = make_tuple(buildingUnitHandlekey, extraNodeValue);
-    }
-
-    void setBuildingUnitHandle(tinygltf::Value value) {
-      buildingUnitHandle = make_tuple(buildingUnitHandlekey, value);
-    }
-
-    // m_buildingUnitMaterialName;
-    std::string buildingUnitMaterialNamekey = "buildingUnitMaterialName";
-    void setBuildingUnitMaterialName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      buildingUnitMaterialName = make_tuple(buildingUnitMaterialNamekey, extraNodeValue);
-    }
-
-    void setBuildingUnitMaterialName(tinygltf::Value value) {
-      buildingUnitMaterialName = make_tuple(buildingUnitMaterialNamekey, value);
-    }
-
-    // m_constructionSetName;
-    std::string constructionSetNamekey = "constructionSetName";
-    void setConstructionSetName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      constructionSetName = make_tuple(constructionSetNamekey, extraNodeValue);
-    }
-
-    void setConstructionSetName(tinygltf::Value value) {
-      constructionSetName = make_tuple(constructionSetNamekey, value);
-    }
-
-    // m_constructionSetHandle;
-    std::string constructionSetHandlekey = "constructionSetHandle";
-    void setConstructionSetHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      constructionSetHandle = make_tuple(constructionSetHandlekey, extraNodeValue);
-    }
-
-    void setConstructionSetHandle(tinygltf::Value value) {
-      constructionSetHandle = make_tuple(constructionSetHandlekey, value);
-    }
-
-    // m_constructionSetMaterialName;
-    std::string constructionSetMaterialNamekey = "constructionSetMaterialName";
-    void setConstructionSetMaterialName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      constructionSetMaterialName = make_tuple(constructionSetMaterialNamekey, extraNodeValue);
-    }
-
-    void setConstructionSetMaterialName(tinygltf::Value value) {
-      constructionSetMaterialName = make_tuple(constructionSetMaterialNamekey, value);
-    }
-
-    // m_outsideBoundaryCondition;
-    std::string outsideBoundaryConditionkey = "outsideBoundaryCondition";
-    void setOutsideBoundaryCondition(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      outsideBoundaryCondition = make_tuple(outsideBoundaryConditionkey, extraNodeValue);
-    }
-
-    void setOutsideBoundaryCondition(tinygltf::Value value) {
-      outsideBoundaryCondition = make_tuple(outsideBoundaryConditionkey, value);
-    }
-
-    // m_outsideBoundaryConditionObjectName;
-    std::string outsideBoundaryConditionObjectNamekey = "outsideBoundaryConditionObjectName";
-    void setOutsideBoundaryConditionObjectName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      outsideBoundaryConditionObjectName = make_tuple(outsideBoundaryConditionObjectNamekey, extraNodeValue);
-    }
-
-    void setOutsideBoundaryConditionObjectName(tinygltf::Value value) {
-      outsideBoundaryConditionObjectName = make_tuple(outsideBoundaryConditionObjectNamekey, value);
-    }
-
-    // m_outsideBoundaryConditionObjectHandle;
-    std::string outsideBoundaryConditionObjectHandlekey = "outsideBoundaryConditionObjectHandle";
-    void setOutsideBoundaryConditionObjectHandle(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      outsideBoundaryConditionObjectHandle = make_tuple(outsideBoundaryConditionObjectHandlekey, extraNodeValue);
-    }
-
-    void setOutsideBoundaryConditionObjectHandle(tinygltf::Value value) {
-      outsideBoundaryConditionObjectHandle = make_tuple(outsideBoundaryConditionObjectHandlekey, value);
-    }
-
-    // m_boundaryMaterialName;
-    std::string boundaryMaterialNamekey = "boundaryMaterialName";
-    void setBoundaryMaterialName(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      boundaryMaterialName = make_tuple(boundaryMaterialNamekey, extraNodeValue);
-    }
-
-    void setBoundaryMaterialName(tinygltf::Value value) {
-      boundaryMaterialName = make_tuple(boundaryMaterialNamekey, value);
-    }
-
-    // bool m_coincidentWithOutsideObject;
-    std::string coincidentWithOutsideObjectkey = "coincidentWithOutsideObject";
-    void setCoincidentWithOutsideObject(bool value) {
-      tinygltf::Value extraNodeValue(value);
-      coincidentWithOutsideObject = make_tuple(coincidentWithOutsideObjectkey, extraNodeValue);
-    }
-
-    void setCoincidentWithOutsideObject(tinygltf::Value value) {
-      coincidentWithOutsideObject = make_tuple(coincidentWithOutsideObjectkey, value);
-    }
-
-    // m_sunExposure;
-    std::string sunExposurekey = "sunExposure";
-    void setSunExposure(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      sunExposure = make_tuple(sunExposurekey, extraNodeValue);
-    }
-
-    void setSunExposure(tinygltf::Value value) {
-      sunExposure = make_tuple(sunExposurekey, value);
-    }
-
-    // m_windExposure;
-    std::string windExposurekey = "windExposure";
-    void setWindExposure(std::string value) {
-      tinygltf::Value extraNodeValue(value);
-      windExposure = make_tuple(windExposurekey, extraNodeValue);
-    }
-
-    void setWindExposure(tinygltf::Value value) {
-      windExposure = make_tuple(windExposurekey, value);
-    }
-
-    // double m_illuminanceSetpoint;
-    std::string illuminanceSetpointkey = "illuminanceSetpoint";
-    void setIlluminanceSetpoint(double value) {
-      tinygltf::Value extraNodeValue(value);
-      illuminanceSetpoint = make_tuple(illuminanceSetpointkey, extraNodeValue);
-    }
-
-    void setIlluminanceSetpoint(tinygltf::Value value) {
-      illuminanceSetpoint = make_tuple(illuminanceSetpointkey, value);
-    }
-
-    // bool m_airWall;
-    std::string airWallkey = "airWall";
-    void setAirWall(bool value) {
-      tinygltf::Value extraNodeValue(value);
-      airWall = make_tuple(airWallkey, extraNodeValue);
-    }
-
-    void setAirWall(tinygltf::Value value) {
-      airWall = make_tuple(airWallkey, value);
-    }
-
-    // vector airLoopHVACNames
-    std::string airLoopHVACNameskey = "airLoopHVACNames";
-    void setAirLoopHVACNames(std::map<std::string, tinygltf::Value> value) {
-      tinygltf::Value extraNodeValue(value);
-      airLoopHVACNames = make_tuple(airLoopHVACNameskey, extraNodeValue);
-    }
-
-    void setAirLoopHVACNames(tinygltf::Value value) {
-      airLoopHVACNames = make_tuple(airLoopHVACNameskey, value);
-    }
-
-    // vector airLoopHVACHandles
-    std::string airLoopHVACHandleskey = "airLoopHVACHandles";
-    void setAirLoopHVACHandles(std::map<std::string, tinygltf::Value> value) {
-      tinygltf::Value extraNodeValue(value);
-      airLoopHVACHandles = make_tuple(airLoopHVACHandleskey, extraNodeValue);
-    }
-
-    void setAirLoopHVACHandles(tinygltf::Value value) {
-      airLoopHVACHandles = make_tuple(airLoopHVACHandleskey, value);
-    }
-
-    // vector airLoopHVACMaterialNames
-    std::string airLoopHVACMaterialNameskey = "airLoopHVACMaterialNames";
-    void setAirLoopHVACMaterialNames(std::map<std::string, tinygltf::Value> value) {
-      tinygltf::Value extraNodeValue(value);
-      airLoopHVACMaterialNames = make_tuple(airLoopHVACMaterialNameskey, extraNodeValue);
-    }
-
-    void setAirLoopHVACMaterialNames(tinygltf::Value value) {
-      airLoopHVACMaterialNames = make_tuple(airLoopHVACMaterialNameskey, value);
-    }
-
-    std::map<std::string, tinygltf::Value> userDataObject;
-    void initializeUserDataObject() {
-      userDataObject.insert({std::get<0>(handle), std::get<1>(handle)});
-      userDataObject.insert({std::get<0>(name), std::get<1>(name)});
-      userDataObject.insert({std::get<0>(coincidentWithOutsideObject), std::get<1>(coincidentWithOutsideObject)});
-      userDataObject.insert({std::get<0>(surfaceType), std::get<1>(surfaceType)});
-      userDataObject.insert({std::get<0>(surfaceTypeMaterailName), std::get<1>(surfaceTypeMaterailName)});
-      userDataObject.insert({std::get<0>(constructionName), std::get<1>(constructionName)});
-      userDataObject.insert({std::get<0>(constructionHandle), std::get<1>(constructionHandle)});
-      userDataObject.insert({std::get<0>(constructionMaterialName), std::get<1>(constructionMaterialName)});
-      userDataObject.insert({std::get<0>(surfaceName), std::get<1>(surfaceName)});
-      userDataObject.insert({std::get<0>(surfaceHandle), std::get<1>(surfaceHandle)});
-      userDataObject.insert({std::get<0>(subSurfaceName), std::get<1>(subSurfaceName)});
-      userDataObject.insert({std::get<0>(subSurfaceHandle), std::get<1>(subSurfaceHandle)});
-      userDataObject.insert({std::get<0>(spaceName), std::get<1>(spaceName)});
-      userDataObject.insert({std::get<0>(spaceHandle), std::get<1>(spaceHandle)});
-      userDataObject.insert({std::get<0>(shadingName), std::get<1>(shadingName)});
-      userDataObject.insert({std::get<0>(shadingHandle), std::get<1>(shadingHandle)});
-      userDataObject.insert({std::get<0>(thermalZoneName), std::get<1>(thermalZoneName)});
-      userDataObject.insert({std::get<0>(thermalZoneHandle), std::get<1>(thermalZoneHandle)});
-      userDataObject.insert({std::get<0>(thermalZoneMaterialName), std::get<1>(thermalZoneMaterialName)});
-      userDataObject.insert({std::get<0>(spaceTypeName), std::get<1>(spaceTypeName)});
-      userDataObject.insert({std::get<0>(spaceTypeHandle), std::get<1>(spaceTypeHandle)});
-      userDataObject.insert({std::get<0>(spaceTypeMaterialName), std::get<1>(spaceTypeMaterialName)});
-      userDataObject.insert({std::get<0>(buildingStoryName), std::get<1>(buildingStoryName)});
-      userDataObject.insert({std::get<0>(buildingStoryHandle), std::get<1>(buildingStoryHandle)});
-      userDataObject.insert({std::get<0>(buildingStoryMaterialName), std::get<1>(buildingStoryMaterialName)});
-      userDataObject.insert({std::get<0>(buildingUnitHandle), std::get<1>(buildingUnitHandle)});
-      userDataObject.insert({std::get<0>(buildingUnitName), std::get<1>(buildingUnitName)});
-      userDataObject.insert({std::get<0>(buildingUnitMaterialName), std::get<1>(buildingUnitMaterialName)});
-      userDataObject.insert({std::get<0>(constructionSetName), std::get<1>(constructionSetName)});
-      userDataObject.insert({std::get<0>(constructionSetHandle), std::get<1>(constructionSetHandle)});
-      userDataObject.insert({std::get<0>(constructionSetMaterialName), std::get<1>(constructionSetMaterialName)});
-      userDataObject.insert({std::get<0>(outsideBoundaryCondition), std::get<1>(outsideBoundaryCondition)});
-      userDataObject.insert({std::get<0>(outsideBoundaryConditionObjectName), std::get<1>(outsideBoundaryConditionObjectName)});
-      userDataObject.insert({std::get<0>(outsideBoundaryConditionObjectHandle), std::get<1>(outsideBoundaryConditionObjectHandle)});
-      userDataObject.insert({std::get<0>(boundaryMaterialName), std::get<1>(boundaryMaterialName)});
-      userDataObject.insert({std::get<0>(coincidentWithOutsideObject), std::get<1>(coincidentWithOutsideObject)});
-      userDataObject.insert({std::get<0>(sunExposure), std::get<1>(sunExposure)});
-      userDataObject.insert({std::get<0>(windExposure), std::get<1>(windExposure)});
-      userDataObject.insert({std::get<0>(illuminanceSetpoint), std::get<1>(illuminanceSetpoint)});
-      userDataObject.insert({std::get<0>(airWall), std::get<1>(airWall)});
-
-      // Collections
-      userDataObject.insert({std::get<0>(airLoopHVACNames), std::get<1>(airLoopHVACNames)});
-      userDataObject.insert({std::get<0>(airLoopHVACHandles), std::get<1>(airLoopHVACHandles)});
-      userDataObject.insert({std::get<0>(airLoopHVACMaterialNames), std::get<1>(airLoopHVACMaterialNames)});
-    }
-
-    void initializeFromNodeExtras(tinygltf::Node node) {
-      userDataObject = node.extras.Get<std::map<std::string, tinygltf::Value>>();
-      initializeFromExtras();
-    }
-
-    std::string getHandle() const {
-      tinygltf::Value v(std::get<1>(handle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getName() const {
-      tinygltf::Value v(std::get<1>(name));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSurfaceType() const {
-      tinygltf::Value v(std::get<1>(surfaceType));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSurfaceTypeMaterailName() const {
-      tinygltf::Value v(std::get<1>(surfaceTypeMaterailName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getConstructionName() const {
-      tinygltf::Value v(std::get<1>(constructionName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getConstructionHandle() const {
-      tinygltf::Value v(std::get<1>(constructionHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getConstructionMaterialName() const {
-      tinygltf::Value v(std::get<1>(constructionMaterialName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSurfaceName() const {
-      tinygltf::Value v(std::get<1>(surfaceName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSurfaceHandle() const {
-      tinygltf::Value v(std::get<1>(surfaceHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSubSurfaceName() const {
-      tinygltf::Value v(std::get<1>(subSurfaceName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSubSurfaceHandle() const {
-      tinygltf::Value v(std::get<1>(subSurfaceHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSpaceName() const {
-      tinygltf::Value v(std::get<1>(spaceName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSpaceHandle() const {
-      tinygltf::Value v(std::get<1>(spaceHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getShadingName() const {
-      tinygltf::Value v(std::get<1>(shadingName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getShadingHandle() const {
-      tinygltf::Value v(std::get<1>(shadingHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getThermalZoneName() const {
-      tinygltf::Value v(std::get<1>(thermalZoneName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getThermalZoneHandle() const {
-      tinygltf::Value v(std::get<1>(thermalZoneHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getThermalZoneMaterialName() const {
-      tinygltf::Value v(std::get<1>(thermalZoneMaterialName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSpaceTypeName() const {
-      tinygltf::Value v(std::get<1>(spaceTypeName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSpaceTypeHandle() const {
-      tinygltf::Value v(std::get<1>(spaceTypeHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getSpaceTypeMaterialName() const {
-      tinygltf::Value v(std::get<1>(spaceTypeMaterialName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getBuildingStoryName() const {
-      tinygltf::Value v(std::get<1>(buildingStoryName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getBuildingStoryHandle() const {
-      tinygltf::Value v(std::get<1>(buildingStoryHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getBuildingStoryMaterialName() const {
-      tinygltf::Value v(std::get<1>(buildingStoryMaterialName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getBuildingUnitName() const {
-      tinygltf::Value v(std::get<1>(buildingUnitName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getBuildingUnitHandle() const {
-      tinygltf::Value v(std::get<1>(buildingUnitHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getBuildingUnitMaterialName() const {
-      tinygltf::Value v(std::get<1>(buildingUnitMaterialName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getConstructionSetName() const {
-      tinygltf::Value v(std::get<1>(constructionSetName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getConstructionSetHandle() const {
-      tinygltf::Value v(std::get<1>(constructionSetHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getConstructionSetMaterialName() const {
-      tinygltf::Value v(std::get<1>(constructionSetMaterialName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getOutsideBoundaryCondition() const {
-      tinygltf::Value v(std::get<1>(outsideBoundaryCondition));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getOutsideBoundaryConditionObjectName() const {
-      tinygltf::Value v(std::get<1>(outsideBoundaryConditionObjectName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getOutsideBoundaryConditionObjectHandle() const {
-      tinygltf::Value v(std::get<1>(outsideBoundaryConditionObjectHandle));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getBoundaryMaterialName() const {
-      tinygltf::Value v(std::get<1>(boundaryMaterialName));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    bool getCoincidentWithOutsideObject() const {
-      tinygltf::Value v(std::get<1>(coincidentWithOutsideObject));
-      bool boolVal = v.Get<bool>();
-      return boolVal;
-    }
-
-    std::string getSunExposure() const {
-      tinygltf::Value v(std::get<1>(sunExposure));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    std::string getWindExposure() const {
-      tinygltf::Value v(std::get<1>(windExposure));
-      std::string stringVal = v.Get<std::string>().c_str();
-      return stringVal;
-    }
-
-    double getIlluminanceSetpoint() const {
-      tinygltf::Value v(std::get<1>(illuminanceSetpoint));
-      double doubleVal = v.Get<double>();
-      return doubleVal;
-    }
-
-    bool getAirWall() const {
-      tinygltf::Value v(std::get<1>(airWall));
-      bool boolVal = v.Get<bool>();
-      return boolVal;
-    }
-
-    std::vector<std::string> getAirLoopHVACNames() {
-      std::vector<std::string> loopHvacNames;
-      tinygltf::Value v(std::get<1>(airLoopHVACNames));
-      auto collection = v.Get<std::map<std::string, tinygltf::Value>>();
-      for (auto const& x : collection) {
-        tinygltf::Value item(x.second);
-        std::string loopName = item.Get<std::string>().c_str();
-        loopHvacNames.push_back(loopName);
-      }
-      return loopHvacNames;
-    }
-
-    std::map<std::string, std::string> userDataPairs;
-    std::map<std::string, std::string> getUserDataPairs() {
-      userDataPairs.insert({handlekey, getHandle()});
-      return userDataPairs;
-    }
-
-   private:
-    std::tuple<std::string, tinygltf::Value> handle;
-    std::tuple<std::string, tinygltf::Value> name;
-    std::tuple<std::string, tinygltf::Value> surfaceType;
-    std::tuple<std::string, tinygltf::Value> surfaceTypeMaterailName;
-    std::tuple<std::string, tinygltf::Value> constructionName;
-    std::tuple<std::string, tinygltf::Value> constructionHandle;
-    std::tuple<std::string, tinygltf::Value> constructionMaterialName;
-    std::tuple<std::string, tinygltf::Value> surfaceName;
-    std::tuple<std::string, tinygltf::Value> surfaceHandle;
-    std::tuple<std::string, tinygltf::Value> subSurfaceName;
-    std::tuple<std::string, tinygltf::Value> subSurfaceHandle;
-    std::tuple<std::string, tinygltf::Value> spaceName;
-    std::tuple<std::string, tinygltf::Value> spaceHandle;
-    std::tuple<std::string, tinygltf::Value> shadingName;
-    std::tuple<std::string, tinygltf::Value> shadingHandle;
-    std::tuple<std::string, tinygltf::Value> thermalZoneName;
-    std::tuple<std::string, tinygltf::Value> thermalZoneHandle;
-    std::tuple<std::string, tinygltf::Value> thermalZoneMaterialName;
-    std::tuple<std::string, tinygltf::Value> spaceTypeName;
-    std::tuple<std::string, tinygltf::Value> spaceTypeHandle;
-    std::tuple<std::string, tinygltf::Value> spaceTypeMaterialName;
-    std::tuple<std::string, tinygltf::Value> buildingStoryName;
-    std::tuple<std::string, tinygltf::Value> buildingStoryHandle;
-    std::tuple<std::string, tinygltf::Value> buildingStoryMaterialName;
-    std::tuple<std::string, tinygltf::Value> buildingUnitName;
-    std::tuple<std::string, tinygltf::Value> buildingUnitHandle;
-    std::tuple<std::string, tinygltf::Value> buildingUnitMaterialName;
-    std::tuple<std::string, tinygltf::Value> constructionSetName;
-    std::tuple<std::string, tinygltf::Value> constructionSetHandle;
-    std::tuple<std::string, tinygltf::Value> constructionSetMaterialName;
-    std::tuple<std::string, tinygltf::Value> outsideBoundaryCondition;
-    std::tuple<std::string, tinygltf::Value> outsideBoundaryConditionObjectName;
-    std::tuple<std::string, tinygltf::Value> outsideBoundaryConditionObjectHandle;
-    std::tuple<std::string, tinygltf::Value> boundaryMaterialName;
-    std::tuple<std::string, tinygltf::Value> coincidentWithOutsideObject;
-    std::tuple<std::string, tinygltf::Value> sunExposure;
-    std::tuple<std::string, tinygltf::Value> windExposure;
-    std::tuple<std::string, tinygltf::Value> illuminanceSetpoint;
-    std::tuple<std::string, tinygltf::Value> airWall;
-    std::tuple<std::string, tinygltf::Value> airLoopHVACNames;
-    std::tuple<std::string, tinygltf::Value> airLoopHVACHandles;
-    std::tuple<std::string, tinygltf::Value> airLoopHVACMaterialNames;
-
-    void initializeAttributesWithDefaults() {
-      setHandle("");
-      setName("");
-      setSurfaceType("");
-      setSurfaceTypeMaterailName("");
-      setConstructionName("");
-      setConstructionHandle("");
-      setConstructionMaterialName("");
-      setSurfaceName("");
-      setSurfaceHandle("");
-      setSubSurfaceName("");
-      setSubSurfaceHandle("");
-      setSpaceName("");
-      setSpaceHandle("");
-      setShadingName("");
-      setShadingHandle("");
-      setThermalZoneName("");
-      setThermalZoneHandle("");
-      setThermalZoneMaterialName("");
-      setSpaceTypeName("");
-      setSpaceTypeHandle("");
-      setSpaceTypeMaterialName("");
-      setBuildingStoryName("");
-      setBuildingStoryHandle("");
-      setBuildingStoryMaterialName("");
-      setBuildingUnitName("");
-      setBuildingUnitHandle("");
-      setBuildingUnitMaterialName("");
-      setConstructionSetName("");
-      setConstructionSetHandle("");
-      setConstructionSetMaterialName("");
-      setOutsideBoundaryCondition("");
-      setOutsideBoundaryConditionObjectName("");
-      setOutsideBoundaryConditionObjectHandle("");
-      setBoundaryMaterialName("");
-      setCoincidentWithOutsideObject(false);
-      setSunExposure("");
-      setWindExposure("");
-      setIlluminanceSetpoint(0.0);
-      setAirWall(false);
-
-      std::map<std::string, tinygltf::Value> airLoopHVACHandlesObject;
-      std::map<std::string, tinygltf::Value> airLoopHVACNamesObject;
-      std::map<std::string, tinygltf::Value> airLoopHVACMaterialNamesObject;
-      setAirLoopHVACHandles(airLoopHVACHandlesObject);
-      setAirLoopHVACNames(airLoopHVACNamesObject);
-      setAirLoopHVACMaterialNames(airLoopHVACMaterialNamesObject);
-    }
-
-    void initializeFromExtras() {
-      setHandle(userDataObject[handlekey]);
-      setName(userDataObject[namekey]);
-      setSurfaceType(userDataObject[surfaceTypekey]);
-      setSurfaceTypeMaterailName(userDataObject[surfaceTypeMaterailNamekey]);
-      setConstructionName(userDataObject[constructionNamekey]);
-      setConstructionHandle(userDataObject[constructionHandlekey]);
-      setConstructionMaterialName(userDataObject[constructionMaterialNamekey]);
-      setSurfaceName(userDataObject[surfaceNamekey]);
-      setSurfaceHandle(userDataObject[surfaceHandlekey]);
-      setSubSurfaceName(userDataObject[subSurfaceNamekey]);
-      setSubSurfaceHandle(userDataObject[subSurfaceHandlekey]);
-      setSpaceName(userDataObject[spaceNamekey]);
-      setSpaceHandle(userDataObject[spaceHandlekey]);
-      setShadingName(userDataObject[shadingNamekey]);
-      setShadingHandle(userDataObject[shadingHandlekey]);
-      setThermalZoneName(userDataObject[thermalZoneNamekey]);
-      setThermalZoneHandle(userDataObject[thermalZoneHandlekey]);
-      setThermalZoneMaterialName(userDataObject[thermalZoneMaterialNamekey]);
-      setSpaceTypeName(userDataObject[spaceTypeNamekey]);
-      setSpaceTypeHandle(userDataObject[spaceTypeHandlekey]);
-      setSpaceTypeMaterialName(userDataObject[spaceTypeMaterialNamekey]);
-      setBuildingStoryName(userDataObject[buildingStoryNamekey]);
-      setBuildingStoryHandle(userDataObject[buildingStoryHandlekey]);
-      setBuildingStoryMaterialName(userDataObject[buildingStoryMaterialNamekey]);
-      setBuildingUnitName(userDataObject[buildingUnitNamekey]);
-      setBuildingUnitHandle(userDataObject[buildingUnitHandlekey]);
-      setBuildingUnitMaterialName(userDataObject[buildingUnitMaterialNamekey]);
-      setConstructionSetName(userDataObject[constructionSetNamekey]);
-      setConstructionSetHandle(userDataObject[constructionSetHandlekey]);
-      setConstructionSetMaterialName(userDataObject[constructionSetMaterialNamekey]);
-      setOutsideBoundaryCondition(userDataObject[outsideBoundaryConditionkey]);
-      setOutsideBoundaryConditionObjectName(userDataObject[outsideBoundaryConditionObjectNamekey]);
-      setOutsideBoundaryConditionObjectHandle(userDataObject[outsideBoundaryConditionObjectHandlekey]);
-      setBoundaryMaterialName(userDataObject[boundaryMaterialNamekey]);
-      // bool
-      setCoincidentWithOutsideObject(userDataObject[coincidentWithOutsideObjectkey]);
-      setSunExposure(userDataObject[sunExposurekey]);
-      setWindExposure(userDataObject[windExposurekey]);
-      setIlluminanceSetpoint(userDataObject[illuminanceSetpointkey]);
-      // bool
-      setAirWall(userDataObject[airWallkey]);
-      // vector string
-      setAirLoopHVACNames(userDataObject[airLoopHVACNameskey]);
-      setAirLoopHVACHandles(userDataObject[airLoopHVACHandleskey]);
-      setAirLoopHVACMaterialNames(userDataObject[airLoopHVACMaterialNameskey]);
-    }
-  };
-
-  // For Indices of Indices, Coordinates & Normal buffers
-  // against each Components
-  struct ShapeComponentIds
-  {
-    int IndicesAccessorId;
-    int VerticesAccessorId;
-    int NormalsAccessorId;
-  };
-
-  // Creates a GLTF material on the basis of raw Material Values
-  // i.e, R, G, B, A & isDoubleSided
-  // and adds to GLTF model's materials
-  // param : materials
-  // param : materialData
-  // returns : index of the created GLTF Material
-  int createMaterial(std::vector<GLTF::Material>& materials, const MaterialData& materialData) {
-    GLTF::Material m;
-    m.name = materialData.materialName;
-    GLTF::PbrMetallicRoughness pbr;
-    // this contains the red, green, blue and alpha components of the main color of the material
-    pbr.baseColorFactor = {(static_cast<float>(materialData.r) / 255.0f), (static_cast<float>(materialData.g) / 255.0f),
-                           (static_cast<float>(materialData.b) / 255.0f), static_cast<float>(materialData.a)};
-    // this indicates that the material should have very minimum reflection characteristics
-    // between that of a metal and non-metal material.
-    pbr.metallicFactor = 0.0;
-    // this makes the material to not be perfectly mirror-like, but instead scatter the
-    // reflected light a bit.
-    pbr.roughnessFactor = 1.0;
-    m.pbrMetallicRoughness = pbr;
-    // emissive texture describes the parts of the object surface that emit light with a certain color
-    m.emissiveFactor = {0.01, 0.01, 0.00};
-    // occlusion texture can be used to simulate the effect of objects self-shadowing each other.
-    // m.occlusionTexture = "";
-    // normal map is a texture applied to modulate the surface normal in a way that makes
-    // it possible to simulate finer geometric details without the cost of a higher mesh.
-    // m.normalTexture = "";
-    m.alphaMode = (materialData.a < 1.0f) ? "BLEND" : "OPAQUE";
-    //alphaCutoff should not be 1.0f else MATERIAL_ALPHA_CUTOFF_INVALID_MODE	Alpha cutoff is supported only for 'MASK' alpha mode
-    m.alphaCutoff = 0.5f;
-    m.doubleSided = materialData.isDoubleSided;
-
-    int ret = materials.size();
-    materials.emplace_back(std::move(m));
-    return ret;
-  }
-
-  // Initializes the SCENE for the GLTF model that will be
-  // aware of all other nodes, meshes, materials, BufferViews, Accessors tightly
-  // tied up in a Heirarchy using indices pointing one to other.
-  // param : scene
-  // param : topNode
-  // param : nodes
-  void initScene(GLTF::Scene& scene, GLTF::Node& topNode, std::vector<GLTF::Node>& nodes) {
-    std::vector<int> ns{0};
-    scene.nodes = ns;
-
-    topNode.name = "Z_UP";
-    std::vector<double> mtrx{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-    topNode.matrix = mtrx;
-
-    nodes.push_back(topNode);
-  }
-
-  // Initializes our two main Buffer Views
-  // one for the indices & other for Coordinates and Normals
-  // param : indicesBv
-  // param : coordinatesBv
-  void initBufferViews(GLTF::BufferView& indicesBv, GLTF::BufferView& coordinatesBv) {
-    GLTF::BufferView bvIndices;
-    bvIndices.buffer = 0;
-    // defining bytestride is not required in this case
-    bvIndices.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
-    indicesBv = bvIndices;
-
-    // The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
-    // at position 8 in the buffer and are of type ARRAY_BUFFER
-    GLTF::BufferView bvCoordinates;
-    bvCoordinates.buffer = 0;
-    bvCoordinates.target = TINYGLTF_TARGET_ARRAY_BUFFER;
-    bvCoordinates.byteStride = 12;
-    coordinatesBv = bvCoordinates;
-  }
-
-  // Creates a collection of raw (values: R,G,B,A & isDoubleSided)
-  // for all pre-defined GLTF material
-  // returns : collection of raw material Values
-  std::vector<MaterialData> getAllMaterials() {
-    std::vector<MaterialData> result{
-      {"Undefined", 255, 255, 255, 1, true},
-
-      {"NormalMaterial", 255, 255, 255, 1, true},
-      {"NormalMaterial_Ext", 255, 255, 255, 1},
-      {"NormalMaterial_Int", 255, 0, 0, 1},
-
-      {"Floor", 140, 140, 140, 1, true},
-      {"Floor_Ext", 128, 128, 128, 1},
-      {"Floor_Int", 191, 191, 191, 1},
-
-      {"Wall", 150, 131, 75, 1, true},
-      {"Wall_Ext", 204, 178, 102, 1},
-      {"Wall_Int", 235, 226, 197, 1},
-
-      {"RoofCeiling", 112, 56, 57, 1, true},
-      {"RoofCeiling_Ext", 153, 76, 76, 1},
-      {"RoofCeiling_Int", 202, 149, 149, 1},
-
-      {"Window", 102, 178, 204, 0.6, true},
-      {"Window_Ext", 102, 178, 204, 0.6},
-      {"Window_Int", 192, 226, 235, 0.6},
-
-      {"Door", 111, 98, 56, 1, true},
-      {"Door_Ext", 153, 133, 76, 1},
-      {"Door_Int", 202, 188, 149, 1},
-
-      {"SiteShading", 55, 90, 109, 1, true},
-      {"SiteShading_Ext", 75, 124, 149, 1},
-      {"SiteShading_Int", 187, 209, 220, 1},
-
-      {"BuildingShading", 83, 56, 111, 1, true},
-      {"BuildingShading_Ext", 113, 76, 153, 1},
-      {"BuildingShading_Int", 216, 203, 229, 1},
-
-      {"SpaceShading", 55, 81, 130, 1, true},
-      {"SpaceShading_Ext", 76, 110, 178, 1},
-      {"SpaceShading_Int", 183, 197, 224, 1},
-
-      {"InteriorPartitionSurface", 117, 138, 105, 1, true},
-      {"InteriorPartitionSurface_Ext", 158, 188, 143, 1},
-      {"InteriorPartitionSurface_Int", 213, 226, 207, 1},
-
-      // start textures for boundary conditions
-      {"Boundary_Surface", 0, 153, 0, 1, true},
-      {"Boundary_Adiabatic", 255, 0, 0, 1, true},
-      {"Boundary_Space", 255, 0, 0, 1, true},
-      {"Boundary_Outdoors", 163, 204, 204, 1, true},
-      {"Boundary_Outdoors_Sun", 40, 204, 204, 1, true},
-      {"Boundary_Outdoors_Wind", 9, 159, 162, 1, true},
-      {"Boundary_Outdoors_SunWind", 68, 119, 161, 1, true},
-      {"Boundary_Ground", 204, 183, 122, 1, true},
-      {"Boundary_Foundation", 117, 30, 122, 1, true},
-      {"Boundary_Groundfcfactormethod", 153, 122, 30, 1, true},
-      {"Boundary_Groundslabpreprocessoraverage", 255, 191, 0, 1, true},
-      {"Boundary_Groundslabpreprocessorcore", 255, 182, 50, 1, true},
-      {"Boundary_Groundslabpreprocessorperimeter", 255, 178, 101, 1, true},
-      {"Boundary_Groundbasementpreprocessoraveragewall", 204, 51, 0, 1, true},
-      {"Boundary_Groundbasementpreprocessoraveragefloor", 204, 81, 40, 1, true},
-      {"Boundary_Groundbasementpreprocessorupperwall", 204, 112, 81, 1, true},
-      {"Boundary_Groundbasementpreprocessorlowerwall", 204, 173, 163, 1, true},
-      {"Boundary_Othersidecoefficients", 63, 63, 63, 1, true},
-      {"Boundary_Othersideconditionsmodel", 153, 0, 76, 1, true},
-
-      // special rendering materials
-      {"SpaceType_Plenum", 192, 192, 192, 0.1, true},
-      {"ThermalZone_Plenum", 192, 192, 192, 0.1, true},
-
-      // special rendering materials, these are components or textures in SketchUp
-      {"DaylightingControl", 102, 178, 204, 0.1, true},
-      {"AirWall", 102, 178, 204, 0.1, true},
-      {"SolarCollector", 255, 255, 255, 1, true},
-      {"Photovoltaic", 255, 255, 255, 0.1, true},
-    };
-    return result;
-  }
-
-  // Adds all pre-defined materials to GLTF Model materials
-  // param : materialList
-  // param : materials
-  void addGLTFMaterials(std::map<std::string, int>& materialList, std::vector<GLTF::Material>& materials) {
-    std::vector<MaterialData> result = getAllMaterials();
-    for (const auto& m : result) {
-      if (materialList.find(m.materialName) != materialList.end()) {
-        LOG_FREE(Debug, "GltfForwardTranslator", "addGLTFMaterials, Key " << m.materialName << " found in materialList");
-      } else {
-        materialList[m.materialName] = createMaterial(materials, m);
-      }
-    }
-  }
-
-  // Gets GLTF Material name on the basis of idd Object Type and Name
-  // param : iddObjectType
-  // param : name
-  // returns : name of GLTF Material Name
-  std::string getObjectGLTFMaterialName(const std::string& iddObjectType, const std::string& name) {
-    std::string result;
-    if (istringEqual(iddObjectType, "OS:Construction")) {
-      result = "Construction_" + name;
-    } else if (istringEqual(iddObjectType, "OS:ThermalZone")) {
-      result = "ThermalZone_" + name;
-    } else if (istringEqual(iddObjectType, "OS:AirLoopHVAC")) {
-      result = "AirLoopHVAC_" + name;
-    } else if (istringEqual(iddObjectType, "OS:SpaceType")) {
-      result = "SpaceType_" + name;
-    } else if (istringEqual(iddObjectType, "OS:BuildingStory")) {
-      result = "BuildingStory_" + name;
-    } else if (istringEqual(iddObjectType, "OS:BuildingUnit")) {
-      result = "BuildingUnit_" + name;
-    } else if (istringEqual(iddObjectType, "OS:Construction:AirBoundary")) {
-      // This shouldn't happen
-      LOG_FREE(Error, "getObjectGLTFMaterialName", "Didn't expect it would be called for '" << iddObjectType << "' (name = '" << name << "')");
-      result = "ConstructionAirBoundary_" + name;
-    } else {
-      LOG_FREE(Error, "getObjectGLTFMaterialName", "Unknown iddObjectType '" << iddObjectType << "'");
-    }
-    return result;
-  }
-
-  // Gets GLTF Material Name on the basis of Model Object
-  // param : object
-  // returns : name of GLTF material Name
-  std::string getObjectGLTFMaterialName(const ModelObject& object) {
-    return getObjectGLTFMaterialName(object.iddObjectType().valueDescription(), object.nameString());
-  }
-
-  // Adds Model Specific GLTF Material to all Materials Collection
-  // param : color
-  // param : materialName
-  // param : isDoubleSided
-  // param : allMaterials
-  void addModelSpecificMaterialToCollection(const RenderingColor& color, const std::string& materialName, bool isDoubleSided,
-                                            std::vector<MaterialData>& allMaterials) {
-    allMaterials.emplace_back(MaterialData{materialName, color.renderingRedValue(), color.renderingGreenValue(), color.renderingBlueValue(),
-                                           color.renderingAlphaValue() / 255.0, true});
-  }
-
-  // Gets GLTF Material name on the basis of Suface Type
-  // param : surfaceType
-  // returns : surface Type
-  std::string getSurfaceTypeGLTFMaterialName(const std::string& surfaceType) {
-    if (istringEqual(surfaceType, "FixedWindow") || istringEqual(surfaceType, "OperableWindow") || istringEqual(surfaceType, "GlassDoor")
-        || istringEqual(surfaceType, "Skylight") || istringEqual(surfaceType, "TubularDaylightDome")
-        || istringEqual(surfaceType, "TubularDaylightDiffuser")) {
-      return "Window";
-    } else if (istringEqual(surfaceType, "Door") || istringEqual(surfaceType, "OverheadDoor")) {
-      return "Door";
-    }
-    return surfaceType;
-  }
-
-  // Finds / Create GLTF Material depending upon MaterialName
-  // param : materialName
-  // param : materialList
-  // param : allMaterials
-  // param : materials
-  // returns : index of Material
-  int getGLTFMaterialIndex(const std::string& materialName, std::map<std::string, int>& materialList, std::vector<MaterialData>& allMaterials,
-                           std::vector<GLTF::Material>& materials) {
-    std::map<std::string, int>::const_iterator it = materialList.find(materialName);
-    if (it != materialList.end()) {
-      return it->second;
-    } else {
-      for (size_t i = 0; i < allMaterials.size(); i++) {
-        if (allMaterials[i].materialName == materialName) {
-          // Create Material and Add to _materials
-          int newMatIndex = createMaterial(materials, allMaterials[i]);
-          // Add to map list
-          materialList[allMaterials[i].materialName] = newMatIndex;
-          // send back index
-          // return newMatIndex;
-          break;
-        }
-      }
-      std::map<std::string, int>::const_iterator it = materialList.find(materialName);
-      if (it != materialList.end()) {
-        return it->second;
-      }
-      it = materialList.find("Undefined");
-      if (it != materialList.end()) {
-        return it->second;
-      }
-    }
-    return 0;
-  }
-
-  // Now: Instead of creating materials for all the objects in Model
-  // we're adding them to the all materials collection and create them only if required
-  // while processing the surface i.e, in MAIN LOOP
-  void buildMaterials(const Model& model, std::map<std::string, int>& materialList, std::vector<MaterialData>& allMaterials) {
-    std::string materialName;
-
-    auto getOrCreateRenderingColor = [&model](auto& object) {
-      boost::optional<RenderingColor> color_ = object.renderingColor();
-      if (!color_) {
-        color_ = RenderingColor(model);
-        object.setRenderingColor(color_.get());
-      }
-      return color_.get();
-    };
-
-    auto getOrCreateMaterial = [&getOrCreateRenderingColor, &allMaterials, &materialList](auto& object) {
-      std::string materialName = getObjectGLTFMaterialName(object);
-      if (materialList.find(materialName) != materialList.end()) {
-        LOG_FREE(Debug, "GltfForwardTranslator", "buildMaterials, Key " << materialName << " found in materialList");
-      } else {
-        // instead of creating the material whose node might get not used inshort to avoid
-        // warning "UNUSED_OBJECT". we'll add the material to our allMaterial collection
-        // and whie processing the surface if required we'll create and the node.
-        // createMaterial(materials, color, materialName, true);
-        auto color = getOrCreateRenderingColor(object);
-        addModelSpecificMaterialToCollection(color, materialName, true, allMaterials);
-      }
-    };
-
-    // make construction materials
-    for (auto& construction : model.getModelObjects<ConstructionBase>()) {
-      // If it's ConstructionAirBoundary, we'll later use the standard material "AirWall"
-      if (!construction.optionalCast<ConstructionAirBoundary>()) {
-        getOrCreateMaterial(construction);
-      }
-    }
-
-    // make thermal zone materials
-    for (auto& thermalZone : model.getConcreteModelObjects<ThermalZone>()) {
-      getOrCreateMaterial(thermalZone);
-    }
-
-    // make space type materials
-    for (auto& spaceType : model.getConcreteModelObjects<SpaceType>()) {
-      getOrCreateMaterial(spaceType);
-    }
-
-    // make building story materials
-    for (auto& buildingStory : model.getConcreteModelObjects<BuildingStory>()) {
-      getOrCreateMaterial(buildingStory);
-    }
-
-    // make building unit materials
-    for (auto& buildingUnit : model.getConcreteModelObjects<BuildingUnit>()) {
-      getOrCreateMaterial(buildingUnit);
-    }
-
-    // make air loop HVAC materials
-    for (auto& airLoopHVAC : model.getConcreteModelObjects<AirLoopHVAC>()) {
-      materialName = getObjectGLTFMaterialName(airLoopHVAC);
-      if (materialList.find(materialName) != materialList.end()) {
-        LOG_FREE(Debug, "GltfForwardTranslator", "buildMaterials, Key " << materialName << " found in materialList");
-      } else {
-        RenderingColor color = RenderingColor(model);
-        addModelSpecificMaterialToCollection(color, materialName, true, allMaterials);
-      }
-    }
-  }
-
-  // Finds the vertex Index from all Vertices of a planar Surface
-  // param : point3d
-  // param : allPoints
-  // param : tol
-  // returns :  index of the Vertex
-  size_t getOrCreateVertexIndexT(const Point3d& point3d, std::vector<Point3d>& allPoints, double tol = 0.001) {
-    size_t n = allPoints.size();
-    for (size_t i = 0; i < n; ++i) {
-      if (openstudio::getDistance(point3d, allPoints[i]) < tol) {
-        return i;
-      }
-    }
-    allPoints.push_back(point3d);
-    return (allPoints.size() - 1);
-  }
-
-  // Get Bytes from an integer
-  // param : paramInt
-  // returns : collection of Bytes
-  std::vector<unsigned char> intToBytes(int paramInt) {
-    std::vector<unsigned char> arrayOfByte(4);
-    for (int i = 0; i < 4; ++i)
-      arrayOfByte[3 - i] = (paramInt >> (i * 8));
-    return arrayOfByte;
-  }
-
-  // Get Bytes from a value
-  // typeparam name :"T"
-  // param : value
-  // returns : collection of bytes
-  template <typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
-  std::vector<uint8_t> splitValueToBytes(T const& value) {
-    std::vector<uint8_t> bytes;
-    for (size_t i = 0; i < sizeof(value); ++i) {
-      uint8_t byte = value >> (i * 8);
-      bytes.insert(bytes.begin(), byte);
-    }
-    return bytes;
-  }
-
-  // Adds & Creates Face Indices buffers and Accessors
-  // This method infers the indicesbuffer and adds them to the glTF model accessor
-  // which expects two types of accessor input one from indicesbuffer and the second
-  // one form coordinates buffer. So here after appending the buffer content it is sending
-  // over the index so the containing node will be aware of which one to refer.
-  // A better overview here at https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/figures/gltfOverview-2.0.0b.png
-  // param : faceIndices
-  // param : _indicesBuffer
-  // param : _accessors
-  // returns : index of the Face Indices
-  int addIndices(std::vector<size_t>& faceIndices, std::vector<unsigned char>& indicesBuffer, std::vector<GLTF::Accessor>& accessors) {
-    auto [min, max] = std::minmax_element(std::cbegin(faceIndices), std::cend(faceIndices));
-
-    // This but seems to be just figuring out the best way to back the indices in
-    // depenbding on the range of numbers
-    int ct = TINYGLTF_COMPONENT_TYPE_BYTE;
-    auto size = 0;
-
-    if (*max <= static_cast<size_t>(std::pow(2, 8))) {
-      ct = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
-      size = sizeof(std::byte);
-    } else if (*max <= static_cast<size_t>(std::pow(2, 16))) {
-      ct = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
-      size = sizeof(short);
-    } else {
-      ct = TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT;
-      size = sizeof(int);
-    }
-    // the offset position needs to be a multiple of the size
-    // (this is from a warning we received in beta testing)
-    // so we inject some padding when needed
-    auto padding = indicesBuffer.size() % size;
-    for (size_t i = 0; i < padding; ++i) {
-      indicesBuffer.push_back(0x00);
-    }
-
-    // To avoid Accessor offset Validation Issue
-    auto _padding = indicesBuffer.size() % 4;
-    for (size_t i = 0; i < _padding; ++i) {
-      indicesBuffer.push_back(0x00);
-    }
-
-    GLTF::Accessor indAccessor;
-    indAccessor.bufferView = 0;
-    indAccessor.componentType = ct;
-    indAccessor.byteOffset = indicesBuffer.size();
-    indAccessor.normalized = false;
-    indAccessor.type = TINYGLTF_TYPE_SCALAR;
-    indAccessor.count = faceIndices.size();
-    indAccessor.minValues = {static_cast<double>(*min)};
-    indAccessor.maxValues = {static_cast<double>(*max)};
-
-    std::vector<unsigned char> indicesBufferData;
-    for (const auto index : faceIndices) {
-      std::vector<unsigned char> arrayOfByte;
-      if (ct == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
-        arrayOfByte.push_back((unsigned char)index);
-      } else if (ct == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
-        arrayOfByte = splitValueToBytes(index);
-      } else {
-        arrayOfByte = splitValueToBytes(index);
-      }
-      indicesBufferData.insert(indicesBufferData.end(), arrayOfByte.begin(), arrayOfByte.end());
-    }
-
-    if (indicesBufferData.size() < 4) {
-      indicesBufferData.push_back(0x00);
-    }
-    indicesBuffer.insert(indicesBuffer.end(), indicesBufferData.begin(), indicesBufferData.end());
-
-    const auto thisIndex = accessors.size();
-    accessors.push_back(indAccessor);
-    return thisIndex;
-  }
-
-  // Creates Coordinates / Normal Buffers and Accessors.
-  // param : values
-  // param : coordinatesBuffer
-  // param : accessors
-  // returns : index
-  int createBuffers(std::vector<float>& values, std::vector<unsigned char>& coordinatesBuffer, std::vector<GLTF::Accessor>& accessors) {
-    // Fixes ACCESSOR_TOTAL_OFFSET_ALIGNMENT
-    // Accessor's total byteOffset XXXX isn't a multiple of componentType length 4.
-    auto _padding = coordinatesBuffer.size() % 4;
-    for (size_t i = 0; i < _padding; ++i) {
-      coordinatesBuffer.push_back((unsigned)0);
-    }
-    int startingBufferPosition = coordinatesBuffer.size();
-    std::vector<float> min = {FLT_MAX, FLT_MAX, FLT_MAX};
-    std::vector<float> max = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
-    int i = 0;
-    for (const auto& value : values) {
-      min[i] = std::min(value, min[i]);
-      max[i] = std::max(value, max[i]);
-      ++i;
-      if (i > 2) i = 0;
-      std::vector<unsigned char> v;
-      const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&value);
-      for (size_t i = 0; i < sizeof(float); ++i) {
-        v.push_back(ptr[i]);
-      }
-      coordinatesBuffer.insert(coordinatesBuffer.end(), v.begin(), v.end());
-    }
-    // To Fix : offset 18 is not a multiple of Comonent Type lenght 4
-    auto padding = coordinatesBuffer.size() % 4;
-    for (size_t i = 0; i < padding; ++i) {
-      coordinatesBuffer.push_back((unsigned)0);
-    }
-    // convert min and max to double
-    std::vector<double> min_d;
-    std::vector<double> max_d;
-    for (const auto mn : min) {
-      min_d.push_back((double)mn);
-    }
-    for (const auto mx : max) {
-      max_d.push_back((double)mx);
-    }
-    GLTF::Accessor coordAccessor;
-    coordAccessor.bufferView = 1;
-    coordAccessor.byteOffset = startingBufferPosition;
-    coordAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
-    coordAccessor.normalized = false;
-    coordAccessor.count = values.size() / 3;
-    coordAccessor.type = TINYGLTF_TYPE_VEC3;
-    coordAccessor.minValues = min_d;
-    coordAccessor.maxValues = max_d;
-
-    auto ret = accessors.size();
-    accessors.push_back(coordAccessor);
-    return ret;
-  }
-
-  // Adds Coordinate Buffers for all vertices of the surface
-  // param : allVertices
-  // param : coordinatesBuffer
-  // param : accessors
-  // returns : index for the Coordinates Buffer
-  int addCoordinates(const Point3dVector& allVertices, std::vector<unsigned char>& coordinatesBuffer, std::vector<GLTF::Accessor>& accessors) {
-    std::vector<float> values(3 * allVertices.size());
-    size_t i = 0;
-    for (const auto& point : allVertices) {
-      values[i++] = static_cast<float>(point.x());
-      values[i++] = static_cast<float>(point.y());
-      values[i++] = static_cast<float>(point.z());
-    }
-    return createBuffers(values, coordinatesBuffer, accessors);
-  }
-
-  // Adds Normal Buffers for all normal Vectors
-  // param : normalVectors
-  // param : coordinatesBuffer
-  // param : accessors
-  // returns : index for the Normals Buffer
-  int addNormals(const Vector3dVector& normalVectors, std::vector<unsigned char>& coordinatesBuffer, std::vector<GLTF::Accessor>& accessors) {
-    std::vector<float> values(3 * normalVectors.size());
-    size_t i = 0;
-    for (const auto& vec : normalVectors) {
-      values[i++] = static_cast<float>(vec.x());
-      values[i++] = static_cast<float>(vec.y());
-      values[i++] = static_cast<float>(vec.z());
-    }
-    return createBuffers(values, coordinatesBuffer, accessors);
-  }
-
-  // Returns material index depending upon the surface type.
-  // param : planarSurface
-  // param : materials
-  // param : materialList
-  // param : allMaterials
-  // returns : index of the Material
-  int getMaterialIndex(const PlanarSurface& planarSurface, std::vector<GLTF::Material>& materials, std::map<std::string, int>& materialList,
-                       std::vector<MaterialData>& allMaterials) {
-    std::string surfaceType;
-    std::string surfaceTypeGLTFMaterialName;
-    if (auto surface = planarSurface.optionalCast<Surface>()) {
-      surfaceType = surface->surfaceType();
-    } else if (planarSurface.optionalCast<SubSurface>()) {
-      surfaceType = planarSurface.cast<SubSurface>().subSurfaceType();
-    } else if (planarSurface.optionalCast<InteriorPartitionSurface>()) {
-      surfaceType = "InteriorPartitionSurface";
-    } else if (planarSurface.optionalCast<ShadingSurface>()) {
-      boost::optional<ShadingSurface> shadingSurface = planarSurface.optionalCast<ShadingSurface>();
-      std::string shadingSurfaceType = "Building";
-      if (shadingSurface->shadingSurfaceGroup()) {
-        shadingSurfaceType = shadingSurface->shadingSurfaceGroup()->shadingSurfaceType();
-      }
-      surfaceType = shadingSurfaceType + "Shading";
-    }
-    surfaceTypeGLTFMaterialName = getSurfaceTypeGLTFMaterialName(surfaceType);
-    return getGLTFMaterialIndex(surfaceTypeGLTFMaterialName, materialList, allMaterials, materials);
-  }
-
-  std::vector<std::byte> to_bytes(std::string const& s) {
-    std::vector<std::byte> bytes;
-    bytes.reserve(std::size(s));
-
-    std::transform(std::begin(s), std::end(s), std::back_inserter(bytes), [](char c) { return std::byte(c); });
-
-    return bytes;
-  }
-
-  std::string toglTFUUID(const std::string& uuid) {
-    // uuid.to_s.gsub('{','').gsub('}','')
-    if (uuid.size() > 2) {
-      if ((uuid[0] == '{') && (uuid[uuid.size() - 1] == '}')) {
-        return uuid.substr(1, uuid.size() - 2);
-      }
-    }
-    return uuid;
-  }
-
-  std::string fromglTFUUID(const std::string& uuid) {
-    if (uuid.size() > 2) {
-      if ((uuid[0] != '{') && (uuid[uuid.size() - 1] != '}')) {
-        return "{" + uuid + "}";
-      }
-    }
-    return uuid;
-  }
-
-  std::string getBoundaryMaterialName(boost::optional<Surface> surface) {
-    std::string result;
-    if (surface->outsideBoundaryCondition() == "Outdoors") {
-      if ((surface->sunExposure() == "SunExposed") && (surface->windExposure() == "WindExposed")) {
-        result = "Boundary_Outdoors_SunWind";
-      } else if (surface->sunExposure() == "SunExposed") {
-        result = "Boundary_Outdoors_Sun";
-      } else if (surface->windExposure() == "WindExposed") {
-        result = "Boundary_Outdoors_Wind";
-      } else {
-        result = "Boundary_Outdoors";
-      }
-    } else {
-      result = "Boundary_" + surface->outsideBoundaryCondition();
-    }
-    return result;
-  }
-
-  std::string getBoundaryMaterialName(const GltfUserData& glTFUserData) {
-    std::string result;
-    if (glTFUserData.getOutsideBoundaryCondition() == "Outdoors") {
-      if ((glTFUserData.getSunExposure() == "SunExposed") && (glTFUserData.getWindExposure() == "WindExposed")) {
-        result = "Boundary_Outdoors_SunWind";
-      } else if (glTFUserData.getSunExposure() == "SunExposed") {
-        result = "Boundary_Outdoors_Sun";
-      } else if (glTFUserData.getWindExposure() == "WindExposed") {
-        result = "Boundary_Outdoors_Wind";
-      } else {
-        result = "Boundary_Outdoors";
-      }
-    } else {
-      result = "Boundary_" + glTFUserData.getOutsideBoundaryCondition();
-    }
-    return result;
-  }
-
-  //
-  // param : planarSurface
-  // returns : UserData object
-  GltfUserData GetUserData(const PlanarSurface& planarSurface) {
-    std::string emptyString = "";
-    // Make sure to get the empty entries if one of the elements is not there
-    // so the UserData node look consistent across all surface nodes
-    GltfUserData glTFUserData;
-
-    std::string name = planarSurface.nameString();
-    boost::optional<Surface> surface = planarSurface.optionalCast<Surface>();
-    boost::optional<ShadingSurface> shadingSurface = planarSurface.optionalCast<ShadingSurface>();
-    boost::optional<InteriorPartitionSurface> interiorPartitionSurface = planarSurface.optionalCast<InteriorPartitionSurface>();
-    boost::optional<SubSurface> subSurface = planarSurface.optionalCast<SubSurface>();
-    boost::optional<PlanarSurfaceGroup> planarSurfaceGroup = planarSurface.planarSurfaceGroup();
-    boost::optional<Space> space = planarSurface.space();
-    boost::optional<ConstructionBase> construction = planarSurface.construction();
-
-    glTFUserData.setHandle(toglTFUUID(toString(planarSurface.handle())));
-    glTFUserData.setName(name);
-    glTFUserData.setCoincidentWithOutsideObject(false);
-    if (surface) {
-      glTFUserData.setSurfaceName(surface->nameString());
-      glTFUserData.setSurfaceHandle(toglTFUUID(toString(surface->handle())));
-      std::string surfaceType = surface->surfaceType();
-      glTFUserData.setSurfaceType(surfaceType);
-      glTFUserData.setSurfaceTypeMaterailName(getSurfaceTypeGLTFMaterialName(surfaceType));
-      glTFUserData.setSunExposure(surface->sunExposure());
-      glTFUserData.setWindExposure(surface->windExposure());
-      glTFUserData.setOutsideBoundaryCondition(surface->outsideBoundaryCondition());
-
-      boost::optional<Surface> adjacentSurface = surface->adjacentSurface();
-      if (adjacentSurface) {
-        glTFUserData.setOutsideBoundaryConditionObjectName(adjacentSurface->nameString());
-        glTFUserData.setOutsideBoundaryConditionObjectHandle(toglTFUUID(toString(adjacentSurface->handle())));
-      }
-      // set boundary conditions before calling getBoundaryMaterialName
-      glTFUserData.setBoundaryMaterialName(getBoundaryMaterialName(surface));
-    }
-
-    if (shadingSurface) {
-      glTFUserData.setShadingHandle(toglTFUUID(toString(shadingSurface->handle())));
-      glTFUserData.setShadingName(shadingSurface->nameString());
-
-      std::string shadingSurfaceType = "Building";
-      if (shadingSurface->shadingSurfaceGroup()) {
-        shadingSurfaceType = shadingSurface->shadingSurfaceGroup()->shadingSurfaceType();
-      }
-      std::string surfaceType = shadingSurfaceType + "Shading";
-      glTFUserData.setSurfaceType(surfaceType);
-      glTFUserData.setSurfaceTypeMaterailName(getSurfaceTypeGLTFMaterialName(surfaceType));
-      glTFUserData.setSunExposure("SunExposed");
-      glTFUserData.setWindExposure("WindExposed");
-      glTFUserData.setOutsideBoundaryCondition(emptyString);
-      glTFUserData.setOutsideBoundaryConditionObjectName(emptyString);
-      glTFUserData.setOutsideBoundaryConditionObjectHandle(emptyString);
-      glTFUserData.setBoundaryMaterialName(emptyString);
-    }
-
-    if (interiorPartitionSurface) {
-      std::string surfaceType = "InteriorPartitionSurface";
-      glTFUserData.setSurfaceType(surfaceType);
-      glTFUserData.setSurfaceTypeMaterailName(getSurfaceTypeGLTFMaterialName(surfaceType));
-      glTFUserData.setSunExposure("NoSun");
-      glTFUserData.setWindExposure("NoWind");
-      glTFUserData.setOutsideBoundaryCondition(emptyString);
-      glTFUserData.setOutsideBoundaryConditionObjectName(emptyString);
-      glTFUserData.setOutsideBoundaryConditionObjectHandle(emptyString);
-      glTFUserData.setBoundaryMaterialName(emptyString);
-    }
-
-    if (subSurface) {
-      glTFUserData.setSubSurfaceHandle(toglTFUUID(toString(subSurface->handle())));
-      glTFUserData.setSubSurfaceName(subSurface->nameString());
-      std::string subSurfaceType = subSurface->subSurfaceType();
-      glTFUserData.setSurfaceType(subSurfaceType);
-      glTFUserData.setSurfaceTypeMaterailName(getSurfaceTypeGLTFMaterialName(subSurfaceType));
-
-      boost::optional<Surface> parentSurface = subSurface->surface();
-      if (parentSurface) {
-        glTFUserData.setOutsideBoundaryCondition(parentSurface->outsideBoundaryCondition());
-        glTFUserData.setSunExposure(parentSurface->sunExposure());
-        glTFUserData.setWindExposure(parentSurface->windExposure());
-        glTFUserData.setSurfaceName(parentSurface->nameString());
-        glTFUserData.setSurfaceHandle(toglTFUUID(toString(parentSurface->handle())));
-      }
-
-      boost::optional<SubSurface> adjacentSubSurface = subSurface->adjacentSubSurface();
-      if (adjacentSubSurface) {
-        glTFUserData.setOutsideBoundaryConditionObjectName(adjacentSubSurface->nameString());
-        glTFUserData.setOutsideBoundaryConditionObjectHandle(toglTFUUID(toString(adjacentSubSurface->handle())));
-        glTFUserData.setBoundaryMaterialName("Boundary_Surface");
-      }
-      // set boundary conditions before calling getBoundaryMaterialName
-      glTFUserData.setBoundaryMaterialName(getBoundaryMaterialName(glTFUserData));
-    }
-
-    if (construction) {
-      glTFUserData.setConstructionSetHandle(toglTFUUID(toString(construction->handle())));
-      glTFUserData.setConstructionName(construction->nameString());
-      // If this is a ConstructionAirBoundary, then set to the standard material "AirWall"
-      if (construction->optionalCast<ConstructionAirBoundary>()) {
-        glTFUserData.setConstructionMaterialName("AirWall");
-      } else {
-        glTFUserData.setConstructionMaterialName(getObjectGLTFMaterialName(*construction));
-      }
-    }
-
-    if (space) {
-      glTFUserData.setSpaceHandle(toglTFUUID(toString(space->handle())));
-      glTFUserData.setSpaceName(space->nameString());
-      boost::optional<ThermalZone> thermalZone = space->thermalZone();
-      if (thermalZone) {
-        glTFUserData.setThermalZoneHandle(toglTFUUID(toString(thermalZone->handle())));
-        glTFUserData.setThermalZoneName(thermalZone->nameString());
-        glTFUserData.setThermalZoneMaterialName(getObjectGLTFMaterialName(*thermalZone));
-        std::vector<AirLoopHVAC> airLoopHVACs = thermalZone->airLoopHVACs();
-        int airLoopHVACHandleCountKey = 0;
-        int airLoopHVACNameCountKey = 0;
-        int airLoopHVACMaterialNameCountKey = 0;
-        std::map<std::string, tinygltf::Value> airLoopHVACHandlesObject;
-        std::map<std::string, tinygltf::Value> airLoopHVACNamesObject;
-        std::map<std::string, tinygltf::Value> airLoopHVACMaterialNamesObject;
-        for (const auto& airLoopHVAC : airLoopHVACs) {
-          tinygltf::Value airLoopHVACHandleExtraNodeValue(toglTFUUID(toString(airLoopHVAC.handle())));
-          airLoopHVACHandlesObject.insert({std::to_string(airLoopHVACHandleCountKey), airLoopHVACHandleExtraNodeValue});
-          airLoopHVACHandleCountKey++;
-
-          tinygltf::Value airLoopHVACNameExtraNodeValue(airLoopHVAC.nameString());
-          airLoopHVACNamesObject.insert({std::to_string(airLoopHVACNameCountKey), airLoopHVACNameExtraNodeValue});
-          airLoopHVACNameCountKey++;
-
-          tinygltf::Value airLoopHVACMaterialNameExtraNodeValue(getObjectGLTFMaterialName(airLoopHVAC));
-          airLoopHVACMaterialNamesObject.insert({std::to_string(airLoopHVACMaterialNameCountKey), airLoopHVACMaterialNameExtraNodeValue});
-          airLoopHVACMaterialNameCountKey++;
-        }
-        glTFUserData.setAirLoopHVACNames(airLoopHVACNamesObject);
-        glTFUserData.setAirLoopHVACHandles(airLoopHVACHandlesObject);
-        glTFUserData.setAirLoopHVACMaterialNames(airLoopHVACMaterialNamesObject);
-      }
-
-      boost::optional<SpaceType> spaceType = space->spaceType();
-      if (spaceType) {
-        glTFUserData.setSpaceTypeHandle(toglTFUUID(toString(spaceType->handle())));
-        glTFUserData.setSpaceTypeName(spaceType->nameString());
-        glTFUserData.setSpaceTypeMaterialName(getObjectGLTFMaterialName(*spaceType));
-      }
-
-      boost::optional<BuildingStory> buildingStory = space->buildingStory();
-      if (buildingStory) {
-        glTFUserData.setBuildingStoryHandle(toglTFUUID(toString(buildingStory->handle())));
-        glTFUserData.setBuildingStoryName(buildingStory->nameString());
-        glTFUserData.setBuildingStoryMaterialName(getObjectGLTFMaterialName(*buildingStory));
-      }
-
-      boost::optional<BuildingUnit> buildingUnit = space->buildingUnit();
-      if (buildingUnit) {
-        glTFUserData.setBuildingUnitHandle(toglTFUUID(toString(buildingUnit->handle())));
-        glTFUserData.setBuildingUnitName(buildingUnit->nameString());
-        glTFUserData.setBuildingUnitMaterialName(getObjectGLTFMaterialName(*buildingUnit));
-      }
-    }
-    return glTFUserData;
-  }
-
-  //
-  // param : userData
-  // param : planarSurface
-  // param : node
-  // param : buildingTransformation
-  // param : vertices
-  void tieUpglTFUserDataAsExtraNode(GltfUserData glTFUserData, const PlanarSurface& planarSurface, GLTF::Node& node,
-                                    const Transformation& buildingTransformation, const Point3dVector& vertices) {
-    // check if the adjacent surface is truly adjacent
-    // this controls display only, not energy model
-    if (!glTFUserData.getOutsideBoundaryConditionObjectHandle().empty()) {
-
-      UUID adjacentHandle = toUUID(fromglTFUUID(glTFUserData.getOutsideBoundaryConditionObjectHandle()));
-      boost::optional<PlanarSurface> adjacentPlanarSurface = planarSurface.model().getModelObject<PlanarSurface>(adjacentHandle);
-      OS_ASSERT(adjacentPlanarSurface);
-
-      Transformation otherBuildingTransformation;
-      if (adjacentPlanarSurface->planarSurfaceGroup()) {
-        otherBuildingTransformation = adjacentPlanarSurface->planarSurfaceGroup()->buildingTransformation();
-      }
-
-      Point3dVector otherVertices = otherBuildingTransformation * adjacentPlanarSurface->vertices();
-      if (circularEqual(buildingTransformation * vertices, reverse(otherVertices))) {
-        glTFUserData.setCoincidentWithOutsideObject(true);
-      } else {
-        glTFUserData.setCoincidentWithOutsideObject(false);
-      }
-    }
-
-    // Initialize UserDataObject Collection with userData private members
-    glTFUserData.initializeUserDataObject();
-
-    tinygltf::Value udObj(glTFUserData.userDataObject);
-    // tie up the final object as extras
-    node.extras = udObj;
-  }
-
-  std::vector<GltfUserData> glTFUserDataVector;
-  GltfMetaData glTFMetaData;
-  GltfMetaDataWrapper glTFMetaDataWrapper;
-  void getglTFMetaData(const Model& model, GLTF::Scene& scene, std::function<void(double)>& updatePercentage,
-                       std::vector<PlanarSurface>::size_type& N, double& n) {
-
-    std::vector<PlanarSurface> planarSurfaces = model.getModelObjects<PlanarSurface>();
-    std::vector<PlanarSurfaceGroup> planarSurfaceGroups = model.getModelObjects<PlanarSurfaceGroup>();
-    std::vector<BuildingStory> buildingStories = model.getConcreteModelObjects<BuildingStory>();
-    std::vector<BuildingUnit> buildingUnits = model.getConcreteModelObjects<BuildingUnit>();
-    std::vector<ThermalZone> thermalZones = model.getConcreteModelObjects<ThermalZone>();
-    std::vector<AirLoopHVAC> airLoopHVACs = model.getConcreteModelObjects<AirLoopHVAC>();
-    std::vector<SpaceType> spaceTypes = model.getConcreteModelObjects<SpaceType>();
-    std::vector<DefaultConstructionSet> defaultConstructionSets = model.getConcreteModelObjects<DefaultConstructionSet>();
-
-    glTFMetaData.setBoundingBox(planarSurfaceGroups, updatePercentage, n, N);
-
-    // Building Story Names
-    glTFMetaData.setBuildingStoryNames(buildingStories, updatePercentage, n, N);
-    // Generator
-    glTFMetaData.setGenerator("OpenStudio");
-    // type  | ??
-    glTFMetaData.setType("Object");
-    // Version
-    glTFMetaData.setVersion("4.3");
-    // North Axis
-    glTFMetaData.setNorthAxis(model);
-
-    // modelObjectMetadata Collection
-    glTFMetaData.setModelObjectMetaDataForStories(buildingStories, updatePercentage, n, N);
-
-    glTFMetaData.setModelObjectMetaDataForBuildingUnits(buildingUnits, updatePercentage, n, N);
-
-    glTFMetaData.setModelObjectMetaDataForThermalZones(thermalZones, updatePercentage, n, N);
-
-    glTFMetaData.setModelObjectMetaDataForSpaceTypes(spaceTypes, updatePercentage, n, N);
-
-    glTFMetaData.setModelObjectMetaDataFordefaultConstructionSets(defaultConstructionSets, updatePercentage, n, N);
-
-    glTFMetaData.setModelObjectMetaDataForAirLoopHVACs(airLoopHVACs, updatePercentage, n, N);
-
-    glTFMetaData.InitializeModelObject();
-
-    tinygltf::Value sceneExtraNode(glTFMetaData.metaData);
-    // final tie up of MetaData structure as extras on Scene Node
-    scene.extras = sceneExtraNode;
-  }
-
-  // Exports a gltf against a Model
-  // param : model
-  // param : outputPath
-  // returns : exports a GLTF file against a Model
-  bool GltfForwardTranslator::modelToGLTF(const Model& model, const path& outputPath) {
-    return modelToGLTF(
-      model, [](double percentage) {}, outputPath);
-  }
-
-  // MAIN PIPELINE TO TRANSLATE OPENSTUDIO MODEL -> GLTF MODEL
-  // param : model
-  // param : updatePercentage
-  // param : outputPath
-  // returns : exports GLTF file aginst the Model
-  bool GltfForwardTranslator::modelToGLTF(const Model& model, std::function<void(double)> updatePercentage, const path& outputPath) {
-    m_logSink.setThreadId(std::this_thread::get_id());
-    m_logSink.resetStringStream();
-
-    bool triangulateSurfaces = true;  //we're always triangulating the surfaces to get the best possible output.
-    bool BufferInBase64 = false;      //no *.bin file is involed | everything is integrated in the mail output gltf file only.
-
-    GLTF::TinyGLTF loader;
-    GLTF::Model gltfModel;
-    std::string err;
-    std::string warning;
-    path p;
-
-    std::vector<GLTF::Accessor> accessors;
-    std::vector<GLTF::Material> materials;
-    std::vector<GLTF::Mesh> meshes;
-    std::vector<GLTF::Node> nodes;
-    std::vector<GLTF::BufferView> bufferViews;
-
-    GLTF::Scene scene;
-    GLTF::Buffer buffer;
-    GLTF::Node topNode;
-
-    GLTF::BufferView indicesBv;
-    GLTF::BufferView coordinatesBv;
-    std::vector<unsigned char> indicesBuffer;
-    std::vector<unsigned char> coordinatesBuffer;
-
-    GLTF::Asset asset;
-
-    // Start Region INIT
-
-    // Start Region SCENE
-
-    initScene(scene, topNode, nodes);
-
-    // End Region SCENE
-
-    // Start Region BUFFERVIEWS
-
-    initBufferViews(indicesBv, coordinatesBv);
-
-    // End Region BUFFERVIEWS
-
-    // End Region INIT
-
-    std::map<std::string, int> materialList;
-    std::map<std::string, int> materialIndicesUsed;
-    std::vector<MaterialData> allMaterials = getAllMaterials();
-
-    /*
-
-    This comprises of the other nodes that GLTF provides
-    for further addition of complex details, textures, lights, etc.
-
-    std::vector<GLTF::Scene> scenes;
-    std::vector<GLTF::Buffer> buffers;
-    std::vector<GLTF::Animation> animations;
-    std::vector<GLTF::Texture> textures;
-    std::vector<GLTF::Image> images;
-    std::vector<GLTF::Skin> skins;
-    std::vector<GLTF::Sampler> samplers;
-    std::vector<GLTF::Camera> cameras;
-    std::vector<GLTF::Light> lights;
-
-    */
-
-    // get number of things to translate
-    std::vector<PlanarSurface> planarSurfaces = model.getModelObjects<PlanarSurface>();
-    std::vector<PlanarSurfaceGroup> planarSurfaceGroups = model.getModelObjects<PlanarSurfaceGroup>();
-    std::vector<BuildingStory> buildingStories = model.getConcreteModelObjects<BuildingStory>();
-    std::vector<BuildingUnit> buildingUnits = model.getConcreteModelObjects<BuildingUnit>();
-    std::vector<ThermalZone> thermalZones = model.getConcreteModelObjects<ThermalZone>();
-    std::vector<AirLoopHVAC> airLoopHVACs = model.getConcreteModelObjects<AirLoopHVAC>();
-    std::vector<SpaceType> spaceTypes = model.getConcreteModelObjects<SpaceType>();
-    std::vector<DefaultConstructionSet> defaultConstructionSets = model.getConcreteModelObjects<DefaultConstructionSet>();
-    double n = 0;
-
-    std::vector<PlanarSurface>::size_type N = planarSurfaces.size() + planarSurfaceGroups.size() + buildingStories.size() + buildingUnits.size()
-                                              + thermalZones.size() + airLoopHVACs.size() + spaceTypes.size() + defaultConstructionSets.size() + 1;
-
-    updatePercentage(0.0);
-
-    // Start Region CREATE MATERIALS
-    // add model specific materials
-    buildMaterials(model, materialList, allMaterials);
-    // End Region CREATE MATERIALS
-
-    TransformationVector transformStack{Transformation{}};
-
-    for (const auto& planarSurface : planarSurfaces) {
-      // Start Region MAIN LOOP
-      int materialIndex = 0;
-      std::string elementName = planarSurface.nameString();
-      // Construct in place
-      GLTF::Node& node = nodes.emplace_back();
-      node.name = elementName;
-
-      // Now the geometry
-      Transformation buildingTransformation;
-      if (boost::optional<PlanarSurfaceGroup> planarSurfaceGroup_ = planarSurface.planarSurfaceGroup()) {
-        buildingTransformation = planarSurfaceGroup_->buildingTransformation();
-      }
-      // get the vertices
-      Point3dVector vertices = planarSurface.vertices();
-      Transformation& t = transformStack.emplace_back(Transformation::alignFace(vertices));
-      Transformation tInv = t.inverse();
-      Point3dVector faceVertices = reverse(tInv * vertices);
-      std::vector<double> matrix = openstudio::toStandardVector(buildingTransformation.vector());
-
-      // Adding a check to avoid warning "NODE_MATRIX_DEFAULT"	<Do not specify default transform matrix>.
-      // This is the identity_matrix<4>
-      std::vector<double> matrixDefaultTransformation{1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0};
-      if (matrixDefaultTransformation != matrix) {
-        node.matrix = matrix;
-      } else {
-        node.matrix = {};
-      }
-      node.mesh = meshes.size();
-
-      // EXTRAS
-
-      // TODO: Based on flag add UserData to nodes..
-      // Initializes all userdata attributes as per the planar Surface
-      GltfUserData glTFUserData = GetUserData(planarSurface);
-
-      GLTF::Mesh& targetMesh = meshes.emplace_back();
-      targetMesh.name = elementName;
-      materialIndex = getMaterialIndex(planarSurface, materials, materialList, allMaterials);
-
-      // get vertices of all sub surfaces
-      Point3dVectorVector faceSubVertices;
-      boost::optional<Surface> surface = planarSurface.optionalCast<Surface>();
-      if (surface) {
-        for (const auto& subSurface : surface->subSurfaces()) {
-          faceSubVertices.push_back(reverse(tInv * subSurface.vertices()));
-        }
-      }
-
-      Point3dVectorVector finalFaceVertices;
-      if (triangulateSurfaces) {
-        finalFaceVertices = computeTriangulation(faceVertices, faceSubVertices);
-        if (finalFaceVertices.empty()) {
-          LOG_FREE(Error, "modelToGLTF", "Failed to triangulate surface " << elementName << " with " << faceSubVertices.size() << " sub surfaces");
-        }
-      } else {
-        finalFaceVertices.push_back(faceVertices);
-      }
-
-      Point3dVector allVertices;
-      Point3dVector triangleVertices;
-      std::vector<size_t> faceIndices;
-      for (const auto& finalFaceVerts : finalFaceVertices) {
-        Point3dVector finalVerts = t * finalFaceVerts;
-        triangleVertices.insert(triangleVertices.end(), finalVerts.begin(), finalVerts.end());
-        Point3dVector::reverse_iterator it = finalVerts.rbegin();
-        Point3dVector::reverse_iterator itend = finalVerts.rend();
-        for (; it != itend; ++it) {
-          faceIndices.push_back(getOrCreateVertexIndexT(*it, allVertices));
-        }
-      }
-
-      Vector3d outwardNormal = planarSurface.outwardNormal();
-      Vector3dVector normalVectors(allVertices.size(), outwardNormal);
-
-      ShapeComponentIds shapeComponentIds{
-        addIndices(faceIndices, indicesBuffer, accessors),          // IndicesAccessorId
-        addCoordinates(allVertices, coordinatesBuffer, accessors),  // VerticesAccessorId
-        addNormals(normalVectors, coordinatesBuffer, accessors)     // NormalsAccessorId
-      };
-
-      GLTF::Primitive& thisPrimitive = targetMesh.primitives.emplace_back();
-      thisPrimitive.attributes["NORMAL"] = shapeComponentIds.NormalsAccessorId;
-      thisPrimitive.attributes["POSITION"] = shapeComponentIds.VerticesAccessorId;
-      thisPrimitive.indices = shapeComponentIds.IndicesAccessorId;
-      thisPrimitive.material = materialIndex;
-      thisPrimitive.mode = TINYGLTF_MODE_TRIANGLES;
-
-      // TODO: Based on a flag override UserData attribute
-      // Addition of UserData as Extras to the node
-      tieUpglTFUserDataAsExtraNode(glTFUserData, planarSurface, node, buildingTransformation, vertices);
-
-      n += 1;
-      updatePercentage(100.0 * n / N);
-      // End Region MAIN
-    }
-    // Start Region BUILD SCENE | ELEMENT
-
-    if (coordinatesBuffer.size() == 0) {
-      return false;
-    }
-
-    if (!BufferInBase64) {
-      // BPS:having a separate input file for the GLTF is old now everything resides
-      // in the main GLTF file only..as a binary buffer data.
-      auto padding = indicesBuffer.size() % 4;
-      for (unsigned int i = 0; i < padding; i++) {
-        indicesBuffer.push_back(0x00);  // padding bytes
-      }
-
-      std::vector<unsigned char> allBuffer = indicesBuffer;  //std::move(_indicesBuffer);
-      allBuffer.insert(allBuffer.end(), coordinatesBuffer.begin(), coordinatesBuffer.end());
-
-      buffer.data = allBuffer;
-    }
-
-    indicesBv.byteLength = indicesBuffer.size();
-    indicesBv.byteOffset = 0;
-
-    coordinatesBv.byteLength = coordinatesBuffer.size();
-    coordinatesBv.byteOffset = indicesBuffer.size();
-
-    bufferViews.emplace_back(std::move(indicesBv));
-    bufferViews.emplace_back(std::move(coordinatesBv));
-
-    // End Region BUILD SCENE | ELEMENT
-
-    gltfModel.accessors = std::move(accessors);
-    gltfModel.bufferViews = std::move(bufferViews);
-    gltfModel.buffers = {buffer};
-
-    // Other tie ups
-    // Define the asset. The version is required
-    asset.version = "2.0";
-    asset.generator = "OpenStudio";
-
-    // SCENE EXTRAS | this will be having all the metadata
-    getglTFMetaData(model, scene, updatePercentage, N, n);
-
-    // Now all that remains is to tie back all the loose objects into the
-    // our single model.
-    gltfModel.scenes.push_back(scene);  // Default scene
-    gltfModel.meshes = meshes;
-
-    std::vector<GLTF::Node> nodesNew;
-    std::vector<int> nodesTemp;
-    nodesTemp.resize(nodes.size() - 1);
-    for (unsigned int i = 1; i < nodes.size(); i++) {
-      int j = i - 1;
-      nodesTemp[j] = i;
-    }
-    topNode.children = nodesTemp;
-
-    nodesNew.push_back(topNode);
-    int sk = 0;
-    for (const auto& nn : nodes) {
-      if (sk != 0) {
-        nodesNew.push_back(nn);
-      }
-      sk++;
-    }
-
-    gltfModel.nodes = std::move(nodesNew);
-    gltfModel.asset = std::move(asset);
-
-    // Add Materials to Model
-    gltfModel.materials = std::move(materials);
-
-    // Save it to a file
-
-    // Uncomment this to use extras_as_string [std::string] instead of extras [tinygltf::Value]
-    loader.SetStoreOriginalJSONForExtrasAndExtensions(true);
-    bool ret = loader.WriteGltfSceneToFile(&gltfModel, toString(outputPath),
-                                           true,    // embedImages
-                                           true,    // embedBuffers
-                                           true,    // pretty print
-                                           false);  // write binary
-
-    updatePercentage(100.0);
-
-    return ret;
-  }
-
-  // To export a Minimal GLTF file (Triangle with 3 Points) using raw buffer data.
-  // param : outputPath
-  // returns : exports triangle.gltf
-  bool GltfForwardTranslator::createTriangleGLTF(const path& outputPath) {
-    GLTF::Model m;
-    GLTF::Scene scene;
-    GLTF::Mesh mesh;
-    GLTF::Primitive primitive;
-    GLTF::Node node;
-    GLTF::Buffer buffer;
-    GLTF::BufferView bufferView1;
-    GLTF::BufferView bufferView2;
-    GLTF::Accessor accessor1;
-    GLTF::Accessor accessor2;
-    GLTF::Asset asset;
-
-    // This is the raw data buffer.
-    buffer.data = {// 6 bytes of indices and two bytes of padding
-                   // 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
-                   0x00, 0x01, 0x02, 0x00,
-                   // 36 bytes of floating point numbers
-                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00};
-
-    // Create an array of size equivalent to vector
-    // unsigned char arr[42]
-
-    // The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
-    // start of the buffer.
-    bufferView1.buffer = 0;
-    bufferView1.byteOffset = 0;
-    bufferView1.byteLength = 3;
-    bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
-
-    // The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
-    // at position 8 in the buffer and are of type ARRAY_BUFFER
-    bufferView2.buffer = 0;
-    bufferView2.byteOffset = 4;
-    bufferView2.byteLength = 36;
-    bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
-
-    // Describe the layout of bufferView1, the indices of the vertices
-    accessor1.bufferView = 0;
-    accessor1.byteOffset = 0;
-    accessor1.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;  // TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
-    accessor1.count = 3;
-    accessor1.type = TINYGLTF_TYPE_SCALAR;
-    accessor1.maxValues.push_back(2);
-    accessor1.minValues.push_back(0);
-
-    // Describe the layout of bufferView2, the vertices themself
-    accessor2.bufferView = 1;
-    accessor2.byteOffset = 0;
-    accessor2.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
-    accessor2.count = 3;
-    accessor2.type = TINYGLTF_TYPE_VEC3;
-    accessor2.maxValues = {1.0, 1.0, 0.0};
-    accessor2.minValues = {0.0, 0.0, 0.0};
-
-    // Build the mesh primitive and add it to the mesh
-    primitive.indices = 0;                 // The index of the accessor for the vertex indices
-    primitive.attributes["POSITION"] = 1;  // The index of the accessor for positions
-    primitive.material = 0;
-    // Other Modes in GLTF TINYGLTF_MODE_POINTS | TINYGLTF_MODE_LINE;
-    primitive.mode = TINYGLTF_MODE_TRIANGLES;
-    mesh.primitives.push_back(primitive);
-
-    // Other tie ups
-    node.mesh = 0;
-    scene.nodes.push_back(0);  // Default scene
-
-    // Define the asset. The version is required
-    asset.version = "2.0";
-    asset.generator = "OpenStudio";
-
-    // Now all that remains is to tie back all the loose objects into the
-    // our single model.
-    m.scenes.push_back(scene);
-    m.meshes.push_back(mesh);
-    m.nodes.push_back(node);
-    m.buffers.push_back(buffer);
-    m.bufferViews.push_back(bufferView1);
-    m.bufferViews.push_back(bufferView2);
-    m.accessors.push_back(accessor1);
-    m.accessors.push_back(accessor2);
-    m.asset = asset;
-
-    // Create a simple material
-    GLTF::Material& mat = m.materials.emplace_back();
-    mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
-    mat.pbrMetallicRoughness.metallicFactor = 0.8;
-    mat.pbrMetallicRoughness.roughnessFactor = 0.5;
-    mat.doubleSided = true;
-
-    // Save it to a file
-    GLTF::TinyGLTF gltf;
-    bool ret = gltf.WriteGltfSceneToFile(&m, toString(outputPath),
-                                         true,    // embedImages
-                                         true,    // embedBuffers
-                                         true,    // pretty print
-                                         false);  // write binary
-    return ret;
-  }
-
-  // To export a Minimal GLTF file (Triangle with 3 Points) using generated
-  // raw data from Point3DVector
-  // param : outputPath
-  // returns : exports triangle_2.gltf
-  bool GltfForwardTranslator::createTriangleGLTFFromPoint3DVector(const path& outputPath) {
-    GLTF::Model m;
-
-    //BPS: Buffer Views will not give the desired result if used emplace_back()
-    GLTF::BufferView bufferView1;
-    GLTF::BufferView bufferView2;
-
-    GLTF::Scene& scene = m.scenes.emplace_back();
-    GLTF::Mesh& mesh = m.meshes.emplace_back();
-    GLTF::Node& node = m.nodes.emplace_back();
-    GLTF::Buffer& buffer = m.buffers.emplace_back();
-    GLTF::Asset& asset = m.asset;
-
-    // Create an array of size equivalent to vector
-    // unsigned char arr[42];
-    // The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
-    // start of the buffer.
-    bufferView1.buffer = 0;
-    bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
-
-    // The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
-    // at position 8 in the buffer and are of type ARRAY_BUFFER
-    bufferView2.buffer = 0;
-    bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
-
-    std::vector<size_t> faceIndices{0, 1, 2};
-    std::vector<unsigned char> _indicesBuffer;
-    std::vector<unsigned char> _coordinatesBuffer;
-    Point3dVector allVertices{
-      {0, 0, 0},
-      {1, 0, 0},
-      {0, 1, 0},
-    };
-
-    ShapeComponentIds shapeComponentIds{
-      addIndices(faceIndices, _indicesBuffer, m.accessors),          //IndicesAccessorId
-      addCoordinates(allVertices, _coordinatesBuffer, m.accessors),  //VerticesAccessorId
-      0                                                              //NormalsAccessorId
-    };
-
-    // Build the mesh primitive and add it to the mesh
-    // The index of the accessor for the vertex indices
-    GLTF::Primitive& primitive = mesh.primitives.emplace_back();
-    primitive.indices = 0;
-    // The index of the accessor for positions
-    primitive.attributes["POSITION"] = shapeComponentIds.VerticesAccessorId;
-    primitive.material = 0;
-    primitive.mode = TINYGLTF_MODE_TRIANGLES;
-
-    bufferView1.byteOffset = 0;
-    bufferView1.byteLength = _indicesBuffer.size();
-    bufferView2.byteOffset = _indicesBuffer.size();
-    bufferView2.byteLength = _coordinatesBuffer.size();
-
-    std::vector<unsigned char> _allBuffer = _indicesBuffer;  //std::move(_indicesBuffer);
-    _allBuffer.insert(_allBuffer.end(), _coordinatesBuffer.begin(), _coordinatesBuffer.end());
-
-    buffer.data = _allBuffer;
-
-    // Other tie ups
-    node.mesh = 0;
-    scene.nodes.push_back(0);  // Default scene
-
-    // Define the asset. The version is required
-    asset.version = "2.0";
-    asset.generator = "OpenStudio";
-
-    // Now all that remains is to tie back all the loose objects into the
-    // our single model.
-    m.bufferViews.emplace_back(std::move(bufferView1));
-    m.bufferViews.emplace_back(std::move(bufferView2));
-
-    // Create a simple material
-    GLTF::Material mat;
-    mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
-    mat.pbrMetallicRoughness.metallicFactor = 1.0;
-    mat.pbrMetallicRoughness.roughnessFactor = 0.5;
-    mat.doubleSided = true;
-    m.materials.emplace_back(std::move(mat));
-
-    // Save it to a file
-    GLTF::TinyGLTF gltf;
-    bool ret = gltf.WriteGltfSceneToFile(&m, toString(outputPath),
-                                         true,    // embedImages
-                                         true,    // embedBuffers
-                                         true,    // pretty print
-                                         false);  // write binary
-    return ret;
-  }
-
-  // To populate a GLTF Model from an existing GLTF file.
-  // also exports a gltf file with a .bin file (non embeded version).
-  // param : inputPath
-  // param : inputNonEmbededPath
-  // returns :
-  bool GltfForwardTranslator::loadGLTF(const path& inputPath, const path& inputNonEmbededPath) {
-    GLTF::TinyGLTF loader;
-    GLTF::Model gltf_Model;
-    std::string err;
-    std::string warning;
-    std::string fileName = toString(inputPath);
-    bool ret = loader.LoadASCIIFromFile(&gltf_Model, &err, &warning, fileName);
-    if (err.size() != 0) {
-      LOG(Error, "Error loading GLTF " << err);
-      //ret = false;
-    }
-    if (!warning.empty()) {
-      LOG(Warn, "Error loading GLTF " << warning);
-    }
-
-    if (!ret) {
-      LOG(Error, "Failed to parse glTF");
-    } else {
-      std::string output_filename = toString(inputNonEmbededPath);
-      std::string embedded_filename = output_filename.substr(0, output_filename.size() - 5) + "-Embedded.gltf";
-      bool a = loader.WriteGltfSceneToFile(&gltf_Model, output_filename);
-      OS_ASSERT(a);
-      // Embedd buffers and (images if present)
-#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
-      bool b = loader.WriteGltfSceneToFile(&gltf_Model, embedded_filename, true, true);
-      OS_ASSERT(b);
-#endif
-    }
-    return ret;
-  }
-
-  GltfBoundingBoxWrapper glTFBoundingBoxWrapper;
-  std::vector<GltfUserDataWrapper> glTFUserDataWrapperVector;
-
-  void initializeBoundingBoxWrapper(tinygltf::Value value) {
-    glTFBoundingBoxWrapper = GltfBoundingBoxWrapper();
-    for (auto const& x : value.Get<std::map<std::string, tinygltf::Value>>()) {
-      std::string key = x.first;
-      if (key == "lookAtR") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setlookAtR(vv);
-      } else if (key == "lookAtX") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setlookAtX(vv);
-      } else if (key == "lookAtY") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setlookAtY(vv);
-      } else if (key == "lookAtZ") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setlookAtZ(vv);
-      } else if (key == "maxX") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setmaxX(vv);
-      } else if (key == "maxY") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setmaxY(vv);
-      } else if (key == "maxZ") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setmaxZ(vv);
-      } else if (key == "minX") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setminX(vv);
-      } else if (key == "minY") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setminY(vv);
-      } else if (key == "minZ") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFBoundingBoxWrapper.setminZ(vv);
-      }
-    }
-  }
-
-  void setModelObjectMetaDataWrapper(tinygltf::Value value) {
-    auto modelObjectMetatDataVector = value.Get<tinygltf::Value::Object>();
-    int countKey = 0;
-    for (auto const& x : modelObjectMetatDataVector) {
-      GltfModelObjectMetadataWrapper gltfModelObjectMetadata;
-      auto key = x.first;
-      tinygltf::Value v(x.second);
-      auto modelObjectMetaData1 = v.Get<tinygltf::Value::Object>();
-      for (auto const& y : modelObjectMetaData1) {
-        auto key1 = y.first;
-        tinygltf::Value v1(y.second);
-        if (key1 == "color") {
-          std::string colorStr = y.second.Get<std::string>().c_str();
-          gltfModelObjectMetadata.setColor(colorStr);
-        } else if (key1 == "handle") {
-          std::string handleStr = y.second.Get<std::string>().c_str();
-          gltfModelObjectMetadata.setHandle(handleStr);
-        } else if (key1 == "iddObjectType") {
-          std::string iddObjectTypeStr = y.second.Get<std::string>().c_str();
-          gltfModelObjectMetadata.setIddObjectType(iddObjectTypeStr);
-        } else if (key1 == "name") {
-          std::string nameStr = y.second.Get<std::string>().c_str();
-          gltfModelObjectMetadata.setName(nameStr);
-        } else if (key1 == "multiplier") {
-          int multiplierVal = y.second.Get<int>();
-          gltfModelObjectMetadata.setMultiplier(multiplierVal);
-        } else if (key1 == "open_to_below") {
-          bool openToBelow = y.second.Get<bool>();
-          gltfModelObjectMetadata.setOpen_to_below(openToBelow);
-        } else if (key1 == "nominal_z_coordinate") {
-          double z = y.second.Get<double>();
-          gltfModelObjectMetadata.setNominal_z_coordinate(z);
-        } else if (key1 == "nominal_floorCeiling_Height") {
-          double h = y.second.Get<double>();
-          gltfModelObjectMetadata.setNominal_floorCeiling_Height(h);
-        }
-      }
-      std::string iddObjectTypeStr = gltfModelObjectMetadata.getIddObjectType();
-      if (iddObjectTypeStr == "OS:BuildingStory") {
-        glTFMetaDataWrapper.storyCountIncrement();
-      } else if (iddObjectTypeStr == "OS:Space") {
-        glTFMetaDataWrapper.spaceCountIncrement();
-      } else if (iddObjectTypeStr == "OS:ThermalZone") {
-        glTFMetaDataWrapper.thermalZoneCountIncrement();
-      } else if (iddObjectTypeStr == "OS:SpaceType") {
-        glTFMetaDataWrapper.spaceTypeCountIncrement();
-      } else if (iddObjectTypeStr == "OS:DefaultConstructionSet") {
-        glTFMetaDataWrapper.constructionSetCountIncrement();
-      } else if (iddObjectTypeStr.compare("OS:AirLoopHVAC") == 0) {
-        glTFMetaDataWrapper.airLoopCountIncrement();
-      }
-      glTFMetaDataWrapper.addModelObjectMetadata(gltfModelObjectMetadata);
-      countKey++;
-    }
-  }
-
-  void initializeFromSceneExtras(const tinygltf::Scene& scene) {
-    glTFMetaDataWrapper = GltfMetaDataWrapper();
-    for (auto const& x : scene.extras.Get<std::map<std::string, tinygltf::Value>>()) {
-      std::string key = x.first;
-      if (key == "generator") {
-        tinygltf::Value v(x.second);
-        auto vv = v.Get<std::string>().c_str();
-        glTFMetaDataWrapper.setGenerator(vv);
-      } else if (key == "type") {
-        tinygltf::Value v(x.second);
-        auto vv = v.Get<std::string>().c_str();
-        glTFMetaDataWrapper.setType(vv);
-      } else if (key == "northAxis") {
-        tinygltf::Value v(x.second);
-        double vv = v.Get<double>();
-        glTFMetaDataWrapper.setNorthAxis(vv);
-      } else if (key == "version") {
-        tinygltf::Value v(x.second);
-        auto vv = v.Get<std::string>().c_str();
-        glTFMetaDataWrapper.setVersion(vv);
-      } else if (key == "boundingbox") {
-        tinygltf::Value v(x.second);
-        initializeBoundingBoxWrapper(v);
-        glTFMetaDataWrapper.setglTFBoundingBoxWrapper(glTFBoundingBoxWrapper);
-      } else if (key == "modelObjectMetaData") {
-        tinygltf::Value v(x.second);
-        setModelObjectMetaDataWrapper(v);
-      } else if (key == "buildingStoryNames") {
-        std::vector<std::string> storyNames;
-        for (const auto& n : x.second.Get<std::map<std::string, tinygltf::Value>>()) {
-          storyNames.push_back(n.second.Get<std::string>().c_str());
-        }
-        glTFMetaDataWrapper.setBuildingStoryNames(storyNames);
-      }
-    }
-  }
-
-  // <summary>
-  // initializes the glTFUserData from the extras attribute attached to the
-  // </summary>
-  // param : node
-  // param : glTFUserDataWrapper
-  void initializeFromNodeExtras(const tinygltf::Node& node, GltfUserDataWrapper& glTFUserDataWrapper) {
-    std::map<std::string, tinygltf::Value> userDataObject = node.extras.Get<std::map<std::string, tinygltf::Value>>();
-    glTFUserDataWrapper.setHandle(userDataObject["handle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setName(userDataObject["name"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSurfaceType(userDataObject["surfaceType"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSurfaceTypeMaterailName(userDataObject["surfaceTypeMaterailName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setConstructionName(userDataObject["constructionName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setConstructionHandle(userDataObject["constructionHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setConstructionMaterialName(userDataObject["constructionMaterialName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSurfaceName(userDataObject["surfaceName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSurfaceHandle(userDataObject["surfaceHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSubSurfaceName(userDataObject["subSurfaceName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSubSurfaceHandle(userDataObject["subSurfaceHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSpaceName(userDataObject["spaceName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSpaceHandle(userDataObject["spaceHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setShadingName(userDataObject["shadingName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setShadingHandle(userDataObject["shadingHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setThermalZoneName(userDataObject["thermalZoneName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setThermalZoneHandle(userDataObject["thermalZoneHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setThermalZoneMaterialName(userDataObject["thermalZoneMaterialName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSpaceTypeName(userDataObject["spaceTypeName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSpaceTypeHandle(userDataObject["spaceTypeHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setSpaceTypeMaterialName(userDataObject["spaceTypeMaterialName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setBuildingStoryName(userDataObject["buildingStoryName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setBuildingStoryHandle(userDataObject["buildingStoryHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setBuildingStoryMaterialName(userDataObject["buildingStoryMaterialName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setBuildingUnitName(userDataObject["buildingUnitName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setBuildingUnitHandle(userDataObject["buildingUnitHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setBuildingUnitMaterialName(userDataObject["buildingUnitMaterialName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setConstructionSetName(userDataObject["constructionSetName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setConstructionSetHandle(userDataObject["constructionSetHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setConstructionSetMaterialName(userDataObject["constructionSetMaterialName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setOutsideBoundaryCondition(userDataObject["outsideBoundaryCondition"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setOutsideBoundaryConditionObjectName(userDataObject["outsideBoundaryConditionObjectName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setOutsideBoundaryConditionObjectHandle(userDataObject["outsideBoundaryConditionObjectHandle"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setBoundaryMaterialName(userDataObject["boundaryMaterialName"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setCoincidentWithOutsideObject(userDataObject["coincidentWithOutsideObject"].Get<double>());
-    glTFUserDataWrapper.setSunExposure(userDataObject["sunExposure"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setWindExposure(userDataObject["windExposure"].Get<std::string>().c_str());
-    glTFUserDataWrapper.setIlluminanceSetpoint(userDataObject["illuminanceSetpoint"].Get<double>());
-    glTFUserDataWrapper.setAirWall(userDataObject["airWall"].Get<bool>());
-    //vector string
-    std::vector<std::string> names;
-    for (const auto& n : userDataObject["airLoopHVACNames"].Get<std::map<std::string, tinygltf::Value>>()) {
-      names.push_back(n.second.Get<std::string>().c_str());
-    }
-    glTFUserDataWrapper.setAirLoopHVACNames(names);
-
-    std::vector<std::string> handles;
-    for (const auto& h : userDataObject["airLoopHVACHandles"].Get<std::map<std::string, tinygltf::Value>>()) {
-      handles.push_back(h.second.Get<std::string>().c_str());
-    }
-    glTFUserDataWrapper.setAirLoopHVACHandles(handles);
-
-    std::vector<std::string> materialNames;
-    for (const auto& mn : userDataObject["airLoopHVACMaterialNames"].Get<std::map<std::string, tinygltf::Value>>()) {
-      materialNames.push_back(mn.second.Get<std::string>().c_str());
-    }
-    glTFUserDataWrapper.setAirLoopHVACMaterialNames(materialNames);
-  }
-
-  bool GltfForwardTranslator::loadGLTF(const path& inputPath) {
-    GLTF::TinyGLTF loader;
-    GLTF::Model gltf_Model;
-    std::string err;
-    std::string warning;
-    std::string fileName = toString(inputPath);
-    bool ret = loader.LoadASCIIFromFile(&gltf_Model, &err, &warning, fileName);
-    if (err.size() != 0) {
-      LOG(Error, "Error loading GLTF " << err);
-      //ret = false;
-    }
-    if (!warning.empty()) {
-      LOG(Warn, "Error loading GLTF " << warning);
-    }
-
-    if (!ret) {
-      LOG(Error, "Failed to parse glTF");
-    } else {
-      // USERDATA INITIALIZATION FROM EACH NODE's EXTRAS
-      glTFUserDataVector.clear();
-      for (unsigned int i = 1; i < gltf_Model.nodes.size(); i++) {
-        GltfUserData glTFUserData;  // reinitialize glTFUserData instance
-        glTFUserData.initializeFromNodeExtras(gltf_Model.nodes[i]);
-        glTFUserDataVector.push_back(glTFUserData);
-
-        GltfUserDataWrapper glTFUserDataWrapper;
-        initializeFromNodeExtras(gltf_Model.nodes[i], glTFUserDataWrapper);
-        glTFUserDataWrapperVector.push_back(glTFUserDataWrapper);
-      }
-
-      // METADATA INITIALIZATION FROM SCENE's EXTRAS
-      glTFMetaData = GltfMetaData();
-      glTFMetaData.initializeFromSceneExtras(gltf_Model.scenes[0]);
-      glTFMetaDataWrapper = GltfMetaDataWrapper();  // reinitialize glTFMetaData instance
-      initializeFromSceneExtras(gltf_Model.scenes[0]);
-    }
-    return ret;
-  }
-
-  GltfUserDataWrapperVector GltfForwardTranslator::getUserDataCollection() {
-    return glTFUserDataWrapperVector;
-  }
-
-  GltfUserDataWrapper GltfForwardTranslator::getUserDataBySurfaceName(const std::string& surfaceName) {
-    GltfUserDataWrapper userdata;
-    // TOOD: Implement find in userdata collection
-    std::vector<GltfUserDataWrapper>::iterator it;
-    it = std::find_if(glTFUserDataWrapperVector.begin(), glTFUserDataWrapperVector.end(),
-                      [&](GltfUserDataWrapper const& obj) { return obj.getName() == surfaceName; });
-    if (it != glTFUserDataWrapperVector.end()) {
-      // found it->getName() | it->getHandle()
-      userdata = *it;
-    } else {
-      // "Item not Found"
-    }
-    return userdata;
-  }
-
-  GltfMetaDataWrapper GltfForwardTranslator::getMetaData() {
-    return glTFMetaDataWrapper;
-  }
-
-  GltfForwardTranslator::GltfForwardTranslator() {
-    m_logSink.setLogLevel(Warn);
-    m_logSink.setThreadId(std::this_thread::get_id());
-  }
-
-  std::vector<LogMessage> GltfForwardTranslator::warnings() const {
-    std::vector<LogMessage> result;
-    for (LogMessage logMessage : m_logSink.logMessages()) {
-      if (logMessage.logLevel() == Warn) {
-        result.push_back(logMessage);
-      }
-    }
-    return result;
-  }
-
-  std::vector<LogMessage> GltfForwardTranslator::errors() const {
-    std::vector<LogMessage> result;
-    for (LogMessage logMessage : m_logSink.logMessages()) {
-      if (logMessage.logLevel() > Warn) {
-        result.push_back(logMessage);
-      }
-    }
-    return result;
-  }
-
-}  // namespace model
-}  // namespace openstudio
diff --git a/src/model/GltfMetaDataWrapper.cpp b/src/model/GltfMetaDataWrapper.cpp
deleted file mode 100644
index 81ca6a2d9f3..00000000000
--- a/src/model/GltfMetaDataWrapper.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/***********************************************************************************************************************
-*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
-*
-*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
-*  following conditions are met:
-*
-*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
-*  disclaimer.
-*
-*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
-*  disclaimer in the documentation and/or other materials provided with the distribution.
-*
-*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
-*  derived from this software without specific prior written permission from the respective party.
-*
-*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
-*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
-*  written permission from Alliance for Sustainable Energy, LLC.
-*
-*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
-*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-***********************************************************************************************************************/
-
-#include "GltfMetaDataWrapper.hpp"
-
-#include <tuple>
-
-namespace openstudio {
-namespace model {
-
-  // TODO: NO GLOBALS!!!
-  std::vector<GltfModelObjectMetadataWrapper> glTFModelObjectMetadataWrapperVector;
-  GltfBoundingBoxWrapper glTFBoundingBox;
-  std::vector<std::string> buildingStoryNames;
-  // string
-  std::tuple<std::string, std::string> generator;
-  std::tuple<std::string, std::string> type;
-  std::tuple<std::string, std::string> version;
-  // double
-  std::tuple<std::string, double> northAxis;
-  // int
-  int storyCount;
-  int thermalZoneCount;
-  int spaceCount;
-  int spaceTypeCount;
-  int constructionSetCount;
-  int airLoopCount;
-
-  void resetModelObjectMetaDataCount() {
-    storyCount = 0;
-    thermalZoneCount = 0;
-    spaceCount = 0;
-    spaceTypeCount = 0;
-    constructionSetCount = 0;
-    airLoopCount = 0;
-  }
-
-  GltfMetaDataWrapper::GltfMetaDataWrapper() {
-    resetModelObjectMetaDataCount();
-  }
-
-  double getBoundingBoxlookAtR() {
-    return glTFBoundingBox.getlookAtR();
-  }
-
-  double getBoundingBoxlookAtX() {
-    return glTFBoundingBox.getlookAtX();
-  }
-
-  double getBoundingBoxlookAtY() {
-    return glTFBoundingBox.getlookAtY();
-  }
-
-  double getBoundingBoxlookAtZ() {
-    return glTFBoundingBox.getlookAtZ();
-  }
-
-  double getBoundingBoxmaxX() {
-    return glTFBoundingBox.getmaxX();
-  }
-
-  double getBoundingBoxmaxY() {
-    return glTFBoundingBox.getmaxY();
-  }
-
-  double getBoundingBoxmaxZ() {
-    return glTFBoundingBox.getmaxZ();
-  }
-
-  double getBoundingBoxminZ() {
-    return glTFBoundingBox.getminZ();
-  }
-
-  double getBoundingBoxminX() {
-    return glTFBoundingBox.getminX();
-  }
-
-  double getBoundingBoxminY() {
-    return glTFBoundingBox.getminY();
-  }
-
-  std::vector<GltfModelObjectMetadataWrapper> getModelObjectMetaDataCollection() {
-    return glTFModelObjectMetadataWrapperVector;
-  }
-
-  void GltfMetaDataWrapper::setBuildingStoryNames(const std::vector<std::string>& storyNames) {
-    buildingStoryNames = storyNames;
-    std::sort(buildingStoryNames.begin(), buildingStoryNames.end(), IstringCompare());
-  }
-
-  void GltfMetaDataWrapper::setGenerator(const std::string& value) {
-    std::string key = "generator";
-    generator = std::make_tuple(key, value);
-  }
-
-  void GltfMetaDataWrapper::setType(const std::string& value) {
-    std::string key = "type";
-    type = std::make_tuple(key, value);
-  }
-
-  void GltfMetaDataWrapper::setVersion(const std::string& value) {
-    std::string key = "version";
-    version = std::make_tuple(key, value);
-  }
-
-  void GltfMetaDataWrapper::setNorthAxis(const double& value) {
-    std::string key = "northAxis";
-    northAxis = std::make_tuple(key, value);
-  }
-
-  std::vector<std::string> GltfMetaDataWrapper::getBuildingStoryNames() const {
-    return buildingStoryNames;
-  }
-
-  std::string GltfMetaDataWrapper::getGenerator() const {
-    return std::get<1>(generator);
-  }
-
-  std::string GltfMetaDataWrapper::getType() const {
-    return std::get<1>(type);
-  }
-
-  std::string GltfMetaDataWrapper::getVersion() const {
-    return std::get<1>(version);
-  }
-
-  double GltfMetaDataWrapper::getNorthAxis() const {
-    return std::get<1>(northAxis);
-  }
-
-  void GltfMetaDataWrapper::storyCountIncrement() {
-    storyCount++;
-  }
-
-  void GltfMetaDataWrapper::thermalZoneCountIncrement() {
-    thermalZoneCount++;
-  }
-
-  void GltfMetaDataWrapper::spaceCountIncrement() {
-    spaceCount++;
-  }
-
-  void GltfMetaDataWrapper::spaceTypeCountIncrement() {
-    spaceTypeCount++;
-  }
-
-  void GltfMetaDataWrapper::constructionSetCountIncrement() {
-    constructionSetCount++;
-  }
-
-  void GltfMetaDataWrapper::airLoopCountIncrement() {
-    airLoopCount++;
-  }
-
-  int GltfMetaDataWrapper::getStoryCount() const {
-    return storyCount;
-  }
-
-  int GltfMetaDataWrapper::getThermalZoneCount() const {
-    return thermalZoneCount;
-  }
-
-  int GltfMetaDataWrapper::getSpaceCount() const {
-    return spaceCount;
-  }
-
-  int GltfMetaDataWrapper::getSpaceTypeCount() const {
-    return spaceTypeCount;
-  }
-
-  int GltfMetaDataWrapper::getConstructionSetCount() const {
-    return constructionSetCount;
-  }
-
-  int GltfMetaDataWrapper::getAirLoopCount() const {
-    return airLoopCount;
-  }
-
-  // TODO: what the what? setting and returning a single global?
-  void GltfMetaDataWrapper::setglTFBoundingBoxWrapper(const GltfBoundingBoxWrapper& gbx) {
-    glTFBoundingBox = gbx;
-  }
-
-  GltfBoundingBoxWrapper GltfMetaDataWrapper::getglTFBoundingBoxWrapper() {
-    return glTFBoundingBox;
-  }
-
-  void GltfMetaDataWrapper::addModelObjectMetadata(GltfModelObjectMetadataWrapper& gbmw) {
-    glTFModelObjectMetadataWrapperVector.push_back(gbmw);
-  }
-
-  GltfModelObjectMetadataWrapperVector GltfMetaDataWrapper::getglTFModelObjectMetadataWrapper() {
-    return glTFModelObjectMetadataWrapperVector;
-  }
-
-}  // namespace model
-}  // namespace openstudio
diff --git a/src/model/GltfModelObjectMetadataWrapper.cpp b/src/model/GltfModelObjectMetadataWrapper.cpp
deleted file mode 100644
index 131bc94b04e..00000000000
--- a/src/model/GltfModelObjectMetadataWrapper.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/***********************************************************************************************************************
-*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
-*
-*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
-*  following conditions are met:
-*
-*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
-*  disclaimer.
-*
-*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
-*  disclaimer in the documentation and/or other materials provided with the distribution.
-*
-*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
-*  derived from this software without specific prior written permission from the respective party.
-*
-*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
-*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
-*  written permission from Alliance for Sustainable Energy, LLC.
-*
-*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
-*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-***********************************************************************************************************************/
-
-#include "GltfModelObjectMetadataWrapper.hpp"
-
-#include <tuple>
-
-namespace openstudio {
-namespace model {
-
-  void GltfModelObjectMetadataWrapper::setColor(const std::string& value) {
-    std::string key = "color";
-    color = std::make_tuple(key, value);
-  }
-
-  void GltfModelObjectMetadataWrapper::setHandle(const std::string& value) {
-    std::string key = "handle";
-    handle = std::make_tuple(key, value);
-  }
-
-  void GltfModelObjectMetadataWrapper::setIddObjectType(const std::string& value) {
-    std::string key = "iddObjectType";
-    iddObjectType = std::make_tuple(key, value);
-  }
-
-  void GltfModelObjectMetadataWrapper::setName(const std::string& value) {
-    std::string key = "name";
-    name = std::make_tuple(key, value);
-  }
-
-  void GltfModelObjectMetadataWrapper::setOpen_to_below(const bool& value) {
-    std::string key = "open_to_below";
-    open_to_below = std::make_tuple(key, value);
-  }
-
-  void GltfModelObjectMetadataWrapper::setNominal_z_coordinate(const double& value) {
-    std::string key = "nominal_z_coordinate";
-    nominal_z_coordinate = std::make_tuple(key, value);
-  }
-
-  void GltfModelObjectMetadataWrapper::setNominal_floorCeiling_Height(const double& value) {
-    std::string key = "nominal_floorCeiling_Height";
-    nominal_floorCeiling_Height = std::make_tuple(key, value);
-  }
-
-  void GltfModelObjectMetadataWrapper::setMultiplier(const int& value) {
-    std::string key = "multiplier";
-    multiplier = std::make_tuple(key, value);
-  }
-
-  // getters
-  std::string GltfModelObjectMetadataWrapper::getColor() const {
-    return std::get<1>(color);
-  }
-
-  std::string GltfModelObjectMetadataWrapper::getHandle() const {
-    return std::get<1>(handle);
-  }
-
-  std::string GltfModelObjectMetadataWrapper::getIddObjectType() const {
-    return std::get<1>(iddObjectType);
-  }
-
-  std::string GltfModelObjectMetadataWrapper::getName() const {
-    return std::get<1>(name);
-  }
-
-  bool GltfModelObjectMetadataWrapper::getOpen_to_below() const {
-    return std::get<1>(open_to_below);
-  }
-
-  double GltfModelObjectMetadataWrapper::getNominal_z_coordinate() const {
-    return std::get<1>(nominal_z_coordinate);
-  }
-
-  double GltfModelObjectMetadataWrapper::getNominal_floorCeiling_Height() const {
-    return std::get<1>(nominal_floorCeiling_Height);
-  }
-
-  int GltfModelObjectMetadataWrapper::getMultiplier() const {
-    return std::get<1>(multiplier);
-  }
-}  // namespace model
-}  // namespace openstudio
diff --git a/src/model/GltfUserDataWrapper.cpp b/src/model/GltfUserDataWrapper.cpp
deleted file mode 100644
index b8cedfc43e7..00000000000
--- a/src/model/GltfUserDataWrapper.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/***********************************************************************************************************************
-*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
-*
-*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
-*  following conditions are met:
-*
-*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
-*  disclaimer.
-*
-*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
-*  disclaimer in the documentation and/or other materials provided with the distribution.
-*
-*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
-*  derived from this software without specific prior written permission from the respective party.
-*
-*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
-*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
-*  written permission from Alliance for Sustainable Energy, LLC.
-*
-*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
-*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-***********************************************************************************************************************/
-
-#include "GltfUserDataWrapper.hpp"
-
-#include <tiny_gltf.h>
-
-#include <algorithm>
-#include <cmath>
-#include <iterator>
-#include <numeric>
-#include <tuple>
-
-namespace openstudio {
-namespace model {
-  // m_handle;
-  std::string handlekey = "handle";
-  void GltfUserDataWrapper::setHandle(const std::string& value) {
-    handle = make_tuple(handlekey, value);
-  }
-
-  // m_name;
-  std::string namekey = "name";
-  void GltfUserDataWrapper::setName(const std::string& value) {
-    name = make_tuple(namekey, value);
-  }
-
-  // m_surfaceType;
-  std::string surfaceTypekey = "surfaceType";
-  void GltfUserDataWrapper::setSurfaceType(const std::string& value) {
-    surfaceType = make_tuple(surfaceTypekey, value);
-  }
-
-  // m_surfaceTypeMaterialName;
-  std::string surfaceTypeMaterailNamekey = "surfaceTypeMaterailName";
-  void GltfUserDataWrapper::setSurfaceTypeMaterailName(const std::string& value) {
-    surfaceTypeMaterailName = make_tuple(surfaceTypeMaterailNamekey, value);
-  }
-
-  // m_constructionName;
-  std::string constructionNamekey = "constructionName";
-  void GltfUserDataWrapper::setConstructionName(const std::string& value) {
-    constructionName = make_tuple(constructionNamekey, value);
-  }
-
-  // m_constructionHandle;
-  std::string constructionHandlekey = "constructionHandle";
-  void GltfUserDataWrapper::setConstructionHandle(const std::string& value) {
-    constructionHandle = make_tuple(constructionHandlekey, value);
-  }
-
-  // m_constructionMaterialName;
-  std::string constructionMaterialNamekey = "constructionMaterialName";
-  void GltfUserDataWrapper::setConstructionMaterialName(const std::string& value) {
-    constructionMaterialName = make_tuple(constructionMaterialNamekey, value);
-  }
-
-  // m_surfaceName;
-  std::string surfaceNamekey = "surfaceName";
-  void GltfUserDataWrapper::setSurfaceName(const std::string& value) {
-    surfaceName = make_tuple(surfaceNamekey, value);
-  }
-
-  // m_surfaceHandle;
-  std::string surfaceHandlekey = "surfaceHandle";
-  void GltfUserDataWrapper::setSurfaceHandle(const std::string& value) {
-    surfaceHandle = make_tuple(surfaceHandlekey, value);
-  }
-
-  // m_subSurfaceName;
-  std::string subSurfaceNamekey = "subSurfaceName";
-  void GltfUserDataWrapper::setSubSurfaceName(const std::string& value) {
-    subSurfaceName = make_tuple(subSurfaceNamekey, value);
-  }
-
-  // m_subSurfaceHandle;
-  std::string subSurfaceHandlekey = "subSurfaceHandle";
-  void GltfUserDataWrapper::setSubSurfaceHandle(const std::string& value) {
-    subSurfaceHandle = make_tuple(subSurfaceHandlekey, value);
-  }
-
-  // m_spaceName;
-  std::string spaceNamekey = "spaceName";
-  void GltfUserDataWrapper::setSpaceName(const std::string& value) {
-    spaceName = make_tuple(spaceNamekey, value);
-  }
-
-  // m_spaceHandle;
-  std::string spaceHandlekey = "spaceHandle";
-  void GltfUserDataWrapper::setSpaceHandle(const std::string& value) {
-    spaceHandle = make_tuple(spaceHandlekey, value);
-  }
-
-  // m_shadingName
-  std::string shadingNamekey = "shadingName";
-  void GltfUserDataWrapper::setShadingName(const std::string& value) {
-    shadingName = make_tuple(shadingNamekey, value);
-  }
-
-  // m_shadingHandle;
-  std::string shadingHandlekey = "shadingHandle";
-  void GltfUserDataWrapper::setShadingHandle(const std::string& value) {
-    shadingHandle = make_tuple(shadingHandlekey, value);
-  }
-
-  // m_thermalZoneName;
-  std::string thermalZoneNamekey = "thermalZoneName";
-  void GltfUserDataWrapper::setThermalZoneName(const std::string& value) {
-    thermalZoneName = make_tuple(thermalZoneNamekey, value);
-  }
-
-  // m_thermalZoneHandle;
-  std::string thermalZoneHandlekey = "thermalZoneHandle";
-  void GltfUserDataWrapper::setThermalZoneHandle(const std::string& value) {
-    thermalZoneHandle = make_tuple(thermalZoneHandlekey, value);
-  }
-
-  // m_thermalZoneMaterialName;
-  std::string thermalZoneMaterialNamekey = "thermalZoneMaterialName";
-  void GltfUserDataWrapper::setThermalZoneMaterialName(const std::string& value) {
-    thermalZoneMaterialName = make_tuple(thermalZoneMaterialNamekey, value);
-  }
-
-  // m_spaceTypeName;
-  std::string spaceTypeNamekey = "spaceTypeName";
-  void GltfUserDataWrapper::setSpaceTypeName(const std::string& value) {
-    spaceTypeName = make_tuple(spaceTypeNamekey, value);
-  }
-
-  // m_spaceTypeHandle;
-  std::string spaceTypeHandlekey = "spaceTypeHandle";
-  void GltfUserDataWrapper::setSpaceTypeHandle(const std::string& value) {
-    spaceTypeHandle = make_tuple(spaceTypeHandlekey, value);
-  }
-
-  // m_spaceTypeMaterialName;
-  std::string spaceTypeMaterialNamekey = "spaceTypeMaterialName";
-  void GltfUserDataWrapper::setSpaceTypeMaterialName(const std::string& value) {
-    spaceTypeMaterialName = make_tuple(spaceTypeMaterialNamekey, value);
-  }
-
-  // m_buildingStoryName;
-  std::string buildingStoryNamekey = "buildingStoryName";
-  void GltfUserDataWrapper::setBuildingStoryName(const std::string& value) {
-    buildingStoryName = make_tuple(buildingStoryNamekey, value);
-  }
-
-  // m_buildingStoryHandle;
-  std::string buildingStoryHandlekey = "buildingStoryHandle";
-  void GltfUserDataWrapper::setBuildingStoryHandle(const std::string& value) {
-    buildingStoryHandle = make_tuple(buildingStoryHandlekey, value);
-  }
-
-  // m_buildingStoryMaterialName;
-  std::string buildingStoryMaterialNamekey = "buildingStoryMaterialName";
-  void GltfUserDataWrapper::setBuildingStoryMaterialName(const std::string& value) {
-    buildingStoryMaterialName = make_tuple(buildingStoryMaterialNamekey, value);
-  }
-
-  // m_buildingUnitName;
-  std::string buildingUnitNamekey = "buildingUnitName";
-  void GltfUserDataWrapper::setBuildingUnitName(const std::string& value) {
-    buildingUnitName = make_tuple(buildingUnitNamekey, value);
-  }
-
-  // m_buildingUnitHandle;
-  std::string buildingUnitHandlekey = "buildingUnitHandle";
-  void GltfUserDataWrapper::setBuildingUnitHandle(const std::string& value) {
-    buildingUnitHandle = make_tuple(buildingUnitHandlekey, value);
-  }
-
-  // m_buildingUnitMaterialName;
-  std::string buildingUnitMaterialNamekey = "buildingUnitMaterialName";
-  void GltfUserDataWrapper::setBuildingUnitMaterialName(const std::string& value) {
-    buildingUnitMaterialName = make_tuple(buildingUnitMaterialNamekey, value);
-  }
-
-  // m_constructionSetName;
-  std::string constructionSetNamekey = "constructionSetName";
-  void GltfUserDataWrapper::setConstructionSetName(const std::string& value) {
-    constructionSetName = make_tuple(constructionSetNamekey, value);
-  }
-
-  // m_constructionSetHandle;
-  std::string constructionSetHandlekey = "constructionSetHandle";
-  void GltfUserDataWrapper::setConstructionSetHandle(const std::string& value) {
-    constructionSetHandle = make_tuple(constructionSetHandlekey, value);
-  }
-
-  // m_constructionSetMaterialName;
-  std::string constructionSetMaterialNamekey = "constructionSetMaterialName";
-  void GltfUserDataWrapper::setConstructionSetMaterialName(const std::string& value) {
-    constructionSetMaterialName = make_tuple(constructionSetMaterialNamekey, value);
-  }
-
-  // m_outsideBoundaryCondition;
-  std::string outsideBoundaryConditionkey = "outsideBoundaryCondition";
-  void GltfUserDataWrapper::setOutsideBoundaryCondition(const std::string& value) {
-    outsideBoundaryCondition = make_tuple(outsideBoundaryConditionkey, value);
-  }
-
-  // m_outsideBoundaryConditionObjectName;
-  std::string outsideBoundaryConditionObjectNamekey = "outsideBoundaryConditionObjectName";
-  void GltfUserDataWrapper::setOutsideBoundaryConditionObjectName(const std::string& value) {
-    outsideBoundaryConditionObjectName = make_tuple(outsideBoundaryConditionObjectNamekey, value);
-  }
-
-  // m_outsideBoundaryConditionObjectHandle;
-  std::string outsideBoundaryConditionObjectHandlekey = "outsideBoundaryConditionObjectHandle";
-  void GltfUserDataWrapper::setOutsideBoundaryConditionObjectHandle(const std::string& value) {
-    outsideBoundaryConditionObjectHandle = make_tuple(outsideBoundaryConditionObjectHandlekey, value);
-  }
-
-  // m_boundaryMaterialName;
-  std::string boundaryMaterialNamekey = "boundaryMaterialName";
-  void GltfUserDataWrapper::setBoundaryMaterialName(const std::string& value) {
-    boundaryMaterialName = make_tuple(boundaryMaterialNamekey, value);
-  }
-
-  // bool m_coincidentWithOutsideObject;
-  std::string coincidentWithOutsideObjectkey = "coincidentWithOutsideObject";
-  void GltfUserDataWrapper::setCoincidentWithOutsideObject(const bool& value) {
-    coincidentWithOutsideObject = make_tuple(coincidentWithOutsideObjectkey, value);
-  }
-
-  // m_sunExposure;
-  std::string sunExposurekey = "sunExposure";
-  void GltfUserDataWrapper::setSunExposure(const std::string& value) {
-    sunExposure = make_tuple(sunExposurekey, value);
-  }
-  // m_windExposure;
-  std::string windExposurekey = "windExposure";
-  void GltfUserDataWrapper::setWindExposure(const std::string& value) {
-    windExposure = make_tuple(windExposurekey, value);
-  }
-
-  // double m_illuminanceSetpoint;
-  std::string illuminanceSetpointkey = "illuminanceSetpoint";
-  void GltfUserDataWrapper::setIlluminanceSetpoint(const double& value) {
-    illuminanceSetpoint = make_tuple(illuminanceSetpointkey, value);
-  }
-
-  // bool m_airWall;
-  std::string airWallkey = "airWall";
-  void GltfUserDataWrapper::setAirWall(const bool& value) {
-    airWall = make_tuple(airWallkey, value);
-  }
-
-  // vector airLoopHVACNames
-  void GltfUserDataWrapper::setAirLoopHVACNames(const std::vector<std::string>& value) {
-    airLoopHVACNames = value;
-  }
-
-  // vector airLoopHVACHandles
-  void GltfUserDataWrapper::setAirLoopHVACHandles(const std::vector<std::string>& value) {
-    airLoopHVACHandles = value;
-  }
-
-  // vector airLoopHVACMaterialNames
-  void GltfUserDataWrapper::setAirLoopHVACMaterialNames(const std::vector<std::string>& value) {
-    airLoopHVACMaterialNames = value;
-  }
-
-  std::string GltfUserDataWrapper::getHandle() const {
-    return std::get<1>(handle);
-  }
-  std::string GltfUserDataWrapper::getName() const {
-    return std::get<1>(name);
-  }
-  std::string GltfUserDataWrapper::getSurfaceType() const {
-    return std::get<1>(surfaceType);
-  }
-  std::string GltfUserDataWrapper::getSurfaceTypeMaterailName() const {
-    return std::get<1>(surfaceTypeMaterailName);
-  }
-  std::string GltfUserDataWrapper::getConstructionName() const {
-    return std::get<1>(constructionName);
-  }
-  std::string GltfUserDataWrapper::getConstructionHandle() const {
-    return std::get<1>(constructionHandle);
-  }
-  std::string GltfUserDataWrapper::getConstructionMaterialName() const {
-    return std::get<1>(constructionMaterialName);
-  }
-  std::string GltfUserDataWrapper::getSurfaceName() const {
-    return std::get<1>(surfaceName);
-  }
-  std::string GltfUserDataWrapper::getSurfaceHandle() const {
-    return std::get<1>(surfaceHandle);
-  }
-  std::string GltfUserDataWrapper::getSubSurfaceName() const {
-    return std::get<1>(subSurfaceName);
-  }
-  std::string GltfUserDataWrapper::getSubSurfaceHandle() const {
-    return std::get<1>(subSurfaceHandle);
-  }
-  std::string GltfUserDataWrapper::getSpaceName() const {
-    return std::get<1>(spaceName);
-  }
-  std::string GltfUserDataWrapper::getSpaceHandle() const {
-    return std::get<1>(spaceHandle);
-  }
-  std::string GltfUserDataWrapper::getShadingName() const {
-    return std::get<1>(shadingName);
-  }
-  std::string GltfUserDataWrapper::getShadingHandle() const {
-    return std::get<1>(shadingHandle);
-  }
-  std::string GltfUserDataWrapper::getThermalZoneName() const {
-    return std::get<1>(thermalZoneName);
-  }
-  std::string GltfUserDataWrapper::getThermalZoneHandle() const {
-    return std::get<1>(thermalZoneHandle);
-  }
-  std::string GltfUserDataWrapper::getThermalZoneMaterialName() const {
-    return std::get<1>(thermalZoneMaterialName);
-  }
-  std::string GltfUserDataWrapper::getSpaceTypeName() const {
-    return std::get<1>(spaceTypeName);
-  }
-  std::string GltfUserDataWrapper::getSpaceTypeHandle() const {
-    return std::get<1>(spaceTypeHandle);
-  }
-  std::string GltfUserDataWrapper::getSpaceTypeMaterialName() const {
-    return std::get<1>(spaceTypeMaterialName);
-  }
-  std::string GltfUserDataWrapper::getBuildingStoryName() const {
-    return std::get<1>(buildingStoryName);
-  }
-  std::string GltfUserDataWrapper::getBuildingStoryHandle() const {
-    return std::get<1>(buildingStoryHandle);
-  }
-  std::string GltfUserDataWrapper::getBuildingStoryMaterialName() const {
-    return std::get<1>(buildingStoryMaterialName);
-  }
-  std::string GltfUserDataWrapper::getBuildingUnitName() const {
-    return std::get<1>(buildingUnitName);
-  }
-  std::string GltfUserDataWrapper::getBuildingUnitHandle() const {
-    return std::get<1>(buildingUnitHandle);
-  }
-  std::string GltfUserDataWrapper::getBuildingUnitMaterialName() const {
-    return std::get<1>(buildingUnitMaterialName);
-  }
-  std::string GltfUserDataWrapper::getConstructionSetName() const {
-    return std::get<1>(constructionSetName);
-  }
-  std::string GltfUserDataWrapper::getConstructionSetHandle() const {
-    return std::get<1>(constructionSetHandle);
-  }
-  std::string GltfUserDataWrapper::getConstructionSetMaterialName() const {
-    return std::get<1>(constructionSetMaterialName);
-  }
-  std::string GltfUserDataWrapper::getOutsideBoundaryCondition() const {
-    return std::get<1>(outsideBoundaryCondition);
-  }
-  std::string GltfUserDataWrapper::getOutsideBoundaryConditionObjectName() const {
-    return std::get<1>(outsideBoundaryConditionObjectName);
-  }
-  std::string GltfUserDataWrapper::getOutsideBoundaryConditionObjectHandle() const {
-    return std::get<1>(outsideBoundaryConditionObjectHandle);
-  }
-  std::string GltfUserDataWrapper::getBoundaryMaterialName() const {
-    return std::get<1>(boundaryMaterialName);
-  }
-  bool GltfUserDataWrapper::getCoincidentWithOutsideObject() const {
-    return std::get<1>(coincidentWithOutsideObject);
-  }
-  std::string GltfUserDataWrapper::getSunExposure() const {
-    return std::get<1>(sunExposure);
-  }
-  std::string GltfUserDataWrapper::getWindExposure() const {
-    return std::get<1>(windExposure);
-  }
-  double GltfUserDataWrapper::getIlluminanceSetpoint() const {
-    return std::get<1>(illuminanceSetpoint);
-  }
-  bool GltfUserDataWrapper::getAirWall() const {
-    return std::get<1>(airWall);
-  }
-  std::vector<std::string> GltfUserDataWrapper::getAirLoopHVACHandles() const {
-    return airLoopHVACHandles;
-  }
-  std::vector<std::string> GltfUserDataWrapper::getAirLoopHVACNames() const {
-    return airLoopHVACNames;
-  }
-  std::vector<std::string> GltfUserDataWrapper::getAirLoopHVACMaterialNames() const {
-    return airLoopHVACMaterialNames;
-  }
-}  // namespace model
-}  // namespace openstudio
diff --git a/src/model/GltfUserDataWrapper.hpp b/src/model/GltfUserDataWrapper.hpp
deleted file mode 100644
index c14d4a5468b..00000000000
--- a/src/model/GltfUserDataWrapper.hpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/***********************************************************************************************************************
-*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
-*
-*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
-*  following conditions are met:
-*
-*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
-*  disclaimer.
-*
-*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
-*  disclaimer in the documentation and/or other materials provided with the distribution.
-*
-*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
-*  derived from this software without specific prior written permission from the respective party.
-*
-*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
-*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
-*  written permission from Alliance for Sustainable Energy, LLC.
-*
-*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
-*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-***********************************************************************************************************************/
-#ifndef MODEL_GLTFUSERDATAWRAPPER_HPP
-#define MODEL_GLTFUSERDATAWRAPPER_HPP
-
-#include "ModelAPI.hpp"
-#include "Model.hpp"
-
-namespace openstudio {
-//class GltfMetaDta;
-namespace model {
-
-  class MODEL_API GltfUserDataWrapper
-  {
-   public:
-    void setHandle(const std::string& value);
-    void setName(const std::string& value);
-    void setSurfaceType(const std::string& value);
-    void setSurfaceTypeMaterailName(const std::string& value);
-    void setConstructionName(const std::string& value);
-    void setConstructionHandle(const std::string& value);
-    void setConstructionMaterialName(const std::string& value);
-    void setSurfaceName(const std::string& value);
-    void setSurfaceHandle(const std::string& value);
-    void setSubSurfaceName(const std::string& value);
-    void setSubSurfaceHandle(const std::string& value);
-    void setSpaceName(const std::string& value);
-    void setSpaceHandle(const std::string& value);
-    void setShadingName(const std::string& value);
-    void setShadingHandle(const std::string& value);
-    void setThermalZoneName(const std::string& value);
-    void setThermalZoneHandle(const std::string& value);
-    void setThermalZoneMaterialName(const std::string& value);
-    void setSpaceTypeName(const std::string& value);
-    void setSpaceTypeHandle(const std::string& value);
-    void setSpaceTypeMaterialName(const std::string& value);
-    void setBuildingStoryName(const std::string& value);
-    void setBuildingStoryHandle(const std::string& value);
-    void setBuildingStoryMaterialName(const std::string& value);
-    void setBuildingUnitName(const std::string& value);
-    void setBuildingUnitHandle(const std::string& value);
-    void setBuildingUnitMaterialName(const std::string& value);
-    void setConstructionSetName(const std::string& value);
-    void setConstructionSetHandle(const std::string& value);
-    void setConstructionSetMaterialName(const std::string& value);
-    void setOutsideBoundaryCondition(const std::string& value);
-    void setOutsideBoundaryConditionObjectName(const std::string& value);
-    void setOutsideBoundaryConditionObjectHandle(const std::string& value);
-    void setBoundaryMaterialName(const std::string& value);
-    void setCoincidentWithOutsideObject(const bool& value);
-    void setSunExposure(const std::string& value);
-    void setWindExposure(const std::string& value);
-    void setIlluminanceSetpoint(const double& value);
-    void setAirWall(const bool& value);
-    void setAirLoopHVACHandles(const std::vector<std::string>& airLoopHvacHandles);
-    void setAirLoopHVACNames(const std::vector<std::string>& airLoopHvacNames);
-    void setAirLoopHVACMaterialNames(const std::vector<std::string>& airLoopHvacMaterialNames);
-
-    std::string getHandle() const;
-    std::string getName() const;
-    std::string getSurfaceType() const;
-    std::string getSurfaceTypeMaterailName() const;
-    std::string getConstructionName() const;
-    std::string getConstructionHandle() const;
-    std::string getConstructionMaterialName() const;
-    std::string getSurfaceName() const;
-    std::string getSurfaceHandle() const;
-    std::string getSubSurfaceName() const;
-    std::string getSubSurfaceHandle() const;
-    std::string getSpaceName() const;
-    std::string getSpaceHandle() const;
-    std::string getShadingName() const;
-    std::string getShadingHandle() const;
-    std::string getThermalZoneName() const;
-    std::string getThermalZoneHandle() const;
-    std::string getThermalZoneMaterialName() const;
-    std::string getSpaceTypeName() const;
-    std::string getSpaceTypeHandle() const;
-    std::string getSpaceTypeMaterialName() const;
-    std::string getBuildingStoryName() const;
-    std::string getBuildingStoryHandle() const;
-    std::string getBuildingStoryMaterialName() const;
-    std::string getBuildingUnitName() const;
-    std::string getBuildingUnitHandle() const;
-    std::string getBuildingUnitMaterialName() const;
-    std::string getConstructionSetName() const;
-    std::string getConstructionSetHandle() const;
-    std::string getConstructionSetMaterialName() const;
-    std::string getOutsideBoundaryCondition() const;
-    std::string getOutsideBoundaryConditionObjectName() const;
-    std::string getOutsideBoundaryConditionObjectHandle() const;
-    std::string getBoundaryMaterialName() const;
-    bool getCoincidentWithOutsideObject() const;
-    std::string getSunExposure() const;
-    std::string getWindExposure() const;
-    double getIlluminanceSetpoint() const;
-    bool getAirWall() const;
-    std::vector<std::string> getAirLoopHVACHandles() const;
-    std::vector<std::string> getAirLoopHVACNames() const;
-    std::vector<std::string> getAirLoopHVACMaterialNames() const;
-
-   private:
-    std::tuple<std::string, std::string> handle;
-    std::tuple<std::string, std::string> name;
-    std::tuple<std::string, std::string> surfaceType;
-    std::tuple<std::string, std::string> surfaceTypeMaterailName;
-    std::tuple<std::string, std::string> constructionName;
-    std::tuple<std::string, std::string> constructionHandle;
-    std::tuple<std::string, std::string> constructionMaterialName;
-    std::tuple<std::string, std::string> surfaceName;
-    std::tuple<std::string, std::string> surfaceHandle;
-    std::tuple<std::string, std::string> subSurfaceName;
-    std::tuple<std::string, std::string> subSurfaceHandle;
-    std::tuple<std::string, std::string> spaceName;
-    std::tuple<std::string, std::string> spaceHandle;
-    std::tuple<std::string, std::string> shadingName;
-    std::tuple<std::string, std::string> shadingHandle;
-    std::tuple<std::string, std::string> thermalZoneName;
-    std::tuple<std::string, std::string> thermalZoneHandle;
-    std::tuple<std::string, std::string> thermalZoneMaterialName;
-    std::tuple<std::string, std::string> spaceTypeName;
-    std::tuple<std::string, std::string> spaceTypeHandle;
-    std::tuple<std::string, std::string> spaceTypeMaterialName;
-    std::tuple<std::string, std::string> buildingStoryName;
-    std::tuple<std::string, std::string> buildingStoryHandle;
-    std::tuple<std::string, std::string> buildingStoryMaterialName;
-    std::tuple<std::string, std::string> buildingUnitName;
-    std::tuple<std::string, std::string> buildingUnitHandle;
-    std::tuple<std::string, std::string> buildingUnitMaterialName;
-    std::tuple<std::string, std::string> constructionSetName;
-    std::tuple<std::string, std::string> constructionSetHandle;
-    std::tuple<std::string, std::string> constructionSetMaterialName;
-    std::tuple<std::string, std::string> outsideBoundaryCondition;
-    std::tuple<std::string, std::string> outsideBoundaryConditionObjectName;
-    std::tuple<std::string, std::string> outsideBoundaryConditionObjectHandle;
-    std::tuple<std::string, std::string> boundaryMaterialName;
-    std::tuple<std::string, bool> coincidentWithOutsideObject;
-    std::tuple<std::string, std::string> sunExposure;
-    std::tuple<std::string, std::string> windExposure;
-    std::tuple<std::string, double> illuminanceSetpoint;
-    std::tuple<std::string, bool> airWall;
-    std::vector<std::string> airLoopHVACNames;
-    std::vector<std::string> airLoopHVACHandles;
-    std::vector<std::string> airLoopHVACMaterialNames;
-  };
-
-}  // namespace model
-}  // namespace openstudio
-
-#endif  //MODEL_GLTFUSERDATAWRAPPER_HPP
diff --git a/src/model/ModelGenerators.i b/src/model/ModelGenerators.i
index 8c1c9fe82e7..23f2f14d73d 100644
--- a/src/model/ModelGenerators.i
+++ b/src/model/ModelGenerators.i
@@ -18,9 +18,6 @@
 // ignore specific overload of ThreeJSForwardTranslator::modelToThreeJS to avoid dealing with std::function<void(double)>updatePercentage
 %ignore openstudio::model::ThreeJSForwardTranslator::modelToThreeJS(const Model& model, bool triangulateSurfaces, std::function<void(double)> updatePercentage);
 
-// ignore specific overload of GltfForwardTranslator::modelToGLTF to avoid dealing with std::function<void(double)>updatePercentage
-%ignore openstudio::model::GltfForwardTranslator::modelToGLTF(const Model& model, std::function<void(double)> updatePercentage, const path& outputPath); 
-
 // All base classes for PV, Generators, inverters and Electrical Storage
 %{
   #include <model/PhotovoltaicPerformance.hpp>
@@ -38,28 +35,14 @@
   #include <model/FloorplanJSForwardTranslator.hpp>
   #include <model/ThreeJSForwardTranslator.hpp>
   #include <model/ThreeJSReverseTranslator.hpp>
-  #include <model/GltfBoundingBoxWrapper.hpp>
-  #include <model/GltfModelObjectMetadataWrapper.hpp>
-  #include <model/GltfMetaDataWrapper.hpp>
-  #include <model/GltfUserDataWrapper.hpp>
-  #include <model/GltfForwardTranslator.hpp>
   #include <model/ModelMerger.hpp>
 %}
 %include <model/FloorplanJSForwardTranslator.hpp>
 %include <model/ThreeJSForwardTranslator.hpp>
 %include <model/ThreeJSReverseTranslator.hpp>
-%include <model/GltfBoundingBoxWrapper.hpp>
-%include <model/GltfModelObjectMetadataWrapper.hpp>
-%include <model/GltfMetaDataWrapper.hpp>
-%include <model/GltfUserDataWrapper.hpp>
-%include <model/GltfForwardTranslator.hpp>
 %include <model/ModelMerger.hpp>
 
 
-// create an instantiation of the vector classes
-%template(GltfUserDataWrapperVector) std::vector<openstudio::model::GltfUserDataWrapper>;
-%template(GltfModelObjectMetadataWrapperVector) std::vector<openstudio::model::GltfModelObjectMetadataWrapper>;
-
 #if defined SWIGCSHARP
 
   #undef _csharp_module_name
diff --git a/src/utilities/CMakeLists.txt b/src/utilities/CMakeLists.txt
index e4775d2c06d..d41acbf2698 100644
--- a/src/utilities/CMakeLists.txt
+++ b/src/utilities/CMakeLists.txt
@@ -407,7 +407,6 @@ set(${target_name}_depends
   CONAN_PKG::cpprestsdk
   CONAN_PKG::openssl
   CONAN_PKG::geographiclib
-  CONAN_PKG::tinygltf
 )
 
 if(WIN32)


Test patch:
diff --git a/ruby/test/Gltf_Test.rb b/ruby/test/Gltf_Test.rb
new file mode 100644
index 00000000000..9abad37c03a
--- /dev/null
+++ b/ruby/test/Gltf_Test.rb
@@ -0,0 +1,74 @@
+########################################################################################################################
+#  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+#  following conditions are met:
+#
+#  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+#  disclaimer.
+#
+#  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+#  disclaimer in the documentation and/or other materials provided with the distribution.
+#
+#  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+#  derived from this software without specific prior written permission from the respective party.
+#
+#  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+#  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+#  written permission from Alliance for Sustainable Energy, LLC.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+#  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+#  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+#  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+#  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+#  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+########################################################################################################################
+
+require 'openstudio'
+require 'json'
+require 'minitest/autorun'
+
+class Gltf_Test < MiniTest::Unit::TestCase
+
+  # def setup
+  # end
+
+  # def teardown
+  # end
+
+  def common_asserts(json)
+    assert(json["asset"])
+    assert(json["asset"]["generator"])
+    assert(json["asset"]["generator"] == "OpenStudio")
+
+    assert(json["nodes"])
+    assert(json["nodes"].size == 31)
+
+    assert(!json['nodes'][0]['extras'])
+    assert(json['nodes'][1]['extras'])
+  end
+
+  def test_gltf_ExampleModel
+
+    m = OpenStudio::Model::exampleModel
+
+    ft = OpenStudio::Gltf::GltfForwardTranslator.new
+
+    json_str = ft.modelToGLTFString(m);
+    json = JSON.parse(json_str)
+    common_asserts(json)
+  end
+
+  def test_gltf_ExampleModel_convenience
+
+    m = OpenStudio::Model::exampleModel
+
+    ft = OpenStudio::Gltf::GltfForwardTranslator.new
+
+    json = ft.modelToGLTFJSON(m);
+    common_asserts(json)
+  end
+end
diff --git a/src/model/GltfBoundingBoxWrapper.hpp b/src/gltf/test/GltfFixture.cpp
similarity index 62%
rename from src/model/GltfBoundingBoxWrapper.hpp
rename to src/gltf/test/GltfFixture.cpp
index a9cfd6696a6..a069d27b53b 100644
--- a/src/model/GltfBoundingBoxWrapper.hpp
+++ b/src/gltf/test/GltfFixture.cpp
@@ -26,54 +26,31 @@
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ***********************************************************************************************************************/
-#ifndef MODEL_GLTFBOUNDINGBOXWRAPPER_HPP
-#define MODEL_GLTFBOUNDINGBOXWRAPPER_HPP
 
-#include "ModelAPI.hpp"
-#include "Model.hpp"
+#include "GltfFixture.hpp"
 
-namespace openstudio {
-//class GltfMetaDta;
-namespace model {
+#include <utilities/idd/IddFactory.hxx>
+#include "../../utilities/core/Compare.hpp"
 
-  class MODEL_API GltfBoundingBoxWrapper
-  {
-   public:
-    void setlookAtR(double value);
-    void setlookAtX(double value);
-    void setlookAtY(double value);
-    void setlookAtZ(double value);
-    void setmaxX(double value);
-    void setmaxY(double value);
-    void setmaxZ(double value);
-    void setminX(double value);
-    void setminY(double value);
-    void setminZ(double value);
+#include <resources.hxx>
+#include <OpenStudio.hxx>
 
-    double getlookAtR() const;
-    double getlookAtX() const;
-    double getlookAtY() const;
-    double getlookAtZ() const;
-    double getmaxX() const;
-    double getmaxY() const;
-    double getmaxZ() const;
-    double getminX() const;
-    double getminY() const;
-    double getminZ() const;
+using namespace openstudio;
 
-   private:
-    std::tuple<std::string, double> lookAtR;
-    std::tuple<std::string, double> lookAtX;
-    std::tuple<std::string, double> lookAtY;
-    std::tuple<std::string, double> lookAtZ;
-    std::tuple<std::string, double> maxX;
-    std::tuple<std::string, double> maxY;
-    std::tuple<std::string, double> maxZ;
-    std::tuple<std::string, double> minX;
-    std::tuple<std::string, double> minY;
-    std::tuple<std::string, double> minZ;
-  };
-}  // namespace model
-}  // namespace openstudio
+void GltfFixture::SetUp() {}
 
-#endif  //MODEL_GLTFBOUNDINGBOXWRAPPER_HPP
+void GltfFixture::TearDown() {}
+
+void GltfFixture::SetUpTestSuite() {
+  // set up logging
+  logFile = FileLogSink(toPath("./GltfFixture.log"));
+  logFile->setLogLevel(Debug);
+  Logger::instance().standardOutLogger().disable();
+}
+
+void GltfFixture::TearDownTestSuite() {
+  logFile->disable();
+}
+
+// static variables
+boost::optional<openstudio::FileLogSink> GltfFixture::logFile;
diff --git a/src/model/GltfModelObjectMetadataWrapper.hpp b/src/gltf/test/GltfFixture.hpp
similarity index 59%
rename from src/model/GltfModelObjectMetadataWrapper.hpp
rename to src/gltf/test/GltfFixture.hpp
index c60e073b1b2..8a9777a0b51 100644
--- a/src/model/GltfModelObjectMetadataWrapper.hpp
+++ b/src/gltf/test/GltfFixture.hpp
@@ -26,56 +26,36 @@
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ***********************************************************************************************************************/
-#ifndef MODEL_GLTFMODELOBJECTMETADATAWRAPPER_HPP
-#define MODEL_GLTFMODELOBJECTMETADATAWRAPPER_HPP
 
-#include "ModelAPI.hpp"
-#include "Model.hpp"
+#ifndef GLTF_TEST_GLTFFIXTURE_HPP
+#define GLTF_TEST_GLTFFIXTURE_HPP
 
-namespace openstudio {
-//class GltfMetaDta;
-namespace model {
+#include <gtest/gtest.h>
 
-  class MODEL_API GltfModelObjectMetadataWrapper
-  {
-   public:
-    void setColor(const std::string& value);
-    void setHandle(const std::string& value);
-    void setIddObjectType(const std::string& value);
-    void setName(const std::string& value);
-    void setOpen_to_below(const bool& value);
-    void setNominal_z_coordinate(const double& value);
-    void setNominal_floorCeiling_Height(const double& value);
-    void setMultiplier(const int& value);
+#include "../../utilities/core/Logger.hpp"
+#include "../../utilities/core/FileLogSink.hpp"
 
-    std::string getColor() const;
-    std::string getHandle() const;
-    std::string getIddObjectType() const;
-    std::string getName() const;
-    bool getOpen_to_below() const;
-    double getNominal_z_coordinate() const;
-    double getNominal_floorCeiling_Height() const;
-    int getMultiplier() const;
+#include <boost/optional.hpp>
 
-   private:
-    // string
-    std::tuple<std::string, std::string> color;
-    std::tuple<std::string, std::string> handle;
-    std::tuple<std::string, std::string> iddObjectType;
-    std::tuple<std::string, std::string> name;
+class GltfFixture : public ::testing::Test
+{
+ protected:
+  /// initialize for each test
+  virtual void SetUp() override;
 
-    // bool
-    std::tuple<std::string, bool> open_to_below;
+  /// tear down after each test
+  virtual void TearDown() override;
 
-    // double
-    std::tuple<std::string, double> nominal_z_coordinate;
-    std::tuple<std::string, double> nominal_floorCeiling_Height;
+  /// initialize static members
+  static void SetUpTestSuite();
 
-    // int
-    std::tuple<std::string, int> multiplier;
-  };
+  /// tear down static members
+  static void TearDownTestSuite();
 
-}  // namespace model
-}  // namespace openstudio
+  REGISTER_LOGGER("GltfFixture");
 
-#endif  //MODEL_GLTFMODELOBJECTMETADATAWRAPPER_HPP
+  // static variables
+  static boost::optional<openstudio::FileLogSink> logFile;
+};
+
+#endif  // GLTF_TEST_GLTFFIXTURE_HPP
diff --git a/src/gltf/test/GltfForwardTranslator_GTest.cpp b/src/gltf/test/GltfForwardTranslator_GTest.cpp
new file mode 100644
index 00000000000..5940c851a84
--- /dev/null
+++ b/src/gltf/test/GltfForwardTranslator_GTest.cpp
@@ -0,0 +1,932 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "GltfFixture.hpp"
+
+#include "../GltfForwardTranslator.hpp"
+#include "../GltfMetaData.hpp"
+#include "../GltfUserData.hpp"
+#include "../GltfModelObjectMetaData.hpp"
+#include "../GltfUtils.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/Space.hpp"
+#include "../../model/Space_Impl.hpp"
+#include "../../model/Surface.hpp"
+#include "../../model/Surface_Impl.hpp"
+#include "../../model/SubSurface.hpp"
+#include "../../model/SubSurface_Impl.hpp"
+#include "../../model/ConstructionAirBoundary.hpp"
+#include "../../model/Construction.hpp"
+
+#include "../../model/PlanarSurface.hpp"
+#include "../../model/PlanarSurface_Impl.hpp"
+#include "../../model/PlanarSurfaceGroup.hpp"
+#include "../../model/PlanarSurfaceGroup_Impl.hpp"
+#include "../../model/BuildingStory.hpp"
+#include "../../model/BuildingStory_Impl.hpp"
+#include "../../model/BuildingUnit.hpp"
+#include "../../model/BuildingUnit_Impl.hpp"
+#include "../../model/ThermalZone.hpp"
+#include "../../model/ThermalZone_Impl.hpp"
+#include "../../model/AirLoopHVAC.hpp"
+#include "../../model/AirLoopHVAC_Impl.hpp"
+#include "../../model/SpaceType.hpp"
+#include "../../model/SpaceType_Impl.hpp"
+#include "../../model/DefaultConstructionSet.hpp"
+#include "../../model/DefaultConstructionSet_Impl.hpp"
+#include "../../model/Space.hpp"
+#include "../../model/Space_Impl.hpp"
+
+#include "../../osversion/VersionTranslator.hpp"
+
+#include "../../utilities/core/Json.hpp"
+
+#include <resources.hxx>
+#include <OpenStudio.hxx>
+
+#include <json/json.h>
+
+#include <algorithm>
+#include <json/value.h>
+
+using namespace openstudio::gltf;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(GltfFixture, GltfForwardTranslator_ExampleModel_FullTest) {
+  GltfForwardTranslator ft;
+
+  Model m = exampleModel();
+  std::string s = ft.modelToGLTFString(m);
+
+  auto planarSurfaces = m.getModelObjects<PlanarSurface>();
+  auto nPlanarSurfaces = planarSurfaces.size();
+
+  // auto planarSurfaceGroups = m.getModelObjects<PlanarSurfaceGroup>();
+  // auto nPlanarSurfaceGroups = planarSurfaceGroups.size();
+
+  auto buildingStories = m.getConcreteModelObjects<BuildingStory>();
+  auto nBuildingStories = buildingStories.size();
+  EXPECT_EQ(1, nBuildingStories);
+
+  auto buildingUnits = m.getConcreteModelObjects<BuildingUnit>();
+  auto nBuildingUnits = buildingUnits.size();
+  EXPECT_EQ(0, nBuildingUnits);
+
+  auto thermalZones = m.getConcreteModelObjects<ThermalZone>();
+  auto nThermalZones = thermalZones.size();
+  EXPECT_EQ(1, nThermalZones);
+
+  auto airLoopHVACs = m.getConcreteModelObjects<AirLoopHVAC>();
+  auto nAirLoopHVACs = airLoopHVACs.size();
+  EXPECT_EQ(1, nAirLoopHVACs);
+
+  auto spaceTypes = m.getConcreteModelObjects<SpaceType>();
+  auto nSpaceTypes = spaceTypes.size();
+  EXPECT_EQ(1, nSpaceTypes);
+
+  auto defaultConstructionSets = m.getConcreteModelObjects<DefaultConstructionSet>();
+  auto nDefaultConstructionSets = defaultConstructionSets.size();
+  EXPECT_EQ(1, nDefaultConstructionSets);
+
+  auto spaces = m.getConcreteModelObjects<Space>();
+  auto nSpaces = spaces.size();
+  EXPECT_EQ(4, nSpaces);
+
+  auto nMetaDataSize = nBuildingStories + nBuildingUnits + nThermalZones + nAirLoopHVACs + nSpaceTypes + nDefaultConstructionSets + nSpaces;
+
+  Json::Reader reader;
+  Json::Value root;
+  bool parsingSuccessful = reader.parse(s, root);
+  ASSERT_TRUE(parsingSuccessful);
+
+  std::vector<std::pair<std::string, Json::ValueType>> allKeysAndTypes{
+    {"accessors", Json::arrayValue}, {"asset", Json::objectValue}, {"bufferViews", Json::arrayValue}, {"buffers", Json::arrayValue},
+    {"materials", Json::arrayValue}, {"meshes", Json::arrayValue}, {"nodes", Json::arrayValue},       {"scenes", Json::arrayValue},
+  };
+  for (const auto& [key, keyType] : allKeysAndTypes) {
+    assertKeyAndType(root, key, keyType);
+  }
+
+  {
+    // Accessors
+
+    // We except 3 accessors for each surfaces:
+    // * 1 SCALAR for indices
+    // * 1 VEC3 for Coordinates
+    // * 1 VEC3 for Normals
+    auto accessors = root.get("accessors", Json::arrayValue);
+    EXPECT_EQ(nPlanarSurfaces * 3, accessors.size());
+    EXPECT_EQ(nPlanarSurfaces, std::count_if(accessors.begin(), accessors.end(),
+                                             [](const auto& accessor) { return accessor.get("type", "").asString() == "SCALAR"; }));
+    EXPECT_EQ(nPlanarSurfaces * 2,
+              std::count_if(accessors.begin(), accessors.end(), [](const auto& accessor) { return accessor.get("type", "").asString() == "VEC3"; }));
+  }
+
+  {
+    // Asset
+    assertKeyAndType(root, "asset", Json::objectValue);
+    auto asset = root.get("asset", Json::objectValue);
+    assertKeyAndType(asset, "generator", Json::stringValue);
+    EXPECT_EQ("OpenStudio", asset.get("generator", Json::stringValue).asString());
+    assertKeyAndType(asset, "version", Json::stringValue);
+    EXPECT_EQ("2.0", asset.get("version", Json::stringValue).asString());
+  }
+
+  {
+    // BufferViews
+    auto bufferViews = root.get("bufferViews", Json::arrayValue);
+    {
+      // First one
+      auto bufferView = bufferViews[0];
+      assertKeyAndType(bufferView, "buffer", Json::intValue);
+      EXPECT_EQ(0, bufferView.get("buffer", -999).asInt());
+      assertKeyAndType(bufferView, "byteLength", Json::intValue);
+      EXPECT_EQ(268, bufferView.get("byteLength", -999).asInt());
+      assertKeyAndType(bufferView, "target", Json::intValue);
+      EXPECT_EQ(34963, bufferView.get("target", -999).asInt());
+
+      // Not needed for the first one
+      EXPECT_FALSE(checkKey(bufferView, "byteOffset"));
+      EXPECT_FALSE(checkKey(bufferView, "byteStride"));
+    }
+    {
+      // Second one
+      auto bufferView = bufferViews[1];
+      assertKeyAndType(bufferView, "buffer", Json::intValue);
+      EXPECT_EQ(0, bufferView.get("buffer", -999).asInt());
+      assertKeyAndType(bufferView, "byteLength", Json::intValue);
+      EXPECT_EQ(3072, bufferView.get("byteLength", -999).asInt());
+      assertKeyAndType(bufferView, "target", Json::intValue);
+      EXPECT_EQ(34962, bufferView.get("target", -999).asInt());
+
+      assertKeyAndType(bufferView, "byteOffset", Json::intValue);
+      EXPECT_EQ(268, bufferView.get("byteOffset", -999).asInt());
+      assertKeyAndType(bufferView, "byteStride", Json::intValue);
+      EXPECT_EQ(12, bufferView.get("byteStride", -999).asInt());
+    }
+  }
+
+  {
+    // Buffers: there's only one
+    assertKeyAndType(root, "buffers", Json::arrayValue);
+    auto buffers = root.get("buffers", Json::arrayValue);
+    ASSERT_EQ(1, buffers.size());
+    auto buffer = buffers[0];
+    ASSERT_TRUE(buffer.isObject());
+
+    assertKeyAndType(buffer, "byteLength", Json::intValue);
+    EXPECT_EQ(3340, buffer.get("byteLength", -999).asInt());
+
+    std::string startsWith = "data:application/octet-stream;base64,";
+    assertKeyAndType(buffer, "uri", Json::stringValue);
+    auto uri = buffer.get("uri", "").asString();
+    EXPECT_EQ(startsWith, uri.substr(0, startsWith.size()));
+  }
+
+  {
+    // Materials
+    auto materials = root.get("materials", Json::arrayValue);
+    EXPECT_EQ(9, materials.size());
+    // This is already sorted
+    std::vector<std::string> expectedMaterialNames{"BuildingShading", "Door", "Floor", "InteriorPartitionSurface", "RoofCeiling", "SiteShading",
+                                                   "SpaceShading",    "Wall", "Window"};
+    std::vector<std::string> foundMaterialNames;
+    std::vector<std::pair<std::string, Json::ValueType>> theKeysAndType{
+      {"doubleSided", Json::booleanValue},
+      {"emissiveFactor", Json::arrayValue},
+      {"name", Json::stringValue},
+      {"pbrMetallicRoughness", Json::objectValue},
+    };
+    for (auto& material : materials) {
+      for (const auto& [key, keyType] : theKeysAndType) {
+        assertKeyAndType(material, key, keyType);
+      }
+      foundMaterialNames.emplace_back(material.get("name", "").asString());
+    }
+    std::sort(foundMaterialNames.begin(), foundMaterialNames.end());
+    EXPECT_EQ(expectedMaterialNames, foundMaterialNames);
+  }
+
+  {
+    // Meshes: one per Surface
+    auto meshes = root.get("meshes", Json::arrayValue);
+    ASSERT_EQ(nPlanarSurfaces, meshes.size());
+
+    std::vector<std::pair<std::string, Json::ValueType>> primitiveKeysAndTypes{
+      {"attributes", Json::objectValue},
+      {"indices", Json::intValue},
+      {"material", Json::intValue},
+      {"mode", Json::intValue},
+    };
+
+    std::vector<std::string> foundMeshNames;
+    for (auto& mesh : meshes) {
+      assertKeyAndType(mesh, "name", Json::stringValue);
+      foundMeshNames.emplace_back(mesh.get("name", "").asString());
+
+      assertKeyAndType(mesh, "primitives", Json::arrayValue);
+      auto primitives = mesh.get("primitives", Json::arrayValue);
+      ASSERT_EQ(1, primitives.size());
+      auto primitive = primitives[0];
+      ASSERT_TRUE(primitive.isObject());
+      for (const auto& [key, keyType] : primitiveKeysAndTypes) {
+        assertKeyAndType(primitive, key, keyType);
+      }
+    }
+
+    std::vector<std::string> expectedMeshNames;
+    for (const auto& planarSurface : planarSurfaces) {
+      expectedMeshNames.emplace_back(planarSurface.nameString());
+    }
+
+    std::sort(expectedMeshNames.begin(), expectedMeshNames.end());
+    std::sort(foundMeshNames.begin(), foundMeshNames.end());
+    EXPECT_EQ(expectedMeshNames, foundMeshNames);
+  }
+
+  {
+
+    // Nodes: the first one is the topNode, and it has all the other ones as children
+    auto nodes = root.get("nodes", Json::arrayValue);
+    EXPECT_EQ(nPlanarSurfaces + 1, nodes.size());
+    std::vector<std::pair<std::string, Json::ValueType>> theKeysAndType{
+      {"matrix", Json::arrayValue},
+      {"name", Json::stringValue},
+    };
+    auto topNode = nodes[0];
+    for (const auto& [key, keyType] : theKeysAndType) {
+      assertKeyAndType(topNode, key, keyType);
+    }
+    EXPECT_EQ("Z_UP", topNode.get("name", "").asString());
+    assertKeyAndType(topNode, "children", Json::arrayValue);
+    auto children = topNode.get("children", Json::arrayValue);
+    ASSERT_EQ(30, children.size());
+    for (int i = 0; i < 30; ++i) {
+      EXPECT_EQ(i + 1, children[i].asInt());
+    }
+    EXPECT_FALSE(checkKey(topNode, "extras"));
+
+    std::vector<std::pair<std::string, Json::ValueType>> extrasKeysAndType{
+      // TODO: THESE SHOULD BE AS AN ARRAY OF OBJECTS
+      {"airLoopHVACHandles", Json::objectValue},
+      {"airLoopHVACMaterialNames", Json::objectValue},
+      {"airLoopHVACNames", Json::objectValue},
+      // Real
+      {"illuminanceSetpoint", Json::realValue},
+      // Booleans
+      {"airWall", Json::booleanValue},
+      {"coincidentWithOutsideObject", Json::booleanValue},
+      // Strings
+      {"boundaryMaterialName", Json::stringValue},
+      {"buildingStoryHandle", Json::stringValue},
+      {"buildingStoryMaterialName", Json::stringValue},
+      {"buildingStoryName", Json::stringValue},
+      {"buildingUnitHandle", Json::stringValue},
+      {"buildingUnitMaterialName", Json::stringValue},
+      {"buildingUnitName", Json::stringValue},
+      {"constructionHandle", Json::stringValue},
+      {"constructionMaterialName", Json::stringValue},
+      {"constructionName", Json::stringValue},
+      {"constructionSetHandle", Json::stringValue},
+      {"constructionSetMaterialName", Json::stringValue},
+      {"constructionSetName", Json::stringValue},
+      {"handle", Json::stringValue},
+      {"name", Json::stringValue},
+      {"outsideBoundaryCondition", Json::stringValue},
+      {"outsideBoundaryConditionObjectHandle", Json::stringValue},
+      {"outsideBoundaryConditionObjectName", Json::stringValue},
+      {"shadingHandle", Json::stringValue},
+      {"shadingName", Json::stringValue},
+      {"spaceHandle", Json::stringValue},
+      {"spaceName", Json::stringValue},
+      {"spaceTypeHandle", Json::stringValue},
+      {"spaceTypeMaterialName", Json::stringValue},
+      {"spaceTypeName", Json::stringValue},
+      {"subSurfaceHandle", Json::stringValue},
+      {"subSurfaceName", Json::stringValue},
+      {"sunExposure", Json::stringValue},
+      {"surfaceHandle", Json::stringValue},
+      {"surfaceName", Json::stringValue},
+      {"surfaceType", Json::stringValue},
+      {"surfaceTypeMaterialName", Json::stringValue},
+      {"thermalZoneHandle", Json::stringValue},
+      {"thermalZoneMaterialName", Json::stringValue},
+      {"thermalZoneName", Json::stringValue},
+      {"windExposure", Json::stringValue},
+    };
+    bool isTopNode = true;
+    for (auto& node : nodes) {
+      if (isTopNode) {
+        isTopNode = false;
+        continue;
+      }
+
+      assertKeyAndType(node, "extras", Json::objectValue);
+      auto extras = node.get("extras", Json::objectValue);
+      for (const auto& [key, keyType] : extrasKeysAndType) {
+        if (keyType != Json::objectValue) {
+          assertKeyAndType(extras, key, keyType);
+        } else {
+          checkKey(extras, key);
+          EXPECT_TRUE(checkType(extras, key, Json::objectValue) || checkType(extras, key, Json::nullValue));
+        }
+      }
+    }
+
+    // TODO: should probably at least spot check one of the node's extras
+    // TODO: There's an (existing) mistake with respect to materials... The node extras define materials that aren't actually in the "material" key
+  }
+
+  {
+    // Scenes: there's only one
+    auto scenes = root.get("scenes", Json::arrayValue);
+    ASSERT_EQ(1, scenes.size());
+    auto scene = scenes[0];
+    ASSERT_TRUE(scene.isObject());
+
+    // "nodes" : [0]
+    assertKeyAndType(scene, "nodes", Json::arrayValue);
+    auto nodes = scene.get("nodes", Json::arrayValue);
+    ASSERT_EQ(1, nodes.size());
+    ASSERT_EQ(0, nodes[0].asInt());
+
+    // extras: that's the main dish
+    assertKeyAndType(scene, "extras", Json::objectValue);
+    auto extras = scene.get("extras", Json::objectValue);
+    std::vector<std::string> allExtrasKeys{"boundingbox", "buildingStoryNames", "generator", "modelObjectMetaData", "northAxis", "type", "version"};
+    for (const auto& key : allExtrasKeys) {
+      assertKey(extras, key);
+    }
+    // Strings
+    assertKeyAndType(extras, "generator", Json::stringValue);
+    EXPECT_EQ("OpenStudio", extras.get("generator", Json::stringValue).asString());
+    assertKeyAndType(extras, "type", Json::stringValue);
+    EXPECT_EQ("Object", extras.get("type", Json::stringValue).asString());
+    assertKeyAndType(extras, "version", Json::stringValue);
+    EXPECT_EQ(openStudioVersion(), extras.get("version", Json::stringValue).asString());
+
+    // North Axis: float
+    assertKeyAndType(extras, "northAxis", Json::realValue);
+    EXPECT_DOUBLE_EQ(0.0, extras.get("northAxis", -999).asDouble());
+
+    {
+      assertKeyAndType(extras, "boundingbox", Json::objectValue);
+      auto boundingbox = extras.get("boundingbox", Json::objectValue);
+      std::vector<std::string> boundingBoxKeys{"lookAtR", "lookAtX", "lookAtY", "lookAtZ", "maxX", "maxY", "maxZ", "minX", "minY", "minZ"};
+      for (const auto& key : boundingBoxKeys) {
+        assertKeyAndType(boundingbox, key, Json::realValue);
+      }
+
+      EXPECT_DOUBLE_EQ(20.615528128088304, boundingbox.get("lookAtR", -999).asDouble());
+      EXPECT_DOUBLE_EQ(0.0, boundingbox.get("lookAtX", -999).asDouble());
+      EXPECT_DOUBLE_EQ(0.0, boundingbox.get("lookAtY", -999).asDouble());
+      EXPECT_DOUBLE_EQ(0.0, boundingbox.get("lookAtZ", -999).asDouble());
+      EXPECT_DOUBLE_EQ(20.55, boundingbox.get("maxX", -999).asDouble());
+      EXPECT_DOUBLE_EQ(20.0, boundingbox.get("maxY", -999).asDouble());
+      EXPECT_DOUBLE_EQ(20.0, boundingbox.get("maxZ", -999).asDouble());
+      EXPECT_DOUBLE_EQ(-30.0, boundingbox.get("minX", -999).asDouble());
+      EXPECT_DOUBLE_EQ(-1.0, boundingbox.get("minY", -999).asDouble());
+      EXPECT_DOUBLE_EQ(0.0, boundingbox.get("minZ", -999).asDouble());
+    }
+    {
+      // TODO: this should be an array!!!
+      assertKeyAndType(extras, "buildingStoryNames", Json::objectValue);
+      auto buildingStoryNames = extras.get("buildingStoryNames", Json::objectValue);
+      assertKeyAndType(buildingStoryNames, "0", Json::stringValue);
+      EXPECT_EQ("Building Story 1", buildingStoryNames.get("0", Json::stringValue).asString());
+    }
+
+    {
+      // TODO: this should be an array!!!
+      assertKeyAndType(extras, "modelObjectMetaData", Json::objectValue);
+      auto modelObjectMetaData = extras.get("modelObjectMetaData", Json::objectValue);
+
+      std::vector<std::pair<std::string, Json::ValueType>> theKeysAndType{
+        {"color", Json::stringValue},
+        {"handle", Json::stringValue},
+        {"iddObjectType", Json::stringValue},
+        {"multiplier", Json::intValue},
+        {"name", Json::stringValue},
+        {"nominal_floorCeiling_Height", Json::realValue},
+        {"nominal_z_coordinate", Json::realValue},
+        {"open_to_below", Json::booleanValue},
+      };
+
+      for (size_t i = 0; i < nMetaDataSize; ++i) {
+        assertKeyAndType(modelObjectMetaData, std::to_string(i), Json::objectValue);
+        auto theMetaData = modelObjectMetaData.get(std::to_string(i), Json::objectValue);
+        for (const auto& [key, keyType] : theKeysAndType) {
+          assertKeyAndType(theMetaData, key, keyType);
+        }
+      }
+
+      // TODO: Should at least spot check one
+    }
+  }
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 9 materials
+// 30 meshes
+// 31 nodes
+// 30 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_ExampleModel) {
+  GltfForwardTranslator ft;
+  openstudio::path outputPath;
+  openstudio::path inputPath;
+  outputPath = resourcesPath() / toPath("utilities/Geometry/exampleModel.gltf");
+  // Create OSM
+  Model model = exampleModel();
+  model.save(resourcesPath() / toPath("model/exampleModel.osm"), true);
+  // Generate glTF
+  bool isExported = ft.modelToGLTF(model, outputPath);
+  ASSERT_TRUE(isExported);
+  inputPath = outputPath;
+  // Load glTF
+  bool isLoaded = ft.loadGLTF(inputPath);
+  ASSERT_TRUE(isLoaded);
+  GltfMetaData glTFMetaData = ft.getMetaData();
+
+  EXPECT_EQ("OpenStudio", glTFMetaData.generator());
+  EXPECT_DOUBLE_EQ(0.0, glTFMetaData.northAxis());
+  EXPECT_EQ("Object", glTFMetaData.type());
+  EXPECT_EQ(openStudioVersion(), glTFMetaData.version());
+
+  GltfBoundingBox glTFBoundingBox = glTFMetaData.glTFBoundingBox();
+  // TODO: add delta during assertion
+  ASSERT_DOUBLE_EQ(glTFBoundingBox.lookAtR(), 20.615528128088304);
+  ASSERT_EQ(glTFBoundingBox.lookAtX(), 0.0);
+  ASSERT_EQ(glTFBoundingBox.lookAtY(), 0.0);
+  ASSERT_EQ(glTFBoundingBox.lookAtZ(), 0.0);
+  ASSERT_EQ(glTFBoundingBox.maxX(), 20.55);
+  ASSERT_EQ(glTFBoundingBox.maxY(), 20);
+  ASSERT_EQ(glTFBoundingBox.maxZ(), 20);
+  ASSERT_EQ(glTFBoundingBox.minX(), -30);
+  ASSERT_EQ(glTFBoundingBox.minY(), -1);
+  ASSERT_EQ(glTFBoundingBox.minZ(), 0.0);
+
+  auto buildingStoreys = glTFMetaData.buildingStoryNames();
+  ASSERT_EQ(1, buildingStoreys.size());
+  ASSERT_TRUE("Building Story 1" == buildingStoreys.front());
+
+  auto _modelObjectMetaDataCollection = glTFMetaData.glTFModelObjectMetaDataVector();
+  ASSERT_EQ(9, _modelObjectMetaDataCollection.size());
+  // TODO: Assert few of the attributes from one of the modelObjectMetaData Collection
+  GltfModelObjectMetaData glTFModelObjectMetadata = _modelObjectMetaDataCollection.front();
+  std::string name0 = _modelObjectMetaDataCollection[0].name();
+  std::string name1 = _modelObjectMetaDataCollection[1].name();
+  ASSERT_FALSE(name0 == name1);
+  /* std::string name2 = _modelObjectMetaDataCollection[2].name();
+  std::string name3 = _modelObjectMetaDataCollection[3].name();
+  std::string name4 = _modelObjectMetaDataCollection[4].name();
+  std::string name5 = _modelObjectMetaDataCollection[5].name();
+  std::string name6 = _modelObjectMetaDataCollection[6].name();
+  std::string name7 = _modelObjectMetaDataCollection[7].name();
+  std::string name8 = _modelObjectMetaDataCollection[8].name();*/
+
+  ASSERT_EQ(glTFMetaData.buildingStoryCount(), 1);
+  ASSERT_EQ(glTFMetaData.thermalZoneCount(), 1);
+  ASSERT_EQ(glTFMetaData.spaceCount(), 4);
+  ASSERT_EQ(glTFMetaData.spaceTypeCount(), 1);
+  ASSERT_EQ(glTFMetaData.constructionSetCount(), 1);
+  ASSERT_EQ(glTFMetaData.airLoopCount(), 1);
+
+  std::vector<GltfUserData> glTFUserDataVector = ft.getUserDataCollection();
+  ASSERT_EQ(glTFUserDataVector.size(), 30);
+  boost::optional<GltfUserData> glTFUserData = ft.getUserDataBySurfaceName("Surface 1");
+  ASSERT_TRUE(glTFUserData);
+  ASSERT_TRUE(glTFUserData->surfaceType() == "Floor");
+  ASSERT_TRUE(glTFUserData->constructionMaterialName() == "Construction_Slab");
+  ASSERT_TRUE(glTFUserData->thermalZoneName() == "Thermal Zone 1");
+  ASSERT_TRUE(glTFUserData->sunExposure() == "NoSun");
+  ASSERT_TRUE(glTFUserData->windExposure() == "NoWind");
+  ASSERT_TRUE(glTFUserData->illuminanceSetpoint() == 0.0);
+  ASSERT_TRUE(glTFUserData->outsideBoundaryCondition() == "Ground");
+  ASSERT_TRUE(glTFUserData->boundaryMaterialName() == "Boundary_Ground");
+}
+
+TEST_F(GltfFixture, GltfForwardTranslator_ParkUnder_Retail_Office_C2) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/ParkUnder_Retail_Office_C2.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/ParkUnder_Retail_Office_C2.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 5 materials
+// 750 meshes
+// 751 nodes
+// 750 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_ASHRAECourthouse) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/ASHRAECourthouse.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/ASHRAECourthouse.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 4 materials
+// 481 meshes
+// 482 nodes
+// 481 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_RefBldgSecondarySchoolNew2004_Chicago) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgSecondarySchoolNew2004_Chicago.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgSecondarySchoolNew2004_Chicago.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 5 materials
+// 443 meshes
+// 444 nodes
+// 443 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_RefBldgHospitalNew2004_Chicago) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgHospitalNew2004_Chicago.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgHospitalNew2004_Chicago.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// 0 animations
+// 5 materials
+// 871 meshes
+// 872 nodes
+// 871 primitives
+// 0 textures
+// Extensions: None
+// FIXED : 1742 Validation issues
+// starting from :
+// ACCESSOR_TOTAL_OFFSET_ALIGNMENT	Accessor's total byteOffset 7162 isn't a multiple of componentType length 4.
+// /accessors/1
+TEST_F(GltfFixture, GltfForwardTranslator_RefBldgOutPatientNew2004_Chicago) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgOutPatientNew2004_Chicago.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgOutPatientNew2004_Chicago.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 5 materials
+// 589 meshes
+// 590 nodes
+// 589 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_RefBldgSmallHotelNew2004_Chicago) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgSmallHotelNew2004_Chicago.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgSmallHotelNew2004_Chicago.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 4 materials
+// 21 meshes
+// 22 nodes
+// 21 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_RefBldgFullServiceRestaurantNew2004_Chicago) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/RefBldgFullServiceRestaurantNew2004_Chicago.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/RefBldgFullServiceRestaurantNew2004_Chicago.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 5 materials
+// 208 meshes
+// 209 nodes
+// 208 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_RefBldgLargeHotelNew2004_Chicago) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/RefBldgLargeHotelNew2004_Chicago.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/RefBldgLargeHotelNew2004_Chicago.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 4 materials
+// 142 meshes
+// 143 nodes
+// 142 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_RefBldgLargeOfficeNew2004_Chicago) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/RefBldgLargeOfficeNew2004_Chicago.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/RefBldgLargeOfficeNew2004_Chicago.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 4 materials
+// 80 meshes
+// 81 nodes
+// 80 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_Space_SurfaceMatch_LargeTest) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/Space_SurfaceMatch_LargeTest.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/Space_SurfaceMatch_LargeTest.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 3 materials
+// 1515 meshes
+// 1516 nodes
+// 1515 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_15023_Model12) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/15023_Model12.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/15023_Model12.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 3 materials
+// 21 meshes
+// 22 nodes
+// 21 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_split_level) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/split_level.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/split_level.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 3 materials
+// 24 meshes
+// 25 nodes
+// 24 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_open_to_below) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/open_to_below.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/open_to_below.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Load Test with and without bin file
+TEST_F(GltfFixture, GltfForwardTranslator_LoadTest) {
+  GltfForwardTranslator ft;
+  openstudio::path inputPath;
+  openstudio::path inputNonEmbededPath;
+  inputPath = resourcesPath() / toPath("utilities/Geometry/minimal_GLTF_File.gltf");
+  inputNonEmbededPath = resourcesPath() / toPath("utilities/Geometry/input.gltf");
+  bool result = ft.loadGLTF(inputPath, inputNonEmbededPath);
+  ASSERT_TRUE(result);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 1 materials
+// 1 meshes
+// 1 nodes
+// 1 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_CreateTriangleGLTFTest) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  openstudio::path output_2;
+  output = resourcesPath() / toPath("utilities/Geometry/triangle.gltf");
+  // Passed Raw buffer data
+  bool result = createTriangleGLTF(output);
+  ASSERT_TRUE(result);
+  output_2 = resourcesPath() / toPath("utilities/Geometry/triangle_2.gltf");
+  // Creates Raw buffer data from Point3dVector
+  bool result_2 = createTriangleGLTFFromPoint3DVector(output_2);
+  ASSERT_TRUE(result_2);
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 4 materials
+// 3915 meshes
+// 3916 nodes
+// 3915 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_7_7_Windows_Complete) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/7-7_Windows_Complete.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/7-7_Windows_Complete.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// VersionTranslator.cpp@590 : Unable to retrieve OpenStudio Version 3.2.2 IDD from the IddFactory."
+// thrown in the test body.
+TEST_F(GltfFixture, GltfForwardTranslator_story_multipliers) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/story_multipliers.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/story_multipliers.osm");
+  //model::OptionalModel model = translator.loadModel(modelPath);
+  //bool result = ft.modelToGLTF(model.get(), output);
+  //ASSERT_TRUE(result);
+}
+
+//  Assertion failed: this->is_initialized() | Optional.hpp 1212
+TEST_F(GltfFixture, GltfForwardTranslator_story_space_heights) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/story_space_heights.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/story_space_heights.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  /*bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);*/
+}
+
+// Validation report
+// Format: glTF 2.0
+// Stats:
+// 0 animations
+// 3 materials
+// 227 meshes
+// 228 nodes
+// 227 primitives
+// 0 textures
+// Extensions: None
+TEST_F(GltfFixture, GltfForwardTranslator_floorplan_school) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/floorplan_school.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/floorplan_school.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);
+}
+
+// Assertion failed: this->is_initialized() | Optional.hpp 1212
+TEST_F(GltfFixture, GltfForwardTranslator_two_stories_pre_intersect) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/two_stories_pre_intersect.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/two_stories_pre_intersect.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  /*bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);*/
+}
+
+// Assertion failed: this->is_initialized() | Optinoal.hpp 1212
+TEST_F(GltfFixture, GltfForwardTranslator_TwoStoryOffice_Trane) {
+  GltfForwardTranslator ft;
+  openstudio::path output;
+  output = resourcesPath() / toPath("utilities/Geometry/TwoStoryOffice_Trane.gltf");
+  osversion::VersionTranslator translator;
+  openstudio::path modelPath = resourcesPath() / toPath("model/TwoStoryOffice_Trane.osm");
+  model::OptionalModel model = translator.loadModel(modelPath);
+  /*bool result = ft.modelToGLTF(model.get(), output);
+  ASSERT_TRUE(result);*/
+}
diff --git a/src/model/test/GltfForwardTranslator_GTest.cpp b/src/model/test/GltfForwardTranslator_GTest.cpp
deleted file mode 100644
index 5d19a8109d5..00000000000
--- a/src/model/test/GltfForwardTranslator_GTest.cpp
+++ /dev/null
@@ -1,523 +0,0 @@
-/***********************************************************************************************************************
-*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
-*
-*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
-*  following conditions are met:
-*
-*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
-*  disclaimer.
-*
-*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
-*  disclaimer in the documentation and/or other materials provided with the distribution.
-*
-*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
-*  derived from this software without specific prior written permission from the respective party.
-*
-*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
-*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
-*  written permission from Alliance for Sustainable Energy, LLC.
-*
-*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
-*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-***********************************************************************************************************************/
-
-#include <gtest/gtest.h>
-#include "ModelFixture.hpp"
-#include "../GltfForwardTranslator.hpp"
-#include "../Model.hpp"
-#include "../Space.hpp"
-#include "../Space_Impl.hpp"
-#include "../Surface.hpp"
-#include "../Surface_Impl.hpp"
-#include "../SubSurface.hpp"
-#include "../SubSurface_Impl.hpp"
-#include "../ConstructionAirBoundary.hpp"
-#include "../../osversion/VersionTranslator.hpp"
-#include "../Construction.hpp"
-#include <algorithm>
-
-using namespace openstudio;
-using namespace openstudio::model;
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 9 materials
-// 30 meshes
-// 31 nodes
-// 30 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_ExampleModel) {
-  GltfForwardTranslator ft;
-  openstudio::path outputPath;
-  openstudio::path inputPath;
-  openstudio::path inputNonEmbededPath;
-  outputPath = resourcesPath() / toPath("utilities/Geometry/exampleModel.gltf");
-  // Create OSM
-  Model model = exampleModel();
-  model.save(resourcesPath() / toPath("model/exampleModel.osm"), true);
-  // Generate glTF
-  bool isExported = ft.modelToGLTF(model, outputPath);
-  ASSERT_TRUE(isExported);
-  inputPath = outputPath;
-  // Load glTF
-  bool isLoaded = ft.loadGLTF(inputPath);
-  ASSERT_TRUE(isLoaded);
-  GltfMetaDataWrapper glTFMetaData = ft.getMetaData();
-
-  ASSERT_TRUE("OpenStudio" == glTFMetaData.getGenerator());
-  ASSERT_EQ(glTFMetaData.getNorthAxis(), -0.00);
-  ASSERT_TRUE("Object" == glTFMetaData.getType());
-  ASSERT_TRUE("4.3" == glTFMetaData.getVersion());
-
-  GltfBoundingBoxWrapper glTFBoundingBox = glTFMetaData.getglTFBoundingBoxWrapper();
-  // TODO: add delta during assertion
-  ASSERT_DOUBLE_EQ(glTFBoundingBox.getlookAtR(), 20.615528128088304);
-  ASSERT_EQ(glTFBoundingBox.getlookAtX(), 0.0);
-  ASSERT_EQ(glTFBoundingBox.getlookAtY(), 0.0);
-  ASSERT_EQ(glTFBoundingBox.getlookAtZ(), 0.0);
-  ASSERT_EQ(glTFBoundingBox.getmaxX(), 20.55);
-  ASSERT_EQ(glTFBoundingBox.getmaxY(), 20);
-  ASSERT_EQ(glTFBoundingBox.getmaxZ(), 20);
-  ASSERT_EQ(glTFBoundingBox.getminX(), -30);
-  ASSERT_EQ(glTFBoundingBox.getminY(), -1);
-  ASSERT_EQ(glTFBoundingBox.getminZ(), 0.0);
-
-  auto buildingStoreys = glTFMetaData.getBuildingStoryNames();
-  ASSERT_EQ(1, buildingStoreys.size());
-  ASSERT_TRUE("Building Story 1" == buildingStoreys.front());
-
-  auto _modelObjectMetaDataCollection = glTFMetaData.getglTFModelObjectMetadataWrapper();
-  ASSERT_EQ(9, _modelObjectMetaDataCollection.size());
-  // TODO: Assert few of the attributes from one of the modelObjectMetaData Collection
-  GltfModelObjectMetadataWrapper glTFModelObjectMetadata = _modelObjectMetaDataCollection.front();
-  std::string name0 = _modelObjectMetaDataCollection[0].getName();
-  std::string name1 = _modelObjectMetaDataCollection[1].getName();
-  ASSERT_FALSE(name0 == name1);
-  /* std::string name2 = _modelObjectMetaDataCollection[2].getName();
-  std::string name3 = _modelObjectMetaDataCollection[3].getName();
-  std::string name4 = _modelObjectMetaDataCollection[4].getName();
-  std::string name5 = _modelObjectMetaDataCollection[5].getName();
-  std::string name6 = _modelObjectMetaDataCollection[6].getName();
-  std::string name7 = _modelObjectMetaDataCollection[7].getName();
-  std::string name8 = _modelObjectMetaDataCollection[8].getName();*/
-
-  ASSERT_EQ(glTFMetaData.getStoryCount(), 1);
-  ASSERT_EQ(glTFMetaData.getThermalZoneCount(), 1);
-  ASSERT_EQ(glTFMetaData.getSpaceCount(), 4);
-  ASSERT_EQ(glTFMetaData.getSpaceTypeCount(), 1);
-  ASSERT_EQ(glTFMetaData.getConstructionSetCount(), 1);
-  ASSERT_EQ(glTFMetaData.getAirLoopCount(), 1);
-
-  std::vector<GltfUserDataWrapper> glTFUserDataVector = ft.getUserDataCollection();
-  ASSERT_EQ(glTFUserDataVector.size(), 30);
-  GltfUserDataWrapper glTFUserData = ft.getUserDataBySurfaceName("Surface 1");
-  ASSERT_TRUE(glTFUserData.getSurfaceType() == "Floor");
-  ASSERT_TRUE(glTFUserData.getConstructionMaterialName() == "Construction_Slab");
-  ASSERT_TRUE(glTFUserData.getThermalZoneName() == "Thermal Zone 1");
-  ASSERT_TRUE(glTFUserData.getSunExposure() == "NoSun");
-  ASSERT_TRUE(glTFUserData.getWindExposure() == "NoWind");
-  ASSERT_TRUE(glTFUserData.getIlluminanceSetpoint() == 0.0);
-  ASSERT_TRUE(glTFUserData.getOutsideBoundaryCondition() == "Ground");
-  ASSERT_TRUE(glTFUserData.getBoundaryMaterialName() == "Boundary_Ground");
-}
-
-TEST_F(ModelFixture, GltfForwardTranslator_ParkUnder_Retail_Office_C2) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/ParkUnder_Retail_Office_C2.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/ParkUnder_Retail_Office_C2.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 5 materials
-// 750 meshes
-// 751 nodes
-// 750 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_ASHRAECourthouse) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/ASHRAECourthouse.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/ASHRAECourthouse.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 4 materials
-// 481 meshes
-// 482 nodes
-// 481 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_RefBldgSecondarySchoolNew2004_Chicago) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgSecondarySchoolNew2004_Chicago.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgSecondarySchoolNew2004_Chicago.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 5 materials
-// 443 meshes
-// 444 nodes
-// 443 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_RefBldgHospitalNew2004_Chicago) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgHospitalNew2004_Chicago.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgHospitalNew2004_Chicago.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// 0 animations
-// 5 materials
-// 871 meshes
-// 872 nodes
-// 871 primitives
-// 0 textures
-// Extensions: None
-// FIXED : 1742 Validation issues
-// starting from :
-// ACCESSOR_TOTAL_OFFSET_ALIGNMENT	Accessor's total byteOffset 7162 isn't a multiple of componentType length 4.
-// /accessors/1
-TEST_F(ModelFixture, GltfForwardTranslator_RefBldgOutPatientNew2004_Chicago) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgOutPatientNew2004_Chicago.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgOutPatientNew2004_Chicago.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 5 materials
-// 589 meshes
-// 590 nodes
-// 589 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_RefBldgSmallHotelNew2004_Chicago) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/Sample_DOE-RefBldgSmallHotelNew2004_Chicago.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgSmallHotelNew2004_Chicago.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 4 materials
-// 21 meshes
-// 22 nodes
-// 21 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_RefBldgFullServiceRestaurantNew2004_Chicago) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/RefBldgFullServiceRestaurantNew2004_Chicago.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/RefBldgFullServiceRestaurantNew2004_Chicago.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 5 materials
-// 208 meshes
-// 209 nodes
-// 208 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_RefBldgLargeHotelNew2004_Chicago) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/RefBldgLargeHotelNew2004_Chicago.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/RefBldgLargeHotelNew2004_Chicago.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 4 materials
-// 142 meshes
-// 143 nodes
-// 142 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_RefBldgLargeOfficeNew2004_Chicago) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/RefBldgLargeOfficeNew2004_Chicago.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/RefBldgLargeOfficeNew2004_Chicago.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 4 materials
-// 80 meshes
-// 81 nodes
-// 80 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_Space_SurfaceMatch_LargeTest) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/Space_SurfaceMatch_LargeTest.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/Space_SurfaceMatch_LargeTest.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 3 materials
-// 1515 meshes
-// 1516 nodes
-// 1515 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_15023_Model12) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/15023_Model12.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/15023_Model12.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 3 materials
-// 21 meshes
-// 22 nodes
-// 21 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_split_level) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/split_level.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/split_level.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 3 materials
-// 24 meshes
-// 25 nodes
-// 24 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_open_to_below) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/open_to_below.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/open_to_below.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Load Test with and without bin file
-TEST_F(ModelFixture, GltfForwardTranslator_LoadTest) {
-  GltfForwardTranslator ft;
-  openstudio::path inputPath;
-  openstudio::path inputNonEmbededPath;
-  inputPath = resourcesPath() / toPath("utilities/Geometry/minimal_GLTF_File.gltf");
-  inputNonEmbededPath = resourcesPath() / toPath("utilities/Geometry/input.gltf");
-  bool result = ft.loadGLTF(inputPath, inputNonEmbededPath);
-  ASSERT_TRUE(result);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 1 materials
-// 1 meshes
-// 1 nodes
-// 1 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_CreateTriangleGLTFTest) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  openstudio::path output_2;
-  output = resourcesPath() / toPath("utilities/Geometry/triangle.gltf");
-  // Passed Raw buffer data
-  bool result = ft.createTriangleGLTF(output);
-  ASSERT_TRUE(result);
-  output_2 = resourcesPath() / toPath("utilities/Geometry/triangle_2.gltf");
-  // Creates Raw buffer data from Point3dVector
-  bool result_2 = ft.createTriangleGLTFFromPoint3DVector(output_2);
-  ASSERT_TRUE(result_2);
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 4 materials
-// 3915 meshes
-// 3916 nodes
-// 3915 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_7_7_Windows_Complete) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/7-7_Windows_Complete.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/7-7_Windows_Complete.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// VersionTranslator.cpp@590 : Unable to retrieve OpenStudio Version 3.2.2 IDD from the IddFactory."
-// thrown in the test body.
-TEST_F(ModelFixture, GltfForwardTranslator_story_multipliers) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/story_multipliers.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/story_multipliers.osm");
-  //model::OptionalModel model = translator.loadModel(modelPath);
-  //bool result = ft.modelToGLTF(model.get(), output);
-  //ASSERT_TRUE(result);
-}
-
-//  Assertion failed: this->is_initialized() | Optional.hpp 1212
-TEST_F(ModelFixture, GltfForwardTranslator_story_space_heights) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/story_space_heights.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/story_space_heights.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  /*bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);*/
-}
-
-// Validation report
-// Format: glTF 2.0
-// Stats:
-// 0 animations
-// 3 materials
-// 227 meshes
-// 228 nodes
-// 227 primitives
-// 0 textures
-// Extensions: None
-TEST_F(ModelFixture, GltfForwardTranslator_floorplan_school) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/floorplan_school.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/floorplan_school.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);
-}
-
-// Assertion failed: this->is_initialized() | Optional.hpp 1212
-TEST_F(ModelFixture, GltfForwardTranslator_two_stories_pre_intersect) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/two_stories_pre_intersect.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("model/two_stories_pre_intersect.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  /*bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);*/
-}
-
-// Assertion failed: this->is_initialized() | Optinoal.hpp 1212
-TEST_F(ModelFixture, GltfForwardTranslator_TwoStoryOffice_Trane) {
-  GltfForwardTranslator ft;
-  openstudio::path output;
-  output = resourcesPath() / toPath("utilities/Geometry/TwoStoryOffice_Trane.gltf");
-  osversion::VersionTranslator translator;
-  openstudio::path modelPath = resourcesPath() / toPath("gbxml/TwoStoryOffice_Trane.osm");
-  model::OptionalModel model = translator.loadModel(modelPath);
-  /*bool result = ft.modelToGLTF(model.get(), output);
-  ASSERT_TRUE(result);*/
-}