/*++ 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 #ifdef __GNUC__ #include #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 (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 & 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 & 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); } }