This commit is contained in:
ninja
2025-12-15 23:22:33 +08:00
parent 019570564b
commit 8782765fbc
809 changed files with 118753 additions and 18289 deletions

View File

@@ -0,0 +1,266 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#include "exchange.h"
#include "he/representation_item.h"
#include "he/model_file.h"
#include <pugixml.hpp>
#include <iostream>
using Part = he::structure::Part;
using ModelFile = he::structure::ModelFile;
namespace model
{
namespace exchange
{
int load_model(const std::string& input_file, A3DAsmModelFile*& mdlFile)
{
// Declare and initialize the file loading options
A3DRWParamsLoadData load_params;
A3D_INITIALIZE_DATA(A3DRWParamsLoadData, load_params);
load_params.m_sGeneral.m_bReadSolids = true;
load_params.m_sAssembly.m_bUseRootDirectory = true;
load_params.m_sAssembly.m_bRootDirRecursive = true;
load_params.m_sGeneral.m_eReadGeomTessMode = kA3DReadGeomAndTess;
load_params.m_sTessellation.m_eTessellationLevelOfDetail = kA3DTessLODHigh;
load_params.m_sGeneral.m_bReadSurfaces = true;
load_params.m_sMultiEntries.m_bLoadDefault = true;
// Pick a file using the standard file open dialog
// std::string const input_folder{ exchange_data_dir };
// std::string input_file = input_folder;
// input_file.append("/catiaV5/CV5_Micro_engine/_micro engine.CATProduct");
// Attempt to load the file
auto const load_status = A3DAsmModelFileLoadFromFile(input_file.c_str(), &load_params, &mdlFile);
if (A3D_SUCCESS != load_status && A3D_LOAD_MISSING_COMPONENTS != load_status)
{
std::cout << "input_file = " << input_file << std::endl;
std::cout << "ERROR::MODELFILE::FILE_NOT_SUCCESSFULLY_READ: " << load_status << std::endl;
return -1;
}
return 0;
}
int collect_leaves(A3DAsmModelFile* model_file, std::vector<Part>& parts)
{
ModelFile mdlFile(model_file);
if (mdlFile.get_status())
return 1;
mdlFile.collect(parts);
return 0;
}
float convert_transparency(const A3DGraphStyleData& sStyle)
{
if (sStyle.m_bIsTransparencyDefined)
return static_cast<float>(sStyle.m_ucTransparency / 255.f);
return 1.f;
}
bool convert_rgba(A3DInt32 index, glm::vec4& values)
{
A3DGraphRgbColorData color_data;
A3D_INITIALIZE_DATA(A3DGraphRgbColorData, color_data);
if (A3DGlobalGetGraphRgbColorData(index, &color_data) == A3D_SUCCESS)
{
values[0] = static_cast<float>(color_data.m_dRed);
values[1] = static_cast<float>(color_data.m_dGreen);
values[2] = static_cast<float>(color_data.m_dBlue);
return true;
}
return false;
}
utils::properties::style::Graphics convert_material(A3DInt32 index, float transparency)
{
A3DGraphMaterialData material_data;
A3D_INITIALIZE_DATA(A3DGraphMaterialData, material_data);
utils::properties::style::Graphics style;
if (A3DGlobalGetGraphMaterialData(index, &material_data) == A3D_SUCCESS)
{
if (convert_rgba(material_data.m_uiAmbient, style.material.ambient)
&& convert_rgba(material_data.m_uiDiffuse, style.material.diffuse)
&& convert_rgba(material_data.m_uiSpecular, style.material.specular)
&& convert_rgba(material_data.m_uiEmissive, style.material.emissive))
{
style.material.ambient[3] = static_cast<float>( transparency != 1. ? transparency: material_data.m_dAmbientAlpha );
style.material.diffuse[3] = static_cast<float>( transparency != 1. ? transparency : material_data.m_dDiffuseAlpha );
style.material.specular[3] = static_cast<float>( transparency != 1. ? transparency : material_data.m_dSpecularAlpha );
style.material.emissive[3] = static_cast<float>( transparency != 1. ? transparency : material_data.m_dEmissiveAlpha );
style.material.shininess = static_cast<float>( material_data.m_dShininess );
style.type = utils::properties::style::Graphics::MATERIAL;
A3DGlobalGetGraphMaterialData(A3D_DEFAULT_MATERIAL_INDEX, &material_data);
}
else
{
A3DGlobalGetGraphMaterialData(A3D_DEFAULT_MATERIAL_INDEX, &material_data);
}
}
return style;
}
utils::properties::style::Graphics convert_style(A3DInt32 style_index)
{
utils::properties::style::Graphics style;
style.id = style_index;
A3DGraphStyleData style_data;
A3D_INITIALIZE_DATA(A3DGraphStyleData, style_data);
if (A3DGlobalGetGraphStyleData(style_index, &style_data) != A3D_SUCCESS)
{
return style;
}
A3DUns32 index = style_data.m_uiRgbColorIndex;
if (index == A3D_DEFAULT_COLOR_INDEX)
{
return style;
}
if (style_data.m_bMaterial == false)
{
if (convert_rgba(index, style.rgba))
{
style.type = utils::properties::style::Graphics::RGBA;
style.rgba[3] = convert_transparency(style_data);
}
return style;
}
A3DBool is_texture = false;
if (A3DGlobalIsMaterialTexture(index, &is_texture) == 0)
{
if (is_texture)
{
style.type = utils::properties::style::Graphics::TEXTURE;
}
else
{
style = convert_material(index, convert_transparency(style_data));
style.id = style_index;
}
}
return style;
}
namespace geometry
{
std::vector<utils::geometry::BufferData> prepare_render_buffer(A3DRiRepresentationItem* ri, const A3DMiscCascadedAttributes* cascaded_attributes)
{
std::vector<utils::geometry::BufferData> buffer_data_array;
he::geometry::RepresentationItem rep_item(ri, cascaded_attributes);
if (rep_item.get_status() != 0)
return buffer_data_array;
rep_item.prepare_render_buffer(buffer_data_array);
return buffer_data_array;
}
}
namespace tree
{
void print_treenode(const A3DTree* tree, const A3DTreeNode* node, pugi::xml_node& xml_parent)
{
if (tree == nullptr || node == nullptr)
return;
// Print node data
pugi::xml_node xml_node = xml_parent.append_child("Node");
// name
A3DUTF8Char* name = nullptr;
if (A3D_SUCCESS == A3DTreeNodeGetName(node, &name) && name)
xml_node.append_attribute("name") = name;
A3DTreeNodeGetName(nullptr, &name);
// Print entity data encapsulated by this node
pugi::xml_node xml_entity = xml_node.append_child("Entity");
A3DEntity* entity = nullptr;
if (A3D_SUCCESS == A3DTreeNodeGetEntity(node, &entity) && entity)
{
// entity type
A3DEEntityType type = kA3DTypeUnknown;
A3DEntityGetType(entity, &type);
xml_entity.append_attribute("type") = A3DMiscGetEntityTypeMsg(type);
// entity persistent id
A3DRootBaseData root_data;
A3D_INITIALIZE_DATA(A3DRootBaseData, root_data);
if (A3D_SUCCESS == A3DRootBaseGet(entity, &root_data))
if(root_data.m_uiPersistentId != 0)
xml_entity.append_attribute("persistentUId") = root_data.m_uiPersistentId;
if(root_data.m_pcPersistentId != nullptr)
xml_entity.append_attribute("persistentId") = root_data.m_pcPersistentId;
A3DRootBaseGet(nullptr, &root_data);
}
// Print children nodes recursively
A3DUns32 children_count;
A3DTreeNode** child_nodes = nullptr;
if (A3D_SUCCESS == A3DTreeNodeGetChildren(tree, node, &children_count, &child_nodes))
{
for (size_t i = 0; i < children_count; ++i) {
print_treenode(tree, child_nodes[i], xml_node);
}
}
A3DTreeNodeGetChildren(nullptr, nullptr, &children_count, &child_nodes);
}
bool print_tree(const A3DAsmModelFile* model, pugi::xml_node& xml_node)
{
A3DTree* tree = nullptr;
if (A3D_SUCCESS != A3DTreeCompute(model, &tree, nullptr))
return false;
A3DTreeNode* node = nullptr;
if (A3D_SUCCESS != A3DTreeGetRootNode(tree, &node))
return false;
std::cout << "Print model tree" << "\n";
print_treenode(tree, node, xml_node);
A3DTreeCompute(nullptr, &tree, nullptr);
return true;
}
void print(const A3DAsmModelFile* model, const std::string& model_file_path, const std::string& model_tree_file_path)
{
pugi::xml_document doc;
try
{
// Print model file path
pugi::xml_node node = doc.append_child("Model");
node.append_attribute("path") = model_file_path.c_str();
// Print tree
print_tree( model, node);
// Save tree in output file
std::cout << "Saving result: " << doc.save_file(model_tree_file_path.c_str()) << std::endl;
}
catch (const std::bad_alloc&)
{
std::cout << "std::bad_alloc exception caught\n";
if (!doc.empty())
doc.save_file(model_tree_file_path.c_str());
}
std::cout << "The corresponding XSD file is `dump_model_tree.xsd` in `MeshViewer` sample folder." << std::endl;
}
}
}
}

