JtReader: allow to open JT files using TKJT
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/InventorObject.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/FileInfo.h>
|
||||
#include <Base/Interpreter.h>
|
||||
@@ -34,6 +35,7 @@
|
||||
#include <CXX/Extensions.hxx>
|
||||
|
||||
#include "TestJtReader.h"
|
||||
#include "TKJtReader.h"
|
||||
|
||||
|
||||
using std::vector;
|
||||
@@ -64,9 +66,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// NOLINTBEGIN
|
||||
Py::Object read(const Py::Tuple& args)
|
||||
{
|
||||
char* Name;
|
||||
char* Name {};
|
||||
if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &Name)) {
|
||||
throw Py::Exception();
|
||||
}
|
||||
@@ -77,7 +80,7 @@ private:
|
||||
}
|
||||
Py::Object open(const Py::Tuple& args)
|
||||
{
|
||||
char* Name;
|
||||
char* Name {};
|
||||
if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &Name)) {
|
||||
throw Py::Exception();
|
||||
}
|
||||
@@ -87,11 +90,24 @@ private:
|
||||
|
||||
|
||||
// Base::Console().Log("Open in Mesh with %s",Name);
|
||||
Base::FileInfo file(EncodedName.c_str());
|
||||
Base::FileInfo file(EncodedName);
|
||||
if (file.hasExtension("jt")) {
|
||||
TestJtReader reader;
|
||||
reader.setFile(EncodedName.c_str());
|
||||
reader.setFile(EncodedName);
|
||||
reader.read();
|
||||
|
||||
#ifdef JTREADER_HAVE_TKJT
|
||||
JtReaderNS::TKJtReader jtReader;
|
||||
jtReader.open(EncodedName);
|
||||
|
||||
App::Document* doc = App::GetApplication().newDocument();
|
||||
std::string objname = file.fileNamePure();
|
||||
auto iv = dynamic_cast<App::InventorObject*>(
|
||||
doc->addObject("App::InventorObject", objname.c_str()));
|
||||
iv->Buffer.setValue(jtReader.getOutput());
|
||||
iv->purgeTouched();
|
||||
#endif
|
||||
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
@@ -99,8 +115,8 @@ private:
|
||||
}
|
||||
Py::Object importer(const Py::Tuple& args)
|
||||
{
|
||||
char* Name;
|
||||
const char* DocName;
|
||||
char* Name {};
|
||||
const char* DocName {};
|
||||
if (!PyArg_ParseTuple(args.ptr(), "ets", "utf-8", &Name, &DocName)) {
|
||||
throw Py::Exception();
|
||||
}
|
||||
@@ -112,21 +128,33 @@ private:
|
||||
|
||||
if (file.hasExtension("jt")) {
|
||||
// add Import feature
|
||||
App::Document* pcDoc = App::GetApplication().getDocument(DocName);
|
||||
if (!pcDoc) {
|
||||
pcDoc = App::GetApplication().newDocument(DocName);
|
||||
App::Document* doc = App::GetApplication().getDocument(DocName);
|
||||
if (!doc) {
|
||||
doc = App::GetApplication().newDocument(DocName);
|
||||
}
|
||||
|
||||
#ifdef JTREADER_HAVE_TKJT
|
||||
JtReaderNS::TKJtReader jtReader;
|
||||
jtReader.open(EncodedName);
|
||||
|
||||
std::string objname = file.fileNamePure();
|
||||
auto iv = dynamic_cast<App::InventorObject*>(
|
||||
doc->addObject("App::InventorObject", objname.c_str()));
|
||||
iv->Buffer.setValue(jtReader.getOutput());
|
||||
iv->purgeTouched();
|
||||
#endif
|
||||
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
throw Py::RuntimeError("unknown file ending");
|
||||
}
|
||||
// NOLINTEND
|
||||
};
|
||||
|
||||
PyObject* initModule()
|
||||
{
|
||||
return Base::Interpreter().addModule(new Module);
|
||||
return Base::Interpreter().addModule(new Module); // NOLINT
|
||||
}
|
||||
|
||||
} // namespace JtReaderNS
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
set(JTREADER_TKJT_INCLUDE_DIRS CACHE PATH "Include directory of TKJT headers")
|
||||
set(JTREADER_TKJT_LIBRARIES CACHE FILEPATH "File path to TKJT library")
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
@@ -12,6 +15,7 @@ link_directories(${OCC_LIBRARY_DIR})
|
||||
|
||||
set(JtReader_LIBS
|
||||
Mesh
|
||||
${OCC_LIBRARIES}
|
||||
#${OCC_OCAF_LIBRARIES}
|
||||
#${OCC_OCAF_DEBUG_LIBRARIES}
|
||||
)
|
||||
@@ -27,6 +31,19 @@ SET(JtReader_SRCS
|
||||
FcLodHandler.cpp
|
||||
)
|
||||
|
||||
if (EXISTS "${JTREADER_TKJT_INCLUDE_DIRS}/JtData_Object.hxx")
|
||||
add_definitions(-DJTREADER_HAVE_TKJT)
|
||||
include_directories(${JTREADER_TKJT_INCLUDE_DIRS})
|
||||
list (APPEND JtReader_LIBS
|
||||
${JTREADER_TKJT_LIBRARIES}
|
||||
)
|
||||
|
||||
list (APPEND JtReader_SRCS
|
||||
TKJtReader.cpp
|
||||
TKJtReader.h
|
||||
)
|
||||
endif ()
|
||||
|
||||
set (JtReader_Scripts
|
||||
../Init.py
|
||||
)
|
||||
|
||||
270
src/Mod/JtReader/App/TKJtReader.cpp
Normal file
270
src/Mod/JtReader/App/TKJtReader.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#include <gp_Trsf.hxx>
|
||||
|
||||
#include "TKJtReader.h"
|
||||
#include <Base/Console.h>
|
||||
#include <Base/FileInfo.h>
|
||||
|
||||
using namespace JtReaderNS;
|
||||
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
const Handle(Standard_Type) Type_JtAttribute_GeometricTransform = STANDARD_TYPE(JtAttribute_GeometricTransform);
|
||||
const Handle(Standard_Type) Type_JtAttribute_Material = STANDARD_TYPE(JtAttribute_Material);
|
||||
const Handle(Standard_Type) Type_JtNode_Partition = STANDARD_TYPE(JtNode_Partition);
|
||||
const Handle(Standard_Type) Type_JtNode_Group = STANDARD_TYPE(JtNode_Group);
|
||||
const Handle(Standard_Type) Type_JtNode_Instance = STANDARD_TYPE(JtNode_Instance);
|
||||
const Handle(Standard_Type) Type_JtNode_RangeLOD = STANDARD_TYPE(JtNode_RangeLOD);
|
||||
const Handle(Standard_Type) Type_JtNode_Shape_Base = STANDARD_TYPE(JtNode_Shape_Base);
|
||||
const Handle(Standard_Type) Type_JtNode_Shape_Vertex = STANDARD_TYPE(JtNode_Shape_Vertex);
|
||||
const Handle(Standard_Type) Type_JtNode_Shape_TriStripSet = STANDARD_TYPE(JtNode_Shape_TriStripSet);
|
||||
// clang-format on
|
||||
} // namespace
|
||||
|
||||
TKJtReader::TKJtReader()
|
||||
: builder {result}
|
||||
{}
|
||||
|
||||
void TKJtReader::clear()
|
||||
{
|
||||
result.str(std::string());
|
||||
result.clear();
|
||||
}
|
||||
|
||||
void TKJtReader::open(const std::string& filename)
|
||||
{
|
||||
clear();
|
||||
|
||||
Base::FileInfo file(filename);
|
||||
jtDir = TCollection_ExtendedString(TCollection_AsciiString((file.dirPath() + '/').c_str()));
|
||||
|
||||
TCollection_ExtendedString aFileName(filename.c_str());
|
||||
Handle(JtData_Model) aModel = new JtData_Model(aFileName);
|
||||
|
||||
if (!aModel.IsNull()) {
|
||||
Handle(JtNode_Partition) aNode = aModel->Init();
|
||||
if (!aNode.IsNull()) {
|
||||
rootNode = aNode;
|
||||
|
||||
builder.addHeader();
|
||||
builder.beginSeparator();
|
||||
Base::ShapeHintsItem shapeHints;
|
||||
shapeHints.setShapeType(Base::ShapeType::Type::UnknownShapeType);
|
||||
shapeHints.setVertexOrdering(Base::VertexOrdering::Ordering::CounterClockwise);
|
||||
builder.addNode(shapeHints);
|
||||
traverseGraph(aNode);
|
||||
builder.endSeparator();
|
||||
rootNode.Nullify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string TKJtReader::getOutput() const
|
||||
{
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void TKJtReader::readMaterialAttribute(const Handle(JtAttribute_Material) & aMaterial)
|
||||
{
|
||||
const Jt_F32* ambient = aMaterial->AmbientColor();
|
||||
const Jt_F32* diffuse = aMaterial->DiffuseColor();
|
||||
const Jt_F32* specular = aMaterial->SpecularColor();
|
||||
// const Jt_F32* emissive = aMaterial->EmissionColor();
|
||||
Jt_F32 shininess = aMaterial->Shininess() / 100.0F;
|
||||
|
||||
// NOLINTBEGIN
|
||||
Base::MaterialItem item;
|
||||
item.setAmbientColor({Base::ColorRGB(ambient[0], ambient[1], ambient[2])});
|
||||
item.setDiffuseColor({Base::ColorRGB(diffuse[0], diffuse[1], diffuse[2])});
|
||||
item.setSpecularColor({Base::ColorRGB(specular[0], specular[1], specular[2])});
|
||||
// Ignore the emissive color as there are sometimes some weird values
|
||||
// item.setEmissiveColor({Base::ColorRGB(emissive[0], emissive[1], emissive[2])});
|
||||
item.setShininess({shininess});
|
||||
// NOLINTEND
|
||||
|
||||
builder.addNode(item);
|
||||
}
|
||||
|
||||
void TKJtReader::readTransformAttribute(const Handle(JtAttribute_GeometricTransform) & aTransform)
|
||||
{
|
||||
gp_Trsf trsf;
|
||||
aTransform->GetTrsf(trsf);
|
||||
gp_Mat mat = trsf.VectorialPart();
|
||||
gp_XYZ xyz = trsf.TranslationPart();
|
||||
Base::Matrix4D mtrx;
|
||||
// NOLINTBEGIN
|
||||
mtrx[0][0] = mat(1, 1);
|
||||
mtrx[0][1] = mat(1, 2);
|
||||
mtrx[0][2] = mat(1, 3);
|
||||
|
||||
mtrx[1][0] = mat(2, 1);
|
||||
mtrx[1][1] = mat(2, 2);
|
||||
mtrx[1][2] = mat(2, 3);
|
||||
|
||||
mtrx[2][0] = mat(3, 1);
|
||||
mtrx[2][1] = mat(3, 2);
|
||||
mtrx[2][2] = mat(3, 3);
|
||||
|
||||
// set pos vector
|
||||
mtrx[0][3] = xyz.X();
|
||||
mtrx[1][3] = xyz.Y();
|
||||
mtrx[2][3] = xyz.Z();
|
||||
// NOLINTEND
|
||||
|
||||
transformations.push_back(mtrx);
|
||||
}
|
||||
|
||||
void TKJtReader::readShapeVertex(const Handle(JtNode_Shape_Vertex) & aShape)
|
||||
{
|
||||
const JtData_Object::VectorOfLateLoads& aLateLoaded = aShape->LateLoads();
|
||||
for (std::size_t index = 0; index < aLateLoaded.Count(); ++index) {
|
||||
Handle(JtData_Object) anObject = aLateLoaded[index]->DefferedObject();
|
||||
if (anObject.IsNull()) {
|
||||
aLateLoaded[index]->Load();
|
||||
anObject = aLateLoaded[index]->DefferedObject();
|
||||
}
|
||||
if (!anObject.IsNull()) {
|
||||
Handle(JtElement_ShapeLOD_TriStripSet) aLOD =
|
||||
Handle(JtElement_ShapeLOD_TriStripSet)::DownCast(anObject);
|
||||
if (!aLOD.IsNull()) {
|
||||
getTriangleStripSet(aLOD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TKJtReader::getTriangleStripSet(const Handle(JtElement_ShapeLOD_TriStripSet) & aLOD)
|
||||
{
|
||||
const int pointsPerFace = 3;
|
||||
std::vector<Base::Vector3f> points;
|
||||
std::vector<int> faces;
|
||||
const JtElement_ShapeLOD_Vertex::VertexData& vertices = aLOD->Vertices();
|
||||
const JtElement_ShapeLOD_Vertex::IndicesVec& indices = aLOD->Indices();
|
||||
float* data = vertices.Data();
|
||||
// NOLINTBEGIN
|
||||
for (int index = 0; index < indices.Count(); index += 3) {
|
||||
int coordIndex = indices[index] * 3;
|
||||
points.emplace_back(data[coordIndex], data[coordIndex + 1], data[coordIndex + 2]);
|
||||
coordIndex = indices[index + 1] * 3;
|
||||
points.emplace_back(data[coordIndex], data[coordIndex + 1], data[coordIndex + 2]);
|
||||
coordIndex = indices[index + 2] * 3;
|
||||
points.emplace_back(data[coordIndex], data[coordIndex + 1], data[coordIndex + 2]);
|
||||
faces.push_back(pointsPerFace);
|
||||
}
|
||||
// NOLINTEND
|
||||
builder.addNode(Base::Coordinate3Item {points});
|
||||
builder.addNode(Base::FaceSetItem {faces});
|
||||
}
|
||||
|
||||
void TKJtReader::readPartition(const Handle(JtNode_Partition) & aPart)
|
||||
{
|
||||
if (rootNode != aPart) {
|
||||
TCollection_ExtendedString aFullPath = jtDir + aPart->FileName();
|
||||
TCollection_AsciiString aFileName(aFullPath);
|
||||
Handle(JtData_Model) aModel = new JtData_Model(aFullPath);
|
||||
Handle(JtNode_Partition) aNode = aModel->Init();
|
||||
if (!aNode.IsNull()) {
|
||||
builder.addNode(Base::InfoItem(std::string(aFileName.ToCString())));
|
||||
traverseGraph(aNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TKJtReader::readGroup(const Handle(JtNode_Group) & aGroup)
|
||||
{
|
||||
if (!transformations.empty()) {
|
||||
builder.addNode(Base::TransformItem {transformations.back()});
|
||||
transformations.pop_back();
|
||||
}
|
||||
const auto& aChildren = aGroup->Children();
|
||||
for (std::size_t aChildIdx = 0; aChildIdx < aChildren.Count(); ++aChildIdx) {
|
||||
Handle(JtNode_Base) aChild = Handle(JtNode_Base)::DownCast(aChildren[aChildIdx]);
|
||||
traverseGraph(aChild);
|
||||
}
|
||||
}
|
||||
|
||||
void TKJtReader::readRangeLOD(const Handle(JtNode_RangeLOD) & aRangeLOD)
|
||||
{
|
||||
readGroup(aRangeLOD);
|
||||
}
|
||||
|
||||
void TKJtReader::readInstance(const Handle(JtNode_Instance) & anInstance)
|
||||
{
|
||||
Handle(JtNode_Base) aBase = Handle(JtNode_Base)::DownCast(anInstance->Object());
|
||||
if (!aBase.IsNull()) {
|
||||
traverseGraph(aBase);
|
||||
}
|
||||
}
|
||||
|
||||
void TKJtReader::readAttributes(const JtData_Object::VectorOfObjects& attr)
|
||||
{
|
||||
for (std::size_t aAttrIdx = 0; aAttrIdx < attr.Count(); ++aAttrIdx) {
|
||||
Handle(JtData_Object) anAttr = attr[aAttrIdx];
|
||||
if (anAttr->IsKind(Type_JtAttribute_GeometricTransform)) {
|
||||
Handle(JtAttribute_GeometricTransform) aTransform =
|
||||
Handle(JtAttribute_GeometricTransform)::DownCast(anAttr);
|
||||
readTransformAttribute(aTransform);
|
||||
}
|
||||
else if (anAttr->IsKind(Type_JtAttribute_Material)) {
|
||||
Handle(JtAttribute_Material) aMaterial = Handle(JtAttribute_Material)::DownCast(anAttr);
|
||||
readMaterialAttribute(aMaterial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TKJtReader::traverseGraph(const Handle(JtNode_Base) & aNode)
|
||||
{
|
||||
readAttributes(aNode->Attributes());
|
||||
|
||||
if (aNode->IsKind(Type_JtNode_Partition)) {
|
||||
Handle(JtNode_Partition) aPart = Handle(JtNode_Partition)::DownCast(aNode);
|
||||
builder.beginSeparator();
|
||||
readPartition(aPart);
|
||||
readGroup(aPart);
|
||||
builder.endSeparator();
|
||||
}
|
||||
else if (aNode->IsKind(Type_JtNode_RangeLOD)) {
|
||||
Handle(JtNode_RangeLOD) aRangeLOD = Handle(JtNode_RangeLOD)::DownCast(aNode);
|
||||
builder.beginSeparator();
|
||||
readRangeLOD(aRangeLOD);
|
||||
builder.endSeparator();
|
||||
}
|
||||
else if (aNode->IsKind(Type_JtNode_Group)) {
|
||||
Handle(JtNode_Group) aGroup = Handle(JtNode_Group)::DownCast(aNode);
|
||||
builder.beginSeparator();
|
||||
readGroup(aGroup);
|
||||
builder.endSeparator();
|
||||
}
|
||||
else if (aNode->IsKind(Type_JtNode_Instance)) {
|
||||
Handle(JtNode_Instance) anInstance = Handle(JtNode_Instance)::DownCast(aNode);
|
||||
readInstance(anInstance);
|
||||
}
|
||||
else if (aNode->IsKind(Type_JtNode_Shape_Vertex)) {
|
||||
Handle(JtNode_Shape_Vertex) aShape = Handle(JtNode_Shape_Vertex)::DownCast(aNode);
|
||||
readShapeVertex(aShape);
|
||||
}
|
||||
}
|
||||
76
src/Mod/JtReader/App/TKJtReader.h
Normal file
76
src/Mod/JtReader/App/TKJtReader.h
Normal file
@@ -0,0 +1,76 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef JT_READER_TKJTREADER_H
|
||||
#define JT_READER_TKJTREADER_H
|
||||
|
||||
#ifdef JTREADER_HAVE_TKJT
|
||||
#include <JtAttribute_GeometricTransform.hxx>
|
||||
#include <JtAttribute_Material.hxx>
|
||||
#include <JtData_Model.hxx>
|
||||
#include <JtElement_ShapeLOD_TriStripSet.hxx>
|
||||
#include <JtNode_Instance.hxx>
|
||||
#include <JtNode_Partition.hxx>
|
||||
#include <JtNode_RangeLOD.hxx>
|
||||
#include <JtNode_Shape_TriStripSet.hxx>
|
||||
#include <JtNode_Shape_Vertex.hxx>
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
#include <TCollection_ExtendedString.hxx>
|
||||
#include <Base/Builder3D.h>
|
||||
|
||||
namespace JtReaderNS
|
||||
{
|
||||
|
||||
class TKJtReader
|
||||
{
|
||||
public:
|
||||
TKJtReader();
|
||||
void open(const std::string& filename);
|
||||
void clear();
|
||||
std::string getOutput() const;
|
||||
|
||||
private:
|
||||
void traverseGraph(const Handle(JtNode_Base) & aNode);
|
||||
void readMaterialAttribute(const Handle(JtAttribute_Material) & aMaterial);
|
||||
void readTransformAttribute(const Handle(JtAttribute_GeometricTransform) & aTransform);
|
||||
void readShapeVertex(const Handle(JtNode_Shape_Vertex) & aShape);
|
||||
void readPartition(const Handle(JtNode_Partition) & aPart);
|
||||
void readGroup(const Handle(JtNode_Group) & aGroup);
|
||||
void readRangeLOD(const Handle(JtNode_RangeLOD) & aRangeLOD);
|
||||
void readInstance(const Handle(JtNode_Instance) & anInstance);
|
||||
void readAttributes(const JtData_Object::VectorOfObjects& attr);
|
||||
void getTriangleStripSet(const Handle(JtElement_ShapeLOD_TriStripSet) & aLOD);
|
||||
|
||||
private:
|
||||
TCollection_ExtendedString jtDir;
|
||||
Handle(JtNode_Partition) rootNode;
|
||||
std::stringstream result;
|
||||
Base::InventorBuilder builder;
|
||||
std::list<Base::Matrix4D> transformations;
|
||||
};
|
||||
|
||||
}; // namespace JtReaderNS
|
||||
|
||||
#endif // JTREADER_HAVE_TKJT
|
||||
|
||||
#endif // JT_READER_TKJTREADER_H
|
||||
Reference in New Issue
Block a user