/
Team8
/
kittycad
Обзор
Документация
Войти
/
Team8
/
kittycad
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/data/templates/flange_coupling.cpp
594 строки
16 KB
levovix
add: drawing linear dimensions for parameters
11 янв 2026, 03:08
11 янв 2026, 03:08
c09faff
Код
Авторство
О чём код?
#include "./flange_coupling.h" #include "graphics/dimensions.h" #include "mb_axis3d.h" #include "data/document.h" #include "data/assembly/assembly.h" #include "data/assembly/constraints.h" #include "data/assembly/solid_clone.h" #include "data/templates/bolt_gost_7814.h" #include "data/templates/bolt_gost_7796.h" #include "data/templates/screw_gost_15521.h" #include "data/templates/shim_gost_6402.h" #include "./template_utils.ipp" #include "gui/strings.h" #include "gui/tools/templates/flange_coupling.h" #include "gui/document_view.h" data::FlangeCoupling::FlangeCoupling() {} data::FlangeCoupling::~FlangeCoupling() {} void data::FlangeCoupling::updateImpl(bool update_solids, bool update_assembly) { double d2 = useCorpusParams? this->d2 : 25; if (!useCorpusParams && D > 85) { d2 = 30; } if (!useCorpusParams && D > 95) { d2 = 40; } if (!useCorpusParams && D > 105) { d2 = 45; } if (!useCorpusParams && D > 115) { d2 = 50; } if (!useCorpusParams && D > 125) { d2 = 55; } if (!useCorpusParams && D > 135) { d2 = 65; } double l1 = useCorpusParams? this->l1 : 8; if (!useCorpusParams && D > 85) { l1 = 10; } if (!useCorpusParams && D > 95) { l1 = 12; } if (!useCorpusParams && D > 105) { l1 = 15; } if (!useCorpusParams && D > 115 && d > 31) { l1 = 16; } if (!useCorpusParams && D > 125) { l1 = 17; } double d3_n = useCorpusParams? this->d3_n : 8.4/1; if (!useCorpusParams && D > 105) { d3_n = 10.5/1; } double d4_n3 = useCorpusParams? this->d4_n3 : 9.0/1; if (!useCorpusParams && D > 105) { d4_n3 = 11.0/1; } double b1_n1 = useCorpusParams? this->b1_n1 : 1.0/4; if (!useCorpusParams && D > 135) { b1_n1 = 1.6/4; } double b2_n2 = useCorpusParams? this->b2_n2 : 0.5/2; if (!useCorpusParams && D > 135) { b2_n2 = 1.0/2; } double D1 = useCorpusParams? this->D1 : D - 25; if (!useCorpusParams && D > 85) { D1 = D - 30; } if (!useCorpusParams && D > 115) { D1 = D - 20; } if (!useCorpusParams && D > 135) { D1 = D - 30; } double R = useExtendedParams? this->R : 0.2; if (!useExtendedParams && d > 31) { R = 0.4; } double l2 = useExtendedParams? this->l2 : 2; double B = useExtendedParams? this->B : 4; if (!useExtendedParams && d > 13) { B = 5; } if (!useExtendedParams && d > 17) { B = 6; } if (!useExtendedParams && d > 21) { B = 8; } if (!useExtendedParams && d > 31) { B = 10; } if (!useExtendedParams && d > 39) { B = 12; } if (!useExtendedParams && d > 44) { B = 14; } double h = useExtendedParams? this->h : d + 1.8; if (!useExtendedParams && d > 13) { h = d + 2.3; } if (!useExtendedParams && d > 17) { h = d + 2.8; } if (!useExtendedParams && d > 23) { h = d + 3.3; } if (!useExtendedParams && d > 29) { h = d + 3.8; } if (!useExtendedParams && d > 39) { h = d + 4.4; } if (!useExtendedParams && d > 44) { h = d + 4.9; } double d1 = useExtendedParams? this->d1 : std::round(d * (40.0 / 25.0)); if (!useExtendedParams) { this->R = R; this->l2 = l2; this->B = B; this->h = h; this->d1 = d1; } if (!useCorpusParams) { this->d2 = d2; this->l1 = l1; this->d3_n = d3_n; this->d4_n3 = d4_n3; this->b1_n1 = b1_n1; this->b2_n2 = b2_n2; this->D1 = D1; } if (update_assembly) { assemblyUpdateRequired = false; if (assembly != nullptr) { auto assemblyRef = assembly; assembly = nullptr; data::C3dObject::destroy(assemblyRef, 2); } } std::vector<Point2> holePoints; { auto p = Point2{0, D1/2}; for (int i = 0; i < z; ++i) { holePoints.push_back(p); p.Rotate(M_PI*2 / z); } } if (update_solids) { { // profile auto& sketch = profile; auto& solid = profileSolid; sketch = Builder<data::Sketch>() .createIn(this, document) .name(toStdString(FlangeCouplingTool::tr("Profile"))) .visible(false) .final; std::array points = { Point2{l, d1/2}, Point2{l, d/2}, Point2{l2, d/2}, Point2{l2, d2/2}, Point2{0, d2/2}, Point2{0, D/2}, Point2{l1, D/2}, Point2{l1, d1/2}, }; auto lines = lineSegmentsFromPoints(points, sketch); addCoinsidencesBetween(lines); createChamferBetween(lines, 0, b1_n1); createChamferBetween(lines, 1, b1_n1); createChamferBetween(lines, 5, b2_n2); createChamferBetween(lines, 6, b2_n2); createFilletBetween(lines, 7, b1_n1); profileSolid = Builder<data::Revolution>() .createIn(this, document) .targetSketch(sketch) .axis({1, 0, 0}) .axisOrigin({}) .name(toStdString(FlangeCouplingTool::tr("Profile revolved"))) .visible(false) .final; } { // holes auto& sketch = holesProfile; auto& solid = holes; sketch = Builder<data::Sketch>() .createIn(this, document) .xAxis({0, 0, 1}) .yAxis({0, 1, 0}) .name(toStdString(FlangeCouplingTool::tr("Holes profile"))) .visible(false) .final; std::array points = { Point2{-B/2, h-(d/2)}, Point2{B/2, h-(d/2)}, Point2{B/2, 0}, Point2{-B/2, 0}, }; auto lines = lineSegmentsFromPoints(points, sketch); addCoinsidencesBetween(lines); createFilletBetween(lines, 0, R); createFilletBetween(lines, 1, R); for (int i = 0; i < holePoints.size(); ++i) { if (i < int(z / 2)) { Builder<data::SketchCircle>() .create(sketch).childOf(sketch) .radius(d3_n/2) .center(holePoints[i]) ; } else { Builder<data::SketchCircle>() .create(sketch).childOf(sketch) .radius(d4_n3/2) .center(holePoints[i]) ; } } solid = Builder<data::Extrusion>() .createIn(this, document) .targetSketch(sketch) .length(l) .axis({1, 0, 0}) .name(toStdString(FlangeCouplingTool::tr("Holes"))) .visible(false) .final; } { // semicoupling semicoupling = Builder<data::Boolean>() .createIn(this, document) .add(profileSolid, Boolean::Union) .add(holes, Boolean::Difference) .name(toStdString(FlangeCouplingTool::tr("Semicoupling"))) .visible(false) .final; } { // boltGost7814 boltGost7814 = Builder<data::BoltGost7814>() .createIn(this, document) .visible(false) .final; boltGost7814->d = d4_n3 - 2; boltGost7814->l = l1 * 3; Document::update( boltGost7814.get(), false, 10, true, nullptr ); } { // boltGost7796 boltGost7796 = Builder<data::BoltGost7796>() .createIn(this, document) .visible(false) .final; boltGost7796->d = boltGost7814->d; boltGost7796->l = boltGost7814->l; } { // screwGost15521 screwGost15521 = Builder<data::ScrewGost15521>() .createIn(this, document) .visible(false) .final; screwGost15521->d = boltGost7814->d; } { // shimGost6402 shimGost6402 = Builder<data::ShimGost6402>() .createIn(this, document) .visible(false) .final; shimGost6402->d = boltGost7814->d; } Document::update( this, true, 10, true, nullptr ); } if (update_assembly) { assert(semicoupling != nullptr && semicoupling->solid != nullptr); int semicoupling_base_index = findAssemblyItem({ .planar = true, .x = 0, .normal = Vec3{-1, 0, 0}, }, semicoupling->solid); std::vector<int> semicoupling_hole_indices; std::vector<uint8_t> semicoupling_hole_reversedNormal; semicoupling_hole_reversedNormal.resize(holePoints.size()); { for (int i = 0; i < holePoints.size(); ++i) { semicoupling_hole_indices.push_back(findAssemblyItem({ .planar = false, .y = holePoints[i].y, .z = holePoints[i].x, .normal = Vec3{1, 0, 0}, .normalWasReversed = reinterpret_cast<bool*>(semicoupling_hole_reversedNormal[i]), }, semicoupling->solid)); } } int semicoupling_right_index = findAssemblyItem({ .planar = true, .x = l1, .normal = Vec3{1, 0, 0}, }, semicoupling->solid); bool bolt1_reversed_normal; int bolt1_plane_index = findAssemblyItem({ .planar = true, .x = 0, .normal = Vec3{1, 0, 0}, .normalWasReversed = &bolt1_reversed_normal, }, boltGost7814->part->solid); int bolt1_axis_index = findAssemblyItem({ .planar = false, .y = 0, .z = 0, .normal = Vec3{1, 0, 0}, }, boltGost7814->part->solid); bool bolt2_reversed_normal; int bolt2_plane_index = findAssemblyItem({ .planar = true, .x = 0, .normal = Vec3{1, 0, 0}, }, boltGost7796->part->solid); int bolt2_axis_index = findAssemblyItem({ .planar = false, .y = 0, .z = 0, .normal = Vec3{1, 0, 0}, .normalWasReversed = &bolt2_reversed_normal, }, boltGost7796->part->solid); bool shim_reversed_normal; int shim_left_index = findAssemblyItem({ .planar = true, .normal = Vec3{-1, 0, 0}, }, shimGost6402->part->solid); int shim_right_index = findAssemblyItem({ .planar = true, .normal = Vec3{1, 0, 0}, }, shimGost6402->part->solid); int shim_axis_index = findAssemblyItem({ .planar = false, .y = 0, .z = 0, .normal = Vec3{1, 0, 0}, .normalWasReversed = &shim_reversed_normal, }, shimGost6402->part->solid); bool screw_reversed_normal; int screw_plane_index = findAssemblyItem({ .planar = true, .x = 0, .normal = Vec3{-1, 0, 0}, }, screwGost15521->part->solid); int screw_axis_index = findAssemblyItem({ .planar = false, .y = 0, .z = 0, .normal = Vec3{1, 0, 0}, .normalWasReversed = &screw_reversed_normal, }, screwGost15521->part->solid); assert(semicoupling_base_index != -1); assert(std::ranges::all_of(semicoupling_hole_indices, [](auto const& x) { return x != -1; })); assert(semicoupling_right_index != -1); assert(bolt1_plane_index != -1); assert(bolt1_axis_index != -1); assert(bolt2_plane_index != -1); assert(bolt2_axis_index != -1); assert(shim_left_index != -1); assert(shim_right_index != -1); assert(shim_axis_index != -1); assert(screw_plane_index != -1); assert(screw_axis_index != -1); { // assembly assembly = Builder<data::Assembly>() .createIn(this, document) .final; auto semicoupling1 = Builder<data::SolidClone>() .create(document).parent(assembly) .targetSolid(semicoupling) .name(toStdString(FlangeCouplingTool::tr("Semi-coupling 1"))) .final; auto semicoupling2 = Builder<data::SolidClone>() .create(document).parent(assembly) .targetSolid(semicoupling) .name(toStdString(FlangeCouplingTool::tr("Semi-coupling 2"))) .final; std::vector<ref<data::SolidClone>> bolts; std::vector<ref<data::SolidClone>> shims; std::vector<ref<data::SolidClone>> screws; for (int i = 0; i < holePoints.size(); ++i) { if (i < int(z / 2)) { bolts.push_back(Builder<data::SolidClone>() .create(document).parent(assembly) .targetSolid(boltGost7814->part) .name(toStdString(FlangeCouplingTool::tr("Bolt ")) + std::to_string(i+1)) .final ); } else { bolts.push_back(Builder<data::SolidClone>() .create(document).parent(assembly) .targetSolid(boltGost7796->part) .name(toStdString(FlangeCouplingTool::tr("Bolt ")) + std::to_string(i+1)) .final ); } shims.push_back(Builder<data::SolidClone>() .create(document).parent(assembly) .targetSolid(shimGost6402->part) .name(toStdString(FlangeCouplingTool::tr("Shim ")) + std::to_string(i+1)) .final ); screws.push_back(Builder<data::SolidClone>() .create(document).parent(assembly) .targetSolid(screwGost15521->part) .name(toStdString(FlangeCouplingTool::tr("Screw ")) + std::to_string(i+1)) .final ); } Builder<data::Fixed3dConstraint>() .create(assembly).childOf(assembly) .item3d({semicoupling1, 0}) ; Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({semicoupling1, semicoupling_base_index}) .item3d_2({semicoupling2, semicoupling_base_index}) .inverseDirection(true) ; for (int i = 0; i < holePoints.size(); ++i) { Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({semicoupling1, semicoupling_hole_indices[i]}) .item3d_2({semicoupling2, semicoupling_hole_indices[(holePoints.size() - i) % holePoints.size()]}) .inverseDirection(true) ; Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({semicoupling1, semicoupling_hole_indices[i]}) .item3d_2({bolts[i], i < int(z / 2) ? bolt1_axis_index : bolt2_axis_index}) .inverseDirection(!((i < int(z / 2) ? bolt1_reversed_normal : bolt2_reversed_normal) ^ semicoupling_hole_reversedNormal[i])) ; Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({semicoupling2, semicoupling_right_index}) .item3d_2({bolts[i], i < int(z / 2) ? bolt1_plane_index : bolt2_plane_index}) .inverseDirection(true) ; Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({semicoupling1, semicoupling_hole_indices[i]}) .item3d_2({shims[i], shim_axis_index}) .inverseDirection(!(shim_reversed_normal ^ semicoupling_hole_reversedNormal[i])) ; Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({semicoupling1, semicoupling_right_index}) .item3d_2({shims[i], shim_left_index}) .inverseDirection(true) ; Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({semicoupling1, semicoupling_hole_indices[i]}) .item3d_2({screws[i], screw_axis_index}) .inverseDirection(!(screw_reversed_normal ^ semicoupling_hole_reversedNormal[i])) ; Builder<data::Coinsidence3dConstraint>() .create(assembly).childOf(assembly) .item3d_1({shims[i], shim_right_index}) .item3d_2({screws[i], screw_plane_index}) .inverseDirection(true) ; } // todo: сделать зависимости в стиле freecad, они удобнее для создания из кода (например одно "совпадение систем координат" с указанием дочерней системы коодинат двух объектов, вместо того чтобы ставить три совпадения поверхностей и/или осей, которые ещё и на модели искать надо) } } } void data::FlangeCoupling::updateFromParams() { assert(m_propertyChanged); m_propertyChanged = false; updateImpl(true, true); } void data::FlangeCoupling::updateFromDependencies() { Template::updateFromDependencies(); if (assemblyUpdateRequired) { updateImpl(false, true); } } void data::FlangeCoupling::markPropertyChanged() { if (autoUpdate) { Template::markPropertyChanged(); } else { // discard } } void data::FlangeCoupling::markDependencyChanged(ref<C3dObject> cause) { if (cause != nullptr && cause->m_parent.lock().get() == this && !std::dynamic_pointer_cast<data::Assembly>(cause)) { // todo: по какой-то причине недостаточно просто сравнить cause.get() != assembly.get() assemblyUpdateRequired = true; } Template::markDependencyChanged(cause); } void data::FlangeCoupling::draw(DrawContext& ctx) { if ( dynamic_cast<FlangeCouplingTool*>(document.lock()->documentView->activeTool()) || dynamic_cast<FlangeCouplingTool*>(document.lock()->documentView->toolForSelectedObject()) ) { drawLinearDim( ctx, {-l1, D/2, 0}, {-l1, -D/2, 0}, {0, 1, 0}, {-(l1 + l), 0, 0}, toStdString(FlangeCouplingTool::tr("D = %1 mm").arg(D)), d1/12 ); drawLinearDim( ctx, {l, d/2, 0}, {l, -d/2, 0}, {0, 1, 0}, {l, 0, 0}, toStdString(FlangeCouplingTool::tr("d = %1 mm").arg(d)), d1/12 ); drawLinearDim( ctx, {0, D/2, 0}, {l, d/2, 0}, {1, 0, 0}, {0, d, 0}, toStdString(FlangeCouplingTool::tr("l = %1 mm").arg(d)), d1/12 ); } } std::string_view data::FlangeCoupling::iconName() const { return "template_flange_coupling"; }