View File

@@ -0,0 +1,45 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#ifndef EXCHANGE_H
#define EXCHANGE_H
#include <string>
#include "../utils/properties.h"
#include "../utils/geometry.h"
#include "he/entity.h"
#include "he/part.h"
namespace model
{
namespace exchange
{
namespace geometry
{
std::vector<utils::geometry::BufferData> prepare_render_buffer(A3DRiRepresentationItem* rep_item, const A3DMiscCascadedAttributes* cascaded_attributes);
}
int load_model(const std::string& input_file, A3DAsmModelFile*& mdlFile);
int collect_leaves(A3DAsmModelFile* mdlFile, std::vector<he::structure::Part>& parts);
utils::properties::style::Graphics convert_style(A3DInt32 index);
namespace tree
{
/*! Dump the model tree in an XML file.
* \param[in] model The model to dump.
* \param[in] model_file_path The model path.
* \param[in] model_tree_file_path The model tree XML file path. */
void print(const A3DAsmModelFile* model, const std::string& model_file_path, const std::string& model_tree_file_path);
}
}
}
#endif // EXCHANGE_H

View File

@@ -0,0 +1,40 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#include "entity.h"
namespace he
{
Entity::Entity(A3DMiscCascadedAttributes* attrib) : attributes(attrib) {}
Entity::~Entity()
{
if (attributes)
{
if (A3DMiscCascadedAttributesDelete(attributes) != A3D_SUCCESS)
status = 1;
}
}
std::vector<A3DEntity*> Entity::sub_levels() const
{
return {};
}
namespace structure
{
int create_cascaded_attributes(const A3DRootBaseWithGraphics* entity, const A3DMiscCascadedAttributes* parent, A3DMiscCascadedAttributes*& attributes)
{
if (A3DMiscCascadedAttributesCreate(&attributes) != 0)
return 1;
if (A3DMiscCascadedAttributesPush(attributes, entity, parent))
return 1;
return 0;
}
}
}

