综合平台编程器项目的远程存储
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

1623 строки
55 KiB

  1. #include "logic_editor_service.h"
  2. #include "project_service.h"
  3. #include <algorithm>
  4. #include <cctype>
  5. #include <cstddef>
  6. #include <iterator>
  7. #include <unordered_set>
  8. #include <type_traits>
  9. #include <utility>
  10. namespace {
  11. bool isBlank(const std::string &value)
  12. {
  13. return value.empty()
  14. || std::all_of(
  15. value.cbegin(), value.cend(),
  16. [](unsigned char character) { return std::isspace(character) != 0; });
  17. }
  18. std::string makeUniqueLogicId(const Project &project)
  19. {
  20. int suffix = 1;
  21. while (true)
  22. {
  23. const std::string candidate = "logic-" + std::to_string(suffix);
  24. const bool found = std::any_of(
  25. project.controlLogics.cbegin(), project.controlLogics.cend(),
  26. [&candidate](const ControlLogic &logic) { return logic.id == candidate; });
  27. if (!found)
  28. {
  29. return candidate;
  30. }
  31. ++suffix;
  32. }
  33. }
  34. LogicNode makeNode(const std::string &id, const LogicNodeConfig &config)
  35. {
  36. return {id, config, false};
  37. }
  38. ConditionExpression makeContainer(
  39. const std::string &id,
  40. ConditionExpressionKind kind,
  41. ConditionExpression first,
  42. ConditionExpression second)
  43. {
  44. ConditionExpression expression;
  45. expression.id = id;
  46. expression.kind = kind;
  47. expression.children.push_back(std::move(first));
  48. expression.children.push_back(std::move(second));
  49. return expression;
  50. }
  51. ConditionExpression *findParentExpression(
  52. ConditionExpression &expression, const std::string &child_id)
  53. {
  54. for (ConditionExpression &child : expression.children)
  55. {
  56. if (child.id == child_id)
  57. {
  58. return &expression;
  59. }
  60. if (ConditionExpression *parent = findParentExpression(child, child_id))
  61. {
  62. return parent;
  63. }
  64. }
  65. return nullptr;
  66. }
  67. using NodeIdSet = std::unordered_set<std::string>;
  68. NodeIdSet conditionLeafIds(const ConditionExpression &expression)
  69. {
  70. NodeIdSet ids;
  71. if (expression.kind == ConditionExpressionKind::Node
  72. || expression.kind == ConditionExpressionKind::Wire)
  73. {
  74. ids.insert(expression.id);
  75. return ids;
  76. }
  77. for (const ConditionExpression &child : expression.children)
  78. {
  79. NodeIdSet child_ids = conditionLeafIds(child);
  80. ids.insert(child_ids.cbegin(), child_ids.cend());
  81. }
  82. return ids;
  83. }
  84. int expressionColumns(const ConditionExpression &expression)
  85. {
  86. if (expression.kind == ConditionExpressionKind::Node)
  87. {
  88. return 1;
  89. }
  90. if (expression.kind == ConditionExpressionKind::Wire)
  91. {
  92. return expression.wire->columnSpan;
  93. }
  94. int columns = expression.kind == ConditionExpressionKind::Series ? 0 : 1;
  95. for (const ConditionExpression &child : expression.children)
  96. {
  97. const int child_columns = expressionColumns(child);
  98. columns = expression.kind == ConditionExpressionKind::Series
  99. ? columns + child_columns : std::max(columns, child_columns);
  100. }
  101. return columns;
  102. }
  103. bool isSubset(const NodeIdSet &subset, const NodeIdSet &values)
  104. {
  105. return std::all_of(
  106. subset.cbegin(), subset.cend(),
  107. [&values](const std::string &value) { return values.count(value) != 0U; });
  108. }
  109. bool sameValues(const NodeIdSet &left, const NodeIdSet &right)
  110. {
  111. return left.size() == right.size() && isSubset(left, right);
  112. }
  113. void addParallelSibling(
  114. ConditionExpression *target,
  115. ConditionExpression branch,
  116. const std::string &container_id)
  117. {
  118. if (target->kind == ConditionExpressionKind::Parallel)
  119. {
  120. target->children.push_back(std::move(branch));
  121. return;
  122. }
  123. ConditionExpression original = std::move(*target);
  124. *target = makeContainer(
  125. container_id,
  126. ConditionExpressionKind::Parallel,
  127. std::move(original),
  128. std::move(branch));
  129. }
  130. bool addParallelForSelection(
  131. ConditionExpression *expression,
  132. const NodeIdSet &selected_ids,
  133. ConditionExpression *branch,
  134. const std::string &parallel_id,
  135. const std::string &series_id)
  136. {
  137. const NodeIdSet expression_ids = conditionLeafIds(*expression);
  138. if (sameValues(expression_ids, selected_ids))
  139. {
  140. addParallelSibling(expression, std::move(*branch), parallel_id);
  141. return true;
  142. }
  143. std::vector<NodeIdSet> child_ids;
  144. child_ids.reserve(expression->children.size());
  145. std::vector<std::size_t> matching_children;
  146. for (std::size_t index = 0; index < expression->children.size(); ++index)
  147. {
  148. child_ids.push_back(conditionLeafIds(expression->children[index]));
  149. const bool intersects = std::any_of(
  150. child_ids.back().cbegin(), child_ids.back().cend(),
  151. [&selected_ids](const std::string &id)
  152. {
  153. return selected_ids.count(id) != 0U;
  154. });
  155. if (intersects)
  156. {
  157. matching_children.push_back(index);
  158. }
  159. }
  160. if (matching_children.empty())
  161. {
  162. return false;
  163. }
  164. if (matching_children.size() == 1U)
  165. {
  166. const std::size_t child_index = matching_children.front();
  167. if (expression->kind == ConditionExpressionKind::Parallel
  168. && sameValues(child_ids[child_index], selected_ids))
  169. {
  170. expression->children.push_back(std::move(*branch));
  171. return true;
  172. }
  173. return addParallelForSelection(
  174. &expression->children[child_index],
  175. selected_ids,
  176. branch,
  177. parallel_id,
  178. series_id);
  179. }
  180. if (expression->kind != ConditionExpressionKind::Series)
  181. {
  182. return false;
  183. }
  184. const std::size_t first = matching_children.front();
  185. const std::size_t last = matching_children.back();
  186. if (last - first + 1U != matching_children.size())
  187. {
  188. return false;
  189. }
  190. NodeIdSet range_ids;
  191. for (std::size_t index = first; index <= last; ++index)
  192. {
  193. range_ids.insert(child_ids[index].cbegin(), child_ids[index].cend());
  194. }
  195. if (!sameValues(range_ids, selected_ids))
  196. {
  197. return false;
  198. }
  199. ConditionExpression range;
  200. range.id = series_id;
  201. range.kind = ConditionExpressionKind::Series;
  202. auto range_begin = expression->children.begin() + static_cast<std::ptrdiff_t>(first);
  203. auto range_end = expression->children.begin() + static_cast<std::ptrdiff_t>(last + 1U);
  204. range.children.insert(
  205. range.children.end(),
  206. std::make_move_iterator(range_begin),
  207. std::make_move_iterator(range_end));
  208. range_begin = expression->children.erase(range_begin, range_end);
  209. ConditionExpression parallel = makeContainer(
  210. parallel_id,
  211. ConditionExpressionKind::Parallel,
  212. std::move(range),
  213. std::move(*branch));
  214. expression->children.insert(range_begin, std::move(parallel));
  215. return true;
  216. }
  217. bool removeExpressionRecursive(
  218. ConditionExpression *expression, const std::string &expression_id)
  219. {
  220. if (expression == nullptr
  221. || expression->kind == ConditionExpressionKind::Node
  222. || expression->kind == ConditionExpressionKind::Wire)
  223. {
  224. return false;
  225. }
  226. const auto removable = std::find_if(
  227. expression->children.begin(),
  228. expression->children.end(),
  229. [&expression_id](const ConditionExpression &child)
  230. {
  231. return child.id == expression_id;
  232. });
  233. if (removable != expression->children.end())
  234. {
  235. expression->children.erase(removable);
  236. return true;
  237. }
  238. for (ConditionExpression &child : expression->children)
  239. {
  240. if (removeExpressionRecursive(&child, expression_id))
  241. {
  242. return true;
  243. }
  244. }
  245. return false;
  246. }
  247. std::optional<int> selectedExpressionColumns(
  248. const ConditionExpression &expression,
  249. const NodeIdSet &selected_ids)
  250. {
  251. const NodeIdSet expression_ids = conditionLeafIds(expression);
  252. if (sameValues(expression_ids, selected_ids))
  253. {
  254. return expressionColumns(expression);
  255. }
  256. if (expression.kind == ConditionExpressionKind::Node
  257. || expression.kind == ConditionExpressionKind::Wire)
  258. {
  259. return std::nullopt;
  260. }
  261. std::vector<NodeIdSet> child_ids;
  262. std::vector<std::size_t> matching_children;
  263. child_ids.reserve(expression.children.size());
  264. for (std::size_t index = 0; index < expression.children.size(); ++index)
  265. {
  266. child_ids.push_back(conditionLeafIds(expression.children[index]));
  267. const bool intersects = std::any_of(
  268. child_ids.back().cbegin(), child_ids.back().cend(),
  269. [&selected_ids](const std::string &id)
  270. {
  271. return selected_ids.count(id) != 0U;
  272. });
  273. if (intersects)
  274. {
  275. matching_children.push_back(index);
  276. }
  277. }
  278. if (matching_children.size() == 1U)
  279. {
  280. return selectedExpressionColumns(
  281. expression.children[matching_children.front()], selected_ids);
  282. }
  283. if (matching_children.empty()
  284. || expression.kind != ConditionExpressionKind::Series)
  285. {
  286. return std::nullopt;
  287. }
  288. const std::size_t first = matching_children.front();
  289. const std::size_t last = matching_children.back();
  290. if (last - first + 1U != matching_children.size())
  291. {
  292. return std::nullopt;
  293. }
  294. NodeIdSet range_ids;
  295. int columns = 0;
  296. for (std::size_t index = first; index <= last; ++index)
  297. {
  298. range_ids.insert(child_ids[index].cbegin(), child_ids[index].cend());
  299. columns += expressionColumns(expression.children[index]);
  300. }
  301. return sameValues(range_ids, selected_ids)
  302. ? std::optional<int>{columns} : std::nullopt;
  303. }
  304. LadderRung *findEditableRung(
  305. Project &project,
  306. const std::string &logic_id,
  307. const std::string &rung_id)
  308. {
  309. const auto logic = std::find_if(
  310. project.controlLogics.begin(), project.controlLogics.end(),
  311. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  312. if (logic == project.controlLogics.end())
  313. {
  314. return nullptr;
  315. }
  316. const auto rung = std::find_if(
  317. logic->rungs.begin(), logic->rungs.end(),
  318. [&rung_id](const LadderRung &candidate) { return candidate.id == rung_id; });
  319. return rung == logic->rungs.end() ? nullptr : &*rung;
  320. }
  321. } // namespace
  322. LogicEditorService::LogicEditorService(ProjectService &project_service)
  323. : project_service_(project_service)
  324. {
  325. }
  326. LogicEditorService::HistoryState LogicEditorService::captureState() const
  327. {
  328. return {project_service_.project().controlLogics};
  329. }
  330. void LogicEditorService::recordHistory(HistoryState before)
  331. {
  332. const HistoryState after = captureState();
  333. history_.record(std::move(before), after, &LogicEditorService::statesEqual);
  334. }
  335. bool LogicEditorService::statesEqual(
  336. const HistoryState &left, const HistoryState &right)
  337. {
  338. if (left.logics.size() != right.logics.size())
  339. {
  340. return false;
  341. }
  342. for (std::size_t index = 0; index < left.logics.size(); ++index)
  343. {
  344. if (!logicsEqual(left.logics[index], right.logics[index]))
  345. {
  346. return false;
  347. }
  348. }
  349. return true;
  350. }
  351. bool LogicEditorService::logicsEqual(
  352. const ControlLogic &left, const ControlLogic &right)
  353. {
  354. if (left.id != right.id || left.name != right.name
  355. || left.enabled != right.enabled || left.rungs.size() != right.rungs.size())
  356. {
  357. return false;
  358. }
  359. for (std::size_t index = 0; index < left.rungs.size(); ++index)
  360. {
  361. if (!rungsEqual(left.rungs[index], right.rungs[index]))
  362. {
  363. return false;
  364. }
  365. }
  366. return true;
  367. }
  368. bool LogicEditorService::rungsEqual(
  369. const LadderRung &left, const LadderRung &right)
  370. {
  371. if (left.id != right.id || left.name != right.name
  372. || left.comment != right.comment
  373. || left.condition.has_value() != right.condition.has_value()
  374. || left.output.has_value() != right.output.has_value())
  375. {
  376. return false;
  377. }
  378. return (!left.condition.has_value()
  379. || expressionsEqual(*left.condition, *right.condition))
  380. && (!left.output.has_value() || nodesEqual(*left.output, *right.output));
  381. }
  382. bool LogicEditorService::expressionsEqual(
  383. const ConditionExpression &left, const ConditionExpression &right)
  384. {
  385. if (left.id != right.id || left.kind != right.kind
  386. || left.node.has_value() != right.node.has_value()
  387. || left.wire.has_value() != right.wire.has_value()
  388. || left.children.size() != right.children.size())
  389. {
  390. return false;
  391. }
  392. if (left.node.has_value() && !nodesEqual(*left.node, *right.node))
  393. {
  394. return false;
  395. }
  396. if (left.wire.has_value()
  397. && left.wire->columnSpan != right.wire->columnSpan)
  398. {
  399. return false;
  400. }
  401. for (std::size_t index = 0; index < left.children.size(); ++index)
  402. {
  403. if (!expressionsEqual(left.children[index], right.children[index]))
  404. {
  405. return false;
  406. }
  407. }
  408. return true;
  409. }
  410. bool LogicEditorService::nodesEqual(
  411. const LogicNode &left, const LogicNode &right)
  412. {
  413. return left.id == right.id && left.config.index() == right.config.index()
  414. && left.configured == right.configured && configsEqual(left.config, right.config);
  415. }
  416. bool LogicEditorService::configsEqual(
  417. const LogicNodeConfig &left, const LogicNodeConfig &right)
  418. {
  419. return std::visit(
  420. [](const auto &left_config, const auto &right_config)
  421. {
  422. using Left = std::decay_t<decltype(left_config)>;
  423. using Right = std::decay_t<decltype(right_config)>;
  424. if constexpr (!std::is_same_v<Left, Right>)
  425. {
  426. return false;
  427. }
  428. else if constexpr (std::is_same_v<Left, ContactNodeConfig>)
  429. {
  430. return left_config.address == right_config.address
  431. && left_config.mode == right_config.mode;
  432. }
  433. else if constexpr (std::is_same_v<Left, EdgeContactNodeConfig>)
  434. {
  435. return left_config.address == right_config.address
  436. && left_config.mode == right_config.mode;
  437. }
  438. else if constexpr (std::is_same_v<Left, TimerContactNodeConfig>)
  439. {
  440. return left_config.address == right_config.address
  441. && left_config.mode == right_config.mode;
  442. }
  443. else if constexpr (std::is_same_v<Left, CounterContactNodeConfig>)
  444. {
  445. return left_config.address == right_config.address
  446. && left_config.mode == right_config.mode;
  447. }
  448. else if constexpr (std::is_same_v<Left, CoilNodeConfig>)
  449. {
  450. return left_config.address == right_config.address
  451. && left_config.mode == right_config.mode;
  452. }
  453. else if constexpr (std::is_same_v<Left, CompareNodeConfig>)
  454. {
  455. return left_config.address == right_config.address
  456. && left_config.comparison == right_config.comparison
  457. && left_config.value == right_config.value;
  458. }
  459. else if constexpr (std::is_same_v<Left, TonNodeConfig>)
  460. {
  461. return left_config.address == right_config.address
  462. && left_config.presetMs == right_config.presetMs;
  463. }
  464. else if constexpr (std::is_same_v<Left, CounterNodeConfig>)
  465. {
  466. return left_config.address == right_config.address
  467. && left_config.mode == right_config.mode
  468. && left_config.currentValueAddress == right_config.currentValueAddress
  469. && left_config.preset.kind == right_config.preset.kind
  470. && left_config.preset.address == right_config.preset.address
  471. && left_config.preset.constant == right_config.preset.constant
  472. && left_config.resetAddress == right_config.resetAddress;
  473. }
  474. else if constexpr (std::is_same_v<Left, MoveNodeConfig>)
  475. {
  476. return left_config.source.kind == right_config.source.kind
  477. && left_config.source.address == right_config.source.address
  478. && left_config.source.constant == right_config.source.constant
  479. && left_config.destination == right_config.destination;
  480. }
  481. else
  482. {
  483. return left_config.operation == right_config.operation
  484. && left_config.left.kind == right_config.left.kind
  485. && left_config.left.address == right_config.left.address
  486. && left_config.left.constant == right_config.left.constant
  487. && left_config.right.kind == right_config.right.kind
  488. && left_config.right.address == right_config.right.address
  489. && left_config.right.constant == right_config.right.constant
  490. && left_config.destination == right_config.destination;
  491. }
  492. },
  493. left,
  494. right);
  495. }
  496. LogicEditorResult LogicEditorService::historyFailure(const std::string &message)
  497. {
  498. return {false, LogicEditorError::InvalidOperation, message, {}};
  499. }
  500. const ControlLogic *LogicEditorService::findLogic(const std::string &logic_id) const
  501. {
  502. const auto &logics = project_service_.project().controlLogics;
  503. const auto logic = std::find_if(
  504. logics.cbegin(), logics.cend(),
  505. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  506. return logic == logics.cend() ? nullptr : &*logic;
  507. }
  508. const LadderRung *LogicEditorService::findRung(
  509. const std::string &logic_id, const std::string &rung_id) const
  510. {
  511. const ControlLogic *logic = findLogic(logic_id);
  512. if (logic == nullptr)
  513. {
  514. return nullptr;
  515. }
  516. const auto rung = std::find_if(
  517. logic->rungs.cbegin(), logic->rungs.cend(),
  518. [&rung_id](const LadderRung &candidate) { return candidate.id == rung_id; });
  519. return rung == logic->rungs.cend() ? nullptr : &*rung;
  520. }
  521. const LogicNode *LogicEditorService::findNode(
  522. const std::string &logic_id, const std::string &node_id) const
  523. {
  524. const ControlLogic *logic = findLogic(logic_id);
  525. if (logic == nullptr)
  526. {
  527. return nullptr;
  528. }
  529. for (const LadderRung &rung : logic->rungs)
  530. {
  531. if (rung.output.has_value() && rung.output->id == node_id)
  532. {
  533. return &*rung.output;
  534. }
  535. if (rung.condition.has_value())
  536. {
  537. if (const LogicNode *node = findConditionNode(*rung.condition, node_id))
  538. {
  539. return node;
  540. }
  541. }
  542. }
  543. return nullptr;
  544. }
  545. const ConditionExpression *LogicEditorService::findExpression(
  546. const std::string &logic_id,
  547. const std::string &rung_id,
  548. const std::string &expression_id) const
  549. {
  550. const LadderRung *rung = findRung(logic_id, rung_id);
  551. return rung == nullptr || !rung->condition.has_value()
  552. ? nullptr : findConditionExpression(*rung->condition, expression_id);
  553. }
  554. std::string LogicEditorService::firstLogicId() const
  555. {
  556. const auto &logics = project_service_.project().controlLogics;
  557. return logics.empty() ? std::string{} : logics.front().id;
  558. }
  559. std::string LogicEditorService::firstRungId(const std::string &logic_id) const
  560. {
  561. const ControlLogic *logic = findLogic(logic_id);
  562. return logic == nullptr || logic->rungs.empty() ? std::string{} : logic->rungs.front().id;
  563. }
  564. std::string LogicEditorService::rungIdForNode(
  565. const std::string &logic_id, const std::string &node_id) const
  566. {
  567. const ControlLogic *logic = findLogic(logic_id);
  568. if (logic == nullptr)
  569. {
  570. return {};
  571. }
  572. for (const LadderRung &rung : logic->rungs)
  573. {
  574. if ((rung.output.has_value() && rung.output->id == node_id)
  575. || (rung.condition.has_value()
  576. && findConditionNode(*rung.condition, node_id) != nullptr))
  577. {
  578. return rung.id;
  579. }
  580. }
  581. return {};
  582. }
  583. std::string LogicEditorService::registerCommentFor(
  584. const RegisterAddress &address) const
  585. {
  586. const RegisterComment *comment = project_service_.project().findRegisterComment(address);
  587. return comment == nullptr ? std::string{} : comment->text;
  588. }
  589. LogicEditorResult LogicEditorService::ensureDefaultLogic()
  590. {
  591. if (!project_service_.project().controlLogics.empty())
  592. {
  593. return {true, LogicEditorError::None, {}, firstLogicId()};
  594. }
  595. ControlLogic logic;
  596. logic.id = "logic-1";
  597. logic.name = "控制逻辑 1";
  598. logic.rungs.push_back({"rung-1", "网络 1", {}, std::nullopt, std::nullopt});
  599. Project &project = project_service_.editProject();
  600. project.controlLogics.push_back(std::move(logic));
  601. return {true, LogicEditorError::None, {}, project.controlLogics.back().id};
  602. }
  603. LogicEditorResult LogicEditorService::addLogic(const std::string &name)
  604. {
  605. if (isBlank(name))
  606. {
  607. return failure(LogicEditorError::InvalidOperation, "控制逻辑名称不能为空");
  608. }
  609. const Project &current = project_service_.project();
  610. const bool duplicate = std::any_of(
  611. current.controlLogics.cbegin(), current.controlLogics.cend(),
  612. [&name](const ControlLogic &logic) { return logic.name == name; });
  613. if (duplicate)
  614. {
  615. return failure(LogicEditorError::DuplicateName, "控制逻辑名称必须唯一");
  616. }
  617. ControlLogic logic;
  618. logic.id = makeUniqueLogicId(current);
  619. logic.name = name;
  620. logic.rungs.push_back({"rung-1", "网络 1", {}, std::nullopt, std::nullopt});
  621. HistoryState before = captureState();
  622. Project &project = project_service_.editProject();
  623. project.controlLogics.push_back(std::move(logic));
  624. recordHistory(std::move(before));
  625. return {true, LogicEditorError::None, {}, project.controlLogics.back().id};
  626. }
  627. LogicEditorResult LogicEditorService::renameLogic(
  628. const std::string &logic_id, const std::string &name)
  629. {
  630. if (isBlank(name))
  631. {
  632. return failure(LogicEditorError::InvalidOperation, "控制逻辑名称不能为空");
  633. }
  634. const Project &current = project_service_.project();
  635. const auto logic = std::find_if(
  636. current.controlLogics.cbegin(), current.controlLogics.cend(),
  637. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  638. if (logic == current.controlLogics.cend())
  639. {
  640. return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
  641. }
  642. const bool duplicate = std::any_of(
  643. current.controlLogics.cbegin(), current.controlLogics.cend(),
  644. [&logic_id, &name](const ControlLogic &candidate)
  645. {
  646. return candidate.id != logic_id && candidate.name == name;
  647. });
  648. if (duplicate)
  649. {
  650. return failure(LogicEditorError::DuplicateName, "控制逻辑名称必须唯一");
  651. }
  652. if (logic->name == name)
  653. {
  654. return {true, LogicEditorError::None, {}, logic_id};
  655. }
  656. HistoryState before = captureState();
  657. Project &project = project_service_.editProject();
  658. auto editable = std::find_if(
  659. project.controlLogics.begin(), project.controlLogics.end(),
  660. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  661. editable->name = name;
  662. recordHistory(std::move(before));
  663. return {true, LogicEditorError::None, {}, logic_id};
  664. }
  665. LogicEditorResult LogicEditorService::removeLogic(const std::string &logic_id)
  666. {
  667. const Project &current = project_service_.project();
  668. const auto logic = std::find_if(
  669. current.controlLogics.cbegin(), current.controlLogics.cend(),
  670. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  671. if (logic == current.controlLogics.cend())
  672. {
  673. return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
  674. }
  675. if (current.controlLogics.size() <= 1)
  676. {
  677. return failure(LogicEditorError::LastLogicRequired, "工程至少需要保留一个控制逻辑");
  678. }
  679. HistoryState before = captureState();
  680. Project &project = project_service_.editProject();
  681. project.controlLogics.erase(
  682. std::remove_if(
  683. project.controlLogics.begin(), project.controlLogics.end(),
  684. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; }),
  685. project.controlLogics.end());
  686. recordHistory(std::move(before));
  687. return {true, LogicEditorError::None, {}, logic_id};
  688. }
  689. LogicEditorResult LogicEditorService::moveLogic(const std::string &logic_id, int offset)
  690. {
  691. if (offset != -1 && offset != 1)
  692. {
  693. return failure(LogicEditorError::InvalidOperation, "控制逻辑每次只能上移或下移一位");
  694. }
  695. const Project &current = project_service_.project();
  696. const auto logic = std::find_if(
  697. current.controlLogics.cbegin(), current.controlLogics.cend(),
  698. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  699. if (logic == current.controlLogics.cend())
  700. {
  701. return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
  702. }
  703. const auto index = std::distance(current.controlLogics.cbegin(), logic);
  704. const std::ptrdiff_t target_index = index + offset;
  705. if (target_index < 0
  706. || target_index
  707. >= static_cast<std::ptrdiff_t>(current.controlLogics.size()))
  708. {
  709. return failure(LogicEditorError::InvalidOperation, "控制逻辑已经位于目标边界");
  710. }
  711. HistoryState before = captureState();
  712. Project &project = project_service_.editProject();
  713. std::iter_swap(
  714. project.controlLogics.begin() + index,
  715. project.controlLogics.begin() + target_index);
  716. recordHistory(std::move(before));
  717. return {true, LogicEditorError::None, {}, logic_id};
  718. }
  719. LogicEditorResult LogicEditorService::setLogicEnabled(
  720. const std::string &logic_id, bool enabled)
  721. {
  722. if (findLogic(logic_id) == nullptr)
  723. {
  724. return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
  725. }
  726. const ControlLogic *existing = findLogic(logic_id);
  727. if (existing->enabled == enabled)
  728. {
  729. return {true, LogicEditorError::None, {}, logic_id};
  730. }
  731. HistoryState before = captureState();
  732. Project &project = project_service_.editProject();
  733. auto logic = std::find_if(
  734. project.controlLogics.begin(), project.controlLogics.end(),
  735. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  736. logic->enabled = enabled;
  737. recordHistory(std::move(before));
  738. return {true, LogicEditorError::None, {}, logic_id};
  739. }
  740. LogicEditorResult LogicEditorService::addRung(const std::string &logic_id)
  741. {
  742. const ControlLogic *logic = findLogic(logic_id);
  743. if (logic == nullptr)
  744. {
  745. return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
  746. }
  747. LadderRung rung;
  748. rung.id = makeUniqueRungId(*logic);
  749. rung.name = "网络 " + std::to_string(logic->rungs.size() + 1U);
  750. HistoryState before = captureState();
  751. Project &project = project_service_.editProject();
  752. auto target = std::find_if(
  753. project.controlLogics.begin(), project.controlLogics.end(),
  754. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  755. target->rungs.push_back(std::move(rung));
  756. recordHistory(std::move(before));
  757. return {true, LogicEditorError::None, {}, target->rungs.back().id};
  758. }
  759. LogicEditorResult LogicEditorService::removeRung(
  760. const std::string &logic_id, const std::string &rung_id)
  761. {
  762. const ControlLogic *logic = findLogic(logic_id);
  763. if (logic == nullptr)
  764. {
  765. return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
  766. }
  767. if (findRung(logic_id, rung_id) == nullptr)
  768. {
  769. return failure(LogicEditorError::RungNotFound, "未找到梯形图网络");
  770. }
  771. if (logic->rungs.size() == 1U)
  772. {
  773. return failure(LogicEditorError::InvalidOperation, "控制逻辑至少需要保留一个网络");
  774. }
  775. HistoryState before = captureState();
  776. Project &project = project_service_.editProject();
  777. auto target = std::find_if(
  778. project.controlLogics.begin(), project.controlLogics.end(),
  779. [&logic_id](const ControlLogic &candidate) { return candidate.id == logic_id; });
  780. target->rungs.erase(
  781. std::remove_if(
  782. target->rungs.begin(), target->rungs.end(),
  783. [&rung_id](const LadderRung &rung) { return rung.id == rung_id; }),
  784. target->rungs.end());
  785. recordHistory(std::move(before));
  786. return {true, LogicEditorError::None, {}, rung_id};
  787. }
  788. LogicEditorResult LogicEditorService::updateRungComment(
  789. const std::string &logic_id,
  790. const std::string &rung_id,
  791. const std::string &comment)
  792. {
  793. const LadderRung *rung = findRung(logic_id, rung_id);
  794. if (rung == nullptr)
  795. {
  796. return failure(LogicEditorError::RungNotFound, "未找到梯形图网络");
  797. }
  798. if (rung->comment == comment)
  799. {
  800. return {true, LogicEditorError::None, {}, rung_id};
  801. }
  802. HistoryState before = captureState();
  803. LadderRung &editable = *findEditableRung(
  804. project_service_.editProject(), logic_id, rung_id);
  805. editable.comment = comment;
  806. recordHistory(std::move(before));
  807. return {true, LogicEditorError::None, {}, rung_id};
  808. }
  809. LogicEditorResult LogicEditorService::appendCondition(
  810. const std::string &logic_id,
  811. const std::string &rung_id,
  812. const LogicNodeConfig &config)
  813. {
  814. const ControlLogic *logic = findLogic(logic_id);
  815. if (logic == nullptr || findRung(logic_id, rung_id) == nullptr)
  816. {
  817. return failure(
  818. logic == nullptr ? LogicEditorError::LogicNotFound : LogicEditorError::RungNotFound,
  819. logic == nullptr ? "未找到控制逻辑" : "未找到梯形图网络");
  820. }
  821. if (!isConditionConfig(config))
  822. {
  823. return failure(LogicEditorError::InvalidNode, "梯形图条件不能使用线圈节点");
  824. }
  825. const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config));
  826. ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config));
  827. HistoryState before = captureState();
  828. Project &project = project_service_.editProject();
  829. LadderRung *rung = findEditableRung(project, logic_id, rung_id);
  830. if (!rung->condition.has_value())
  831. {
  832. rung->condition = std::move(leaf);
  833. }
  834. else if (rung->condition->kind == ConditionExpressionKind::Series)
  835. {
  836. rung->condition->children.push_back(std::move(leaf));
  837. }
  838. else
  839. {
  840. rung->condition = makeContainer(
  841. makeUniqueExpressionId(*logic),
  842. ConditionExpressionKind::Series,
  843. std::move(*rung->condition),
  844. std::move(leaf));
  845. }
  846. recordHistory(std::move(before));
  847. return {true, LogicEditorError::None, {}, node_id};
  848. }
  849. LogicEditorResult LogicEditorService::appendWire(
  850. const std::string &logic_id,
  851. const std::string &rung_id,
  852. int column_span)
  853. {
  854. const ControlLogic *logic = findLogic(logic_id);
  855. if (logic == nullptr || findRung(logic_id, rung_id) == nullptr)
  856. {
  857. return failure(
  858. logic == nullptr ? LogicEditorError::LogicNotFound
  859. : LogicEditorError::RungNotFound,
  860. logic == nullptr ? "未找到控制逻辑" : "未找到梯形图网络");
  861. }
  862. WireSegment wire{column_span};
  863. std::string error;
  864. if (!wire.validate(&error))
  865. {
  866. return failure(LogicEditorError::InvalidOperation, error);
  867. }
  868. const std::string wire_id = makeUniqueWireId(*logic);
  869. ConditionExpression leaf = ConditionExpression::fromWire(wire_id, column_span);
  870. HistoryState before = captureState();
  871. LadderRung *rung = findEditableRung(
  872. project_service_.editProject(), logic_id, rung_id);
  873. if (!rung->condition.has_value())
  874. {
  875. rung->condition = std::move(leaf);
  876. }
  877. else if (rung->condition->kind == ConditionExpressionKind::Series)
  878. {
  879. rung->condition->children.push_back(std::move(leaf));
  880. }
  881. else
  882. {
  883. rung->condition = makeContainer(
  884. makeUniqueExpressionId(*logic),
  885. ConditionExpressionKind::Series,
  886. std::move(*rung->condition),
  887. std::move(leaf));
  888. }
  889. recordHistory(std::move(before));
  890. return {true, LogicEditorError::None, {}, wire_id};
  891. }
  892. LogicEditorResult LogicEditorService::insertConditionAfter(
  893. const std::string &logic_id,
  894. const std::string &rung_id,
  895. const std::string &target_node_id,
  896. const LogicNodeConfig &config)
  897. {
  898. const ControlLogic *logic = findLogic(logic_id);
  899. if (logic == nullptr || findRung(logic_id, rung_id) == nullptr)
  900. {
  901. return failure(LogicEditorError::RungNotFound, "未找到梯形图网络");
  902. }
  903. const LadderRung *existing_rung = findRung(logic_id, rung_id);
  904. if (!isConditionConfig(config)
  905. || existing_rung == nullptr
  906. || !existing_rung->condition.has_value()
  907. || findConditionNode(*existing_rung->condition, target_node_id) == nullptr)
  908. {
  909. return failure(LogicEditorError::NodeNotFound, "未找到串联插入目标");
  910. }
  911. const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config));
  912. ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config));
  913. HistoryState before = captureState();
  914. Project &project = project_service_.editProject();
  915. LadderRung *rung = findEditableRung(project, logic_id, rung_id);
  916. ConditionExpression *target = findConditionExpression(*rung->condition, target_node_id);
  917. ConditionExpression *parent = findParentExpression(*rung->condition, target_node_id);
  918. if (parent != nullptr && parent->kind == ConditionExpressionKind::Series)
  919. {
  920. const auto target_iterator = std::find_if(
  921. parent->children.begin(), parent->children.end(),
  922. [&target_node_id](const ConditionExpression &child)
  923. {
  924. return child.id == target_node_id;
  925. });
  926. parent->children.insert(target_iterator + 1, std::move(leaf));
  927. }
  928. else
  929. {
  930. ConditionExpression original = std::move(*target);
  931. *target = makeContainer(
  932. makeUniqueExpressionId(*logic),
  933. ConditionExpressionKind::Series,
  934. std::move(original),
  935. std::move(leaf));
  936. }
  937. recordHistory(std::move(before));
  938. return {true, LogicEditorError::None, {}, node_id};
  939. }
  940. LogicEditorResult LogicEditorService::insertWireAfter(
  941. const std::string &logic_id,
  942. const std::string &rung_id,
  943. const std::string &target_expression_id,
  944. int column_span)
  945. {
  946. const ControlLogic *logic = findLogic(logic_id);
  947. const LadderRung *existing_rung = findRung(logic_id, rung_id);
  948. const ConditionExpression *target = findExpression(
  949. logic_id, rung_id, target_expression_id);
  950. WireSegment wire{column_span};
  951. std::string error;
  952. if (logic == nullptr || existing_rung == nullptr || target == nullptr)
  953. {
  954. return failure(LogicEditorError::ExpressionNotFound, "未找到横线插入位置");
  955. }
  956. if ((target->kind != ConditionExpressionKind::Node
  957. && target->kind != ConditionExpressionKind::Wire)
  958. || !wire.validate(&error))
  959. {
  960. return failure(
  961. LogicEditorError::InvalidOperation,
  962. error.empty() ? "只能在触点或横线后插入横线" : error);
  963. }
  964. const std::string wire_id = makeUniqueWireId(*logic);
  965. ConditionExpression leaf = ConditionExpression::fromWire(wire_id, column_span);
  966. HistoryState before = captureState();
  967. LadderRung *rung = findEditableRung(
  968. project_service_.editProject(), logic_id, rung_id);
  969. ConditionExpression *editable_target = findConditionExpression(
  970. *rung->condition, target_expression_id);
  971. ConditionExpression *parent = findParentExpression(
  972. *rung->condition, target_expression_id);
  973. if (parent != nullptr && parent->kind == ConditionExpressionKind::Series)
  974. {
  975. const auto target_iterator = std::find_if(
  976. parent->children.begin(), parent->children.end(),
  977. [&target_expression_id](const ConditionExpression &child)
  978. {
  979. return child.id == target_expression_id;
  980. });
  981. parent->children.insert(target_iterator + 1, std::move(leaf));
  982. }
  983. else
  984. {
  985. ConditionExpression original = std::move(*editable_target);
  986. *editable_target = makeContainer(
  987. makeUniqueExpressionId(*logic),
  988. ConditionExpressionKind::Series,
  989. std::move(original),
  990. std::move(leaf));
  991. }
  992. recordHistory(std::move(before));
  993. return {true, LogicEditorError::None, {}, wire_id};
  994. }
  995. LogicEditorResult LogicEditorService::replaceWireWithCondition(
  996. const std::string &logic_id,
  997. const std::string &rung_id,
  998. const std::string &wire_expression_id,
  999. const LogicNodeConfig &config)
  1000. {
  1001. const ControlLogic *logic = findLogic(logic_id);
  1002. const ConditionExpression *wire = findExpression(
  1003. logic_id, rung_id, wire_expression_id);
  1004. if (logic == nullptr || wire == nullptr
  1005. || wire->kind != ConditionExpressionKind::Wire)
  1006. {
  1007. return failure(LogicEditorError::ExpressionNotFound, "未找到要替换的横线");
  1008. }
  1009. if (!isConditionConfig(config))
  1010. {
  1011. return failure(LogicEditorError::InvalidNode, "横线只能替换为条件节点");
  1012. }
  1013. const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config));
  1014. HistoryState before = captureState();
  1015. LadderRung *rung = findEditableRung(
  1016. project_service_.editProject(), logic_id, rung_id);
  1017. ConditionExpression *editable = findConditionExpression(
  1018. *rung->condition, wire_expression_id);
  1019. *editable = ConditionExpression::fromNode(makeNode(node_id, config));
  1020. recordHistory(std::move(before));
  1021. return {true, LogicEditorError::None, {}, node_id};
  1022. }
  1023. LogicEditorResult LogicEditorService::addParallelBranch(
  1024. const std::string &logic_id,
  1025. const std::string &rung_id,
  1026. const std::vector<std::string> &selected_node_ids,
  1027. const LogicNodeConfig &config)
  1028. {
  1029. const ControlLogic *logic = findLogic(logic_id);
  1030. if (logic == nullptr || findRung(logic_id, rung_id) == nullptr)
  1031. {
  1032. return failure(LogicEditorError::RungNotFound, "未找到梯形图网络");
  1033. }
  1034. if (!isConditionConfig(config) || selected_node_ids.empty())
  1035. {
  1036. return failure(LogicEditorError::InvalidOperation, "建立并联支路前必须选择节点");
  1037. }
  1038. const LadderRung *existing_rung = findRung(logic_id, rung_id);
  1039. if (!existing_rung->condition.has_value())
  1040. {
  1041. return failure(LogicEditorError::InvalidOperation, "梯形图网络尚无条件节点");
  1042. }
  1043. NodeIdSet selected_ids(selected_node_ids.cbegin(), selected_node_ids.cend());
  1044. if (selected_ids.size() != selected_node_ids.size())
  1045. {
  1046. return failure(
  1047. LogicEditorError::InvalidOperation,
  1048. "并联选择中存在重复节点");
  1049. }
  1050. const NodeIdSet available_ids = conditionLeafIds(*existing_rung->condition);
  1051. if (!isSubset(selected_ids, available_ids))
  1052. {
  1053. return failure(
  1054. LogicEditorError::NodeNotFound,
  1055. "并联选择中包含未知节点");
  1056. }
  1057. const std::string node_id = makeUniqueNodeId(*logic, nodePrefix(config));
  1058. ConditionExpression leaf = ConditionExpression::fromNode(makeNode(node_id, config));
  1059. const std::string parallel_id = makeUniqueExpressionId(*logic);
  1060. std::string series_id = parallel_id + "-range";
  1061. while (findExpression(logic_id, rung_id, series_id) != nullptr)
  1062. {
  1063. series_id += "-range";
  1064. }
  1065. HistoryState before = captureState();
  1066. Project &project = project_service_.editProject();
  1067. LadderRung *rung = findEditableRung(project, logic_id, rung_id);
  1068. if (!addParallelForSelection(
  1069. &*rung->condition,
  1070. selected_ids,
  1071. &leaf,
  1072. parallel_id,
  1073. series_id))
  1074. {
  1075. return failure(
  1076. LogicEditorError::InvalidOperation,
  1077. "并联选择必须是一个连续的逻辑范围");
  1078. }
  1079. recordHistory(std::move(before));
  1080. return {true, LogicEditorError::None, {}, node_id};
  1081. }
  1082. LogicEditorResult LogicEditorService::addParallelWireBranch(
  1083. const std::string &logic_id,
  1084. const std::string &rung_id,
  1085. const std::vector<std::string> &selected_expression_ids)
  1086. {
  1087. const ControlLogic *logic = findLogic(logic_id);
  1088. const LadderRung *existing_rung = findRung(logic_id, rung_id);
  1089. if (logic == nullptr || existing_rung == nullptr
  1090. || !existing_rung->condition.has_value())
  1091. {
  1092. return failure(LogicEditorError::RungNotFound, "未找到梯形图条件网络");
  1093. }
  1094. if (selected_expression_ids.empty())
  1095. {
  1096. return failure(
  1097. LogicEditorError::InvalidOperation,
  1098. "建立竖线连接前必须选择连续的触点或横线");
  1099. }
  1100. NodeIdSet selected_ids(
  1101. selected_expression_ids.cbegin(), selected_expression_ids.cend());
  1102. if (selected_ids.size() != selected_expression_ids.size())
  1103. {
  1104. return failure(LogicEditorError::InvalidOperation, "并联选择中存在重复对象");
  1105. }
  1106. const NodeIdSet available_ids = conditionLeafIds(*existing_rung->condition);
  1107. if (!isSubset(selected_ids, available_ids))
  1108. {
  1109. return failure(LogicEditorError::ExpressionNotFound, "并联选择中包含未知对象");
  1110. }
  1111. const std::optional<int> column_span = selectedExpressionColumns(
  1112. *existing_rung->condition, selected_ids);
  1113. if (!column_span.has_value()
  1114. || *column_span > WireSegment::kMaximumColumnSpan)
  1115. {
  1116. return failure(
  1117. LogicEditorError::InvalidOperation,
  1118. "竖线连接只能围绕同一支路中的连续逻辑范围");
  1119. }
  1120. const std::string wire_id = makeUniqueWireId(*logic);
  1121. ConditionExpression wire = ConditionExpression::fromWire(
  1122. wire_id, *column_span);
  1123. const std::string parallel_id = makeUniqueExpressionId(*logic);
  1124. std::string series_id = parallel_id + "-range";
  1125. while (findExpression(logic_id, rung_id, series_id) != nullptr)
  1126. {
  1127. series_id += "-range";
  1128. }
  1129. HistoryState before = captureState();
  1130. LadderRung *rung = findEditableRung(
  1131. project_service_.editProject(), logic_id, rung_id);
  1132. if (!addParallelForSelection(
  1133. &*rung->condition,
  1134. selected_ids,
  1135. &wire,
  1136. parallel_id,
  1137. series_id))
  1138. {
  1139. return failure(
  1140. LogicEditorError::InvalidOperation,
  1141. "竖线连接只能围绕同一支路中的连续逻辑范围");
  1142. }
  1143. recordHistory(std::move(before));
  1144. return {true, LogicEditorError::None, {}, wire_id};
  1145. }
  1146. LogicEditorResult LogicEditorService::setOutput(
  1147. const std::string &logic_id,
  1148. const std::string &rung_id,
  1149. const LogicNodeConfig &config,
  1150. bool configured)
  1151. {
  1152. const ControlLogic *logic = findLogic(logic_id);
  1153. const LadderRung *existing_rung = findRung(logic_id, rung_id);
  1154. if (logic == nullptr || existing_rung == nullptr || !isOutputConfig(config))
  1155. {
  1156. return failure(
  1157. LogicEditorError::InvalidNode,
  1158. "梯形图输出必须使用有效的输出指令");
  1159. }
  1160. const std::string node_id = existing_rung->output.has_value()
  1161. ? existing_rung->output->id : makeUniqueNodeId(*logic, nodePrefix(config));
  1162. LogicNode node = makeNode(node_id, config);
  1163. node.configured = configured;
  1164. if (existing_rung->output.has_value()
  1165. && nodesEqual(*existing_rung->output, node))
  1166. {
  1167. return {true, LogicEditorError::None, {}, node_id};
  1168. }
  1169. HistoryState before = captureState();
  1170. Project &project = project_service_.editProject();
  1171. findEditableRung(project, logic_id, rung_id)->output = std::move(node);
  1172. recordHistory(std::move(before));
  1173. return {true, LogicEditorError::None, {}, node_id};
  1174. }
  1175. LogicEditorResult LogicEditorService::updateNodeConfig(
  1176. const std::string &logic_id,
  1177. const std::string &node_id,
  1178. const LogicNodeConfig &config)
  1179. {
  1180. const LogicNode *node = findNode(logic_id, node_id);
  1181. if (node == nullptr)
  1182. {
  1183. return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点");
  1184. }
  1185. if (node->config.index() != config.index())
  1186. {
  1187. return failure(
  1188. LogicEditorError::UnsupportedNodeChange,
  1189. "节点创建后不能修改节点类别");
  1190. }
  1191. LogicNode candidate{node_id, config, true};
  1192. std::string error;
  1193. if (!candidate.validate(&error))
  1194. {
  1195. return failure(LogicEditorError::InvalidNode, error);
  1196. }
  1197. if (nodesEqual(*node, candidate))
  1198. {
  1199. return {true, LogicEditorError::None, {}, node_id};
  1200. }
  1201. HistoryState before = captureState();
  1202. Project &project = project_service_.editProject();
  1203. for (ControlLogic &logic : project.controlLogics)
  1204. {
  1205. if (logic.id != logic_id)
  1206. {
  1207. continue;
  1208. }
  1209. for (LadderRung &rung : logic.rungs)
  1210. {
  1211. if (rung.output.has_value() && rung.output->id == node_id)
  1212. {
  1213. *rung.output = candidate;
  1214. recordHistory(std::move(before));
  1215. return {true, LogicEditorError::None, {}, node_id};
  1216. }
  1217. if (rung.condition.has_value())
  1218. {
  1219. if (LogicNode *editable = findConditionNode(*rung.condition, node_id))
  1220. {
  1221. *editable = candidate;
  1222. recordHistory(std::move(before));
  1223. return {true, LogicEditorError::None, {}, node_id};
  1224. }
  1225. }
  1226. }
  1227. }
  1228. return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点");
  1229. }
  1230. LogicEditorResult LogicEditorService::removeNode(
  1231. const std::string &logic_id, const std::string &node_id)
  1232. {
  1233. return removeNodes(logic_id, {node_id});
  1234. }
  1235. LogicEditorResult LogicEditorService::removeNodes(
  1236. const std::string &logic_id,
  1237. const std::vector<std::string> &node_ids)
  1238. {
  1239. if (findLogic(logic_id) == nullptr)
  1240. {
  1241. return failure(LogicEditorError::LogicNotFound, "未找到控制逻辑");
  1242. }
  1243. if (node_ids.empty())
  1244. {
  1245. return failure(LogicEditorError::InvalidOperation, "请先选择要删除的逻辑节点");
  1246. }
  1247. std::unordered_set<std::string> selected_ids;
  1248. for (const std::string &node_id : node_ids)
  1249. {
  1250. if (!selected_ids.insert(node_id).second)
  1251. {
  1252. return failure(LogicEditorError::InvalidOperation, "删除列表中存在重复节点");
  1253. }
  1254. if (findNode(logic_id, node_id) == nullptr)
  1255. {
  1256. return failure(LogicEditorError::NodeNotFound, "未找到逻辑节点");
  1257. }
  1258. }
  1259. HistoryState before = captureState();
  1260. Project &project = project_service_.editProject();
  1261. ControlLogic *editable_logic = nullptr;
  1262. for (ControlLogic &candidate : project.controlLogics)
  1263. {
  1264. if (candidate.id == logic_id)
  1265. {
  1266. editable_logic = &candidate;
  1267. break;
  1268. }
  1269. }
  1270. for (LadderRung &rung : editable_logic->rungs)
  1271. {
  1272. if (rung.output.has_value()
  1273. && selected_ids.find(rung.output->id) != selected_ids.end())
  1274. {
  1275. rung.output.reset();
  1276. }
  1277. if (rung.condition.has_value())
  1278. {
  1279. for (const std::string &node_id : node_ids)
  1280. {
  1281. if (rung.condition->kind == ConditionExpressionKind::Node
  1282. && rung.condition->id == node_id)
  1283. {
  1284. rung.condition.reset();
  1285. break;
  1286. }
  1287. removeExpressionRecursive(&*rung.condition, node_id);
  1288. }
  1289. if (rung.condition.has_value())
  1290. {
  1291. normalizeConditionExpression(&rung.condition);
  1292. }
  1293. }
  1294. }
  1295. recordHistory(std::move(before));
  1296. return {true, LogicEditorError::None, {}, node_ids.front()};
  1297. }
  1298. LogicEditorResult LogicEditorService::removeExpression(
  1299. const std::string &logic_id,
  1300. const std::string &rung_id,
  1301. const std::string &expression_id)
  1302. {
  1303. if (findExpression(logic_id, rung_id, expression_id) == nullptr)
  1304. {
  1305. return failure(LogicEditorError::ExpressionNotFound, "未找到条件支路");
  1306. }
  1307. HistoryState before = captureState();
  1308. Project &project = project_service_.editProject();
  1309. LadderRung *rung = findEditableRung(project, logic_id, rung_id);
  1310. if (rung->condition->id == expression_id)
  1311. {
  1312. rung->condition.reset();
  1313. }
  1314. else
  1315. {
  1316. removeExpressionRecursive(&*rung->condition, expression_id);
  1317. normalizeConditionExpression(&rung->condition);
  1318. }
  1319. recordHistory(std::move(before));
  1320. return {true, LogicEditorError::None, {}, expression_id};
  1321. }
  1322. LogicEditorResult LogicEditorService::removeExpressions(
  1323. const std::string &logic_id,
  1324. const std::string &rung_id,
  1325. const std::vector<std::string> &expression_ids)
  1326. {
  1327. const LadderRung *existing_rung = findRung(logic_id, rung_id);
  1328. if (existing_rung == nullptr || !existing_rung->condition.has_value())
  1329. {
  1330. return failure(LogicEditorError::RungNotFound, "未找到梯形图条件网络");
  1331. }
  1332. if (expression_ids.empty())
  1333. {
  1334. return failure(LogicEditorError::InvalidOperation, "请先选择要删除的条件或横线");
  1335. }
  1336. NodeIdSet unique_ids;
  1337. for (const std::string &expression_id : expression_ids)
  1338. {
  1339. const ConditionExpression *expression = findExpression(
  1340. logic_id, rung_id, expression_id);
  1341. if (!unique_ids.insert(expression_id).second)
  1342. {
  1343. return failure(LogicEditorError::InvalidOperation, "删除列表中存在重复对象");
  1344. }
  1345. if (expression == nullptr)
  1346. {
  1347. return failure(
  1348. LogicEditorError::ExpressionNotFound,
  1349. "删除列表中包含未知条件表达式");
  1350. }
  1351. }
  1352. HistoryState before = captureState();
  1353. LadderRung *rung = findEditableRung(
  1354. project_service_.editProject(), logic_id, rung_id);
  1355. for (const std::string &expression_id : expression_ids)
  1356. {
  1357. if (!rung->condition.has_value())
  1358. {
  1359. break;
  1360. }
  1361. if (rung->condition->id == expression_id)
  1362. {
  1363. rung->condition.reset();
  1364. break;
  1365. }
  1366. removeExpressionRecursive(&*rung->condition, expression_id);
  1367. }
  1368. normalizeConditionExpression(&rung->condition);
  1369. recordHistory(std::move(before));
  1370. return {true, LogicEditorError::None, {}, expression_ids.front()};
  1371. }
  1372. bool LogicEditorService::canUndo() const
  1373. {
  1374. return history_.canUndo();
  1375. }
  1376. bool LogicEditorService::canRedo() const
  1377. {
  1378. return history_.canRedo();
  1379. }
  1380. LogicEditorResult LogicEditorService::undo()
  1381. {
  1382. const std::optional<HistoryState> target = history_.undo(captureState());
  1383. if (!target.has_value())
  1384. {
  1385. return historyFailure("没有可撤销的梯形图编辑操作");
  1386. }
  1387. project_service_.editProject().controlLogics = target->logics;
  1388. return {true, LogicEditorError::None, {}, {}};
  1389. }
  1390. LogicEditorResult LogicEditorService::redo()
  1391. {
  1392. const std::optional<HistoryState> target = history_.redo(captureState());
  1393. if (!target.has_value())
  1394. {
  1395. return historyFailure("没有可重做的梯形图编辑操作");
  1396. }
  1397. project_service_.editProject().controlLogics = target->logics;
  1398. return {true, LogicEditorError::None, {}, {}};
  1399. }
  1400. void LogicEditorService::clearHistory()
  1401. {
  1402. history_.clear();
  1403. }
  1404. bool LogicEditorService::isConditionConfig(const LogicNodeConfig &config)
  1405. {
  1406. return std::holds_alternative<ContactNodeConfig>(config)
  1407. || std::holds_alternative<EdgeContactNodeConfig>(config)
  1408. || std::holds_alternative<TimerContactNodeConfig>(config)
  1409. || std::holds_alternative<CounterContactNodeConfig>(config)
  1410. || std::holds_alternative<CompareNodeConfig>(config);
  1411. }
  1412. bool LogicEditorService::isOutputConfig(const LogicNodeConfig &config)
  1413. {
  1414. return std::holds_alternative<CoilNodeConfig>(config)
  1415. || std::holds_alternative<TonNodeConfig>(config)
  1416. || std::holds_alternative<CounterNodeConfig>(config)
  1417. || std::holds_alternative<MoveNodeConfig>(config)
  1418. || std::holds_alternative<ArithmeticNodeConfig>(config);
  1419. }
  1420. std::string LogicEditorService::nodePrefix(const LogicNodeConfig &config)
  1421. {
  1422. return std::visit(
  1423. [](const auto &value) -> std::string
  1424. {
  1425. using Config = std::decay_t<decltype(value)>;
  1426. if constexpr (std::is_same_v<Config, ContactNodeConfig>)
  1427. {
  1428. return "contact";
  1429. }
  1430. else if constexpr (std::is_same_v<Config, EdgeContactNodeConfig>)
  1431. {
  1432. return "edge";
  1433. }
  1434. else if constexpr (std::is_same_v<Config, TimerContactNodeConfig>)
  1435. {
  1436. return "timer-contact";
  1437. }
  1438. else if constexpr (std::is_same_v<Config, CounterContactNodeConfig>)
  1439. {
  1440. return "counter-contact";
  1441. }
  1442. else if constexpr (std::is_same_v<Config, CoilNodeConfig>)
  1443. {
  1444. return "coil";
  1445. }
  1446. else if constexpr (std::is_same_v<Config, TonNodeConfig>)
  1447. {
  1448. return "ton";
  1449. }
  1450. else if constexpr (std::is_same_v<Config, CounterNodeConfig>)
  1451. {
  1452. return "counter";
  1453. }
  1454. else if constexpr (std::is_same_v<Config, MoveNodeConfig>)
  1455. {
  1456. return "move";
  1457. }
  1458. else if constexpr (std::is_same_v<Config, ArithmeticNodeConfig>)
  1459. {
  1460. return "arithmetic";
  1461. }
  1462. else
  1463. {
  1464. return "compare";
  1465. }
  1466. },
  1467. config);
  1468. }
  1469. std::string LogicEditorService::makeUniqueNodeId(
  1470. const ControlLogic &logic, const std::string &prefix)
  1471. {
  1472. for (std::size_t index = 1;; ++index)
  1473. {
  1474. const std::string candidate = prefix + '-' + std::to_string(index);
  1475. bool found = false;
  1476. for (const LadderRung &rung : logic.rungs)
  1477. {
  1478. found = found || (rung.output.has_value() && rung.output->id == candidate)
  1479. || (rung.condition.has_value()
  1480. && findConditionNode(*rung.condition, candidate) != nullptr);
  1481. }
  1482. if (!found)
  1483. {
  1484. return candidate;
  1485. }
  1486. }
  1487. }
  1488. std::string LogicEditorService::makeUniqueWireId(const ControlLogic &logic)
  1489. {
  1490. for (std::size_t index = 1;; ++index)
  1491. {
  1492. const std::string candidate = "wire-" + std::to_string(index);
  1493. const bool found = std::any_of(
  1494. logic.rungs.cbegin(), logic.rungs.cend(),
  1495. [&candidate](const LadderRung &rung)
  1496. {
  1497. return rung.condition.has_value()
  1498. && findConditionExpression(*rung.condition, candidate) != nullptr;
  1499. });
  1500. if (!found)
  1501. {
  1502. return candidate;
  1503. }
  1504. }
  1505. }
  1506. std::string LogicEditorService::makeUniqueExpressionId(const ControlLogic &logic)
  1507. {
  1508. for (std::size_t index = 1;; ++index)
  1509. {
  1510. const std::string candidate = "expression-" + std::to_string(index);
  1511. bool found = false;
  1512. for (const LadderRung &rung : logic.rungs)
  1513. {
  1514. found = found || (rung.condition.has_value()
  1515. && findConditionExpression(*rung.condition, candidate) != nullptr);
  1516. }
  1517. if (!found)
  1518. {
  1519. return candidate;
  1520. }
  1521. }
  1522. }
  1523. std::string LogicEditorService::makeUniqueRungId(const ControlLogic &logic)
  1524. {
  1525. for (std::size_t index = 1;; ++index)
  1526. {
  1527. const std::string candidate = "rung-" + std::to_string(index);
  1528. if (std::none_of(
  1529. logic.rungs.cbegin(), logic.rungs.cend(),
  1530. [&candidate](const LadderRung &rung) { return rung.id == candidate; }))
  1531. {
  1532. return candidate;
  1533. }
  1534. }
  1535. }
  1536. LogicEditorResult LogicEditorService::failure(
  1537. LogicEditorError error, const std::string &message)
  1538. {
  1539. return {false, error, message, {}};
  1540. }