| 521 | } |
| 522 | |
| 523 | void mitk::Label::AddToolUse(AlgorithmType algoType, const std::string& algoName) |
| 524 | { |
| 525 | if (algoName.empty()) // nothing to record; leave the existing provenance untouched |
| 526 | return; |
| 527 | |
| 528 | // Keep the provenance string parseable: TOOL_SEPARATOR ("|") and PREFIX_SEPARATOR (": ") are |
| 529 | // reserved. Throwing here would be too late (this runs at the writeback choke point, after pixels |
| 530 | // are committed, and the throw would skip undo registration), so instead neutralize the separator |
| 531 | // characters and warn. Tool authors are pointed at this constraint in Tool::GetName(). |
| 532 | std::string sanitized = algoName; |
| 533 | std::replace(sanitized.begin(), sanitized.end(), '|', '#'); |
| 534 | std::replace(sanitized.begin(), sanitized.end(), ':', '#'); |
| 535 | if (sanitized != algoName) |
| 536 | MITK_WARN << "Label::AddToolUse: tool name \"" << algoName << "\" contains reserved separator " |
| 537 | "characters ('|' or ':'); recorded as \"" << sanitized << "\" to keep the provenance " |
| 538 | "string parseable."; |
| 539 | |
| 540 | std::string currentName = this->GetAlgorithmName(); // MITK prefix only for internally-created names |
| 541 | // An empty stored name (e.g. a legacy persisted empty algorithm_name property, which the native-JSON |
| 542 | // reader restores verbatim via SetProperty) is equivalent to "no name recorded": normalize it to the |
| 543 | // bare prefix so the first tool is appended as "MITK Segmentation: <tool>" rather than "|<tool>". |
| 544 | if (currentName.empty()) |
| 545 | currentName = DEFAULT_ALGORITHM_NAME; |
| 546 | |
| 547 | // A name equal to just the prefix means no dedicated tool has been recorded yet (the construction- |
| 548 | // default state), so the first tool's name is appended after the prefix separator. |
| 549 | const bool noToolRecorded = (currentName == DEFAULT_ALGORITHM_NAME); |
| 550 | |
| 551 | // The first contribution to a still-Undefined label defines its type. Any type already present |
| 552 | // (a genuine MANUAL loaded from a DICOM SEG, or a prior tool's type) is real provenance: preserve |
| 553 | // it, and mix to SEMIAUTOMATIC when a later tool of a different type contributes. |
| 554 | const auto currentType = this->GetAlgorithmType(); |
| 555 | if (currentType == AlgorithmType::Undefined) |
| 556 | this->SetAlgorithmType(algoType); |
| 557 | else if (currentType != algoType) |
| 558 | this->SetAlgorithmType(AlgorithmType::SEMIAUTOMATIC); // mixed tool types |
| 559 | |
| 560 | if (!ToolAlreadyRecorded(currentName, sanitized)) // keep the prefix, append the dedicated tool |
| 561 | this->SetAlgorithmName(currentName + (noToolRecorded ? PREFIX_SEPARATOR : TOOL_SEPARATOR) + sanitized); |
| 562 | } |
| 563 | |
| 564 | void mitk::Label::MergeToolUses(const Label* other) |
| 565 | { |