View File

@@ -0,0 +1,45 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#ifndef ENTITY_H
#define ENTITY_H
#include <vector>
#include <A3DSDKIncludes.h>
namespace he
{
namespace structure
{
int create_cascaded_attributes(const A3DRootBaseWithGraphics* entity, const A3DMiscCascadedAttributes* parent, A3DMiscCascadedAttributes*& attributes);
}
class Entity
{
protected:
int status = A3D_SUCCESS;
A3DMiscCascadedAttributes* attributes = nullptr;
public:
Entity(A3DMiscCascadedAttributes* attributes = nullptr);
~Entity();
int get_status() const {
return status;
}
const A3DMiscCascadedAttributes* get_attributes() const {
return attributes;
}
virtual std::vector<A3DEntity*> sub_levels() const;
};
}
#endif // ENTITY_H

View File

@@ -0,0 +1,60 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#include "model_file.h"
#include "part.h"
#include "product_occurrence.h"
namespace he
{
namespace structure
{
ModelFile::ModelFile(A3DAsmModelFile* mdlFile)
{
A3D_INITIALIZE_DATA(A3DAsmModelFileData, data);
status = A3DAsmModelFileGet(mdlFile, &data);
if (status != A3D_SUCCESS)
return;
status = A3DMiscCascadedAttributesCreate(&attributes);
}
ModelFile::~ModelFile()
{
A3DAsmModelFileGet(nullptr, &data);
}
int ModelFile::collect(std::vector<Part>& parts)
{
if (status)
return 1;
A3DMiscCascadedAttributes* mdl_attribs = nullptr;
A3DMiscCascadedAttributesCreate(&mdl_attribs);
for (const auto po_entity : sub_levels())
{
A3DMiscCascadedAttributes* new_attributes = nullptr;
if (create_cascaded_attributes(po_entity, mdl_attribs, new_attributes) != 0)
return 1;
if (A3DMiscCascadedAttributesEntityReferencePush(new_attributes, po_entity, nullptr) != 0)
continue;
ProductOccurrence po(po_entity, new_attributes);
po.collect(parts, nullptr);
}
return 0;
}
std::vector<A3DEntity*> ModelFile::sub_levels() const
{
return std::vector<A3DEntity*>(data.m_ppPOccurrences, data.m_ppPOccurrences + data.m_uiPOccurrencesSize);
}
}
}

View File

