f8c998f6ff
- primo commit.
782 lines
28 KiB
C++
782 lines
28 KiB
C++
/*++
|
|
|
|
Copyright (C) 2019 3MF Consortium
|
|
|
|
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.
|
|
|
|
Abstract:
|
|
|
|
NMR_ModelWriterNode100_Mesh.cpp implements the Model Writer Mesh Node Class.
|
|
This is the class for exporting the 3mf mesh node.
|
|
|
|
--*/
|
|
|
|
#include "Model/Writer/v100/NMR_ModelWriterNode100_Mesh.h"
|
|
#include "Common/MeshInformation/NMR_MeshInformation_Properties.h"
|
|
|
|
#include "Common/NMR_Exception.h"
|
|
#include "Common/NMR_Exception_Windows.h"
|
|
#include "Common/NMR_StringUtils.h"
|
|
|
|
#include "Common/3MF_ProgressMonitor.h"
|
|
|
|
#include <cmath>
|
|
|
|
#ifdef __GNUC__
|
|
#include <stdio.h>
|
|
#endif // __GNUC__
|
|
|
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
|
|
|
namespace NMR {
|
|
|
|
CModelWriterNode100_Mesh::CModelWriterNode100_Mesh(_In_ CModelMeshObject * pModelMeshObject, _In_ CXmlWriter * pXMLWriter, _In_ PProgressMonitor pProgressMonitor,
|
|
_In_ PMeshInformation_PropertyIndexMapping pPropertyIndexMapping, _In_ int nPosAfterDecPoint, _In_ nfBool bWriteMaterialExtension, _In_ nfBool bWriteBeamLatticeExtension)
|
|
:CModelWriterNode_ModelBase(pModelMeshObject->getModel(), pXMLWriter, pProgressMonitor), m_nPosAfterDecPoint(nPosAfterDecPoint), m_nPutDoubleFactor((int)(pow(10, CModelWriterNode100_Mesh::m_nPosAfterDecPoint)))
|
|
{
|
|
__NMRASSERT(pModelMeshObject != nullptr);
|
|
if (!pPropertyIndexMapping.get())
|
|
throw CNMRException(NMR_ERROR_INVALIDPARAM);
|
|
|
|
m_bWriteMaterialExtension = bWriteMaterialExtension;
|
|
m_bWriteBeamLatticeExtension = bWriteBeamLatticeExtension;
|
|
|
|
m_pModelMeshObject = pModelMeshObject;
|
|
m_pPropertyIndexMapping = pPropertyIndexMapping;
|
|
|
|
// Initialize buffer arrays
|
|
m_nTriangleBufferPos = 0;
|
|
m_nVertexBufferPos = 0;
|
|
m_nBeamBufferPos = 0;
|
|
m_nBallBufferPos = 0;
|
|
m_nBeamRefBufferPos = 0;
|
|
m_nBallRefBufferPos = 0;
|
|
putVertexString(MODELWRITERMESH100_VERTEXLINESTART);
|
|
putTriangleString(MODELWRITERMESH100_TRIANGLELINESTART);
|
|
putBeamString(MODELWRITERMESH100_BEAMLATTICE_BEAMLINESTART);
|
|
putBallString(MODELWRITERMESH100_BEAMLATTICE_BALLLINESTART);
|
|
putBeamRefString(MODELWRITERMESH100_BEAMLATTICE_REFLINESTART);
|
|
putBallRefString(MODELWRITERMESH100_BEAMLATTICE_BALLREFLINESTART);
|
|
}
|
|
|
|
bool stringRepresentationsDiffer(double a, double b, double putFactor) {
|
|
return fabs(a - b) * putFactor > 0.1;
|
|
}
|
|
|
|
std::string capModeToString(eModelBeamLatticeCapMode eCapMode) {
|
|
switch (eCapMode) {
|
|
case eModelBeamLatticeCapMode::MODELBEAMLATTICECAPMODE_SPHERE: return XML_3MF_BEAMLATTICE_CAPMODE_SPHERE; break;
|
|
case eModelBeamLatticeCapMode::MODELBEAMLATTICECAPMODE_HEMISPHERE: return XML_3MF_BEAMLATTICE_CAPMODE_HEMISPHERE; break;
|
|
case eModelBeamLatticeCapMode::MODELBEAMLATTICECAPMODE_BUTT: return XML_3MF_BEAMLATTICE_CAPMODE_BUTT; break;
|
|
default:
|
|
return XML_3MF_BEAMLATTICE_CAPMODE_SPHERE;
|
|
}
|
|
}
|
|
|
|
std::string clipModeToString(eModelBeamLatticeClipMode eClipMode) {
|
|
switch (eClipMode) {
|
|
case eModelBeamLatticeClipMode::MODELBEAMLATTICECLIPMODE_INSIDE: return XML_3MF_BEAMLATTICE_CLIPMODE_INSIDE; break;
|
|
case eModelBeamLatticeClipMode::MODELBEAMLATTICECLIPMODE_OUTSIDE: return XML_3MF_BEAMLATTICE_CLIPMODE_OUTSIDE; break;
|
|
case eModelBeamLatticeClipMode::MODELBEAMLATTICECLIPMODE_NONE: return XML_3MF_BEAMLATTICE_CLIPMODE_NONE; break;
|
|
default:
|
|
return XML_3MF_BEAMLATTICE_CLIPMODE_NONE;
|
|
}
|
|
}
|
|
|
|
std::string ballModeToString(eModelBeamLatticeBallMode eBallMode) {
|
|
switch (eBallMode) {
|
|
case eModelBeamLatticeBallMode::MODELBEAMLATTICEBALLMODE_NONE: return XML_3MF_BEAMLATTICE_BALLMODE_NONE; break;
|
|
case eModelBeamLatticeBallMode::MODELBEAMLATTICEBALLMODE_MIXED: return XML_3MF_BEAMLATTICE_BALLMODE_MIXED; break;
|
|
case eModelBeamLatticeBallMode::MODELBEAMLATTICEBALLMODE_ALL: return XML_3MF_BEAMLATTICE_BALLMODE_ALL; break;
|
|
default:
|
|
return XML_3MF_BEAMLATTICE_BALLMODE_NONE;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::writeToXML()
|
|
{
|
|
__NMRASSERT(m_pXMLWriter);
|
|
__NMRASSERT(m_pModel);
|
|
|
|
CMesh * pMesh = m_pModelMeshObject->getMesh();
|
|
|
|
const nfUint32 nNodeCount = pMesh->getNodeCount ();
|
|
const nfUint32 nFaceCount = pMesh->getFaceCount();
|
|
const nfUint32 nBeamCount = pMesh->getBeamCount();
|
|
const nfUint32 nBallCount = pMesh->getBallCount();
|
|
nfUint32 nNodeIndex, nFaceIndex, nBeamIndex, nBallIndex;
|
|
|
|
// Write Mesh Element
|
|
writeStartElement(XML_3MF_ELEMENT_MESH);
|
|
|
|
m_pProgressMonitor->SetProgressIdentifier(ProgressIdentifier::PROGRESS_WRITENODES);
|
|
// Write Vertices
|
|
writeStartElement(XML_3MF_ELEMENT_VERTICES);
|
|
for (nNodeIndex = 0; nNodeIndex < nNodeCount; nNodeIndex++) {
|
|
// Get Mesh Node
|
|
MESHNODE * pMeshNode = pMesh->getNode(nNodeIndex);
|
|
writeVertexData(pMeshNode);
|
|
|
|
/* The following works, but would be a major output speed bottleneck!
|
|
|
|
// Write Vertex
|
|
writeStartElement(XML_3MF_ELEMENT_VERTEX);
|
|
writeFloatAttribute(XML_3MF_ATTRIBUTE_VERTEX_X, pMeshNode->m_position.m_values.x);
|
|
writeFloatAttribute(XML_3MF_ATTRIBUTE_VERTEX_Y, pMeshNode->m_position.m_values.y);
|
|
writeFloatAttribute(XML_3MF_ATTRIBUTE_VERTEX_Z, pMeshNode->m_position.m_values.z);
|
|
writeEndElement(); */
|
|
|
|
if (nNodeIndex % PROGRESS_NODEUPDATE == PROGRESS_NODEUPDATE-1) {
|
|
m_pProgressMonitor->ReportProgressAndQueryCancelled(true);
|
|
}
|
|
}
|
|
writeFullEndElement();
|
|
|
|
// Retrieve Mesh Informations
|
|
CMeshInformation_Properties * pProperties = NULL;
|
|
|
|
UniqueResourceID nObjectLevelPropertyID = 0;
|
|
ModelResourceIndex nObjectLevelPropertyIndex = 0;
|
|
|
|
CMeshInformationHandler * pMeshInformationHandler = pMesh->getMeshInformationHandler();
|
|
if (pMeshInformationHandler) {
|
|
// Get generic property handler
|
|
CMeshInformation *pInformation = pMeshInformationHandler->getInformationByType(0, emiProperties);
|
|
if (pInformation) {
|
|
pProperties = dynamic_cast<CMeshInformation_Properties *> (pInformation);
|
|
NMR::MESHINFORMATION_PROPERTIES * pDefaultData = (NMR::MESHINFORMATION_PROPERTIES*)pProperties->getDefaultData();
|
|
|
|
if (pDefaultData && pDefaultData->m_nUniqueResourceID != 0) {
|
|
nObjectLevelPropertyID = pDefaultData->m_nUniqueResourceID;
|
|
nObjectLevelPropertyIndex = m_pPropertyIndexMapping->mapPropertyIDToIndex(nObjectLevelPropertyID, pDefaultData->m_nPropertyIDs[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool bMeshHasAProperty = false;
|
|
|
|
m_pProgressMonitor->SetProgressIdentifier(ProgressIdentifier::PROGRESS_WRITETRIANGLES);
|
|
// Write Triangles
|
|
writeStartElement(XML_3MF_ELEMENT_TRIANGLES);
|
|
for (nFaceIndex = 0; nFaceIndex < nFaceCount; nFaceIndex++) {
|
|
if (nFaceIndex % PROGRESS_TRIANGLEUPDATE == PROGRESS_TRIANGLEUPDATE - 1) {
|
|
m_pProgressMonitor->ReportProgressAndQueryCancelled(true);
|
|
}
|
|
|
|
// Get Mesh Face
|
|
MESHFACE * pMeshFace = pMesh->getFace(nFaceIndex);
|
|
|
|
UniqueResourceID nPropertyID = 0;
|
|
ModelResourceIndex nPropertyIndex1 = 0;
|
|
ModelResourceIndex nPropertyIndex2 = 0;
|
|
ModelResourceIndex nPropertyIndex3 = 0;
|
|
|
|
nfChar * pAdditionalString = nullptr;
|
|
// Retrieve Property Indices
|
|
if (pProperties != nullptr) {
|
|
MESHINFORMATION_PROPERTIES* pFaceData = (MESHINFORMATION_PROPERTIES*)pProperties->getFaceData(nFaceIndex);
|
|
if (pFaceData != nullptr) {
|
|
if (pFaceData->m_nUniqueResourceID) {
|
|
nPropertyID = pFaceData->m_nUniqueResourceID;
|
|
nPropertyIndex1 = m_pPropertyIndexMapping->mapPropertyIDToIndex(nPropertyID, pFaceData->m_nPropertyIDs[0]);
|
|
nPropertyIndex2 = m_pPropertyIndexMapping->mapPropertyIDToIndex(nPropertyID, pFaceData->m_nPropertyIDs[1]);
|
|
nPropertyIndex3 = m_pPropertyIndexMapping->mapPropertyIDToIndex(nPropertyID, pFaceData->m_nPropertyIDs[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (nPropertyID != 0) {
|
|
bMeshHasAProperty = true;
|
|
// TODO: this is slow
|
|
ModelResourceID nPropertyModelResourceID = m_pModel->findPackageResourceID(nPropertyID)->getModelResourceID();
|
|
if ((nPropertyIndex1 != nPropertyIndex2) || (nPropertyIndex1 != nPropertyIndex3)) {
|
|
writeFaceData_ThreeProperties(pMeshFace, nPropertyModelResourceID, nPropertyIndex1, nPropertyIndex2, nPropertyIndex3, pAdditionalString);
|
|
}
|
|
else {
|
|
if ((nPropertyID == nObjectLevelPropertyID) && (nPropertyIndex1 == nObjectLevelPropertyIndex)){
|
|
writeFaceData_Plain(pMeshFace, pAdditionalString);
|
|
} else {
|
|
writeFaceData_OneProperty(pMeshFace, nPropertyModelResourceID, nPropertyIndex1, pAdditionalString);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
writeFaceData_Plain(pMeshFace, pAdditionalString);
|
|
}
|
|
|
|
/* The following works, but would be a major output speed bottleneck!
|
|
|
|
// Write Triangle
|
|
writeStartElement(XML_3MF_ELEMENT_TRIANGLE);
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_TRIANGLE_V1, pMeshFace->m_nodeindices[0]);
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_TRIANGLE_V2, pMeshFace->m_nodeindices[1]);
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_TRIANGLE_V3, pMeshFace->m_nodeindices[2]);
|
|
|
|
// Write Property Indices
|
|
if (nPropertyID != 0) {
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_TRIANGLE_PID, nPropertyID);
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_TRIANGLE_P1, nPropertyIndex1);
|
|
if ((nPropertyIndex1 != nPropertyIndex2) || (nPropertyIndex1 != nPropertyIndex3)) {
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_TRIANGLE_P2, nPropertyIndex2);
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_TRIANGLE_P3, nPropertyIndex3);
|
|
}
|
|
}
|
|
|
|
writeEndElement(); */
|
|
}
|
|
writeFullEndElement();
|
|
|
|
if (bMeshHasAProperty && !(nObjectLevelPropertyID != 0)) {
|
|
throw CNMRException(NMR_ERROR_MISSINGOBJECTLEVELPID);
|
|
}
|
|
|
|
if (m_bWriteBeamLatticeExtension) {
|
|
if (nBeamCount > 0) {
|
|
// write beamlattice
|
|
writeStartElementWithPrefix(XML_3MF_ELEMENT_BEAMLATTICE, XML_3MF_NAMESPACEPREFIX_BEAMLATTICE);
|
|
nfDouble dDefaultRadius = pMesh->getDefaultBeamRadius();
|
|
nfDouble dDefaultBallRadius = pMesh->getDefaultBallRadius();
|
|
nfBool bWriteBallsElement = nBallCount > 0;
|
|
writeFloatAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_RADIUS, float(dDefaultRadius));
|
|
writeFloatAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_MINLENGTH, float(pMesh->getBeamLatticeMinLength()));
|
|
eModelBeamLatticeBallMode eBallMode = pMesh->getBeamLatticeBallMode();
|
|
|
|
if (eBallMode == eModelBeamLatticeBallMode::MODELBEAMLATTICEBALLMODE_ALL) {
|
|
if (dDefaultBallRadius > 0) {
|
|
writeStringAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_BALLMODE, ballModeToString(eBallMode));
|
|
writeFloatAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_BALLRADIUS, float(dDefaultBallRadius));
|
|
|
|
// Check if any balls do not use dDefaultBallRadius
|
|
bWriteBallsElement = false;
|
|
for (nfUint32 iBall = 0; iBall < nBallCount; iBall++) {
|
|
if (stringRepresentationsDiffer(pMesh->getBall(iBall)->m_radius, dDefaultBallRadius, m_nPutDoubleFactor)) {
|
|
bWriteBallsElement = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
throw CNMRException(NMR_ERROR_BEAMLATTICEINVALIDATTRIBUTE);
|
|
}
|
|
}
|
|
else if (nBallCount > 0) {
|
|
if (eBallMode == eModelBeamLatticeBallMode::MODELBEAMLATTICEBALLMODE_MIXED) {
|
|
if (dDefaultBallRadius > 0) {
|
|
writeStringAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_BALLMODE, ballModeToString(eBallMode));
|
|
writeFloatAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_BALLRADIUS, float(dDefaultBallRadius));
|
|
}
|
|
else {
|
|
throw CNMRException(NMR_ERROR_BEAMLATTICEINVALIDATTRIBUTE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pModelMeshObject->getBeamLatticeAttributes()->m_bHasClippingMeshID) {
|
|
writeStringAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_CLIPPINGMODE, clipModeToString(m_pModelMeshObject->getBeamLatticeAttributes()->m_eClipMode));
|
|
PPackageResourceID pID = m_pModelMeshObject->getBeamLatticeAttributes()->m_pClippingMeshUniqueID;
|
|
if (pID->getPath() != m_pModel->currentPath())
|
|
throw CNMRException(NMR_ERROR_MODELRESOURCE_IN_DIFFERENT_MODEL);
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_CLIPPINGMESH, pID->getModelResourceID());
|
|
}
|
|
|
|
if (m_pModelMeshObject->getBeamLatticeAttributes()->m_bHasRepresentationMeshID) {
|
|
PPackageResourceID pID = m_pModelMeshObject->getBeamLatticeAttributes()->m_pRepresentationUniqueID;
|
|
if (pID->getPath() != m_pModel->currentPath())
|
|
throw CNMRException(NMR_ERROR_MODELRESOURCE_IN_DIFFERENT_MODEL);
|
|
writeIntAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_REPRESENTATIONMESH, pID->getModelResourceID());
|
|
}
|
|
|
|
eModelBeamLatticeCapMode eDefaultCapMode = pMesh->getBeamLatticeCapMode();
|
|
writeConstStringAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_CAPMODE, capModeToString(eDefaultCapMode).c_str());
|
|
{
|
|
// write beamlattice: beams
|
|
writeStartElementWithPrefix(XML_3MF_ELEMENT_BEAMS, XML_3MF_NAMESPACEPREFIX_BEAMLATTICE);
|
|
for (nBeamIndex = 0; nBeamIndex < nBeamCount; nBeamIndex++) {
|
|
// write beamlattice: beam
|
|
MESHBEAM * pMeshBeam = pMesh->getBeam(nBeamIndex);
|
|
writeBeamData(pMeshBeam, dDefaultRadius, eDefaultCapMode);
|
|
}
|
|
writeFullEndElement();
|
|
|
|
// write beamlattice: balls
|
|
// Only if there is at least 1 ball
|
|
if (bWriteBallsElement) {
|
|
writeStartElementWithPrefix(XML_3MF_ELEMENT_BALLS, XML_3MF_NAMESPACEPREFIX_BEAMLATTICE);
|
|
for (nBallIndex = 0; nBallIndex < nBallCount; nBallIndex++) {
|
|
// write beamlattice: ball
|
|
MESHBALL * pMeshBall = pMesh->getBall(nBallIndex);
|
|
writeBallData(pMeshBall, eBallMode, dDefaultBallRadius);
|
|
}
|
|
writeFullEndElement();
|
|
}
|
|
|
|
const nfUint32 nBeamSetCount = pMesh->getBeamSetCount();
|
|
if (nBeamSetCount > 0) {
|
|
// write beamlattice: beamsets
|
|
writeStartElementWithPrefix(XML_3MF_ELEMENT_BEAMSETS, XML_3MF_NAMESPACEPREFIX_BEAMLATTICE);
|
|
for (nfUint32 nBeamSetIndex = 0; nBeamSetIndex < nBeamSetCount; nBeamSetIndex++) {
|
|
const PBEAMSET pBeamSet = pMesh->getBeamSet(nBeamSetIndex);
|
|
{
|
|
// write beamlattice: beamset
|
|
writeStartElementWithPrefix(XML_3MF_ELEMENT_BEAMSET, XML_3MF_NAMESPACEPREFIX_BEAMLATTICE);
|
|
if (pBeamSet->m_sName.length()>0)
|
|
writeConstStringAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_NAME, pBeamSet->m_sName.c_str());
|
|
if (pBeamSet->m_sIdentifier.length()>0)
|
|
writeConstStringAttribute(XML_3MF_ATTRIBUTE_BEAMLATTICE_IDENTIFIER, pBeamSet->m_sIdentifier.c_str());
|
|
const nfUint32 nRefCount = (nfUint32)pBeamSet->m_Refs.size();
|
|
for (nfUint32 nRefIndex = 0; nRefIndex < nRefCount; nRefIndex++) {
|
|
// write beamlattice: ref
|
|
writeRefData(pBeamSet->m_Refs[nRefIndex]);
|
|
}
|
|
const nfUint32 nBallRefCount = (nfUint32)pBeamSet->m_BallRefs.size();
|
|
for (nfUint32 nBallRefIndex = 0; nBallRefIndex < nBallRefCount; nBallRefIndex++) {
|
|
// write beamlattice: ballref
|
|
writeBallRefData(pBeamSet->m_BallRefs[nBallRefIndex]);
|
|
}
|
|
writeFullEndElement();
|
|
}
|
|
}
|
|
writeFullEndElement();
|
|
}
|
|
}
|
|
writeFullEndElement();
|
|
}
|
|
}
|
|
|
|
// Finish Mesh Element
|
|
writeFullEndElement();
|
|
}
|
|
|
|
|
|
void CModelWriterNode100_Mesh::putVertexString(_In_ const nfChar * pszString)
|
|
{
|
|
__NMRASSERT(pszString);
|
|
const nfChar * pChar = pszString;
|
|
nfChar * pTarget = &m_VertexLine[m_nVertexBufferPos];
|
|
|
|
while (*pChar != 0) {
|
|
*pTarget = *pChar;
|
|
pTarget++;
|
|
pChar++;
|
|
m_nVertexBufferPos++;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putFloat(_In_ const nfFloat fValue, _In_ std::array<nfChar, MODELWRITERMESH100_LINEBUFFERSIZE> & line, _In_ nfUint32 & nBufferPos) {
|
|
// Format float with "%.$ACCf" syntax where $ACC = m_snPosAfterDecPoint
|
|
nfInt64 nAbsValue = (nfInt64)(fValue * m_nPutDoubleFactor);
|
|
nAbsValue = MAX(nAbsValue, -nAbsValue);
|
|
nfBool bIsNegative = fValue < 0;
|
|
|
|
int nStart = nBufferPos;
|
|
int nCount = 0;
|
|
|
|
if (!nAbsValue) {
|
|
line[nBufferPos++] = '0';
|
|
}
|
|
else {
|
|
// Write the string in reverse order
|
|
while (nAbsValue || nCount < m_nPosAfterDecPoint) {
|
|
line[nBufferPos++] = '0' + (nAbsValue % 10);
|
|
nAbsValue /= 10;
|
|
nCount++;
|
|
if (nCount == m_nPosAfterDecPoint) {
|
|
line[nBufferPos++] = '.';
|
|
if (!nAbsValue) {
|
|
line[nBufferPos++] = '0';
|
|
}
|
|
nCount++;
|
|
}
|
|
}
|
|
if (bIsNegative) {
|
|
line[nBufferPos++] = '-';
|
|
nCount++;
|
|
}
|
|
}
|
|
|
|
// Reverse the float string
|
|
int nEnd = nBufferPos - 1;
|
|
while (nStart < nEnd) {
|
|
char temp = line[nStart];
|
|
line[nStart] = line[nEnd];
|
|
line[nEnd] = temp;
|
|
nStart++;
|
|
nEnd--;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putDouble(_In_ const nfDouble dValue, _In_ std::array<nfChar, MODELWRITERMESH100_LINEBUFFERSIZE> & line, _In_ nfUint32 & nBufferPos) {
|
|
// Format float with "%.$ACCf" syntax where $ACC = m_snPosAfterDecPoint
|
|
nfInt64 nAbsValue = (nfInt64)(dValue * m_nPutDoubleFactor);
|
|
nAbsValue = MAX(nAbsValue, -nAbsValue);
|
|
nfBool bIsNegative = dValue < 0;
|
|
|
|
int nStart = nBufferPos;
|
|
int nCount = 0;
|
|
|
|
if (!nAbsValue) {
|
|
line[nBufferPos++] = '0';
|
|
}
|
|
else {
|
|
// Write the string in reverse order
|
|
while (nAbsValue || nCount < m_nPosAfterDecPoint) {
|
|
line[nBufferPos++] = '0' + (nAbsValue % 10);
|
|
nAbsValue /= 10;
|
|
nCount++;
|
|
if (nCount == m_nPosAfterDecPoint) {
|
|
line[nBufferPos++] = '.';
|
|
if (!nAbsValue) {
|
|
line[nBufferPos++] = '0';
|
|
}
|
|
nCount++;
|
|
}
|
|
}
|
|
if (bIsNegative) {
|
|
line[nBufferPos++] = '-';
|
|
nCount++;
|
|
}
|
|
}
|
|
|
|
// Reverse the float string
|
|
int nEnd = nBufferPos - 1;
|
|
while (nStart < nEnd) {
|
|
char temp = line[nStart];
|
|
line[nStart] = line[nEnd];
|
|
line[nEnd] = temp;
|
|
nStart++;
|
|
nEnd--;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putVertexFloat(_In_ const nfFloat fValue)
|
|
{
|
|
putFloat(fValue, m_VertexLine, m_nVertexBufferPos);
|
|
}
|
|
|
|
|
|
void CModelWriterNode100_Mesh::putTriangleString(_In_ const nfChar * pszString)
|
|
{
|
|
__NMRASSERT(pszString);
|
|
const nfChar * pChar = pszString;
|
|
nfChar * pTarget = &m_TriangleLine[m_nTriangleBufferPos];
|
|
|
|
while (*pChar != 0) {
|
|
*pTarget = *pChar;
|
|
pTarget++;
|
|
pChar++;
|
|
m_nTriangleBufferPos++;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putTriangleUInt32(_In_ const nfUint32 nValue)
|
|
{
|
|
|
|
#ifdef __GNUC__
|
|
int nCount = sprintf(&m_TriangleLine[m_nTriangleBufferPos], "%d", nValue);
|
|
#else
|
|
int nCount = sprintf_s(&m_TriangleLine[m_nTriangleBufferPos], MODELWRITERMESH100_LINEBUFFERSIZE - m_nTriangleBufferPos, "%d", nValue);
|
|
#endif // __GNUC__
|
|
|
|
if (nCount < 1)
|
|
throw CNMRException(NMR_ERROR_COULDNOTCONVERTNUMBER);
|
|
m_nTriangleBufferPos += nCount;
|
|
}
|
|
|
|
|
|
void CModelWriterNode100_Mesh::putBeamString(_In_ const nfChar * pszString)
|
|
{
|
|
__NMRASSERT(pszString);
|
|
const nfChar * pChar = pszString;
|
|
nfChar * pTarget = &m_BeamLine[m_nBeamBufferPos];
|
|
|
|
while (*pChar != 0) {
|
|
*pTarget = *pChar;
|
|
pTarget++;
|
|
pChar++;
|
|
m_nBeamBufferPos++;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBeamUInt32(_In_ const nfUint32 nValue)
|
|
{
|
|
#ifdef __GNUC__
|
|
int nCount = sprintf(&m_BeamLine[m_nBeamBufferPos], "%d", nValue);
|
|
#else
|
|
int nCount = sprintf_s(&m_BeamLine[m_nBeamBufferPos], MODELWRITERMESH100_LINEBUFFERSIZE - m_nBeamBufferPos, "%d", nValue);
|
|
#endif // __GNUC__
|
|
|
|
if (nCount < 1)
|
|
throw CNMRException(NMR_ERROR_COULDNOTCONVERTNUMBER);
|
|
m_nBeamBufferPos += nCount;
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBeamDouble(_In_ const nfDouble dValue)
|
|
{
|
|
putDouble(dValue, m_BeamLine, m_nBeamBufferPos);
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBallString(_In_ const nfChar * pszString)
|
|
{
|
|
__NMRASSERT(pszString);
|
|
const nfChar * pChar = pszString;
|
|
nfChar * pTarget = &m_BallLine[m_nBallBufferPos];
|
|
|
|
while (*pChar != 0) {
|
|
*pTarget = *pChar;
|
|
pTarget++;
|
|
pChar++;
|
|
m_nBallBufferPos++;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBallUInt32(_In_ const nfUint32 nValue)
|
|
{
|
|
#ifdef __GNUC__
|
|
int nCount = sprintf(&m_BallLine[m_nBallBufferPos], "%d", nValue);
|
|
#else
|
|
int nCount = sprintf_s(&m_BallLine[m_nBallBufferPos], MODELWRITERMESH100_LINEBUFFERSIZE - m_nBallBufferPos, "%d", nValue);
|
|
#endif // __GNUC__
|
|
|
|
if (nCount < 1)
|
|
throw CNMRException(NMR_ERROR_COULDNOTCONVERTNUMBER);
|
|
m_nBallBufferPos += nCount;
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBallDouble(_In_ const nfDouble dValue)
|
|
{
|
|
putDouble(dValue, m_BallLine, m_nBallBufferPos);
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBeamRefString(_In_ const nfChar * pszString)
|
|
{
|
|
__NMRASSERT(pszString);
|
|
const nfChar * pChar = pszString;
|
|
nfChar * pTarget = &m_BeamRefLine[m_nBeamRefBufferPos];
|
|
|
|
while (*pChar != 0) {
|
|
*pTarget = *pChar;
|
|
pTarget++;
|
|
pChar++;
|
|
m_nBeamRefBufferPos++;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBeamRefUInt32(_In_ const nfUint32 nValue)
|
|
{
|
|
#ifdef __GNUC__
|
|
int nCount = sprintf(&m_BeamRefLine[m_nBeamRefBufferPos], "%d", nValue);
|
|
#else
|
|
int nCount = sprintf_s(&m_BeamRefLine[m_nBeamRefBufferPos], MODELWRITERMESH100_LINEBUFFERSIZE - m_nBeamRefBufferPos, "%d", nValue);
|
|
#endif // __GNUC__
|
|
|
|
if (nCount < 1)
|
|
throw CNMRException(NMR_ERROR_COULDNOTCONVERTNUMBER);
|
|
m_nBeamRefBufferPos += nCount;
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBallRefString(_In_ const nfChar* pszString)
|
|
{
|
|
__NMRASSERT(pszString);
|
|
const nfChar * pChar = pszString;
|
|
nfChar * pTarget = &m_BallRefLine[m_nBallRefBufferPos];
|
|
|
|
while (*pChar != 0) {
|
|
*pTarget = *pChar;
|
|
pTarget++;
|
|
pChar++;
|
|
m_nBallRefBufferPos++;
|
|
}
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::putBallRefUInt32(_In_ const nfUint32 nValue)
|
|
{
|
|
#ifdef __GNUC__
|
|
int nCount = sprintf(&m_BallRefLine[m_nBallRefBufferPos], "%d", nValue);
|
|
#else
|
|
int nCount = sprintf_s(&m_BallRefLine[m_nBallRefBufferPos], MODELWRITERMESH100_LINEBUFFERSIZE - m_nBallRefBufferPos, "%d", nValue);
|
|
#endif // __GNUC__
|
|
|
|
if (nCount < 1)
|
|
throw CNMRException(NMR_ERROR_COULDNOTCONVERTNUMBER);
|
|
m_nBallRefBufferPos += nCount;
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::writeVertexData(_In_ MESHNODE * pNode)
|
|
{
|
|
__NMRASSERT(pNode);
|
|
m_nVertexBufferPos = MODELWRITERMESH100_VERTEXLINESTARTLENGTH;
|
|
putVertexFloat(pNode->m_position.m_values.x);
|
|
putVertexString("\" y=\"");
|
|
putVertexFloat(pNode->m_position.m_values.y);
|
|
putVertexString("\" z=\"");
|
|
putVertexFloat(pNode->m_position.m_values.z);
|
|
putVertexString("\" />");
|
|
|
|
m_pXMLWriter->WriteRawLine(&m_VertexLine[0], m_nVertexBufferPos);
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::writeFaceData_Plain(_In_ MESHFACE * pFace, _In_opt_ const nfChar * pszAdditionalString)
|
|
{
|
|
__NMRASSERT(pFace);
|
|
m_nTriangleBufferPos = MODELWRITERMESH100_TRIANGLELINESTARTLENGTH;
|
|
putTriangleUInt32(pFace->m_nodeindices[0]);
|
|
putTriangleString("\" v2=\"");
|
|
putTriangleUInt32(pFace->m_nodeindices[1]);
|
|
putTriangleString("\" v3=\"");
|
|
putTriangleUInt32(pFace->m_nodeindices[2]);
|
|
putTriangleString("\"");
|
|
if (pszAdditionalString) {
|
|
putTriangleString(pszAdditionalString);
|
|
}
|
|
putTriangleString(" />");
|
|
m_pXMLWriter->WriteRawLine(&m_TriangleLine[0], m_nTriangleBufferPos);
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::writeFaceData_OneProperty(_In_ MESHFACE * pFace, _In_ const ModelResourceID nPropertyID, _In_ const ModelResourceIndex nPropertyIndex, _In_opt_ const nfChar * pszAdditionalString)
|
|
{
|
|
__NMRASSERT(pFace);
|
|
m_nTriangleBufferPos = MODELWRITERMESH100_TRIANGLELINESTARTLENGTH;
|
|
putTriangleUInt32(pFace->m_nodeindices[0]);
|
|
putTriangleString("\" v2=\"");
|
|
putTriangleUInt32(pFace->m_nodeindices[1]);
|
|
putTriangleString("\" v3=\"");
|
|
putTriangleUInt32(pFace->m_nodeindices[2]);
|
|
if (nPropertyID != 0) {
|
|
putTriangleString("\" pid=\"");
|
|
putTriangleUInt32(nPropertyID);
|
|
}
|
|
putTriangleString("\" p1=\"");
|
|
putTriangleUInt32(nPropertyIndex);
|
|
putTriangleString("\"");
|
|
if (pszAdditionalString) {
|
|
putTriangleString(pszAdditionalString);
|
|
}
|
|
putTriangleString(" />");
|
|
m_pXMLWriter->WriteRawLine(&m_TriangleLine[0], m_nTriangleBufferPos);
|
|
}
|
|
|
|
void CModelWriterNode100_Mesh::writeFaceData_ThreeProperties(_In_ MESHFACE * pFace, _In_ const ModelResourceID nPropertyID, _In_ const ModelResourceIndex nPropertyIndex1, _In_ const ModelResourceIndex nPropertyIndex2, _In_ const ModelResourceIndex nPropertyIndex3, _In_opt_ const nfChar * pszAdditionalString)
|
|
{
|
|
__NMRASSERT(pFace);
|
|
m_nTriangleBufferPos = MODELWRITERMESH100_TRIANGLELINESTARTLENGTH;
|
|
putTriangleUInt32(pFace->m_nodeindices[0]);
|
|
putTriangleString("\" v2=\"");
|
|
putTriangleUInt32(pFace->m_nodeindices[1]);
|
|
putTriangleString("\" v3=\"");
|
|
putTriangleUInt32(pFace->m_nodeindices[2]);
|
|
if (nPropertyID != 0) {
|
|
putTriangleString("\" pid=\"");
|
|
putTriangleUInt32(nPropertyID);
|
|
}
|
|
putTriangleString("\" p1=\"");
|
|
putTriangleUInt32(nPropertyIndex1);
|
|
putTriangleString("\" p2=\"");
|
|
putTriangleUInt32(nPropertyIndex2);
|
|
putTriangleString("\" p3=\"");
|
|
putTriangleUInt32(nPropertyIndex3);
|
|
putTriangleString("\"");
|
|
if (pszAdditionalString) {
|
|
putTriangleString(pszAdditionalString);
|
|
}
|
|
putTriangleString(" />");
|
|
m_pXMLWriter->WriteRawLine(&m_TriangleLine[0], m_nTriangleBufferPos);
|
|
}
|
|
|
|
__NMR_INLINE void CModelWriterNode100_Mesh::writeBeamData(_In_ MESHBEAM * pBeam, _In_ nfDouble dRadius, _In_ eModelBeamLatticeCapMode eDefaultCapMode)
|
|
{
|
|
__NMRASSERT(pBeam);
|
|
m_nBeamBufferPos = MODELWRITERMESH100_BEAMLATTICE_BEAMSTARTLENGTH;
|
|
putBeamUInt32(pBeam->m_nodeindices[0]);
|
|
const std::string sV2 = "\" " + std::string(XML_3MF_ATTRIBUTE_BEAMLATTICE_V2) + "=\"";
|
|
putBeamString(sV2.c_str());
|
|
putBeamUInt32(pBeam->m_nodeindices[1]);
|
|
|
|
nfBool bWriteR2 = stringRepresentationsDiffer(pBeam->m_radius[0], pBeam->m_radius[1], m_nPutDoubleFactor);
|
|
nfBool bWriteR1 = bWriteR2 || stringRepresentationsDiffer(pBeam->m_radius[0], dRadius, m_nPutDoubleFactor);
|
|
if (bWriteR1) {
|
|
const std::string sR1 = "\" " + std::string(XML_3MF_ATTRIBUTE_BEAMLATTICE_R1) + "=\"";
|
|
putBeamString(sR1.c_str());
|
|
putBeamDouble(pBeam->m_radius[0]);
|
|
}
|
|
if (bWriteR2) {
|
|
const std::string sR2 = "\" " + std::string(XML_3MF_ATTRIBUTE_BEAMLATTICE_R2) + "=\"";
|
|
putBeamString(sR2.c_str());
|
|
putBeamDouble(pBeam->m_radius[1]);
|
|
}
|
|
|
|
if ( eDefaultCapMode != pBeam->m_capMode[0] ) {
|
|
const std::string sCap1 = "\" " + std::string(XML_3MF_ATTRIBUTE_BEAMLATTICE_CAP1) + "=\""
|
|
+ capModeToString(eModelBeamLatticeCapMode(pBeam->m_capMode[0]));
|
|
putBeamString(sCap1.c_str());
|
|
}
|
|
if (eDefaultCapMode != pBeam->m_capMode[1]) {
|
|
const std::string sCap2 = "\" " + std::string(XML_3MF_ATTRIBUTE_BEAMLATTICE_CAP2) + "=\""
|
|
+ capModeToString(eModelBeamLatticeCapMode(pBeam->m_capMode[1]));
|
|
putBeamString(sCap2.c_str());
|
|
}
|
|
|
|
putBeamString("\"/>");
|
|
m_pXMLWriter->WriteRawLine(&m_BeamLine[0], m_nBeamBufferPos);
|
|
}
|
|
|
|
__NMR_INLINE void CModelWriterNode100_Mesh::writeBallData(_In_ MESHBALL* pBall, _In_ eModelBeamLatticeBallMode eBallMode, _In_ nfDouble dRadius)
|
|
{
|
|
__NMRASSERT(pBall);
|
|
|
|
nfBool bWriteR = stringRepresentationsDiffer(pBall->m_radius, dRadius, m_nPutDoubleFactor);
|
|
if (!bWriteR && eBallMode == eModelBeamLatticeBallMode::MODELBEAMLATTICEBALLMODE_ALL) {
|
|
return;
|
|
}
|
|
|
|
m_nBallBufferPos = MODELWRITERMESH100_BEAMLATTICE_BALLSTARTLENGTH;
|
|
putBallUInt32(pBall->m_nodeindex);
|
|
if (bWriteR) {
|
|
const std::string sR = "\" " + std::string(XML_3MF_ATTRIBUTE_BEAMLATTICE_BALL_R) + "=\"";
|
|
putBallString(sR.c_str());
|
|
putBallDouble(pBall->m_radius);
|
|
}
|
|
|
|
putBallString("\"/>");
|
|
m_pXMLWriter->WriteRawLine(&m_BallLine[0], m_nBallBufferPos);
|
|
}
|
|
|
|
__NMR_INLINE void CModelWriterNode100_Mesh::writeRefData(_In_ INT nRefID)
|
|
{
|
|
m_nBeamRefBufferPos = MODELWRITERMESH100_BEAMLATTICE_REFSTARTLENGTH;
|
|
putBeamRefUInt32(nRefID);
|
|
putBeamRefString("\"/>");
|
|
m_pXMLWriter->WriteRawLine(&m_BeamRefLine[0], m_nBeamRefBufferPos);
|
|
}
|
|
|
|
__NMR_INLINE void CModelWriterNode100_Mesh::writeBallRefData(_In_ INT nBallRefID)
|
|
{
|
|
m_nBallRefBufferPos = MODELWRITERMESH100_BEAMLATTICE_BALLREFSTARTLENGTH;
|
|
putBallRefUInt32(nBallRefID);
|
|
putBallRefString("\"/>");
|
|
m_pXMLWriter->WriteRawLine(&m_BallRefLine[0], m_nBallRefBufferPos);
|
|
}
|
|
|
|
}
|