Line data Source code
1 : #include <imageanalysis/Annotations/AnnRegion.h>
2 :
3 : #include <casacore/casa/Exceptions/Error.h>
4 : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
5 : #include <casacore/coordinates/Coordinates/SpectralCoordinate.h>
6 : #include <casacore/coordinates/Coordinates/StokesCoordinate.h>
7 : //#include <imageanalysis/Regions/CasacRegionManager.h>
8 : #include <imageanalysis/IO/ParameterParser.h>
9 : #include <casacore/images/Regions/WCExtension.h>
10 : #include <casacore/images/Regions/WCUnion.h>
11 : #include <casacore/tables/Tables/TableRecord.h>
12 :
13 : #include <iomanip>
14 :
15 : using namespace casacore;
16 : namespace casa {
17 :
18 : const String AnnRegion::_class = "AnnRegion";
19 :
20 0 : AnnRegion::AnnRegion(
21 : const Type shape, const String& dirRefFrameString,
22 : const CoordinateSystem& csys,
23 : const IPosition& imShape,
24 : const Quantity& beginFreq,
25 : const Quantity& endFreq,
26 : const String& freqRefFrame,
27 : const String& dopplerString,
28 : const Quantity& restfreq,
29 : const Vector<Stokes::StokesTypes> stokes,
30 : const Bool annotationOnly,
31 : const Bool requireImageRegion
32 0 : ) : AnnotationBase(
33 : shape, dirRefFrameString, csys, beginFreq, endFreq,
34 : freqRefFrame, dopplerString, restfreq, stokes
35 : ),
36 0 : _requireImageRegion(requireImageRegion),
37 0 : _isAnnotationOnly(annotationOnly),
38 0 : _isDifference(false), _constructing(true), _imShape(imShape),
39 0 : _spectralPixelRange(vector<Double>(0)) {
40 0 : _init();
41 : // just before returning
42 0 : _constructing = false;
43 0 : }
44 :
45 0 : AnnRegion::AnnRegion(
46 : const Type shape,
47 : const CoordinateSystem& csys,
48 : const IPosition& imShape,
49 : const Vector<Stokes::StokesTypes>& stokes,
50 : const Bool requireImageRegion
51 0 : ) : AnnotationBase(shape, csys, stokes),
52 0 : _requireImageRegion(requireImageRegion),
53 0 : _isDifference(false), _constructing(true), _imShape(imShape),
54 0 : _spectralPixelRange(vector<Double>(0)) {
55 0 : _init();
56 : // just before returning
57 0 : _constructing = false;
58 0 : }
59 :
60 0 : AnnRegion::AnnRegion(const AnnRegion& other)
61 : : AnnotationBase(other),
62 0 : _requireImageRegion(other._requireImageRegion),
63 0 : _imageRegion(other._imageRegion),
64 0 : _directionRegion(other._directionRegion),
65 0 : _isAnnotationOnly(other._isAnnotationOnly),
66 0 : _isDifference(other._isDifference),
67 0 : _constructing(other._constructing),
68 0 : _imShape(other._imShape),
69 0 : _spectralPixelRange(other._spectralPixelRange) {}
70 :
71 :
72 0 : AnnRegion::~AnnRegion() {}
73 :
74 0 : AnnRegion& AnnRegion::operator= (const AnnRegion& other) {
75 0 : if (&other != this) {
76 0 : AnnotationBase::operator= (other);
77 0 : _isAnnotationOnly = other._isAnnotationOnly;
78 0 : _requireImageRegion = other._requireImageRegion;
79 0 : _imageRegion = other._imageRegion;
80 0 : _directionRegion = other._directionRegion;
81 0 : _isDifference = other._isDifference;
82 0 : _constructing = other._constructing;
83 0 : _imShape.resize(other._imShape.size());
84 0 : _imShape = other._imShape;
85 0 : _spectralPixelRange = other._spectralPixelRange;
86 : }
87 0 : return *this;
88 : }
89 :
90 0 : Bool AnnRegion::operator== (const AnnRegion& other) const {
91 0 : return &other == this || (
92 0 : _isAnnotationOnly == other._isAnnotationOnly
93 0 : && _requireImageRegion == other._requireImageRegion
94 0 : && _imageRegion == other._imageRegion
95 0 : && _directionRegion == other._directionRegion
96 0 : && _isDifference == other._isDifference
97 0 : && _constructing == other._constructing
98 0 : && _imShape == other._imShape
99 0 : && _spectralPixelRange == other._spectralPixelRange
100 0 : );
101 : }
102 :
103 :
104 0 : void AnnRegion::setAnnotationOnly(const Bool isAnnotationOnly) {
105 0 : _isAnnotationOnly = isAnnotationOnly;
106 0 : }
107 :
108 0 : Bool AnnRegion::isAnnotationOnly() const {
109 0 : return _isAnnotationOnly;
110 : }
111 :
112 0 : Bool AnnRegion::_hasDirectionRegion() {
113 0 : return (_directionRegion.isWCRegion() || _directionRegion.isLCRegion() || _directionRegion.isLCSlicer());
114 : }
115 :
116 0 : Bool AnnRegion::hasImageRegion() const {
117 0 : return (_imageRegion.isWCRegion() || _imageRegion.isLCRegion() || _imageRegion.isLCSlicer());
118 : }
119 :
120 0 : void AnnRegion::setDifference(const Bool difference) {
121 0 : _isDifference = difference;
122 0 : }
123 :
124 0 : Bool AnnRegion::isDifference() const {
125 0 : return _isDifference;
126 : }
127 :
128 0 : TableRecord AnnRegion::asRecord() const {
129 0 : return _imageRegion.toRecord("");
130 : }
131 :
132 0 : ImageRegion AnnRegion::asImageRegion() const {
133 0 : return _imageRegion;
134 : }
135 :
136 0 : CountedPtr<const WCRegion> AnnRegion::getRegion() const {
137 0 : if (hasImageRegion()) {
138 0 : return _imageRegion.asWCRegionPtr()->cloneRegion();
139 : } else {
140 0 : return CountedPtr<const WCRegion>(nullptr);
141 : }
142 : }
143 :
144 0 : std::shared_ptr<const WCRegion> AnnRegion::getRegion2() const {
145 0 : if (hasImageRegion()) {
146 0 : return std::shared_ptr<const WCRegion>(_imageRegion.asWCRegionPtr()->cloneRegion());
147 : } else {
148 0 : return std::shared_ptr<const WCRegion>(nullptr);
149 : }
150 : }
151 :
152 0 : Bool AnnRegion::isRegion() const {
153 0 : return true;
154 : }
155 :
156 0 : void AnnRegion::_init() {
157 0 : if (_imShape.nelements() != getCsys().nPixelAxes()) {
158 0 : ostringstream oss;
159 0 : oss << _class << "::" << __FUNCTION__ << ": Number of coordinate axes ("
160 0 : << getCsys().nPixelAxes() << ") differs from number of dimensions in image shape ("
161 0 : << _imShape.nelements() << ")";
162 0 : throw AipsError(oss.str());
163 0 : }
164 :
165 0 : }
166 :
167 0 : Bool AnnRegion::setFrequencyLimits(
168 : const Quantity& beginFreq,
169 : const Quantity& endFreq,
170 : const String& freqRefFrame,
171 : const String& dopplerString,
172 : const Quantity& restfreq
173 : ) {
174 0 : if (
175 0 : AnnotationBase::setFrequencyLimits(
176 : beginFreq, endFreq, freqRefFrame, dopplerString, restfreq
177 : )
178 : ) {
179 0 : if (! _constructing) {
180 : // have to re-extend the direction region because of new freq range.
181 : // but not during object construction
182 0 : _extend();
183 : }
184 0 : return true;
185 : }
186 : else {
187 0 : return false;
188 : }
189 : }
190 :
191 0 : void AnnRegion::_setDirectionRegion(const ImageRegion& region) {
192 0 : _directionRegion = region;
193 0 : }
194 :
195 :
196 0 : vector<Double> AnnRegion::getSpectralPixelRange() const {
197 0 : return _spectralPixelRange;
198 : }
199 :
200 :
201 0 : void AnnRegion::_extend() {
202 0 : if (!_hasDirectionRegion()) {
203 0 : return; // nothing to extend
204 : }
205 0 : Int stokesAxis = -1;
206 0 : Int spectralAxis = -1;
207 0 : Vector<Quantity> freqRange;
208 0 : uInt nBoxes = 0;
209 0 : Vector<MFrequency> freqLimits = getFrequencyLimits();
210 0 : const CoordinateSystem& csys = getCsys();
211 0 : if (csys.hasSpectralAxis() && freqLimits.size() == 2) {
212 0 : SpectralCoordinate spcoord = csys.spectralCoordinate();
213 0 : spectralAxis = csys.spectralAxisNumber();
214 :
215 0 : if (spectralAxis < 0) {
216 0 : throw AipsError(
217 0 : String(__FUNCTION__) + ": A spectral range was specified "
218 0 : + "but the spectral pixel axis in the supplied coordinate "
219 0 : + "system is not present."
220 0 : );
221 : }
222 :
223 0 : String unit = spcoord.worldAxisUnits()[0];
224 0 : _spectralPixelRange.resize(2);
225 0 : spcoord.toPixel(_spectralPixelRange[0], freqLimits[0]);
226 0 : spcoord.toPixel(_spectralPixelRange[1], freqLimits[1]);
227 0 : freqRange.resize(2);
228 0 : freqRange[0] = freqLimits[0].get(unit);
229 0 : freqRange[1] = freqLimits[1].get(unit);
230 0 : if (_spectralPixelRange[1] <= _spectralPixelRange[0]) {
231 0 : std::swap(_spectralPixelRange[0], _spectralPixelRange[1]);
232 0 : std::swap(freqRange[0], freqRange[1]);
233 : }
234 0 : nBoxes = 1;
235 0 : }
236 0 : vector<Stokes::StokesTypes> stokesRanges;
237 0 : Vector<Stokes::StokesTypes> stokes = getStokes();
238 0 : if (
239 0 : csys.hasPolarizationCoordinate() && stokes.size() > 0
240 0 : && (stokesAxis = csys.polarizationAxisNumber()) >= 0
241 : ) {
242 0 : vector<uInt> stokesNumbers(2*stokes.size());
243 0 : for (uInt i=0; i<stokes.size(); i++) {
244 0 : stokesNumbers[2*i] = (uInt)stokes[i];
245 0 : stokesNumbers[2*i + 1] = stokesNumbers[2*i];
246 : }
247 0 : uInt nSel = 0;
248 : vector<uInt> orderedRanges = ParameterParser::consolidateAndOrderRanges(
249 : nSel, stokesNumbers
250 0 : );
251 0 : for (uInt i=0; i<orderedRanges.size(); i++) {
252 0 : stokesRanges.push_back(Stokes::type(orderedRanges[i]));
253 : }
254 0 : nBoxes = stokesRanges.size()/2;
255 0 : }
256 0 : if (nBoxes == 0) {
257 0 : _imageRegion = _directionRegion;
258 : }
259 : else {
260 0 : uInt nExtendAxes = 0;
261 0 : if (spectralAxis >= 0) {
262 0 : nExtendAxes++;
263 : }
264 0 : if (stokesAxis >= 0) {
265 0 : nExtendAxes++;
266 : }
267 :
268 0 : IPosition pixelAxes(nExtendAxes);
269 0 : uInt n = 0;
270 : // spectral axis must be first to be consistent with _makeExtensionBox()
271 0 : if (spectralAxis > 0) {
272 0 : pixelAxes[n] = spectralAxis;
273 0 : n++;
274 : }
275 0 : if (stokesAxis > 0) {
276 0 : pixelAxes[n] = stokesAxis;
277 0 : n++;
278 : }
279 0 : if (nBoxes == 1) {
280 0 : Vector<Stokes::StokesTypes> const stokesRangesV(stokesRanges);
281 0 : WCBox wbox = _makeExtensionBox(freqRange, stokesRangesV, pixelAxes);
282 0 : _imageRegion = ImageRegion(WCExtension(_directionRegion, wbox));
283 0 : }
284 : else {
285 0 : PtrBlock<const WCRegion*> regions(nBoxes);
286 0 : for (uInt i=0; i<nBoxes; i++) {
287 0 : Vector<Stokes::StokesTypes> stokesRange(2);
288 0 : stokesRange[0] = stokesRanges[2*i];
289 0 : stokesRange[1] = stokesRanges[2*i + 1];
290 0 : WCBox wbox = _makeExtensionBox(freqRange, stokesRange, pixelAxes);
291 0 : regions[i] = new WCExtension(_directionRegion, wbox);
292 0 : }
293 0 : _imageRegion = ImageRegion(WCUnion(true, regions));
294 0 : }
295 0 : }
296 : try {
297 0 : _imageRegion.asWCRegionPtr()->toLCRegion(csys, _imShape);
298 : }
299 0 : catch (const AipsError& x) {
300 0 : throw (ToLCRegionConversionError(x.getMesg()));
301 0 : }
302 0 : }
303 :
304 0 : WCBox AnnRegion::_makeExtensionBox(
305 : const Vector<Quantity>& freqRange,
306 : const Vector<Stokes::StokesTypes>& stokesRange,
307 : const IPosition& pixelAxes
308 : ) const {
309 0 : uInt n = 0;
310 0 : Vector<Quantity> blc(pixelAxes.size());
311 0 : Vector<Quantity> trc(pixelAxes.size());
312 0 : Vector<Int> absRel(pixelAxes.size(), RegionType::Abs);
313 0 : if (freqRange.size() == 2) {
314 0 : blc[n] = freqRange[0];
315 0 : trc[n] = freqRange[1];
316 0 : n++;
317 : }
318 0 : if (stokesRange.size() == 2) {
319 0 : blc[n] = Quantity(stokesRange[0], "");
320 0 : trc[n] = Quantity(stokesRange[1], "");
321 : }
322 0 : WCBox wbox(blc, trc, pixelAxes, getCsys(), absRel);
323 0 : return wbox;
324 0 : }
325 :
326 0 : Quantity AnnRegion::_lengthToAngle(
327 : const Quantity& quantity, const uInt pixelAxis
328 : ) const {
329 0 : if(quantity.getUnit() == "pix") {
330 0 : return getCsys().toWorldLength(quantity.getValue(), pixelAxis);
331 : }
332 0 : else if (! quantity.isConform("rad")) {
333 0 : throw AipsError (
334 0 : "Quantity " + String::toString(quantity)
335 0 : + " is not an angular measure nor is it in pixel units."
336 0 : );
337 : }
338 : else {
339 0 : return quantity;
340 : }
341 : }
342 :
343 0 : void AnnRegion::_printPrefix(ostream& os) const {
344 0 : if (isAnnotationOnly()) {
345 0 : os << "ann ";
346 : }
347 0 : else if (isDifference()) {
348 0 : os << "- ";
349 : }
350 0 : }
351 :
352 : }
353 :
|