@@ -0,0 +1,39 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#ifndef MDL_FILE_H
#define MDL_FILE_H
#include "entity.h"
#include "part.h"
namespace he
{
namespace structure
{
class ModelFile : public Entity
{
A3DAsmModelFileData data;
A3DAsmModelFile* entity;
public:
ModelFile(A3DAsmModelFile* mdlFile);
~ModelFile();
const A3DAsmModelFileData& get_data() const {
return data;
}
std::vector<A3DEntity*> sub_levels() const override;
int collect(std::vector<Part>& parts);
};
}
}
#endif // MDL_FILE_H

View File

@@ -0,0 +1,130 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#include "part.h"
#include <algorithm>
#include <A3DSDKIncludes.h>
namespace he
{
namespace structure
{
Part::Part(const Part& other) : Entity(other)
{
this->entity = other.entity;
this->contexts = other.contexts;
}
Part& Part::operator=(const Part& other)
{
if (this != &other)
{
this->entity = other.entity;
this->contexts = other.contexts;
}
return *this;
}
Part::Part(Part&& other) noexcept
{
this->entity = other.entity;
this->contexts = std::move(other.contexts);
}
Part& Part::operator=(Part&& other) noexcept
{
if (this != &other)
{
this->entity = other.entity;
this->contexts = std::move(other.contexts);
}
return *this;
}
Part::Part(A3DAsmPartDefinition* part, const A3DMiscCascadedAttributes* attributes, const glm::mat4& parentPosition) : entity(part)
{
A3DMiscCascadedAttributesData graphics_data;
A3D_INITIALIZE_DATA(A3DMiscCascadedAttributesData, graphics_data);
status = A3DMiscCascadedAttributesGet(attributes, &graphics_data);
contexts.push_back({ attributes, graphics_data, {parentPosition} });
}
const A3DAsmPartDefinition* Part::get_entity() const
{
return entity;
}
const std::vector<Context>& Part::get_contexts() const
{
return contexts;
}
std::vector<Context>& Part::grab_contexts()
{
return contexts;
}
bool Part::isSame(const A3DAsmPartDefinition* part_def, const A3DMiscCascadedAttributes* graphics, glm::mat4&& position)
{
if (this->entity != part_def)
return false;
A3DMiscCascadedAttributesData graphics_data;
A3D_INITIALIZE_DATA(A3DMiscCascadedAttributesData, graphics_data);
status = A3DMiscCascadedAttributesGet(graphics, &graphics_data);
if (status != A3D_SUCCESS)
return false;
auto it = std::find_if(
contexts.begin(),
contexts.end(),
[&] (Context& context)
{
const auto& gpx = std::get<1>(context);
auto& positions = std::get<2>(context);
if (graphics_data.m_sStyle.m_dWidth != gpx.m_sStyle.m_dWidth || graphics_data.m_sStyle.m_bVPicture != gpx.m_sStyle.m_bVPicture || graphics_data.m_sStyle.m_uiLinePatternIndex != gpx.m_sStyle.m_uiLinePatternIndex || graphics_data.m_sStyle.m_bMaterial != gpx.m_sStyle.m_bMaterial || graphics_data.m_sStyle.m_uiRgbColorIndex != gpx.m_sStyle.m_uiRgbColorIndex || graphics_data.m_sStyle.m_bIsTransparencyDefined != gpx.m_sStyle.m_bIsTransparencyDefined || graphics_data.m_sStyle.m_ucTransparency != gpx.m_sStyle.m_ucTransparency || graphics_data.m_sStyle.m_bSpecialCulling != gpx.m_sStyle.m_bSpecialCulling || graphics_data.m_sStyle.m_bFrontCulling != gpx.m_sStyle.m_bFrontCulling || graphics_data.m_sStyle.m_bBackCulling != gpx.m_sStyle.m_bBackCulling || graphics_data.m_sStyle.m_bNoLight != gpx.m_sStyle.m_bNoLight || graphics_data.m_sStyle.m_eRenderingMode != gpx.m_sStyle.m_eRenderingMode
// || graphics_data.m_usLayer != gpx.m_usLayer
)
{
contexts.push_back({ graphics, graphics_data, {position} });
return true;
}
positions.push_back(position);
return true;
});
if (it == contexts.end())
contexts.push_back({ graphics, graphics_data, {position} });
return true;
}
void traverse_ri(A3DRiRepresentationItem* ri, std::vector<A3DRiRepresentationItem*>& ri_list)
{
A3DEEntityType type = kA3DTypeUnknown;
A3DEntityGetType(ri, &type);
if (type == kA3DTypeRiSet)
{
A3DRiSetData data;
A3D_INITIALIZE_DATA(A3DRiSetData, data);
if (A3D_SUCCESS != A3DRiSetGet(ri, &data))
return;
for (A3DUns32 i = 0; i < data.m_uiRepItemsSize; i++)
traverse_ri(data.m_ppRepItems[i], ri_list);
}
else if(type != kA3DTypeRiPlane)
ri_list.push_back(ri);
};
void Part::ri_list(std::vector<A3DRiRepresentationItem*>& ri_list) const
{
A3DAsmPartDefinitionData data;
A3D_INITIALIZE_DATA(A3DAsmPartDefinitionData, data);
if (A3D_SUCCESS != A3DAsmPartDefinitionGet(entity, &data) || data.m_uiRepItemsSize == 0)
return;
for (A3DUns32 i = 0; i < data.m_uiRepItemsSize; i++)
traverse_ri(data.m_ppRepItems[i], ri_list);
A3DAsmPartDefinitionGet(nullptr, &data);
}
}
}

