Mercurial > hg > orthanc-stone
diff Framework/Toolbox/DicomStructure2.h @ 998:38b6bb0bdd72
added a new set of classes that correctly handle non-convex polygons (not
used yet because of limitations in coordinates computing): DicomStructure2,
DicomStructureSet2, DicomStructurePolygon2, DicomStructureSetSlicer2. Too
many shortcuts have been taken when computing the actual position.
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Fri, 20 Sep 2019 11:58:00 +0200 |
parents | |
children | 29f5f2031310 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Toolbox/DicomStructure2.h Fri Sep 20 11:58:00 2019 +0200 @@ -0,0 +1,155 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. + **/ + +#pragma once + +#include "DicomStructurePolygon2.h" +#include "DicomStructureSetUtils.h" + +namespace OrthancStone +{ + + /* + A structure has a color, a name, a set of slices.. + + Each slice is a polygon. + */ + struct DicomStructure2 + { + DicomStructure2() : + red_(0), green_(0), blue_(0), sliceThickness_(0), state_(Building) {} + + void AddPolygon(const DicomStructurePolygon2& polygon); + + /** + Once all polygons have been added, this method will determine: + - the slice orientation (through the normal vector) + - the spacing between slices (slice thickness) + + it will also set up the info required to efficiently compute plane + intersections later on. + */ + void ComputeDependentProperties(); + + /** + Being given a plane that is PARALLEL to the set of polygon contours, this + returns a pointer to the polygon located at that position (if it is closer + than thickness/2) or NULL if there is none. + + TODO: use sorted vector to improve + + DO NOT STORE THE RETURNED POINTER! + */ + const DicomStructurePolygon2* GetPolygonClosestToSlice(const CoordinateSystem3D& plane) const; + + Vector GetNormal() const; + + Color GetColor() const + { + return Color(red_, green_, blue_); + } + + bool IsValid() const + { + return state_ == Valid; + } + + /** + This method is used to project the 3D structure on a 2D plane. + + A structure is a stack of polygons, representing a volume. + + We need to compute the intersection between this volume and the supplied + cutting plane (the "slice"). This is more than a cutting plane: it is also + a 2D-coordinate system (the plane has axes vectors) + + The cutting plane is always parallel to the plane defined by two of the + world coordinate system axes. + + The result is a set of closed polygons. + + If the cut is parallel to the polygons, we pick the polygon closest to + the slice, project it on the slice and return it in slice coordinates. + + If the cut is perpendicular to the polygons, for each polygon, we compute + the intersection between the cutting plane and the polygon slab (imaginary + volume created by extruding the polygon above and below its plane by + thickness/2) : + - each slab, intersected by the plane, gives a set of 0..* rectangles \ + (only one if the polygon is convex) + - when doing this for the whole stack of slabs, we get a set of rectangles: + To compute these rectangles, for each polygon, we compute the intersection + between : + - the line defined by the intersection of the polygon plane and the cutting + plane + - the polygon itself + This yields 0 or 2*K points along the line C. These are turned into K + rectangles by taking two consecutive points along the line and extruding + this segment by sliceThickness/2 in the orientation of the polygon normal, + in both directions. + + Then, once this list of rectangles is computed, we need to group the + connected rectangles together. Connected, here, means sharing at least part + of an edge --> union/find data structures and algorithm. + */ + bool Project(std::vector< std::pair<Point2D, Point2D> >& polygons, const CoordinateSystem3D& plane) const; + + std::string interpretation_; + std::string name_; + uint8_t red_; + uint8_t green_; + uint8_t blue_; + + /** Internal */ + const std::vector<DicomStructurePolygon2>& GetPolygons() const + { + return polygons_; + } + + /** Internal */ + double GetSliceThickness() const + { + return sliceThickness_; + } + + private: + enum State + { + Building, + NormalComputed, + Valid, // When normal components AND slice thickness are computed + Invalid + }; + + void ComputeNormal(); + void ComputeSliceThickness(); + + std::vector<DicomStructurePolygon2> polygons_; + Vector3D normal_; + double sliceThickness_; + + /* + After creation (and while polygons are added), state is Building. + After ComputeDependentProperties() is called, state can either be + Valid or Invalid. In any case, the object becomes immutable. + */ + State state_; + }; +}