Merge branch 'develop' into feature/CNX-651_Add_Properties_from_Properties_and_Classification_tab_to_send

# Conflicts:
#	SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp
#	SpeckleLib/Speckle/Record/Element/Element.cpp
#	SpeckleLib/SpeckleLib17.vcxproj.filters
This commit is contained in:
Ralph Wessel
2024-10-23 09:54:11 +01:00
13 changed files with 945 additions and 19 deletions
@@ -13,6 +13,8 @@
#include "Speckle/Record/Element/Column.h"
#include "Speckle/Record/Element/ColumnSegment.h"
#include "Speckle/Record/Element/ModelElement.h"
#include "Speckle/Record/Element/Beam.h"
#include "Speckle/Record/Element/BeamSegment.h"
#include "Speckle/Record/Element/Memo.h"
#include "Speckle/Utility/Guid.h"
#include "Speckle/Utility/String.h"
@@ -76,11 +78,14 @@ namespace {
return std::make_unique<Column>(elementData, tableID);
case API_ColumnSegmentID:
return std::make_unique<ColumnSegment>(elementData, tableID);
case API_BeamID:
return std::make_unique<Beam>(elementData, tableID);
case API_BeamSegmentID:
return std::make_unique<BeamSegment>(elementData, tableID);
default:
return std::make_unique<ModelElement>(elementData, tableID);
}
}
}
/*--------------------------------------------------------------------
@@ -30,6 +30,21 @@ namespace {
}
/*--------------------------------------------------------------------
Append a single face to the Mesh given by the vertices
--------------------------------------------------------------------*/
void Mesh::appendFace(const std::vector<double>& vertices) {
if (vertices.empty())
return;
m_vertices.insert(m_vertices.end(), vertices.begin(), vertices.end());
int lastVertexIndex = m_faces.empty() ? -1 : m_faces.back();
int faceSize = vertices.size() / 3;
m_faces.push_back(faceSize);
for (int i = 0; i < faceSize; i++)
m_faces.push_back(++lastVertexIndex);
}
/*--------------------------------------------------------------------
Fill an inventory with the package items
+16 -1
View File
@@ -29,10 +29,19 @@ namespace speckle::primitive {
Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{utility::Guid{true}, utility::Guid{}, unit} {}
/*!
Constructor
@param unit The mesh unit type
@param material The mesh material
*/
Mesh(const ModelerAPI::Material& material,
active::measure::LengthType unit = active::measure::LengthType::metre) :
base{ utility::Guid{true}, utility::Guid{}, unit }, m_material{ material } {}
/*!
Constructor
@param unit The mesh unit type
@param vertices The mesh vertices
@param faces The mesh faces (the number of indices in the face followed by the vertex indices)
@param colors The mesh face colours
@param unit The mesh unit type
@param material The mesh material
*/
Mesh(std::vector<double>&& vertices, std::vector<int>&& faces, std::vector<int>&& colors, const ModelerAPI::Material& material,
active::measure::LengthType unit = active::measure::LengthType::metre) :
@@ -45,6 +54,12 @@ namespace speckle::primitive {
@return The speckle type (relevant objects should override as required)
*/
speckle::utility::String getSpeckleType() const override { return "Objects.Geometry.Mesh"; }
/*!
Append a single face to the Mesh given by the vertices
@param vertices The vertices to append
*/
void appendFace(const std::vector<double>& vertices);
// MARK: - Serialisation
+174
View File
@@ -0,0 +1,174 @@
#include "Speckle/Record/Element/Beam.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Primitive/Mesh/Mesh.h"
#include "Speckle/SpeckleResource.h"
#include "Speckle/Utility/Guid.h"
using namespace active::serialise;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::utility;
#include <array>
#include <memory>
namespace speckle::record::element {
class Beam::Data {
public:
friend class Beam;
#ifdef ARCHICAD
Data(const API_Element& elem) : root{ std::make_unique<API_BeamType>(elem.beam) } {}
Data(const Data& source) : root{ std::make_unique<API_BeamType>(*source.root) } {}
#endif
private:
std::unique_ptr<API_BeamType> root;
};
}
namespace {
///Serialisation fields
enum FieldIndex {
segmentID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"segments"},
};
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Beam::Beam() {
} //Beam::Beam
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Constructor
elemData: Archicad element data
tableID: The element table ID (AC database, e.g. floor plan, 3D)
--------------------------------------------------------------------*/
Beam::Beam(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } {
m_data = std::make_unique<Data>(elemData);
} //Beam::Beam
#endif
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
Beam::Beam(const Beam& source) : base{ source } {
m_data = source.m_data ? std::make_unique<Data>(*m_data) : nullptr;
} //Beam::Beam
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Beam::~Beam() {}
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the (immutable) API element header data
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Elem_Head& Beam::getHead() const {
return m_data->root->head;
} //Beam::getHead
/*--------------------------------------------------------------------
Get the (mutable) API element header data
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Elem_Head& Beam::getHead() {
return m_data->root->head;
} //Beam::getHead
/*--------------------------------------------------------------------
Load the element memo structure (elements must override according to requirements)
filter: Filter bits specifying memo requirements
--------------------------------------------------------------------*/
void Beam::loadMemo(filter_bits filter, std::unique_ptr<Memo>& memo) const {
//Establish the memo filter for this element
if (!SegmentedBeam::isMemoLoaded())
filter |= SegmentedBeam::getPartFilter();
Element::loadMemo(filter, memo);
//Receive the memo data into the element (when available)
if (memo) {
if (filter & SegmentedBeam::getPartFilter())
SegmentedBeam::receive(*memo);
}
SegmentedBeam::setMemoLoaded(true); //Always mark the data as loaded to prevent repeated attempts on error
} //Beam::loadMemo
#endif
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool Beam::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[segmentID], segmentID, getSegmentCount(), std::nullopt }, //TODO: implement other fields
},
}.withType(&typeid(Beam)));
return base::fillInventory(inventory);
} //Beam::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Beam::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(Beam))
return base::getCargo(item);
using namespace active::serialise;
switch (item.index) {
case segmentID:
if (auto segment = getSegment(item.available); segment != nullptr) {
return Cargo::Unique{new PackageWrap{*segment}};
} else
return nullptr;
default:
return nullptr; //Requested an unknown index
}
} //Beam::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
void Beam::setDefault() {
base::setDefault();
m_data.reset();
} //Beam::setDefault
+137
View File
@@ -0,0 +1,137 @@
#ifndef SPECKLE_RECORD_ELEMENT_BEAM
#define SPECKLE_RECORD_ELEMENT_BEAM
#include "Speckle/Record/Element/BeamSegment.h"
#include "Speckle/Record/Element/Element.h"
#include "Speckle/Record/Element/Interface/Assembly/Path.h"
#include "Speckle/Record/Element/Interface/SegmentedBeam.h"
namespace speckle::record::element {
class BeamSegment;
/*!
BIM beam class
*/
class Beam : public Element, public SegmentedBeam, public assembly::Path {
public:
// MARK: - Types
using base = Element;
///Unique pointer
using Unique = std::unique_ptr<Beam>;
///Shared pointer
using Shared = std::shared_ptr<Beam>;
///Optional
using Option = std::optional<Beam>;
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Beam();
#ifdef ARCHICAD
/*!
Constructor
@param elemData Archicad element data
@param tableID The beam element ID (AC database, e.g. floor plan, 3D)
*/
Beam(const API_Element& elemData, const speckle::utility::Guid& tableID);
#endif
/*!
Copy constructor
@param source The object to copy
*/
Beam(const Beam& source);
/*!
Destructor
*/
~Beam();
/*!
Object cloning
@return A clone of this object
*/
Beam* clonePtr() const override { return new Beam{*this}; }
// MARK: - Functions (const)
/*!
Get the BIM application parent table ID
@return The BIM table ID
*/
virtual database::BIMRecordID getTableID() const override { return Element::getTableID(); }
/*!
Get the element body
@return nullptr (Beams don't explicitly have a 3D body - this comes from its child segments)
*/
virtual Body* getBody() const override { return nullptr; }
/*!
Get the number of segments in the path (elements must override according to requirements)
@return The segment count
*/
virtual size_t getSegmentCount() const override { return SegmentedBeam::getSegmentCount(); }
/*!
Get a segment from the path (elements must override according to requirements)
@param index The index of the required segment
@return The requested segment (nullptr on failure)
*/
virtual BeamSegment* getSegment(size_t index) const override { return SegmentedBeam::getSegment(index); }
#ifdef ARCHICAD
/*!
Get the (immutable) API element header data
@return The element header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
const API_Elem_Head& getHead() const override;
#endif
// MARK: - Functions (mutating)
#ifdef ARCHICAD
/*!
Get the (mutable) API element header data
@return The element header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
API_Elem_Head& getHead() override;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
void setDefault() override;
protected:
/*!
Load the element memo structure (elements must override according to requirements)
@param filter Filter bits specifying memo requirements
*/
virtual void loadMemo(filter_bits filter, std::unique_ptr<Memo>& memo) const override;
private:
class Data;
///The beam data
std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_BEAM
@@ -0,0 +1,159 @@
#include "Speckle/Record/Element/BeamSegment.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Primitive/Mesh/Mesh.h"
#include "Speckle/SpeckleResource.h"
#include "Speckle/Utility/Guid.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#endif
using namespace active::serialise;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::utility;
#include <array>
#include <memory>
namespace speckle::record::element {
class BeamSegment::Data {
public:
friend class BeamSegment;
#ifdef ARCHICAD
Data(const API_BeamSegmentType& seg) : root{ std::make_unique<API_BeamSegmentType>(seg) } {}
Data(const Data& source) : root{ std::make_unique<API_BeamSegmentType>(*source.root) } {}
private:
std::unique_ptr<API_BeamSegmentType> root;
#endif
};
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
BeamSegment::BeamSegment() {
} //BeamSegment::BeamSegment
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Constructor
elemData: Archicad element data
tableID: The element table ID (AC database, e.g. floor plan, 3D)
--------------------------------------------------------------------*/
BeamSegment::BeamSegment(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } {
m_data = std::make_unique<Data>(elemData.beamSegment);
} //BeamSegment::BeamSegment
/*--------------------------------------------------------------------
Constructor
segment: The segment element data
tableID: The parent table ID
cutOrigin: Cut at the segment origin
cutEnd: Cut at the segment end
scheme: The segment scheme
profile: The segment profile (nullptr = none)
--------------------------------------------------------------------*/
BeamSegment::BeamSegment(const API_BeamSegmentType& segment, const speckle::utility::Guid& tableID, const API_AssemblySegmentCutData& cutOrigin,
const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme,
const API_AssemblySegmentProfileData* profile) :
base{segment.head.guid, tableID}, assembly::Segment{cutOrigin, cutEnd, scheme, profile} {
m_data = std::make_unique<Data>(segment);
} //BeamSegment::BeamSegment
#endif
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
BeamSegment::BeamSegment(const BeamSegment& source) : base{ source } {
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
} //BeamSegment::BeamSegment
/*--------------------------------------------------------------------
Move constructor
source: The object to move
--------------------------------------------------------------------*/
BeamSegment::BeamSegment(BeamSegment&& source) noexcept : base{source} {
m_data = std::move(source.m_data);
} //BeamSegment::BeamSegment
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
BeamSegment::~BeamSegment() {}
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the (immutable) API element header data
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Elem_Head& BeamSegment::getHead() const {
return m_data->root->head;
} //BeamSegment::getHead
/*--------------------------------------------------------------------
Get the (mutable) API element header data
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Elem_Head& BeamSegment::getHead() {
return m_data->root->head;
} //BeamSegment::getHead
#endif
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool BeamSegment::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
//TODO: Implement other fields as required
return base::fillInventory(inventory);
} //BeamSegment::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique BeamSegment::getCargo(const Inventory::Item& item) const {
//TODO: Implement other fields as required
return base::getCargo(item);
} //BeamSegment::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
void BeamSegment::setDefault() {
m_data.reset();
} //BeamSegment::setDefault
@@ -0,0 +1,130 @@
#ifndef SPECKLE_RECORD_ELEMENT_BEAM_SEGMENT
#define SPECKLE_RECORD_ELEMENT_BEAM_SEGMENT
#include "Speckle/Record/Element/Element.h"
#include "Speckle/Record/Element/Interface/Assembly/Segment.h"
namespace speckle::record::element {
class SegmentedBeam;
/*!
BIM beam class
*/
class BeamSegment : public Element, public assembly::Segment {
public:
// MARK: - Types
using base = Element;
///Unique pointer
using Unique = std::unique_ptr<BeamSegment>;
///Shared pointer
using Shared = std::shared_ptr<BeamSegment>;
///Optional
using Option = std::optional<BeamSegment>;
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
BeamSegment();
#ifdef ARCHICAD
/*!
Constructor
@param elemData Archicad element data
@param tableID The element table ID (AC database, e.g. floor plan, 3D)
*/
BeamSegment(const API_Element& elemData, const speckle::utility::Guid& tableID);
#endif
/*!
Copy constructor
@param source The object to copy
*/
BeamSegment(const BeamSegment& source);
/*!
Move constructor
@param source The object to move
*/
BeamSegment(BeamSegment&& source) noexcept;
/*!
Destructor
*/
~BeamSegment();
/*!
Object cloning
@return A clone of this object
*/
BeamSegment* clonePtr() const override { return new BeamSegment{*this}; }
// MARK: - Functions (const)
#ifdef ARCHICAD
/*!
Get the (immutable) API element header data
@return The element header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
const API_Elem_Head& getHead() const override;
#endif
// MARK: - Functions (mutating)
#ifdef ARCHICAD
/*!
Get the (mutable) API element header data
@return The element header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
API_Elem_Head& getHead() override;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
void setDefault() override;
protected:
friend class SegmentedBeam;
#ifdef ARCHICAD
/*!
Constructor
@param segment The segment element data
@param tableID The parent table ID
@param cutOrigin Cut at the segment origin
@param cutEnd Cut at the segment end
@param scheme The segment scheme
@param profile The segment profile (nullptr = none)
*/
BeamSegment(const API_BeamSegmentType& segment, const speckle::utility::Guid& tableID, const API_AssemblySegmentCutData& cutOrigin,
const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme,
const API_AssemblySegmentProfileData* profile = nullptr);
#endif
private:
class Data;
///The beam data
std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_BEAM_SEGMENT
@@ -109,7 +109,7 @@ bool Element::fillInventory(Inventory& inventory) const {
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Element::getCargo(const Inventory::Item& item) const {
return base::getCargo(item);
return base::getCargo(item);
} //Element::getCargo
@@ -0,0 +1,160 @@
#include "Speckle/Record/Element/Interface/SegmentedBeam.h"
#include "Speckle/Record/Element/BeamSegment.h"
#include "Speckle/Record/Element/Memo.h"
#include "Speckle/Record/Element/Interface/Assembly/Path.h"
#include "Speckle/Utility/BIMMemory.h"
using namespace active::serialise;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::utility;
namespace speckle::record::element {
class SegmentedBeam::Data {
public:
friend class SegmentedBeam;
std::vector<BeamSegment> segments;
};
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
SegmentedBeam::SegmentedBeam() {
} //SegmentedBeam::SegmentedBeam
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
SegmentedBeam::SegmentedBeam(const SegmentedBeam& source) : base{ source } {
m_data = source.m_data ? std::make_unique<Data>(*m_data) : nullptr;
} //SegmentedBeam::SegmentedBeam
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
SegmentedBeam::~SegmentedBeam() {}
/*--------------------------------------------------------------------
Get the number of segments
return. The number of segments (0 on error)
--------------------------------------------------------------------*/
size_t SegmentedBeam::getSegmentCount() const {
confirmPart(getPartFilter());
return m_data ? m_data->segments.size() : 0;
} //SegmentedBeam::getSegmentCount
/*--------------------------------------------------------------------
Get a beam segment
index: The index of the required segment
return: The requested segment, nullptr on error
--------------------------------------------------------------------*/
BeamSegment* SegmentedBeam::getSegment(size_t index) const {
confirmPart(getPartFilter());
return (m_data && (index < m_data->segments.size())) ? &m_data->segments[index] : nullptr;
} //SegmentedBeam::getSegment
/*--------------------------------------------------------------------
Return the bits for the part filter required to load the data necessary to build this object
return: The required filter bits
--------------------------------------------------------------------*/
Part::filter_bits SegmentedBeam::getPartFilter() const {
#ifdef ARCHICAD
return APIMemoMask_BeamSegment | APIMemoMask_AssemblySegmentCut | APIMemoMask_AssemblySegmentScheme | APIMemoMask_AssemblySegmentProfile;
#endif
} //SegmentedBeam::getPartFilter
/*--------------------------------------------------------------------
Determine if the element memo content has been validated (elements must override according to requirements)
return: True if the element memo content is valid
--------------------------------------------------------------------*/
bool SegmentedBeam::isPartValid() const {
return m_data && !m_data->segments.empty();
} //SegmentedBeam::isPartValid
/*--------------------------------------------------------------------
Load the element memo structure (elements must override according to requirements)
filter: Filter bits specifying memo requirements
--------------------------------------------------------------------*/
void SegmentedBeam::loadMemo(filter_bits filter, std::unique_ptr<Memo>& memo) const {
} //SegmentedBeam::loadMemo
/*--------------------------------------------------------------------
Send the element part back to a memo structure for storage (elements must override according to requirements)
memo: The memo to carry the data
return: True if the data was successfully sent
--------------------------------------------------------------------*/
bool SegmentedBeam::send(Memo* memo) const {
//TODO: Complete when required
return false;
} //SegmentedBeam::send
/*--------------------------------------------------------------------
Receive the element memo data from a memo structure (elements must override according to requirements)
memo: The memo carrying the data
return: True if the data was successfully received
--------------------------------------------------------------------*/
bool SegmentedBeam::receive(const Memo& memo) const {
#ifdef ARCHICAD
if (!memo || (memo.root()->beamSegments == nullptr))
return false;
if (m_data)
m_data->segments.clear();
else
m_data = std::make_unique<Data>();
//Confirm that required data is present in the memo
auto segmentPtr = memo.root()->beamSegments;
auto cutPtr = memo.root()->assemblySegmentCuts;
auto schemePtr = memo.root()->assemblySegmentSchemes;
auto profilePtr = memo.root()->assemblySegmentProfiles;
if ((segmentPtr == nullptr) || (cutPtr == nullptr) || (schemePtr == nullptr))
return false;
//Determine available item count
auto segmentCount = BIMMemory::getPtrSize(segmentPtr) / sizeof(API_BeamSegmentType);
auto cutCount = BIMMemory::getPtrSize(cutPtr) / sizeof(API_AssemblySegmentCutData);
auto schemeCount = BIMMemory::getPtrSize(schemePtr) / sizeof(API_AssemblySegmentSchemeData);
auto profileCount = BIMMemory::getPtrSize(profilePtr) / sizeof(API_AssemblySegmentProfileData);
if ((segmentCount == 0) || (cutCount != (segmentCount + 1)) || (schemeCount != segmentCount))
return false;
auto path = dynamic_cast<const assembly::Path*>(this);
for (size_t n = 0 ; n < segmentCount; ++n) {
const API_AssemblySegmentProfileData* thisProfile = nullptr;
for (size_t i = 0; i < profileCount; ++i) {
if (profilePtr[i].segmentIndex == n) {
thisProfile = profilePtr + i;
break;
}
}
m_data->segments.emplace_back(BeamSegment{segmentPtr[n], getTableID(), cutPtr[n], cutPtr[n + 1], schemePtr[n], thisProfile});
m_data->segments.back().setPath(path);
}
setMemoLoaded(true);
#endif
return true;
} //SegmentedBeam::receive
@@ -0,0 +1,103 @@
#ifndef SPECKLE_RECORD_ELEMENT_SEGMENTED_BEAM
#define SPECKLE_RECORD_ELEMENT_SEGMENTED_BEAM
#include "Speckle/Database/Identity/BIMRecordID.h"
#include "Speckle/Record/Element/Interface/Part.h"
namespace speckle::record::element {
class BeamSegment;
/*!
Interface for a beam type that is made up of consecutive segments
Note that the child segments use lazy loading to avoid high overheads when accessing data relevant to the parent beam only
*/
class SegmentedBeam : public Part {
public:
// MARK: - Types
using base = Part;
///Unique pointer
using Unique = std::unique_ptr<SegmentedBeam>;
///Shared pointer
using Shared = std::shared_ptr<SegmentedBeam>;
///Optional
using Option = std::optional<SegmentedBeam>;
// MARK: - Constructors
/*!
Default constructor
*/
SegmentedBeam();
/*!
Copy constructor
@param source The object to copy
*/
SegmentedBeam(const SegmentedBeam& source);
/*!
Destructor
*/
~SegmentedBeam();
// MARK: - Functions (const)
/*!
Get the BIM application parent table ID
@return The BIM table ID
*/
virtual database::BIMRecordID getTableID() const = 0;
/*!
Get the number of segments
@return The number of segments (0 on error)
*/
size_t getSegmentCount() const;
/*!
Get a beam segment
@param index The index of the required segment
@return The requested segment, nullptr on error
*/
BeamSegment* getSegment(size_t index) const;
// MARK: - Functions (mutating)
protected:
/*!
Return the bits for the part filter required to load the data necessary to build this object
@return The required filter bits */
filter_bits getPartFilter() const;
/*!
Determine if the element part content has been validated (elements must override according to requirements)
@return True if the element part content is valid
*/
bool isPartValid() const override;
/*!
Load the element memo structure (elements must override according to requirements)
@param filter Filter bits specifying memo requirements
*/
void loadMemo(filter_bits filter, std::unique_ptr<Memo>& memo) const override;
/*!
Send the element part back to a memo structure for storage (elements must override according to requirements)
@param memo The memo to carry the data
@return True if the data was successfully sent
*/
bool send(Memo* memo) const override;
/*!
Receive the element memo data from a memo structure (elements must override according to requirements)
@param memo The memo carrying the data
@return True if the data was successfully received
*/
bool receive(const Memo& memo) const override;
private:
class Data;
///The segment data - mutable to support lazy loading
mutable std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_SEGMENTED_BEAM
@@ -129,7 +129,6 @@ ModelElement::Body* ModelElement::getBody() const {
return m_data->m_cache.get();
}
void* dummy = nullptr;
GSErrCode err = ACAPI_Sight_GetCurrentWindowSight(&dummy);
if (err != NoError)
@@ -149,6 +148,9 @@ ModelElement::Body* ModelElement::getBody() const {
auto elementBody = new ModelElement::Body();
// Map to collect meshes per material name
std::map<GS::UniString, primitive::Mesh> materialMeshMap;
Int32 nElements = acModel.GetElementCount();
for (Int32 iElement = 1; iElement <= nElements; iElement++)
{
@@ -166,49 +168,51 @@ ModelElement::Body* ModelElement::getBody() const {
Int32 polyCount = body.GetPolygonCount();
for (Int32 polyIndex = 1; polyIndex <= polyCount; ++polyIndex)
{
ModelerAPI::Polygon polygon{};
ModelerAPI::Polygon polygon{};
body.GetPolygon(polyIndex, &polygon);
ModelerAPI::Material material{};
polygon.GetMaterial(&material);
auto materialName = material.GetName();
if (materialMeshMap.find(materialName) == materialMeshMap.end()) {
materialMeshMap[materialName] = primitive::Mesh(material);
}
Int32 convexPolyCount = polygon.GetConvexPolygonCount();
for (Int32 convPolyIndex = 1; convPolyIndex <= convexPolyCount; ++convPolyIndex)
{
std::vector<double> vertices;
std::vector<int> faces;
std::vector<int> colors;
ModelerAPI::ConvexPolygon convexPolygon{};
polygon.GetConvexPolygon(convPolyIndex, &convexPolygon);
Int32 vertexCount = convexPolygon.GetVertexCount();
faces.push_back(vertexCount);
for (Int32 vertexIndex = 1; vertexIndex <= vertexCount; ++vertexIndex)
{
ModelerAPI::Vertex vertex{};
body.GetVertex(convexPolygon.GetVertexIndex(vertexIndex), &vertex);
// TODO: change vertices array to hold Vertex instead of double values
// Collect vertices (as doubles for now, but should be changed to Vertex type)
vertices.push_back(vertex.x);
vertices.push_back(vertex.y);
vertices.push_back(vertex.z);
//double alpha = material.GetTransparency();
//ModelerAPI::Color color = material.GetSurfaceColor();
//colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue));
faces.push_back(vertexIndex - 1);
}
elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors), material));
materialMeshMap[materialName].appendFace(std::move(vertices));
}
}
}
}
for (auto& [materialName, mesh] : materialMeshMap)
{
elementBody->push_back(std::move(mesh));
}
m_data->m_cache.reset(elementBody);
return m_data->m_cache.get();
#endif
}
} //ModelElement::getBody
#ifdef ARCHICAD
+6
View File
@@ -76,6 +76,8 @@
<ClInclude Include="Speckle\Record\Credentials\ServerInfo.h" />
<ClInclude Include="Speckle\Record\Credentials\ServerMigration.h" />
<ClInclude Include="Speckle\Record\Credentials\UserInfo.h" />
<ClInclude Include="Speckle\Record\Element\Beam.h" />
<ClInclude Include="Speckle\Record\Element\BeamSegment.h" />
<ClInclude Include="Speckle\Record\Element\Column.h" />
<ClInclude Include="Speckle\Record\Element\ColumnSegment.h" />
<ClInclude Include="Speckle\Record\Element\DrawingElement.h" />
@@ -85,6 +87,7 @@
<ClInclude Include="Speckle\Record\Element\Interface\Assembly\Path.h" />
<ClInclude Include="Speckle\Record\Element\Interface\Assembly\Segment.h" />
<ClInclude Include="Speckle\Record\Element\Interface\Part.h" />
<ClInclude Include="Speckle\Record\Element\Interface\SegmentedBeam.h" />
<ClInclude Include="Speckle\Record\Element\Interface\SegmentedColumn.h" />
<ClInclude Include="Speckle\Record\Element\Memo.h" />
<ClInclude Include="Speckle\Record\Element\ModelElement.h" />
@@ -155,6 +158,8 @@
<ClCompile Include="Speckle\Record\Credentials\ServerInfo.cpp" />
<ClCompile Include="Speckle\Record\Credentials\ServerMigration.cpp" />
<ClCompile Include="Speckle\Record\Credentials\UserInfo.cpp" />
<ClCompile Include="Speckle\Record\Element\Beam.cpp" />
<ClCompile Include="Speckle\Record\Element\BeamSegment.cpp" />
<ClCompile Include="Speckle\Record\Element\Column.cpp" />
<ClCompile Include="Speckle\Record\Element\ColumnSegment.cpp" />
<ClCompile Include="Speckle\Record\Element\DrawingElement.cpp" />
@@ -164,6 +169,7 @@
<ClCompile Include="Speckle\Record\Element\Interface\Assembly\Path.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\Assembly\Segment.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\Part.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\SegmentedBeam.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\SegmentedColumn.cpp" />
<ClCompile Include="Speckle\Record\Element\Memo.cpp" />
<ClCompile Include="Speckle\Record\Element\ModelElement.cpp" />
+19 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resource Files">
@@ -406,6 +406,15 @@
<ClInclude Include="Speckle\Record\Property\Group.h">
<Filter>Speckle\Record\Property</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Interface\SegmentedBeam.h">
<Filter>Speckle\Record\Element\Interface</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Beam.h">
<Filter>Speckle\Record\Element</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\BeamSegment.h">
<Filter>Speckle\Record\Element</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Speckle\Environment\Addon.cpp">
@@ -612,6 +621,15 @@
<ClCompile Include="Speckle\Record\Property\Group.cpp">
<Filter>Speckle\Record\Property</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Interface\SegmentedBeam.cpp">
<Filter>Speckle\Record\Element\Interface</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Beam.cpp">
<Filter>Speckle\Record\Element</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\BeamSegment.cpp">
<Filter>Speckle\Record\Element</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="Speckle\CMakeLists.txt">