View File

@@ -0,0 +1,50 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#ifndef PART_H
#define PART_H
#include <tuple>
#include <vector>
#include <glm/mat4x4.hpp>
#include "entity.h"
namespace he
{
namespace structure
{
using Context = std::tuple<const A3DMiscCascadedAttributes*, A3DMiscCascadedAttributesData, std::vector<glm::mat4>>;
class Part : public Entity
{
A3DAsmPartDefinition* entity = nullptr;
std::vector<Context> contexts;
public:
Part(A3DAsmPartDefinition* part, const A3DMiscCascadedAttributes* attributes, const glm::mat4& parentPosition);
~Part() = default;
Part(const Part& other);
Part& operator=(const Part& other);
Part(Part&& other) noexcept;
Part& operator=(Part&& other) noexcept;
public:
bool isSame(const A3DAsmPartDefinition* part_def, const A3DMiscCascadedAttributes* graphics, glm::mat4&& position);
const A3DAsmPartDefinition* get_entity() const;
void ri_list(std::vector<A3DRiRepresentationItem*>& ri_list) const;
const std::vector<Context>& get_contexts() const;
std::vector<Context>& grab_contexts();
};
}
}
#endif // PART_H

View File

@@ -0,0 +1,227 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#include "product_occurrence.h"
#include <algorithm>
#include <tuple>
#include <glm/gtc/type_ptr.hpp>
#include <glm/mat4x4.hpp>
namespace he
{
namespace structure
{
ProductOccurrence::ProductOccurrence(const A3DAsmProductOccurrence* entity,
A3DMiscCascadedAttributes* attributes) : Entity(attributes)
{
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, data);
status = A3DAsmProductOccurrenceGet(entity, &data);
if (status != A3D_SUCCESS)
return;
A3D_INITIALIZE_DATA(A3DMiscCascadedAttributesData, attribute_data);
status = A3DMiscCascadedAttributesGet(attributes, &attribute_data);
if (status != A3D_SUCCESS)
return;
}
ProductOccurrence::~ProductOccurrence()
{
status = A3DMiscCascadedAttributesGet(nullptr, &attribute_data);
A3DAsmProductOccurrenceGet(nullptr, &data);
}
A3DAsmProductOccurrence* ProductOccurrence::get_reference()
{
if (data.m_pPrototype)
{
return data.m_pPrototype;
}
if (data.m_pExternalData)
{
return data.m_pExternalData;
}
return nullptr;
}
A3DMiscTransformation* ProductOccurrence::get_position()
{
if (data.m_pLocation)
{
return data.m_pLocation;
}
auto reference = get_reference();
if (reference)
{
ProductOccurrence next(reference);
return next.get_position();
}
return nullptr;
}
A3DAsmPartDefinition* ProductOccurrence::get_partdefinition()
{
if (data.m_pPart)
{
return data.m_pPart;
}
auto reference = get_reference();
if (reference)
{
ProductOccurrence next(reference);
return next.get_partdefinition();
}
return nullptr;
}
A3DVector3dData cross_product(const A3DVector3dData& X, const A3DVector3dData& Y)
{
A3DVector3dData Z;
Z.m_dX = X.m_dY * Y.m_dZ - X.m_dZ * Y.m_dY;
Z.m_dY = X.m_dZ * Y.m_dX - X.m_dX * Y.m_dZ;
Z.m_dZ = X.m_dX * Y.m_dY - X.m_dY * Y.m_dX;
return Z;
}
int get_glm_matrix(const A3DMiscTransformation* transfo, glm::mat4& matrix_out)
{
A3DEEntityType type = kA3DTypeUnknown;
A3DEntityGetType(transfo, &type);
if (type == kA3DTypeMiscCartesianTransformation)
{
A3DMiscCartesianTransformationData data;
A3D_INITIALIZE_DATA(A3DMiscCartesianTransformationData, data);
if (A3DMiscCartesianTransformationGet(transfo, &data))
return 1;
const auto sZVector = cross_product(data.m_sXVector, data.m_sYVector);
const double dMirror = ( data.m_ucBehaviour & kA3DTransformationMirror ) ? -1. : 1.;
double matrix[16];
matrix[12] = data.m_sOrigin.m_dX;
matrix[13] = data.m_sOrigin.m_dY;
matrix[14] = data.m_sOrigin.m_dZ;
matrix[15] = 1.;
matrix[0] = data.m_sXVector.m_dX * data.m_sScale.m_dX;
matrix[1] = data.m_sXVector.m_dY * data.m_sScale.m_dX;
matrix[2] = data.m_sXVector.m_dZ * data.m_sScale.m_dX;
matrix[3] = 0.;
matrix[4] = data.m_sYVector.m_dX * data.m_sScale.m_dY;
matrix[5] = data.m_sYVector.m_dY * data.m_sScale.m_dY;
matrix[6] = data.m_sYVector.m_dZ * data.m_sScale.m_dY;
matrix[7] = 0.;
matrix[8] = dMirror * sZVector.m_dX * data.m_sScale.m_dZ;
matrix[9] = dMirror * sZVector.m_dY * data.m_sScale.m_dZ;
matrix[10] = dMirror * sZVector.m_dZ * data.m_sScale.m_dZ;
matrix[11] = 0.;
matrix_out = glm::make_mat4(matrix);
if (A3DMiscCartesianTransformationGet(nullptr, &data))
return 1;
return 0;
}
else
{
return 1;
}
}
glm::mat4 ProductOccurrence::compute_position(const glm::mat4* parent_position)
{
A3DMiscTransformation* pLocation = get_position();
glm::mat4 local_position = glm::mat4(1.f);
if (pLocation)
get_glm_matrix(pLocation, local_position);
if (parent_position)
local_position = ( *parent_position ) * local_position;
return local_position;
}
int compare(const A3DMiscCascadedAttributesData& data1, const A3DMiscCascadedAttributesData& data2)
{
return ( data1.m_sStyle.m_dWidth == data2.m_sStyle.m_dWidth
&& data1.m_sStyle.m_bVPicture == data2.m_sStyle.m_bVPicture
&& data1.m_sStyle.m_uiLinePatternIndex == data2.m_sStyle.m_uiLinePatternIndex
&& data1.m_sStyle.m_bMaterial == data2.m_sStyle.m_bMaterial
&& data1.m_sStyle.m_uiRgbColorIndex == data2.m_sStyle.m_uiRgbColorIndex
&& data1.m_sStyle.m_bIsTransparencyDefined == data2.m_sStyle.m_bIsTransparencyDefined
&& data1.m_sStyle.m_ucTransparency == data2.m_sStyle.m_ucTransparency
&& data1.m_sStyle.m_bSpecialCulling == data2.m_sStyle.m_bSpecialCulling
&& data1.m_sStyle.m_bFrontCulling == data2.m_sStyle.m_bFrontCulling
&& data1.m_sStyle.m_bBackCulling == data2.m_sStyle.m_bBackCulling
&& data1.m_sStyle.m_bNoLight == data2.m_sStyle.m_bNoLight
&& data1.m_sStyle.m_eRenderingMode == data2.m_sStyle.m_eRenderingMode
);
}
void ProductOccurrence::push_part(std::vector<Part>& parts, const glm::mat4& new_position)
{
auto new_part = get_partdefinition();
if (!new_part)
return;
A3DMiscCascadedAttributes* new_attributes;
create_cascaded_attributes(new_part, attributes, new_attributes);
auto it = std::find_if(parts.begin(), parts.end(), [&new_part] (Part& part)
{ return part.get_entity() == new_part; });
if (it == parts.end())
parts.emplace_back(Part(new_part, new_attributes, new_position));
else
{
A3DMiscCascadedAttributesData attrib_data;
A3D_INITIALIZE_DATA(A3DMiscCascadedAttributesData, attrib_data);
A3DMiscCascadedAttributesGet(new_attributes, &attrib_data);
std::vector<Context>& contexes = ( it )->grab_contexts();
auto context_it = std::find_if(contexes.begin(), contexes.end(), [&attrib_data] (const Context& context) {
const auto& gpx = std::get<1>(context);
return compare(attrib_data, gpx);
});
if (context_it == contexes.end())
contexes.push_back({ new_attributes, attrib_data, {new_position} });
else
{
auto& positions = std::get<2>(*context_it);
positions.push_back(new_position);
}
}
}
std::vector<A3DEntity*> ProductOccurrence::sub_levels() const
{
return std::vector<A3DEntity*>(data.m_ppPOccurrences, data.m_ppPOccurrences + data.m_uiPOccurrencesSize);
}
bool ProductOccurrence::skip() const
{
return (
!attribute_data.m_bShow || attribute_data.m_bRemoved || data.m_ucBehaviour != 1 );
}
int ProductOccurrence::collect(std::vector<Part>& parts, const glm::mat4* parent_position)
{
auto new_position = compute_position(parent_position);
push_part(parts, new_position);
for (const auto& po_entity : sub_levels())
{
A3DMiscCascadedAttributes* new_attributes;
if (create_cascaded_attributes(po_entity, get_attributes(), new_attributes) != 0)
continue;
if (A3DMiscCascadedAttributesEntityReferencePush(new_attributes, po_entity, nullptr) != 0)
continue;
ProductOccurrence po(po_entity, new_attributes);
if (po.collect(parts, &new_position))
return 1;
}
return 0;
}
}
}

