/*++

Copyright (C) 2024 3MF Consortium (Original Author)

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.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 OR CONTRIBUTORS 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.

This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop.

Abstract: This is an autogenerated Java file in order to allow an easy
 use of the 3MF Library

Interface version: 2.5.0

*/

package lib3mf;

import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import java.lang.ref.Cleaner;


import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

public class Model extends Base {

	public Model(Lib3MFWrapper wrapper, Pointer handle) {
		super(wrapper, handle);
	}

	/**
	 * Returns the PackagePart within the OPC package that holds the root model.
	 *
	 * @return the PackagePart within the OPC package that holds the model-file
	 * @throws Lib3MFException
	 */
	public PackagePart rootModelPart() throws Lib3MFException {
		Pointer bufferRootModelPart = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_rootmodelpart.invokeInt(new java.lang.Object[]{mHandle, bufferRootModelPart}));
		Pointer valueRootModelPart = bufferRootModelPart.getPointer(0);
		PackagePart rootModelPart = null;
		if (valueRootModelPart == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "RootModelPart was a null pointer");
		}
		rootModelPart = mWrapper.PolymorphicFactory(valueRootModelPart, PackagePart.class);
		return rootModelPart;
	}

	/**
	 * Returns a new PackagePart for use within the OPC package.
	 *
	 * @param absolutePath the absolute Path (physical location) within the OPC package
	 * @return the new PackagePart within the OPC package
	 * @throws Lib3MFException
	 */
	public PackagePart findOrCreatePackagePart(String absolutePath) throws Lib3MFException {
		byte[] bytesAbsolutePath = absolutePath.getBytes(StandardCharsets.UTF_8);
		Memory bufferAbsolutePath = new Memory(bytesAbsolutePath.length + 1);
		bufferAbsolutePath.write(0, bytesAbsolutePath, 0, bytesAbsolutePath.length);
		bufferAbsolutePath.setByte(bytesAbsolutePath.length, (byte)0);
		Pointer bufferModelPart = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_findorcreatepackagepart.invokeInt(new java.lang.Object[]{mHandle, bufferAbsolutePath, bufferModelPart}));
		Pointer valueModelPart = bufferModelPart.getPointer(0);
		PackagePart modelPart = null;
		if (valueModelPart == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ModelPart was a null pointer");
		}
		modelPart = mWrapper.PolymorphicFactory(valueModelPart, PackagePart.class);
		return modelPart;
	}

	/**
	 * sets the units of a model.
	 *
	 * @param unit Unit enum value for the model unit
	 * @throws Lib3MFException
	 */
	public void setUnit(Lib3MFWrapper.ModelUnit unit) throws Lib3MFException {
		mWrapper.checkError(this, mWrapper.lib3mf_model_setunit.invokeInt(new java.lang.Object[]{mHandle, Lib3MFWrapper.EnumConversion.convertModelUnitToConst(unit)}));
	}

	/**
	 * returns the units of a model.
	 *
	 * @return Unit enum value for the model unit
	 * @throws Lib3MFException
	 */
	public Lib3MFWrapper.ModelUnit getUnit() throws Lib3MFException {
		Pointer bufferUnit = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getunit.invokeInt(new java.lang.Object[]{mHandle, bufferUnit}));
		return Lib3MFWrapper.EnumConversion.convertConstToModelUnit(bufferUnit.getInt(0));
	}

	/**
	 * retrieves the language of a model
	 *
	 * @return language identifier
	 * @throws Lib3MFException
	 */
	public String getLanguage() throws Lib3MFException {
		Pointer bytesNeededLanguage = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getlanguage.invokeInt(new java.lang.Object[]{mHandle, 0, bytesNeededLanguage, null}));
		int sizeLanguage = bytesNeededLanguage.getInt(0);
		Pointer bufferLanguage = new Memory(sizeLanguage);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getlanguage.invokeInt(new java.lang.Object[]{mHandle, sizeLanguage, bytesNeededLanguage, bufferLanguage}));
		return new String(bufferLanguage.getByteArray(0, sizeLanguage - 1), StandardCharsets.UTF_8);
	}

	/**
	 * sets the language of a model
	 *
	 * @param language language identifier
	 * @throws Lib3MFException
	 */
	public void setLanguage(String language) throws Lib3MFException {
		byte[] bytesLanguage = language.getBytes(StandardCharsets.UTF_8);
		Memory bufferLanguage = new Memory(bytesLanguage.length + 1);
		bufferLanguage.write(0, bytesLanguage, 0, bytesLanguage.length);
		bufferLanguage.setByte(bytesLanguage.length, (byte)0);
		mWrapper.checkError(this, mWrapper.lib3mf_model_setlanguage.invokeInt(new java.lang.Object[]{mHandle, bufferLanguage}));
	}

	/**
	 * creates a model writer instance for a specific file type
	 *
	 * @param writerClass  string identifier for the file type
	 * @return  string identifier for the file type
	 * @throws Lib3MFException
	 */
	public Writer queryWriter(String writerClass) throws Lib3MFException {
		byte[] bytesWriterClass = writerClass.getBytes(StandardCharsets.UTF_8);
		Memory bufferWriterClass = new Memory(bytesWriterClass.length + 1);
		bufferWriterClass.write(0, bytesWriterClass, 0, bytesWriterClass.length);
		bufferWriterClass.setByte(bytesWriterClass.length, (byte)0);
		Pointer bufferWriterInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_querywriter.invokeInt(new java.lang.Object[]{mHandle, bufferWriterClass, bufferWriterInstance}));
		Pointer valueWriterInstance = bufferWriterInstance.getPointer(0);
		Writer writerInstance = null;
		if (valueWriterInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "WriterInstance was a null pointer");
		}
		writerInstance = mWrapper.PolymorphicFactory(valueWriterInstance, Writer.class);
		return writerInstance;
	}

	/**
	 * creates a model reader instance for a specific file type
	 *
	 * @param readerClass  string identifier for the file type
	 * @return  string identifier for the file type
	 * @throws Lib3MFException
	 */
	public Reader queryReader(String readerClass) throws Lib3MFException {
		byte[] bytesReaderClass = readerClass.getBytes(StandardCharsets.UTF_8);
		Memory bufferReaderClass = new Memory(bytesReaderClass.length + 1);
		bufferReaderClass.write(0, bytesReaderClass, 0, bytesReaderClass.length);
		bufferReaderClass.setByte(bytesReaderClass.length, (byte)0);
		Pointer bufferReaderInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_queryreader.invokeInt(new java.lang.Object[]{mHandle, bufferReaderClass, bufferReaderInstance}));
		Pointer valueReaderInstance = bufferReaderInstance.getPointer(0);
		Reader readerInstance = null;
		if (valueReaderInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ReaderInstance was a null pointer");
		}
		readerInstance = mWrapper.PolymorphicFactory(valueReaderInstance, Reader.class);
		return readerInstance;
	}

	/**
	 * finds a model resource by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the resource instance
	 * @throws Lib3MFException
	 */
	public Resource getResourceByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferResource = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getresourcebyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferResource}));
		Pointer valueResource = bufferResource.getPointer(0);
		Resource resource = null;
		if (valueResource == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Resource was a null pointer");
		}
		resource = mWrapper.PolymorphicFactory(valueResource, Resource.class);
		return resource;
	}

	/**
	 * finds a model texture by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the texture2d instance
	 * @throws Lib3MFException
	 */
	public Texture2D getTexture2DByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferTextureInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_gettexture2dbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferTextureInstance}));
		Pointer valueTextureInstance = bufferTextureInstance.getPointer(0);
		Texture2D textureInstance = null;
		if (valueTextureInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TextureInstance was a null pointer");
		}
		textureInstance = mWrapper.PolymorphicFactory(valueTextureInstance, Texture2D.class);
		return textureInstance;
	}

	/**
	 * returns a Property's type
	 *
	 * @param uniqueResourceID Resource ID of the Property to Query
	 * @return returns a Property's type
	 * @throws Lib3MFException
	 */
	public Lib3MFWrapper.PropertyType getPropertyTypeByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferThePropertyType = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getpropertytypebyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferThePropertyType}));
		return Lib3MFWrapper.EnumConversion.convertConstToPropertyType(bufferThePropertyType.getInt(0));
	}

	/**
	 * finds a model base material group by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the BaseMaterialGroup instance
	 * @throws Lib3MFException
	 */
	public BaseMaterialGroup getBaseMaterialGroupByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferBaseMaterialGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getbasematerialgroupbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferBaseMaterialGroupInstance}));
		Pointer valueBaseMaterialGroupInstance = bufferBaseMaterialGroupInstance.getPointer(0);
		BaseMaterialGroup baseMaterialGroupInstance = null;
		if (valueBaseMaterialGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "BaseMaterialGroupInstance was a null pointer");
		}
		baseMaterialGroupInstance = mWrapper.PolymorphicFactory(valueBaseMaterialGroupInstance, BaseMaterialGroup.class);
		return baseMaterialGroupInstance;
	}

	/**
	 * finds a model texture2d group by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the Texture2DGroup instance
	 * @throws Lib3MFException
	 */
	public Texture2DGroup getTexture2DGroupByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferTexture2DGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_gettexture2dgroupbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferTexture2DGroupInstance}));
		Pointer valueTexture2DGroupInstance = bufferTexture2DGroupInstance.getPointer(0);
		Texture2DGroup texture2DGroupInstance = null;
		if (valueTexture2DGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Texture2DGroupInstance was a null pointer");
		}
		texture2DGroupInstance = mWrapper.PolymorphicFactory(valueTexture2DGroupInstance, Texture2DGroup.class);
		return texture2DGroupInstance;
	}

	/**
	 * finds a model CompositeMaterials by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the CompositeMaterials instance
	 * @throws Lib3MFException
	 */
	public CompositeMaterials getCompositeMaterialsByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferCompositeMaterialsInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getcompositematerialsbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferCompositeMaterialsInstance}));
		Pointer valueCompositeMaterialsInstance = bufferCompositeMaterialsInstance.getPointer(0);
		CompositeMaterials compositeMaterialsInstance = null;
		if (valueCompositeMaterialsInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "CompositeMaterialsInstance was a null pointer");
		}
		compositeMaterialsInstance = mWrapper.PolymorphicFactory(valueCompositeMaterialsInstance, CompositeMaterials.class);
		return compositeMaterialsInstance;
	}

	/**
	 * finds a model MultiPropertyGroup by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the MultiPropertyGroup instance
	 * @throws Lib3MFException
	 */
	public MultiPropertyGroup getMultiPropertyGroupByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferMultiPropertyGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getmultipropertygroupbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferMultiPropertyGroupInstance}));
		Pointer valueMultiPropertyGroupInstance = bufferMultiPropertyGroupInstance.getPointer(0);
		MultiPropertyGroup multiPropertyGroupInstance = null;
		if (valueMultiPropertyGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "MultiPropertyGroupInstance was a null pointer");
		}
		multiPropertyGroupInstance = mWrapper.PolymorphicFactory(valueMultiPropertyGroupInstance, MultiPropertyGroup.class);
		return multiPropertyGroupInstance;
	}

	/**
	 * finds a mesh object by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the mesh object instance
	 * @throws Lib3MFException
	 */
	public MeshObject getMeshObjectByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferMeshObjectInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getmeshobjectbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferMeshObjectInstance}));
		Pointer valueMeshObjectInstance = bufferMeshObjectInstance.getPointer(0);
		MeshObject meshObjectInstance = null;
		if (valueMeshObjectInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "MeshObjectInstance was a null pointer");
		}
		meshObjectInstance = mWrapper.PolymorphicFactory(valueMeshObjectInstance, MeshObject.class);
		return meshObjectInstance;
	}

	/**
	 * finds a components object by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the components object instance
	 * @throws Lib3MFException
	 */
	public ComponentsObject getComponentsObjectByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferComponentsObjectInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getcomponentsobjectbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferComponentsObjectInstance}));
		Pointer valueComponentsObjectInstance = bufferComponentsObjectInstance.getPointer(0);
		ComponentsObject componentsObjectInstance = null;
		if (valueComponentsObjectInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ComponentsObjectInstance was a null pointer");
		}
		componentsObjectInstance = mWrapper.PolymorphicFactory(valueComponentsObjectInstance, ComponentsObject.class);
		return componentsObjectInstance;
	}

	/**
	 * finds a model color group by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the ColorGroup instance
	 * @throws Lib3MFException
	 */
	public ColorGroup getColorGroupByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferColorGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getcolorgroupbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferColorGroupInstance}));
		Pointer valueColorGroupInstance = bufferColorGroupInstance.getPointer(0);
		ColorGroup colorGroupInstance = null;
		if (valueColorGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ColorGroupInstance was a null pointer");
		}
		colorGroupInstance = mWrapper.PolymorphicFactory(valueColorGroupInstance, ColorGroup.class);
		return colorGroupInstance;
	}

	/**
	 * finds a model slicestack by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the slicestack instance
	 * @throws Lib3MFException
	 */
	public SliceStack getSliceStackByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferSliceStacInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getslicestackbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferSliceStacInstance}));
		Pointer valueSliceStacInstance = bufferSliceStacInstance.getPointer(0);
		SliceStack sliceStacInstance = null;
		if (valueSliceStacInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "SliceStacInstance was a null pointer");
		}
		sliceStacInstance = mWrapper.PolymorphicFactory(valueSliceStacInstance, SliceStack.class);
		return sliceStacInstance;
	}

	/**
	 * finds a level set object by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the level set object instance
	 * @throws Lib3MFException
	 */
	public LevelSet getLevelSetByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferLevelSetObjectInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getlevelsetbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferLevelSetObjectInstance}));
		Pointer valueLevelSetObjectInstance = bufferLevelSetObjectInstance.getPointer(0);
		LevelSet levelSetObjectInstance = null;
		if (valueLevelSetObjectInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "LevelSetObjectInstance was a null pointer");
		}
		levelSetObjectInstance = mWrapper.PolymorphicFactory(valueLevelSetObjectInstance, LevelSet.class);
		return levelSetObjectInstance;
	}

	/**
	 * returns, whether a build has a UUID and, if true, the build's UUID
	 *
	 * @return GetBuildUUID Result Tuple
	 * @throws Lib3MFException
	 */
	public GetBuildUUIDResult getBuildUUID() throws Lib3MFException {
		Pointer bufferHasUUID = new Memory(1);
		Pointer bytesNeededUUID = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getbuilduuid.invokeInt(new java.lang.Object[]{mHandle, bufferHasUUID, 0, bytesNeededUUID, null}));
		int sizeUUID = bytesNeededUUID.getInt(0);
		Pointer bufferUUID = new Memory(sizeUUID);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getbuilduuid.invokeInt(new java.lang.Object[]{mHandle, bufferHasUUID, sizeUUID, bytesNeededUUID, bufferUUID}));
		GetBuildUUIDResult returnTuple = new GetBuildUUIDResult();
		returnTuple.HasUUID = bufferHasUUID.getByte(0) != 0;
		returnTuple.UUID = new String(bufferUUID.getByteArray(0, sizeUUID - 1), StandardCharsets.UTF_8);
		return returnTuple;
	}

	public static class GetBuildUUIDResult {
		/**
		 * flag whether the build has a UUID
		 */
		public boolean HasUUID;

		/**
		 * the UUID as string of the form 'xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx'
		 */
		public String UUID;

	}
	/**
	 * sets the build's UUID
	 *
	 * @param uUID the UUID as string of the form 'xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx'
	 * @throws Lib3MFException
	 */
	public void setBuildUUID(String uUID) throws Lib3MFException {
		byte[] bytesUUID = uUID.getBytes(StandardCharsets.UTF_8);
		Memory bufferUUID = new Memory(bytesUUID.length + 1);
		bufferUUID.write(0, bytesUUID, 0, bytesUUID.length);
		bufferUUID.setByte(bytesUUID.length, (byte)0);
		mWrapper.checkError(this, mWrapper.lib3mf_model_setbuilduuid.invokeInt(new java.lang.Object[]{mHandle, bufferUUID}));
	}

	/**
	 * creates a build item iterator instance with all build items.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public BuildItemIterator getBuildItems() throws Lib3MFException {
		Pointer bufferBuildItemIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getbuilditems.invokeInt(new java.lang.Object[]{mHandle, bufferBuildItemIterator}));
		Pointer valueBuildItemIterator = bufferBuildItemIterator.getPointer(0);
		BuildItemIterator buildItemIterator = null;
		if (valueBuildItemIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "BuildItemIterator was a null pointer");
		}
		buildItemIterator = mWrapper.PolymorphicFactory(valueBuildItemIterator, BuildItemIterator.class);
		return buildItemIterator;
	}

	/**
	 * Returns the outbox of a Model
	 *
	 * @return Outbox of this Model
	 * @throws Lib3MFException
	 */
	public Box getOutbox() throws Lib3MFException {
		Pointer bufferOutbox = new Memory(Box.SIZE);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getoutbox.invokeInt(new java.lang.Object[]{mHandle, bufferOutbox}));
		Box outbox = new Box();
		outbox.readFromPointer(bufferOutbox, 0);
		return outbox;
	}

	/**
	 * creates a resource iterator instance with all resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public ResourceIterator getResources() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getresources.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		ResourceIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, ResourceIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a resource iterator instance with all object resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public ObjectIterator getObjects() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getobjects.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		ObjectIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, ObjectIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a resource iterator instance with all mesh object resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public MeshObjectIterator getMeshObjects() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getmeshobjects.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		MeshObjectIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, MeshObjectIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a resource iterator instance with all components object resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public ComponentsObjectIterator getComponentsObjects() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getcomponentsobjects.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		ComponentsObjectIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, ComponentsObjectIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a Texture2DIterator instance with all texture2d resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public Texture2DIterator getTexture2Ds() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_gettexture2ds.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		Texture2DIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, Texture2DIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a BaseMaterialGroupIterator instance with all base material resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public BaseMaterialGroupIterator getBaseMaterialGroups() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getbasematerialgroups.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		BaseMaterialGroupIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, BaseMaterialGroupIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a ColorGroupIterator instance with all ColorGroup resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public ColorGroupIterator getColorGroups() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getcolorgroups.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		ColorGroupIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, ColorGroupIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a Texture2DGroupIterator instance with all base material resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public Texture2DGroupIterator getTexture2DGroups() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_gettexture2dgroups.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		Texture2DGroupIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, Texture2DGroupIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a CompositeMaterialsIterator instance with all CompositeMaterials resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public CompositeMaterialsIterator getCompositeMaterials() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getcompositematerials.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		CompositeMaterialsIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, CompositeMaterialsIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a MultiPropertyGroupsIterator instance with all MultiPropertyGroup resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public MultiPropertyGroupIterator getMultiPropertyGroups() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getmultipropertygroups.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		MultiPropertyGroupIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, MultiPropertyGroupIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a resource iterator instance with all slice stack resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public SliceStackIterator getSliceStacks() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getslicestacks.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		SliceStackIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, SliceStackIterator.class);
		return resourceIterator;
	}

	/**
	 * creates a resource iterator instance with all image3d resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public Image3DIterator getImage3Ds() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getimage3ds.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		Image3DIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, Image3DIterator.class);
		return resourceIterator;
	}

	/**
	 * Merges all components and objects which are referenced by a build item into a mesh. The memory is duplicated and a new model is created.
	 *
	 * @return returns the merged model instance
	 * @throws Lib3MFException
	 */
	public Model mergeToModel() throws Lib3MFException {
		Pointer bufferMergedModelInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_mergetomodel.invokeInt(new java.lang.Object[]{mHandle, bufferMergedModelInstance}));
		Pointer valueMergedModelInstance = bufferMergedModelInstance.getPointer(0);
		Model mergedModelInstance = null;
		if (valueMergedModelInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "MergedModelInstance was a null pointer");
		}
		mergedModelInstance = mWrapper.PolymorphicFactory(valueMergedModelInstance, Model.class);
		return mergedModelInstance;
	}

	/**
	 * Merges the given model into this model.
	 *
	 * @param modelInstance model to be merged
	 * @throws Lib3MFException
	 */
	public void mergeFromModel(Model modelInstance) throws Lib3MFException {
		Pointer modelInstanceHandle = null;
		if (modelInstance != null) {
			modelInstanceHandle = modelInstance.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ModelInstance is a null value.");
		}
		mWrapper.checkError(this, mWrapper.lib3mf_model_mergefrommodel.invokeInt(new java.lang.Object[]{mHandle, modelInstanceHandle}));
	}

	/**
	 * adds an empty mesh object to the model.
	 *
	 * @return  returns the mesh object instance
	 * @throws Lib3MFException
	 */
	public MeshObject addMeshObject() throws Lib3MFException {
		Pointer bufferMeshObjectInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addmeshobject.invokeInt(new java.lang.Object[]{mHandle, bufferMeshObjectInstance}));
		Pointer valueMeshObjectInstance = bufferMeshObjectInstance.getPointer(0);
		MeshObject meshObjectInstance = null;
		if (valueMeshObjectInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "MeshObjectInstance was a null pointer");
		}
		meshObjectInstance = mWrapper.PolymorphicFactory(valueMeshObjectInstance, MeshObject.class);
		return meshObjectInstance;
	}

	/**
	 * adds an empty component object to the model.
	 *
	 * @return  returns the components object instance
	 * @throws Lib3MFException
	 */
	public ComponentsObject addComponentsObject() throws Lib3MFException {
		Pointer bufferComponentsObjectInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addcomponentsobject.invokeInt(new java.lang.Object[]{mHandle, bufferComponentsObjectInstance}));
		Pointer valueComponentsObjectInstance = bufferComponentsObjectInstance.getPointer(0);
		ComponentsObject componentsObjectInstance = null;
		if (valueComponentsObjectInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ComponentsObjectInstance was a null pointer");
		}
		componentsObjectInstance = mWrapper.PolymorphicFactory(valueComponentsObjectInstance, ComponentsObject.class);
		return componentsObjectInstance;
	}

	/**
	 * creates a new model slicestack by its id
	 *
	 * @param zBottom Bottom Z value of the slicestack
	 * @return returns the new slicestack instance
	 * @throws Lib3MFException
	 */
	public SliceStack addSliceStack(double zBottom) throws Lib3MFException {
		Pointer bufferSliceStackInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addslicestack.invokeInt(new java.lang.Object[]{mHandle, zBottom, bufferSliceStackInstance}));
		Pointer valueSliceStackInstance = bufferSliceStackInstance.getPointer(0);
		SliceStack sliceStackInstance = null;
		if (valueSliceStackInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "SliceStackInstance was a null pointer");
		}
		sliceStackInstance = mWrapper.PolymorphicFactory(valueSliceStackInstance, SliceStack.class);
		return sliceStackInstance;
	}

	/**
	 * adds a texture2d resource to the model. Its path is given by that of an existing attachment.
	 *
	 * @param textureAttachment attachment containing the image data.
	 * @return returns the new texture instance.
	 * @throws Lib3MFException
	 */
	public Texture2D addTexture2DFromAttachment(Attachment textureAttachment) throws Lib3MFException {
		Pointer textureAttachmentHandle = null;
		if (textureAttachment != null) {
			textureAttachmentHandle = textureAttachment.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TextureAttachment is a null value.");
		}
		Pointer bufferTexture2DInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addtexture2dfromattachment.invokeInt(new java.lang.Object[]{mHandle, textureAttachmentHandle, bufferTexture2DInstance}));
		Pointer valueTexture2DInstance = bufferTexture2DInstance.getPointer(0);
		Texture2D texture2DInstance = null;
		if (valueTexture2DInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Texture2DInstance was a null pointer");
		}
		texture2DInstance = mWrapper.PolymorphicFactory(valueTexture2DInstance, Texture2D.class);
		return texture2DInstance;
	}

	/**
	 * adds an empty BaseMaterialGroup resource to the model.
	 *
	 * @return returns the new base material instance.
	 * @throws Lib3MFException
	 */
	public BaseMaterialGroup addBaseMaterialGroup() throws Lib3MFException {
		Pointer bufferBaseMaterialGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addbasematerialgroup.invokeInt(new java.lang.Object[]{mHandle, bufferBaseMaterialGroupInstance}));
		Pointer valueBaseMaterialGroupInstance = bufferBaseMaterialGroupInstance.getPointer(0);
		BaseMaterialGroup baseMaterialGroupInstance = null;
		if (valueBaseMaterialGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "BaseMaterialGroupInstance was a null pointer");
		}
		baseMaterialGroupInstance = mWrapper.PolymorphicFactory(valueBaseMaterialGroupInstance, BaseMaterialGroup.class);
		return baseMaterialGroupInstance;
	}

	/**
	 * adds an empty ColorGroup resource to the model.
	 *
	 * @return returns the new ColorGroup instance.
	 * @throws Lib3MFException
	 */
	public ColorGroup addColorGroup() throws Lib3MFException {
		Pointer bufferColorGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addcolorgroup.invokeInt(new java.lang.Object[]{mHandle, bufferColorGroupInstance}));
		Pointer valueColorGroupInstance = bufferColorGroupInstance.getPointer(0);
		ColorGroup colorGroupInstance = null;
		if (valueColorGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ColorGroupInstance was a null pointer");
		}
		colorGroupInstance = mWrapper.PolymorphicFactory(valueColorGroupInstance, ColorGroup.class);
		return colorGroupInstance;
	}

	/**
	 * adds an empty Texture2DGroup resource to the model.
	 *
	 * @param texture2DInstance The texture2D instance of the created Texture2DGroup.
	 * @return returns the new Texture2DGroup instance.
	 * @throws Lib3MFException
	 */
	public Texture2DGroup addTexture2DGroup(Texture2D texture2DInstance) throws Lib3MFException {
		Pointer texture2DInstanceHandle = null;
		if (texture2DInstance != null) {
			texture2DInstanceHandle = texture2DInstance.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Texture2DInstance is a null value.");
		}
		Pointer bufferTexture2DGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addtexture2dgroup.invokeInt(new java.lang.Object[]{mHandle, texture2DInstanceHandle, bufferTexture2DGroupInstance}));
		Pointer valueTexture2DGroupInstance = bufferTexture2DGroupInstance.getPointer(0);
		Texture2DGroup texture2DGroupInstance = null;
		if (valueTexture2DGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Texture2DGroupInstance was a null pointer");
		}
		texture2DGroupInstance = mWrapper.PolymorphicFactory(valueTexture2DGroupInstance, Texture2DGroup.class);
		return texture2DGroupInstance;
	}

	/**
	 * adds an empty CompositeMaterials resource to the model.
	 *
	 * @param baseMaterialGroupInstance The BaseMaterialGroup instance of the created CompositeMaterials.
	 * @return returns the new CompositeMaterials instance.
	 * @throws Lib3MFException
	 */
	public CompositeMaterials addCompositeMaterials(BaseMaterialGroup baseMaterialGroupInstance) throws Lib3MFException {
		Pointer baseMaterialGroupInstanceHandle = null;
		if (baseMaterialGroupInstance != null) {
			baseMaterialGroupInstanceHandle = baseMaterialGroupInstance.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "BaseMaterialGroupInstance is a null value.");
		}
		Pointer bufferCompositeMaterialsInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addcompositematerials.invokeInt(new java.lang.Object[]{mHandle, baseMaterialGroupInstanceHandle, bufferCompositeMaterialsInstance}));
		Pointer valueCompositeMaterialsInstance = bufferCompositeMaterialsInstance.getPointer(0);
		CompositeMaterials compositeMaterialsInstance = null;
		if (valueCompositeMaterialsInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "CompositeMaterialsInstance was a null pointer");
		}
		compositeMaterialsInstance = mWrapper.PolymorphicFactory(valueCompositeMaterialsInstance, CompositeMaterials.class);
		return compositeMaterialsInstance;
	}

	/**
	 * adds an empty MultiPropertyGroup resource to the model.
	 *
	 * @return returns the new MultiPropertyGroup instance.
	 * @throws Lib3MFException
	 */
	public MultiPropertyGroup addMultiPropertyGroup() throws Lib3MFException {
		Pointer bufferMultiPropertyGroupInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addmultipropertygroup.invokeInt(new java.lang.Object[]{mHandle, bufferMultiPropertyGroupInstance}));
		Pointer valueMultiPropertyGroupInstance = bufferMultiPropertyGroupInstance.getPointer(0);
		MultiPropertyGroup multiPropertyGroupInstance = null;
		if (valueMultiPropertyGroupInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "MultiPropertyGroupInstance was a null pointer");
		}
		multiPropertyGroupInstance = mWrapper.PolymorphicFactory(valueMultiPropertyGroupInstance, MultiPropertyGroup.class);
		return multiPropertyGroupInstance;
	}

	/**
	 * creates a new 3D Image Resource
	 *
	 * @param columnCount the number of columns in each sheet.
	 * @param rowCount the number of rows in each sheet.
	 * @param sheetCount the number of sheets in the image stack.
	 * @return returns the new ImageStack instance
	 * @throws Lib3MFException
	 */
	public ImageStack addImageStack(int columnCount, int rowCount, int sheetCount) throws Lib3MFException {
		Pointer bufferInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addimagestack.invokeInt(new java.lang.Object[]{mHandle, columnCount, rowCount, sheetCount, bufferInstance}));
		Pointer valueInstance = bufferInstance.getPointer(0);
		ImageStack instance = null;
		if (valueInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Instance was a null pointer");
		}
		instance = mWrapper.PolymorphicFactory(valueInstance, ImageStack.class);
		return instance;
	}

	/**
	 * finds an ImageStack object by its UniqueResourceID
	 *
	 * @param uniqueResourceID UniqueResourceID
	 * @return returns the image stack instance
	 * @throws Lib3MFException
	 */
	public ImageStack getImageStackByID(int uniqueResourceID) throws Lib3MFException {
		Pointer bufferImageStackInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getimagestackbyid.invokeInt(new java.lang.Object[]{mHandle, uniqueResourceID, bufferImageStackInstance}));
		Pointer valueImageStackInstance = bufferImageStackInstance.getPointer(0);
		ImageStack imageStackInstance = null;
		if (valueImageStackInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ImageStackInstance was a null pointer");
		}
		imageStackInstance = mWrapper.PolymorphicFactory(valueImageStackInstance, ImageStack.class);
		return imageStackInstance;
	}

	/**
	 * adds a build item to the model.
	 *
	 * @param object Object instance.
	 * @param transform Transformation matrix.
	 * @return returns the build item instance.
	 * @throws Lib3MFException
	 */
	public BuildItem addBuildItem(Object object, Transform transform) throws Lib3MFException {
		Pointer objectHandle = null;
		if (object != null) {
			objectHandle = object.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Object is a null value.");
		}
		Pointer bufferTransform = new Memory(Transform.SIZE);
		transform.writeToPointer(bufferTransform, 0);
		Pointer bufferBuildItemInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addbuilditem.invokeInt(new java.lang.Object[]{mHandle, objectHandle, bufferTransform, bufferBuildItemInstance}));
		Pointer valueBuildItemInstance = bufferBuildItemInstance.getPointer(0);
		BuildItem buildItemInstance = null;
		if (valueBuildItemInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "BuildItemInstance was a null pointer");
		}
		buildItemInstance = mWrapper.PolymorphicFactory(valueBuildItemInstance, BuildItem.class);
		return buildItemInstance;
	}

	/**
	 * removes a build item from the model
	 *
	 * @param buildItemInstance Build item to remove.
	 * @throws Lib3MFException
	 */
	public void removeBuildItem(BuildItem buildItemInstance) throws Lib3MFException {
		Pointer buildItemInstanceHandle = null;
		if (buildItemInstance != null) {
			buildItemInstanceHandle = buildItemInstance.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "BuildItemInstance is a null value.");
		}
		mWrapper.checkError(this, mWrapper.lib3mf_model_removebuilditem.invokeInt(new java.lang.Object[]{mHandle, buildItemInstanceHandle}));
	}

	/**
	 * Returns the metadata of the model as MetaDataGroup
	 *
	 * @return returns an Instance of the metadatagroup of the model
	 * @throws Lib3MFException
	 */
	public MetaDataGroup getMetaDataGroup() throws Lib3MFException {
		Pointer bufferTheMetaDataGroup = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getmetadatagroup.invokeInt(new java.lang.Object[]{mHandle, bufferTheMetaDataGroup}));
		Pointer valueTheMetaDataGroup = bufferTheMetaDataGroup.getPointer(0);
		MetaDataGroup theMetaDataGroup = null;
		if (valueTheMetaDataGroup == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TheMetaDataGroup was a null pointer");
		}
		theMetaDataGroup = mWrapper.PolymorphicFactory(valueTheMetaDataGroup, MetaDataGroup.class);
		return theMetaDataGroup;
	}

	/**
	 * adds an attachment stream to the model. The OPC part will be related to the model stream with a certain relationship type.
	 *
	 * @param uRI Path of the attachment
	 * @param relationShipType Relationship type of the attachment
	 * @return Instance of the attachment object
	 * @throws Lib3MFException
	 */
	public Attachment addAttachment(String uRI, String relationShipType) throws Lib3MFException {
		byte[] bytesURI = uRI.getBytes(StandardCharsets.UTF_8);
		Memory bufferURI = new Memory(bytesURI.length + 1);
		bufferURI.write(0, bytesURI, 0, bytesURI.length);
		bufferURI.setByte(bytesURI.length, (byte)0);
		byte[] bytesRelationShipType = relationShipType.getBytes(StandardCharsets.UTF_8);
		Memory bufferRelationShipType = new Memory(bytesRelationShipType.length + 1);
		bufferRelationShipType.write(0, bytesRelationShipType, 0, bytesRelationShipType.length);
		bufferRelationShipType.setByte(bytesRelationShipType.length, (byte)0);
		Pointer bufferAttachmentInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addattachment.invokeInt(new java.lang.Object[]{mHandle, bufferURI, bufferRelationShipType, bufferAttachmentInstance}));
		Pointer valueAttachmentInstance = bufferAttachmentInstance.getPointer(0);
		Attachment attachmentInstance = null;
		if (valueAttachmentInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "AttachmentInstance was a null pointer");
		}
		attachmentInstance = mWrapper.PolymorphicFactory(valueAttachmentInstance, Attachment.class);
		return attachmentInstance;
	}

	/**
	 * Removes attachment from the model.
	 *
	 * @param attachmentInstance Attachment instance to remove
	 * @throws Lib3MFException
	 */
	public void removeAttachment(Attachment attachmentInstance) throws Lib3MFException {
		Pointer attachmentInstanceHandle = null;
		if (attachmentInstance != null) {
			attachmentInstanceHandle = attachmentInstance.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "AttachmentInstance is a null value.");
		}
		mWrapper.checkError(this, mWrapper.lib3mf_model_removeattachment.invokeInt(new java.lang.Object[]{mHandle, attachmentInstanceHandle}));
	}

	/**
	 * retrieves an attachment stream object from the model..
	 *
	 * @param index Index of the attachment stream
	 * @return Instance of the attachment object
	 * @throws Lib3MFException
	 */
	public Attachment getAttachment(int index) throws Lib3MFException {
		Pointer bufferAttachmentInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getattachment.invokeInt(new java.lang.Object[]{mHandle, index, bufferAttachmentInstance}));
		Pointer valueAttachmentInstance = bufferAttachmentInstance.getPointer(0);
		Attachment attachmentInstance = null;
		if (valueAttachmentInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "AttachmentInstance was a null pointer");
		}
		attachmentInstance = mWrapper.PolymorphicFactory(valueAttachmentInstance, Attachment.class);
		return attachmentInstance;
	}

	/**
	 * retrieves an attachment stream object from the model.
	 *
	 * @param uRI Path URI in the package
	 * @return Instance of the attachment object
	 * @throws Lib3MFException
	 */
	public Attachment findAttachment(String uRI) throws Lib3MFException {
		byte[] bytesURI = uRI.getBytes(StandardCharsets.UTF_8);
		Memory bufferURI = new Memory(bytesURI.length + 1);
		bufferURI.write(0, bytesURI, 0, bytesURI.length);
		bufferURI.setByte(bytesURI.length, (byte)0);
		Pointer bufferAttachmentInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_findattachment.invokeInt(new java.lang.Object[]{mHandle, bufferURI, bufferAttachmentInstance}));
		Pointer valueAttachmentInstance = bufferAttachmentInstance.getPointer(0);
		Attachment attachmentInstance = null;
		if (valueAttachmentInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "AttachmentInstance was a null pointer");
		}
		attachmentInstance = mWrapper.PolymorphicFactory(valueAttachmentInstance, Attachment.class);
		return attachmentInstance;
	}

	/**
	 * retrieves the number of attachments of the model.
	 *
	 * @return Returns the number of attachments.
	 * @throws Lib3MFException
	 */
	public int getAttachmentCount() throws Lib3MFException {
		Pointer bufferAttachmentCount = new Memory(4);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getattachmentcount.invokeInt(new java.lang.Object[]{mHandle, bufferAttachmentCount}));
		return bufferAttachmentCount.getInt(0);
	}

	/**
	 * Retrieve whether the OPC package contains a package thumbnail.
	 *
	 * @return returns whether the OPC package contains a package thumbnail
	 * @throws Lib3MFException
	 */
	public boolean hasPackageThumbnailAttachment() throws Lib3MFException {
		Pointer bufferHasThumbnail = new Memory(1);
		mWrapper.checkError(this, mWrapper.lib3mf_model_haspackagethumbnailattachment.invokeInt(new java.lang.Object[]{mHandle, bufferHasThumbnail}));
		return bufferHasThumbnail.getByte(0) != 0;
	}

	/**
	 * Create a new or the existing package thumbnail for the OPC package.
	 *
	 * @return Instance of a new or the existing thumbnailattachment object.
	 * @throws Lib3MFException
	 */
	public Attachment createPackageThumbnailAttachment() throws Lib3MFException {
		Pointer bufferAttachment = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_createpackagethumbnailattachment.invokeInt(new java.lang.Object[]{mHandle, bufferAttachment}));
		Pointer valueAttachment = bufferAttachment.getPointer(0);
		Attachment attachment = null;
		if (valueAttachment == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Attachment was a null pointer");
		}
		attachment = mWrapper.PolymorphicFactory(valueAttachment, Attachment.class);
		return attachment;
	}

	/**
	 * Get the attachment to the OPC package containing the package thumbnail.
	 *
	 * @return Instance of the thumbnailattachment object or NULL.
	 * @throws Lib3MFException
	 */
	public Attachment getPackageThumbnailAttachment() throws Lib3MFException {
		Pointer bufferAttachment = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getpackagethumbnailattachment.invokeInt(new java.lang.Object[]{mHandle, bufferAttachment}));
		Pointer valueAttachment = bufferAttachment.getPointer(0);
		Attachment attachment = null;
		if (valueAttachment != Pointer.NULL) {
		  attachment = mWrapper.PolymorphicFactory(valueAttachment, Attachment.class);
		}
		return attachment;
	}

	/**
	 * Remove the attachment to the OPC package containing the package thumbnail.
	 *
	 * @throws Lib3MFException
	 */
	public void removePackageThumbnailAttachment() throws Lib3MFException {
		mWrapper.checkError(this, mWrapper.lib3mf_model_removepackagethumbnailattachment.invokeInt(new java.lang.Object[]{mHandle}));
	}

	/**
	 * Adds a new Content Type to the model.
	 *
	 * @param extension File Extension
	 * @param contentType Content Type Identifier
	 * @throws Lib3MFException
	 */
	public void addCustomContentType(String extension, String contentType) throws Lib3MFException {
		byte[] bytesExtension = extension.getBytes(StandardCharsets.UTF_8);
		Memory bufferExtension = new Memory(bytesExtension.length + 1);
		bufferExtension.write(0, bytesExtension, 0, bytesExtension.length);
		bufferExtension.setByte(bytesExtension.length, (byte)0);
		byte[] bytesContentType = contentType.getBytes(StandardCharsets.UTF_8);
		Memory bufferContentType = new Memory(bytesContentType.length + 1);
		bufferContentType.write(0, bytesContentType, 0, bytesContentType.length);
		bufferContentType.setByte(bytesContentType.length, (byte)0);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addcustomcontenttype.invokeInt(new java.lang.Object[]{mHandle, bufferExtension, bufferContentType}));
	}

	/**
	 * Removes a custom Content Type from the model (UTF8 version).
	 *
	 * @param extension File Extension
	 * @throws Lib3MFException
	 */
	public void removeCustomContentType(String extension) throws Lib3MFException {
		byte[] bytesExtension = extension.getBytes(StandardCharsets.UTF_8);
		Memory bufferExtension = new Memory(bytesExtension.length + 1);
		bufferExtension.write(0, bytesExtension, 0, bytesExtension.length);
		bufferExtension.setByte(bytesExtension.length, (byte)0);
		mWrapper.checkError(this, mWrapper.lib3mf_model_removecustomcontenttype.invokeInt(new java.lang.Object[]{mHandle, bufferExtension}));
	}

	/**
	 * Sets the random number generator callback for use in the library
	 *
	 * @param theCallback The callback used to generate random numbers
	 * @param userData Userdata to be passed to the callback function
	 * @throws Lib3MFException
	 */
	public void setRandomNumberCallback(Lib3MFWrapper.RandomNumberCallback theCallback, Pointer userData) throws Lib3MFException {
		mWrapper.checkError(this, mWrapper.lib3mf_model_setrandomnumbercallback.invokeInt(new java.lang.Object[]{mHandle, theCallback, userData}));
	}

	/**
	 * Gets the keystore associated with this model
	 *
	 * @return The package keystore
	 * @throws Lib3MFException
	 */
	public KeyStore getKeyStore() throws Lib3MFException {
		Pointer bufferKeyStore = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getkeystore.invokeInt(new java.lang.Object[]{mHandle, bufferKeyStore}));
		Pointer valueKeyStore = bufferKeyStore.getPointer(0);
		KeyStore keyStore = null;
		if (valueKeyStore == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "KeyStore was a null pointer");
		}
		keyStore = mWrapper.PolymorphicFactory(valueKeyStore, KeyStore.class);
		return keyStore;
	}

	/**
	 * creates a resource iterator for all functions
	 *
	 * @return returns the resource iterator
	 * @throws Lib3MFException
	 */
	public FunctionIterator getFunctions() throws Lib3MFException {
		Pointer bufferTheResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getfunctions.invokeInt(new java.lang.Object[]{mHandle, bufferTheResourceIterator}));
		Pointer valueTheResourceIterator = bufferTheResourceIterator.getPointer(0);
		FunctionIterator theResourceIterator = null;
		if (valueTheResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "TheResourceIterator was a null pointer");
		}
		theResourceIterator = mWrapper.PolymorphicFactory(valueTheResourceIterator, FunctionIterator.class);
		return theResourceIterator;
	}

	/**
	 * adds a function described by nodes to the model
	 *
	 * @return returns the function instance
	 * @throws Lib3MFException
	 */
	public ImplicitFunction addImplicitFunction() throws Lib3MFException {
		Pointer bufferFunctionInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addimplicitfunction.invokeInt(new java.lang.Object[]{mHandle, bufferFunctionInstance}));
		Pointer valueFunctionInstance = bufferFunctionInstance.getPointer(0);
		ImplicitFunction functionInstance = null;
		if (valueFunctionInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "FunctionInstance was a null pointer");
		}
		functionInstance = mWrapper.PolymorphicFactory(valueFunctionInstance, ImplicitFunction.class);
		return functionInstance;
	}

	/**
	 * adds a function defined by an image3d to the model
	 *
	 * @param image3DInstance the Image3D-instance used for this function
	 * @return returns the function instance
	 * @throws Lib3MFException
	 */
	public FunctionFromImage3D addFunctionFromImage3D(Image3D image3DInstance) throws Lib3MFException {
		Pointer image3DInstanceHandle = null;
		if (image3DInstance != null) {
			image3DInstanceHandle = image3DInstance.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Image3DInstance is a null value.");
		}
		Pointer bufferFunctionInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addfunctionfromimage3d.invokeInt(new java.lang.Object[]{mHandle, image3DInstanceHandle, bufferFunctionInstance}));
		Pointer valueFunctionInstance = bufferFunctionInstance.getPointer(0);
		FunctionFromImage3D functionInstance = null;
		if (valueFunctionInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "FunctionInstance was a null pointer");
		}
		functionInstance = mWrapper.PolymorphicFactory(valueFunctionInstance, FunctionFromImage3D.class);
		return functionInstance;
	}

	/**
	 * adds a volume data resource to the model.
	 *
	 * @return returns the new volume data instance.
	 * @throws Lib3MFException
	 */
	public VolumeData addVolumeData() throws Lib3MFException {
		Pointer bufferVolumeDataInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addvolumedata.invokeInt(new java.lang.Object[]{mHandle, bufferVolumeDataInstance}));
		Pointer valueVolumeDataInstance = bufferVolumeDataInstance.getPointer(0);
		VolumeData volumeDataInstance = null;
		if (valueVolumeDataInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "VolumeDataInstance was a null pointer");
		}
		volumeDataInstance = mWrapper.PolymorphicFactory(valueVolumeDataInstance, VolumeData.class);
		return volumeDataInstance;
	}

	/**
	 * adds an empty boundary shape object to the model.
	 *
	 * @return  returns the mesh object instance
	 * @throws Lib3MFException
	 */
	public LevelSet addLevelSet() throws Lib3MFException {
		Pointer bufferLevelSetInstance = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_addlevelset.invokeInt(new java.lang.Object[]{mHandle, bufferLevelSetInstance}));
		Pointer valueLevelSetInstance = bufferLevelSetInstance.getPointer(0);
		LevelSet levelSetInstance = null;
		if (valueLevelSetInstance == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "LevelSetInstance was a null pointer");
		}
		levelSetInstance = mWrapper.PolymorphicFactory(valueLevelSetInstance, LevelSet.class);
		return levelSetInstance;
	}

	/**
	 * creates a resource iterator instance with all boundary shape resources.
	 *
	 * @return returns the iterator instance.
	 * @throws Lib3MFException
	 */
	public LevelSetIterator getLevelSets() throws Lib3MFException {
		Pointer bufferResourceIterator = new Memory(8);
		mWrapper.checkError(this, mWrapper.lib3mf_model_getlevelsets.invokeInt(new java.lang.Object[]{mHandle, bufferResourceIterator}));
		Pointer valueResourceIterator = bufferResourceIterator.getPointer(0);
		LevelSetIterator resourceIterator = null;
		if (valueResourceIterator == Pointer.NULL) {
		  throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "ResourceIterator was a null pointer");
		}
		resourceIterator = mWrapper.PolymorphicFactory(valueResourceIterator, LevelSetIterator.class);
		return resourceIterator;
	}

	/**
	 * Removes a resource from the model
	 *
	 * @param resource The resource to remove
	 * @throws Lib3MFException
	 */
	public void removeResource(Resource resource) throws Lib3MFException {
		Pointer resourceHandle = null;
		if (resource != null) {
			resourceHandle = resource.getHandle();
		} else {
			throw new Lib3MFException(Lib3MFException.LIB3MF_ERROR_INVALIDPARAM, "Resource is a null value.");
		}
		mWrapper.checkError(this, mWrapper.lib3mf_model_removeresource.invokeInt(new java.lang.Object[]{mHandle, resourceHandle}));
	}


}

