/
levovix
/
kittycad
Обзор
Документация
Войти
/
levovix
/
kittycad
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/data/assembly/assembly.cpp
306 строк
11 KB
levovix
add: allow to disable solver
02 мар 2026, 21:02
02 мар 2026, 21:02
77c55d2
Код
Авторство
О чём код?
#include "./assembly.h" #include <bitset> #include <surf_plane.h> #include <vsn_scenecontent.h> #include <vsn_scenesegment.h> #include <gcm_types.h> #include <gcm_api.h> #include <gcm_reposition.h> #include "data/document.h" #include "data/assembly/solid_clone.h" #include "data/assembly/constraints.h" using namespace VSN; data::Assembly::~Assembly() { if (gcmSystem != nullptr) { GCM_RemoveSystem(gcmSystem); } } bool bruteForceSolveWithBlackboxes(data::Assembly& assembly) { std::vector<ref<data::AssemblyConstraint>> constraintWithBlackboxes; for (auto const& cns : assembly.constraints) { if (auto ent = std::dynamic_pointer_cast<data::Transmission3dConstraint>(cns)) { constraintWithBlackboxes.emplace_back(cns); } else if (auto ent = std::dynamic_pointer_cast<data::RackAndPinion3dConstraint>(cns)) { constraintWithBlackboxes.emplace_back(cns); } } if (constraintWithBlackboxes.size() >= 64) { return false; } uint64_t combinations = std::pow(2, constraintWithBlackboxes.size()); for (uint64_t combination = 0; combination < combinations; ++combination) { std::bitset<64> cbits = combination; GCM_ClearSystem(assembly.gcmSystem); for (auto const& obj : assembly.objects) { obj->registerInGcm(assembly.gcmSystem); } for (auto const& cns : assembly.constraints) { cns->registerInGcm(assembly.gcmSystem); } { int i = 0; for (auto const& cns : constraintWithBlackboxes) { if (auto ent = std::dynamic_pointer_cast<data::Transmission3dConstraint>(cns)) { ent->setDirection(cbits[i]); } else if (auto ent = std::dynamic_pointer_cast<data::RackAndPinion3dConstraint>(cns)) { ent->setDirection(cbits[i]); } ++i; } } for (auto const& cns : assembly.constraints) { addBlackBoxes(cns, assembly.gcmSolver); } // todo: замораживать объект-источник перестраивания, чтобы не получалось так что двигаешь объект, а он возвращается обратно GCM_result res = GCM_Evaluate(assembly.gcmSystem); if (res == GCM_RESULT_Satisfied) { return true; } } return false; } void data::Assembly::updateFromParams() { assert(m_dependencyChanged || m_propertyChanged); m_propertyChanged = false; m_dependencyChanged = false; if (gcmSolver == nullptr) { gcmSolver = GCM_CreateSolver(nullptr); // todo: use ItPositionManager gcmSystem = gcmSolver->System(); } currentlyUpdatingConstraints = true; struct Guard { Assembly& s; ~Guard() { s.currentlyUpdatingConstraints = false; } } guard{*this}; if (!disableSolver) { GCM_ClearSystem(gcmSystem); for (auto const& obj : objects) { obj->registerInGcm(gcmSystem); } for (auto const& cns : constraints) { cns->registerInGcm(gcmSystem); } for (auto obj : changedObjects) { if (obj.expired()) { continue; } if (auto ent = std::dynamic_pointer_cast<data::SolidClone>(obj.lock())) { disableAllReversedConstraintsStartingWith(ent); } } changedObjects.clear(); for (auto const& cns : constraints) { addBlackBoxes(cns, gcmSolver); } // todo: замораживать объект-источник перестраивания, чтобы не получалось так что двигаешь объект, а он возвращается обратно GCM_result res = GCM_Evaluate(gcmSystem); #ifdef DEBUG_GCM_EVALUATE_RESULT printf("gcm result: %s\n", toString(res)); #endif if (res == GCM_RESULT_Satisfied) { for (auto const& obj : objects) { obj->updateFromGcm(gcmSystem); } for (auto const& cns : constraints) { cns->updateFromGcm(gcmSystem); } } else if (bruteForceSolveWithBlackboxes(*this)) { // успешно решили грубой силой } else { // for (auto const& obj : objects) { obj->updateFromGcm(gcmSystem); } // for (auto const& cns : constraints) { cns->updateFromGcm(gcmSystem); } // todo: отобразить ошибку } // некоторые ограничения могут читать систему в время отрисовки, так что пока не будем её чистить } else { // позволить кинематических ограничениям запомнить новые положения тел for (auto const& obj : objects) { obj->updateFromGcm(gcmSystem); } for (auto const& cns : constraints) { cns->updateFromGcm(gcmSystem); } } } void data::Assembly::updateFromDependencies() { updateFromParams(); } void data::Assembly::buildVisual() { assert(m_visualChanged); m_visualChanged = false; if (visual == nullptr) { visual = new SceneSegment(); document.lock()->sceneContent->GetRootSegment()->AddSegment(visual); document.lock()->sceneToData[visual] = weak_from_this(); visual->SetVisible(visible); } } void data::Assembly::markDependencyChanged(ref<C3dObject> cause) { C3dObject::markDependencyChanged(cause); changedObjects.emplace_back(cause); } std::string_view data::Assembly::iconName() const { return "tool_assembly"; } int data::Assembly::childCount() { return objects.size() + constraints.size() + C3dObject::childCount(); } ref<data::C3dObject> data::Assembly::childAt(int i) { if (i >= 0 && i < objects.size()) { return objects[i]; } i -= objects.size(); if (i >= 0 && i < constraints.size()) { return constraints[i]; } i -= constraints.size(); return C3dObject::childAt(i); } int data::Assembly::childIndex(ref<C3dObject> const& child) { int i = C3dObject::childIndex(child); if (i != -1) { return i; } i = C3dObject::childCount(); for (auto const& x : objects) { if (x.get() == child.get()) { return i; } ++i; } for (auto const& x : constraints) { if (x.get() == child.get()) { return i; } ++i; } return -1; } void data::Assembly::removeChild(ref<C3dObject> const& child) { if (generic_remove_child(this, objects, child)) { return; } if (generic_remove_child(this, constraints, child)) { return; } } void data::Assembly::addChild(ref<C3dObject> const& child) { auto thisRef = std::static_pointer_cast<Assembly>(this->shared_from_this()); removeTemporary(child); if (auto ent = std::dynamic_pointer_cast<data::SolidClone>(child)) { objects.push_back(ent); ent->m_parent = thisRef; ent->parentAssembly = thisRef; } if (auto ent = std::dynamic_pointer_cast<data::AssemblyConstraint>(child)) { constraints.push_back(ent); ent->m_parent = thisRef; ent->assembly = thisRef; } } void data::Assembly::addTemporary(ref<C3dObject> child) { auto thisRef = std::static_pointer_cast<Assembly>(this->shared_from_this()); if (auto ent = std::dynamic_pointer_cast<data::SolidClone>(child)) { temporaryObjects.push_back(ent); ent->m_parent = thisRef; ent->parentAssembly = thisRef; } if (auto ent = std::dynamic_pointer_cast<data::AssemblyConstraint>(child)) { temporaryConstraints.push_back(ent); ent->m_parent = thisRef; ent->assembly = thisRef; } if (!document.expired()) { document.lock()->updateRequested = true; } } void data::Assembly::removeTemporary(ref<C3dObject> child) { for (auto it = temporaryObjects.begin(); it < temporaryObjects.end();) { if ((*it).expired()) { it = temporaryObjects.erase(it); } else if ((*it).lock().get() == child.get()) { it = temporaryObjects.erase(it); } else { ++it; } } for (auto it = temporaryConstraints.begin(); it < temporaryConstraints.end();) { if ((*it).expired()) { it = temporaryConstraints.erase(it); } else if ((*it).lock().get() == child.get()) { it = temporaryConstraints.erase(it); } else { ++it; } } if (!document.expired()) { document.lock()->updateRequested = true; } } char const* toString(GCM_result res) { switch (res) { case GCM_RESULT_None: { return "GCM_RESULT_None"; } break; case GCM_RESULT_Ok: { return "GCM_RESULT_Ok"; } break; case GCM_RESULT_Overconstrained: { return "GCM_RESULT_Overconstrained"; } break; case GCM_RESULT_MatedFixation: { return "GCM_RESULT_MatedFixation"; } break; case GCM_RESULT_DraggingFailed: { return "GCM_RESULT_DraggingFailed"; } break; case GCM_RESULT_Not_Satisfied: { return "GCM_RESULT_Not_Satisfied"; } break; case GCM_RESULT_Unsolvable: { return "GCM_RESULT_Unsolvable"; } break; case GCM_RESULT_DependentConstraintUnsolved: { return "GCM_RESULT_DependentConstraintUnsolved"; } break; case GCM_RESULT_Error: { return "GCM_RESULT_Error"; } break; case GCM_RESULT_InappropriateAlignment: { return "GCM_RESULT_InappropriateAlignment"; } break; case GCM_RESULT_InappropriateArgument: { return "GCM_RESULT_InappropriateArgument"; } break; case GCM_RESULT_IncompatibleArguments: { return "GCM_RESULT_IncompatibleArguments"; } break; case GCM_RESULT_InconsistentAlignment: { return "GCM_RESULT_InconsistentAlignment"; } break; case GCM_RESULT_Duplicated: { return "GCM_RESULT_Duplicated"; } break; case GCM_RESULT_CyclicDependence: { return "GCM_RESULT_CyclicDependence"; } break; case GCM_RESULT_MultiDependedGeom: { return "GCM_RESULT_MultiDependedGeom"; } break; case GCM_RESULT_OverconstrainingDependedGeoms: { return "GCM_RESULT_OverconstrainingDependedGeoms"; } break; case GCM_RESULT_DependedGeomCantBeFixed: { return "GCM_RESULT_DependedGeomCantBeFixed"; } break; case GCM_RESULT_InvalidArguments: { return "GCM_RESULT_InvalidArguments"; } break; case GCM_RESULT_UnsupportedTangencyChoice: { return "GCM_RESULT_UnsupportedTangencyChoice"; } break; case GCM_RESULT_InconsistentTangencyChoice: { return "GCM_RESULT_InconsistentTangencyChoice"; } break; case GCM_RESULT_CoaxialGearTransmissionUnsupported: { return "GCM_RESULT_CoaxialGearTransmissionUnsupported"; } break; case GCM_RESULT_OverconstrainedCamMechanism: { return "GCM_RESULT_OverconstrainedCamMechanism"; } break; case GCM_RESULT_CamMechanismsInCyclicDependency: { return "GCM_RESULT_CamMechanismsInCyclicDependency"; } break; case GCM_RESULT_InconsistentFollowerAxis: { return "GCM_RESULT_InconsistentFollowerAxis"; } break; case GCM_RESULT_InconsistentPlanarAngle: { return "GCM_RESULT_InconsistentPlanarAngle"; } break; case GCM_RESULT_UnsupportedFollowerSurface: { return "GCM_RESULT_UnsupportedFollowerSurface"; } break; case GCM_RESULT_ItsNotDrivingDimension: { return "GCM_RESULT_ItsNotDrivingDimension"; } break; case GCM_RESULT_IncorrectDimensionInterval: { return "GCM_RESULT_IncorrectDimensionInterval"; } break; case GCM_RESULT_Unregistered: { return "GCM_RESULT_Unregistered"; } break; case GCM_RESULT_InternalError: { return "GCM_RESULT_InternalError"; } break; case GCM_RESULT_ImmutableData: { return "GCM_RESULT_ImmutableData"; } break; case GCM_RESULT_Aborted: { return "GCM_RESULT_Aborted"; } break; case GCM_RESULT_Last_: { return "GCM_RESULT_Last_"; } break; } return "invalid GCM_RESULT value"; }