View File

@@ -0,0 +1,51 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#ifndef PRODUCT_OCCURENCE_H
#define PRODUCT_OCCURENCE_H
#include "entity.h"
#include "part.h"
namespace he
{
namespace structure
{
class ProductOccurrence : public Entity
{
A3DAsmProductOccurrenceData data;
A3DMiscCascadedAttributesData attribute_data;
private:
A3DMiscTransformation* get_position();
A3DAsmPartDefinition* get_partdefinition();
A3DAsmProductOccurrence* get_reference();
glm::mat4 compute_position(const glm::mat4* parent_position);
void push_part(std::vector<Part>& parts, const glm::mat4& new_position);
public:
ProductOccurrence(const A3DAsmProductOccurrence* asmProductOccurrence,
A3DMiscCascadedAttributes* attributes = nullptr);
~ProductOccurrence();
const A3DAsmProductOccurrenceData& get_data() const {
return data;
}
const A3DMiscCascadedAttributesData& get_attribute_data() const {
return attribute_data;
}
std::vector<A3DEntity*> sub_levels() const override;
bool skip() const;
int collect(std::vector<Part>& parts, const glm::mat4* parent_position);
};
}
}
#endif // PRODUCT_OCCURENCE_H

View File

@@ -0,0 +1,171 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#include <map>
#include "representation_item.h"
#include "../../utils/properties.h"
#include "../../utils/bounding_box.h"
#include "../../utils/geometry.h"
#include "../../model/exchange.h"
namespace he
{
namespace geometry
{
RepresentationItem::RepresentationItem(A3DRiRepresentationItem* rep_item, const A3DMiscCascadedAttributes* cascaded_attributes) :
Entity()
{
A3D_INITIALIZE_DATA(A3DMeshData, mesh_data);
// for each representation item list, we compute a mesh based on triangle only.
status = A3DRiComputeMesh(rep_item, cascaded_attributes, &mesh_data, nullptr);
if (status != A3D_SUCCESS)
{
A3DRWParamsTessellationData tess_params;
A3D_INITIALIZE_DATA(A3DRWParamsTessellationData, tess_params);
tess_params.m_eTessellationLevelOfDetail = kA3DTessLODMedium;
A3DRiRepresentationItemComputeTessellation(rep_item, &tess_params);
status = A3DRiComputeMesh(rep_item, cascaded_attributes, &mesh_data, nullptr);
}
}
RepresentationItem::~RepresentationItem()
{
A3DRiComputeMesh(nullptr, nullptr, &mesh_data, nullptr);
}
bool RepresentationItem::is_unicolor() const
{
return mesh_data.m_puiStyleIndexPerFace == nullptr;
}
void RepresentationItem::prepare_render_buffer(std::vector <utils::geometry::BufferData>& buffer_data_array)
{
if (is_unicolor())
{
utils::geometry::BufferData buffer_data;
build_one_buffer(buffer_data);
buffer_data_array.push_back(buffer_data);
}
else
{
build_buffer_per_style(buffer_data_array);
}
}
void RepresentationItem::build_one_buffer(utils::geometry::BufferData& buffer_data) const
{
buffer_data.vertices.reserve(mesh_data.m_uiCoordSize / 3);
// For each mesh, we create model buffer, and store graphical information, and all positions
// associated to it.
for (A3DUns32 vertex_i = 0; vertex_i < mesh_data.m_uiCoordSize; vertex_i+=3)
{
utils::geometry::Vertex vertex;
vertex.position = glm::vec3(mesh_data.m_pdCoords[vertex_i],
mesh_data.m_pdCoords[vertex_i + 1],
mesh_data.m_pdCoords[vertex_i + 2]);
vertex.normal = glm::vec3(mesh_data.m_pdNormals[vertex_i],
mesh_data.m_pdNormals[vertex_i + 1],
mesh_data.m_pdNormals[vertex_i + 2]);
buffer_data.mesh_box.add_point(vertex.position);
buffer_data.vertices.push_back(vertex);
}
// Count the total number of indices
size_t indiceCount = 0;
for (A3DUns32 face_i = 0; face_i < mesh_data.m_uiFaceSize; ++face_i) {
indiceCount += mesh_data.m_puiTriangleCountPerFace[face_i];
}
indiceCount *= 3; // 3 indices per triangle
buffer_data.indices.reserve(indiceCount);
for (A3DUns32 vertex_i = 0; vertex_i < indiceCount; vertex_i++)
buffer_data.indices.push_back(mesh_data.m_puiVertexIndicesPerFace[vertex_i]);
buffer_data.graphics = model::exchange::convert_style(mesh_data.m_uiStyleIndex);
}
void RepresentationItem::build_buffer_per_style(std::vector <utils::geometry::BufferData>& buffers_data) const
{
int idx = 0;
// sort face by style, and create one buffer data per style
std::map<A3DUns32, std::vector<A3DUns32>> style_face_indices;
std::vector<std::vector<A3DUns32>> vertex_indices_per_face(mesh_data.m_uiFaceSize);
A3DUns32 vertex_index = 0;
for (A3DUns32 f = 0; f < mesh_data.m_uiFaceSize; f++)
{
const A3DUns32 triangle_count = mesh_data.m_puiTriangleCountPerFace[f];
if (triangle_count == 0)
continue;
A3DUns32 face_style = mesh_data.m_puiStyleIndexPerFace[f];
style_face_indices[face_style].push_back(f);
// Store vertex indices per face
const A3DUns32 start_index = vertex_index;
const A3DUns32 end_index = vertex_index + (triangle_count * 3);
for (A3DUns32 v = start_index; v < end_index; ++v)
{
vertex_indices_per_face[f].push_back(mesh_data.m_puiVertexIndicesPerFace[v]);
}
vertex_index = end_index;
}
// for each mesh, we create OnpenGL model (buffer), and store graphical information, and all positions
// associated to it.
for (auto iter = style_face_indices.begin(); iter != style_face_indices.end(); ++iter)
{
utils::geometry::BufferData buffer_data;
buffer_data.graphics = model::exchange::convert_style(iter->first);
idx = 0;
for (auto& f : iter->second)
{
// for each face
A3DUns32 triangle_count = mesh_data.m_puiTriangleCountPerFace[f];
const std::vector<A3DUns32>& vertex_indices = vertex_indices_per_face[f];
std::vector<utils::geometry::Vertex> vertices;
utils::geometry::BoundingBox box;
utils::geometry::Vertex vertex;
for (A3DUns32 t = 0; t < triangle_count; t++)
{
// for each triangle
for (A3DUns32 v = 0; v < 3; v++)
{
const uint32_t indice = vertex_indices[t * 3 + v] * 3;
vertex.position = glm::vec3(mesh_data.m_pdCoords[indice],
mesh_data.m_pdCoords[indice + 1],
mesh_data.m_pdCoords[indice + 2]);
vertex.normal = glm::vec3(mesh_data.m_pdNormals[indice],
mesh_data.m_pdNormals[indice + 1],
mesh_data.m_pdNormals[indice + 2]);
buffer_data.mesh_box.add_point(vertex.position);
buffer_data.vertices.push_back(vertex);
buffer_data.indices.push_back(idx++);
}
}
}
buffers_data.push_back(buffer_data);
}
}
}
}

View File

@@ -0,0 +1,36 @@
/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
#ifndef REP_ITEM_H
#define REP_ITEM_H
#include "entity.h"
#include "../../utils/geometry.h"
namespace he
{
namespace geometry
{
class RepresentationItem : public Entity
{
A3DMeshData mesh_data;
public:
RepresentationItem(A3DRiRepresentationItem* rep_item, const A3DMiscCascadedAttributes* cascaded_attributes);
~RepresentationItem();
bool is_unicolor() const;
void prepare_render_buffer(std::vector <utils::geometry::BufferData>& buffer_data_array);
private:
void build_one_buffer(utils::geometry::BufferData& buffer_data) const;
void build_buffer_per_style(std::vector <utils::geometry::BufferData>& buffers_data) const;
};
}
}
#endif // REP_ITEM_H