# HG changeset patch # User Sebastien Jodogne # Date 1603294397 -7200 # Node ID bd180f97c734675fed0446cf9d685e5f6d7057e2 # Parent c8644706e78b79732bfa4d0fde333b892978b41b parsing osirix annotations diff -r c8644706e78b -r bd180f97c734 OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake --- a/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake Tue Oct 20 20:21:21 2020 +0200 +++ b/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake Wed Oct 21 17:33:17 2020 +0200 @@ -270,6 +270,21 @@ endif() +if (ENABLE_PUGIXML) + list(APPEND ORTHANC_STONE_SOURCES + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/AngleAnnotation.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/Annotation.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/ArrayValue.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/CollectionOfAnnotations.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/DictionaryValue.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/IValue.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/LineAnnotation.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/StringValue.cpp + ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OsiriX/TextAnnotation.cpp + ) +endif() + + list(APPEND ORTHANC_STONE_SOURCES ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OrthancDatasets/DicomDatasetReader.cpp ${ORTHANC_STONE_ROOT}/Sources/Toolbox/OrthancDatasets/DicomPath.cpp diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/AngleAnnotation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/AngleAnnotation.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,60 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "AngleAnnotation.h" + +#include "ArrayValue.h" +#include "IntegerValue.h" +#include "StringValue.h" + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + AngleAnnotation::AngleAnnotation(const DictionaryValue& dict) + { + SetupCommon(dict); + + const IntegerValue& number = dynamic_cast(dict.GetValue("NumberOfPoints")); + const ArrayValue& points = dynamic_cast(dict.GetValue("Point_mm")); + + if (number.GetValue() != 3 || + points.GetSize() != 3) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + dynamic_cast(points.GetValue(0)).ParseVector(a_); + dynamic_cast(points.GetValue(1)).ParseVector(center_); + dynamic_cast(points.GetValue(2)).ParseVector(b_); + + if (a_.size() != 3u || + center_.size() != 3u || + b_.size() != 3u) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/AngleAnnotation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/AngleAnnotation.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,64 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "Annotation.h" + +#include "../LinearAlgebra.h" // For "Vector" + + +namespace OrthancStone +{ + namespace OsiriX + { + class AngleAnnotation : public Annotation + { + private: + Vector a_; + Vector center_; + Vector b_; + + public: + AngleAnnotation(const DictionaryValue& dict); + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Angle; + } + + const Vector& GetA() const + { + return a_; + } + + const Vector& GetB() const + { + return b_; + } + + const Vector& GetCenter() const + { + return center_; + } + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/Annotation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/Annotation.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,104 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "Annotation.h" + +#include "AngleAnnotation.h" +#include "IntegerValue.h" +#include "LineAnnotation.h" +#include "StringValue.h" +#include "TextAnnotation.h" + +#include + +namespace OrthancStone +{ + namespace OsiriX + { + void Annotation::SetupCommon(const DictionaryValue& dict) + { + const IValue* value = dict.LookupValue("Name"); + if (value == NULL) + { + name_.clear(); + } + else + { + name_ = dynamic_cast(*value).GetValue(); + } + + value = dict.LookupValue("StudyInstanceUID"); + if (value == NULL) + { + studyInstanceUid_.clear(); + } + else + { + studyInstanceUid_ = dynamic_cast(*value).GetValue(); + } + + value = dict.LookupValue("SeriesInstanceUID"); + if (value == NULL) + { + seriesInstanceUid_.clear(); + } + else + { + seriesInstanceUid_ = dynamic_cast(*value).GetValue(); + } + + value = dict.LookupValue("SOPInstanceUID"); + if (value == NULL) + { + sopInstanceUid_.clear(); + } + else + { + sopInstanceUid_ = dynamic_cast(*value).GetValue(); + } + } + + + Annotation* Annotation::Create(const DictionaryValue& dict) + { + const IntegerValue& type = dynamic_cast(dict.GetValue("Type")); + + switch (type.GetValue()) + { + case 5: + return new LineAnnotation(dict, false); + + case 12: + return new AngleAnnotation(dict); + + case 13: + return new TextAnnotation(dict); + + case 14: + return new LineAnnotation(dict, true); + + default: + LOG(WARNING) << "Unsupported OsiriX annotation type: " << type.GetValue(); + return NULL; + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/Annotation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/Annotation.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,79 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "DictionaryValue.h" + + +namespace OrthancStone +{ + namespace OsiriX + { + class Annotation : public boost::noncopyable + { + private: + std::string name_; + std::string studyInstanceUid_; + std::string seriesInstanceUid_; + std::string sopInstanceUid_; + + protected: + void SetupCommon(const DictionaryValue& dict); + + public: + enum Type + { + Type_Angle, + Type_Line, + Type_Text + }; + + virtual ~Annotation() + { + } + + virtual Type GetType() const = 0; + + const std::string& GetName() const + { + return name_; + } + + const std::string& GetStudyInstanceUid() const + { + return studyInstanceUid_; + } + + const std::string& GetSeriesInstanceUid() const + { + return seriesInstanceUid_; + } + + const std::string& GetSopInstanceUid() const + { + return sopInstanceUid_; + } + + static Annotation* Create(const DictionaryValue& dict); + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/ArrayValue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/ArrayValue.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,67 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "ArrayValue.h" + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + ArrayValue::~ArrayValue() + { + for (size_t i = 0; i < content_.size(); i++) + { + assert(content_[i] != NULL); + delete content_[i]; + } + } + + + void ArrayValue::Append(IValue* item) // Takes ownership + { + if (item == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + content_.push_back(item); + } + } + + + const IValue& ArrayValue::GetValue(size_t i) const + { + if (i >= content_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + else + { + assert(content_[i] != NULL); + return *content_[i]; + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/ArrayValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/ArrayValue.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,62 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "IValue.h" + +#include + +#include + +namespace OrthancStone +{ + namespace OsiriX + { + class ArrayValue : public IValue + { + private: + std::vector content_; + + public: + virtual ~ArrayValue(); + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Array; + } + + void Append(IValue* item); // Takes ownership + + void Reserve(size_t n) + { + content_.reserve(n); + } + + size_t GetSize() const + { + return content_.size(); + } + + const IValue& GetValue(size_t i) const; + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/CollectionOfAnnotations.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/CollectionOfAnnotations.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,145 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "CollectionOfAnnotations.h" + +#include "ArrayValue.h" +#include "IntegerValue.h" + +#include + +#include + +namespace OrthancStone +{ + namespace OsiriX + { + static void GetAttributes(std::map& target, + const pugi::xml_node& node) + { + for (pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) + { + target[attr.name()] = attr.value(); + } + } + + + CollectionOfAnnotations::~CollectionOfAnnotations() + { + for (size_t i = 0; i < annotations_.size(); i++) + { + assert(annotations_[i] != NULL); + delete annotations_[i]; + } + } + + + const Annotation& CollectionOfAnnotations::GetAnnotation(size_t i) const + { + if (i >= annotations_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + else + { + assert(annotations_[i] != NULL); + return *annotations_[i]; + } + } + + + void CollectionOfAnnotations::AddAnnotation(Annotation* annotation) + { + if (annotation == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + annotations_.push_back(annotation); + } + } + + void CollectionOfAnnotations::ParseXml(const std::string& xml) + { + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_buffer(xml.empty() ? NULL : xml.c_str(), xml.size()); + if (!result) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + const pugi::xml_node& root = doc.document_element(); + if (std::string(root.name()) != "plist" || + !root.first_child() || + root.first_child() != root.last_child()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + std::map attributes; + GetAttributes(attributes, root); + + std::map::const_iterator version = attributes.find("version"); + if (version == attributes.end() || + version->second != "1.0") + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + std::unique_ptr value(IValue::Parse(root.first_child())); + + const DictionaryValue& dict = dynamic_cast(*value); + + std::set annotations; + dict.GetMembers(annotations); + + for (std::set::const_iterator + it = annotations.begin(); it != annotations.end(); ++it) + { + const ArrayValue& images = dynamic_cast(dict.GetValue(*it)); + + for (size_t i = 0; i < images.GetSize(); i++) + { + const DictionaryValue& image = dynamic_cast(images.GetValue(i)); + const IntegerValue& number = dynamic_cast(image.GetValue("NumberOfROIs")); + const ArrayValue& rois = dynamic_cast(image.GetValue("ROIs")); + + if (static_cast(rois.GetSize()) != number.GetValue()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + for (size_t j = 0; j < rois.GetSize(); j++) + { + const DictionaryValue& roi = dynamic_cast(rois.GetValue(i)); + + std::unique_ptr annotation(Annotation::Create(roi)); + if (annotation.get() != NULL) + { + AddAnnotation(annotation.release()); + } + } + } + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/CollectionOfAnnotations.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/CollectionOfAnnotations.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,53 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "Annotation.h" + +#include + +namespace OrthancStone +{ + namespace OsiriX + { + class CollectionOfAnnotations : public boost::noncopyable + { + private: + std::vector annotations_; + + public: + ~CollectionOfAnnotations(); + + size_t GetSize() const + { + return annotations_.size(); + } + + const Annotation& GetAnnotation(size_t i) const; + + void AddAnnotation(Annotation* annotation); // takes ownership + + // Parse an XML from OsiriX + void ParseXml(const std::string& xml); + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/DictionaryValue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/DictionaryValue.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,108 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "DictionaryValue.h" + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + DictionaryValue::~DictionaryValue() + { + for (Content::iterator it = content_.begin(); it != content_.end(); ++it) + { + assert(it->second != NULL); + delete it->second; + } + } + + + void DictionaryValue::SetValue(const std::string& key, + IValue* value /* takes ownership */) + { + if (value == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + std::unique_ptr protection(value); + + Content::iterator found = content_.find(key); + if (found == content_.end()) + { + content_[key] = protection.release(); + } + else + { + assert(found->second != NULL); + delete found->second; + found->second = protection.release(); + } + } + } + + + const IValue* DictionaryValue::LookupValue(const std::string& key) const + { + Content::const_iterator found = content_.find(key); + + if (found == content_.end()) + { + return NULL; + } + else + { + assert(found->second != NULL); + return found->second; + } + } + + + const IValue& DictionaryValue::GetValue(const std::string& key) const + { + const IValue* value = LookupValue(key); + if (value == NULL) + { + // "HasValue()" should have been called + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return *value; + } + } + + + void DictionaryValue::GetMembers(std::set& target) const + { + target.clear(); + + for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) + { + target.insert(it->first); + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/DictionaryValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/DictionaryValue.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,68 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "IValue.h" + +#include + +#include +#include +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + class DictionaryValue : public IValue + { + private: + typedef std::map Content; + + Content content_; + + public: + virtual ~DictionaryValue(); + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Dictionary; + } + + void SetValue(const std::string& key, + IValue* value /* takes ownership */); + + // Will return "false" if no such item + const IValue* LookupValue(const std::string& key) const; + + bool HasValue(const std::string& key) const + { + return LookupValue(key) != NULL; + } + + const IValue& GetValue(const std::string& key) const; + + void GetMembers(std::set& target) const; + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/IValue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/IValue.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,119 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "ArrayValue.h" +#include "DictionaryValue.h" +#include "IntegerValue.h" +#include "RealValue.h" +#include "StringValue.h" + +#include +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + IValue* IValue::Parse(const pugi::xml_node& node) + { + const std::string name(node.name()); + + if (name == "dict") + { + std::unique_ptr dict(new DictionaryValue); + + for (pugi::xml_node child = node.first_child(); child; child = child.next_sibling()) + { + const std::string name2(child.name()); + + if (name2 != "key" || + child.text().get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + const std::string key(child.text().get()); + + child = child.next_sibling(); + if (!child) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + dict->SetValue(key, IValue::Parse(child)); + } + + return dict.release(); + } + else if (name == "array") + { + std::unique_ptr array(new ArrayValue); + + for (pugi::xml_node child = node.first_child(); child; child = child.next_sibling()) + { + array->Append(IValue::Parse(child)); + } + + return array.release(); + } + else if (name == "integer") + { + const std::string s = Orthanc::Toolbox::StripSpaces(node.text().get()); + + try + { + int64_t value = boost::lexical_cast(s); + return new IntegerValue(value); + } + catch (boost::bad_lexical_cast&) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Cannot parse an integer: " + s); + } + } + else if (name == "real") + { + const std::string s = Orthanc::Toolbox::StripSpaces(node.text().get()); + + try + { + double value = boost::lexical_cast(s); + return new RealValue(value); + } + catch (boost::bad_lexical_cast&) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Cannot parse a real number: " + s); + } + } + else if (name == "string") + { + return new StringValue(node.text().get()); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Unknown XML element: " + name); + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/IValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/IValue.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,66 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + + +#pragma once + +#if !defined(ORTHANC_ENABLE_PUGIXML) +# error The macro ORTHANC_ENABLE_PUGIXML must be defined +#endif + +#if ORTHANC_ENABLE_PUGIXML != 1 +# error Support for XML (pugixml) must be enabled to use this file +#endif + +#include +#include + +namespace OrthancStone +{ + namespace OsiriX + { + /** + * This is actually a compatibility layer above the "property + * lists" from Apple, that are used by OsiriX to store the ROIs as + * XML files. https://www.apple.com/DTDs/PropertyList-1.0.dtd + **/ + class IValue : public boost::noncopyable + { + public: + enum Type + { + Type_Array, + Type_Dictionary, + Type_Real, + Type_Integer, + Type_String + }; + + virtual ~IValue() + { + } + + virtual Type GetType() const = 0; + + static IValue* Parse(const pugi::xml_node& node); + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/IntegerValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/IntegerValue.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,57 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "IValue.h" + +#include + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + class IntegerValue : public IValue + { + private: + int64_t value_; + + public: + IntegerValue(int64_t value) : + value_(value) + { + } + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Integer; + } + + int64_t GetValue() const + { + return value_; + } + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/LineAnnotation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/LineAnnotation.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,60 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "LineAnnotation.h" + +#include "ArrayValue.h" +#include "IntegerValue.h" +#include "StringValue.h" + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + LineAnnotation::LineAnnotation(const DictionaryValue& dict, + bool isArrow) : + isArrow_(isArrow) + { + SetupCommon(dict); + + const IntegerValue& number = dynamic_cast(dict.GetValue("NumberOfPoints")); + const ArrayValue& points = dynamic_cast(dict.GetValue("Point_mm")); + + if (number.GetValue() != 2 || + points.GetSize() != 2) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + dynamic_cast(points.GetValue(0)).ParseVector(p1_); + dynamic_cast(points.GetValue(1)).ParseVector(p2_); + + if (p1_.size() != 3u || + p2_.size() != 3u) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/LineAnnotation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/LineAnnotation.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,64 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "Annotation.h" +#include "../LinearAlgebra.h" // For "Vector" + + +namespace OrthancStone +{ + namespace OsiriX + { + class LineAnnotation : public Annotation + { + private: + Vector p1_; + Vector p2_; + bool isArrow_; + + public: + LineAnnotation(const DictionaryValue& dict, + bool isArrow); + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Line; + } + + const Vector& GetPoint1() const + { + return p1_; + } + + const Vector& GetPoint2() const + { + return p2_; + } + + bool IsArrow() const + { + return isArrow_; + } + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/RealValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/RealValue.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,55 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "IValue.h" + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + class RealValue : public IValue + { + private: + double value_; + + public: + RealValue(double value) : + value_(value) + { + } + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Real; + } + + double GetValue() const + { + return value_; + } + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/StringValue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/StringValue.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,66 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "StringValue.h" + +#include +#include + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + void StringValue::ParseVector(Vector& v) const + { + size_t a = value_.find('('); + size_t b = value_.rfind(')'); + if (a == std::string::npos || + b == std::string::npos || + a >= b) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Cannot parse vector: " + value_); + } + else + { + std::vector tokens; + Orthanc::Toolbox::TokenizeString(tokens, value_.substr(a + 1, b - (a + 1)), ','); + + v.resize(tokens.size()); + for (size_t i = 0; i < tokens.size(); i++) + { + try + { + v[i] = boost::lexical_cast(Orthanc::Toolbox::StripSpaces(tokens[i])); + } + catch (boost::bad_lexical_cast&) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Not a real number: " + tokens[i]); + } + } + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/StringValue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/StringValue.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,60 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "IValue.h" +#include "../LinearAlgebra.h" // For "Vector" + +#include + +#include + + +namespace OrthancStone +{ + namespace OsiriX + { + class StringValue : public IValue + { + private: + std::string value_; + + public: + StringValue(const std::string& value) : + value_(value) + { + } + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Dictionary; + } + + const std::string& GetValue() const + { + return value_; + } + + void ParseVector(Vector& v) const; + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/TextAnnotation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/TextAnnotation.cpp Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,44 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "TextAnnotation.h" + +#include "StringValue.h" + +#include + +namespace OrthancStone +{ + namespace OsiriX + { + TextAnnotation::TextAnnotation(const DictionaryValue& dict) + { + SetupCommon(dict); + + dynamic_cast(dict.GetValue("Center")).ParseVector(center_); + + if (center_.size() != 3u) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/Sources/Toolbox/OsiriX/TextAnnotation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OsiriX/TextAnnotation.h Wed Oct 21 17:33:17 2020 +0200 @@ -0,0 +1,57 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "Annotation.h" + +#include "../LinearAlgebra.h" // For "Vector" + + +namespace OrthancStone +{ + namespace OsiriX + { + class TextAnnotation : public Annotation + { + private: + Vector center_; + + public: + TextAnnotation(const DictionaryValue& dict); + + virtual Type GetType() const ORTHANC_OVERRIDE + { + return Type_Text; + } + + const Vector& GetCenter() const + { + return center_; + } + + const std::string& GetText() const + { + return GetName(); // This is just an alias + } + }; + } +} diff -r c8644706e78b -r bd180f97c734 OrthancStone/UnitTestsSources/CMakeLists.txt --- a/OrthancStone/UnitTestsSources/CMakeLists.txt Tue Oct 20 20:21:21 2020 +0200 +++ b/OrthancStone/UnitTestsSources/CMakeLists.txt Wed Oct 21 17:33:17 2020 +0200 @@ -18,6 +18,7 @@ endif() set(ENABLE_OPENGL OFF) +set(ENABLE_PUGIXML ON) include(${ORTHANC_STONE_ROOT}/Resources/CMake/OrthancStoneConfiguration.cmake)