Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Region code to RegionState and RegionConverter #1352

Merged
merged 34 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5459b63
Rename spatial profiles test, for cursor only
pford Dec 7, 2023
8f2add5
Rename region (line and point) spatial profile test
pford Dec 7, 2023
f9d47cf
Remove unused methods, update test CMakeLists
pford Dec 7, 2023
e3f5966
Add region histogram and stats tests
pford Dec 8, 2023
760e940
Tweak tests and rename test suite
pford Dec 8, 2023
9de1192
Add tests for Region in reference image
pford Dec 9, 2023
213fd7b
Add tests for matched regions and rotbox
pford Dec 9, 2023
6dee2a7
Convert test utils CmpValues and CmpVectors to template
pford Jan 2, 2024
c000246
Add region spectral profile test
pford Jan 2, 2024
4a1fb69
Remove float versions of test utils CmpValues and CmpVectors
pford Jan 2, 2024
abaf732
Fix formatting
pford Jan 2, 2024
e21ff82
Merge branch 'dev' into pam/1347_region_converter
pford Jan 2, 2024
8180a13
Fix includes after removing Message.h from Region.cc
pford Jan 8, 2024
bed62df
Use FileFinder for image path in tests
pford Jan 8, 2024
e7c0044
Move rotbox tests into region and matched region tests
pford Jan 8, 2024
8452b43
Refactor Region into RegionConverter and add tests
pford Jan 17, 2024
cb91489
Remove debug output
pford Jan 17, 2024
d49bed0
Add performance time for line spatial profile
pford Jan 17, 2024
bbf1700
Merge branch 'dev' into pam/1347_region_converter
pford Jan 18, 2024
58a3fa8
Remove tab from CMakeLists
pford Jan 18, 2024
f7a525a
Add spatial profile test for point outside image
pford Jan 19, 2024
5c7955f
Add region import/export test and bug fixes from refactoring
pford Jan 22, 2024
ea65135
Fix formatting
pford Jan 23, 2024
4b9e148
Merge branch 'dev' into pam/1347_region_converter
pford Jan 23, 2024
9462ebd
Add changelog entry
pford Jan 23, 2024
b4f9be4
Fix PvPreviewCut profile using nchan in preview image
pford Jan 31, 2024
6a25678
Fix ellipse record from control points for export
pford Jan 31, 2024
224f9e0
Fix point region spectral profile and add test
pford Feb 1, 2024
ef64598
Fix format
pford Feb 1, 2024
6a3b0f2
Merge branch 'dev' into pam/1347_region_converter
pford Feb 1, 2024
1476e9e
Update protobuf
pford Feb 1, 2024
5697d51
Use double for ellipse angle in record for accurate unit conversion
pford Mar 7, 2024
0b965b4
Merge branch 'dev' into pam/1347_region_converter
pford Mar 20, 2024
a62fda6
Merge branch 'dev' into pam/1347_region_converter
confluence Apr 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor Region into RegionConverter and add tests
  • Loading branch information
pford committed Jan 17, 2024
commit 8452b435d7b660fd9c1a2882d1f2925cad412ab2
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ set(LINK_LIBS

set(SOURCE_FILES
${SOURCE_FILES}
third-party/pugixml/src/pugixml.cpp
third-party/pugixml/src/pugixml.cpp
src/Cache/LoaderCache.cc
src/Cache/TileCache.cc
src/Cache/TilePool.cc
Expand Down Expand Up @@ -225,14 +225,15 @@ set(SOURCE_FILES
src/ImageStats/Histogram.cc
src/ImageStats/StatsCalculator.cc
src/Logger/Logger.cc
src/Logger/CartaLogSink.cc
src/Logger/CartaLogSink.cc
src/Main/Main.cc
src/Main/ProgramSettings.cc
src/Main/WebBrowser.cc
src/Region/CrtfImportExport.cc
src/Region/Ds9ImportExport.cc
src/Region/LineBoxRegions.cc
src/Region/Region.cc
src/Region/RegionConverter.cc
src/Region/RegionHandler.cc
src/Region/RegionImportExport.cc
src/Session/CursorSettings.cc
Expand Down
1,300 changes: 122 additions & 1,178 deletions src/Region/Region.cc

Large diffs are not rendered by default.

194 changes: 41 additions & 153 deletions src/Region/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
SPDX-License-Identifier: GPL-3.0-or-later
*/

//# Region.h: class for managing 2D region parameters
//# Region.h: class for managing 2D region parameters in reference image

#ifndef CARTA_SRC_REGION_REGION_H_
#define CARTA_SRC_REGION_REGION_H_
Expand All @@ -15,112 +15,53 @@
#include <vector>

#include <casacore/coordinates/Coordinates/CoordinateSystem.h>
#include <casacore/images/Regions/WCRegion.h>
#include <casacore/lattices/LRegions/LCPolygon.h>
#include <casacore/lattices/LRegions/LCRegion.h>
#include <casacore/lattices/Lattices/ArrayLattice.h>
#include <casacore/tables/Tables/TableRecord.h>

#include "Util/Message.h"
#include "RegionConverter.h"
#include "RegionState.h"
#include "Util/Stokes.h"

#define DEFAULT_VERTEX_COUNT 1000

namespace carta {

inline std::string RegionName(CARTA::RegionType type) {
std::unordered_map<CARTA::RegionType, std::string> region_names = {{CARTA::POINT, "point"}, {CARTA::LINE, "line"},
{CARTA::POLYLINE, "polyline"}, {CARTA::RECTANGLE, "rectangle"}, {CARTA::ELLIPSE, "ellipse"}, {CARTA::ANNULUS, "annulus"},
{CARTA::POLYGON, "polygon"}, {CARTA::ANNPOINT, "ann point"}, {CARTA::ANNLINE, "ann line"}, {CARTA::ANNPOLYLINE, "ann polyline"},
{CARTA::ANNRECTANGLE, "ann rectangle"}, {CARTA::ANNELLIPSE, "ann ellipse"}, {CARTA::ANNPOLYGON, "ann polygon"},
{CARTA::ANNVECTOR, "vector"}, {CARTA::ANNRULER, "ruler"}, {CARTA::ANNTEXT, "text"}, {CARTA::ANNCOMPASS, "compass"}};
return region_names[type];
}

struct RegionState {
// struct used for region parameters
int reference_file_id;
CARTA::RegionType type;
std::vector<CARTA::Point> control_points;
float rotation;

RegionState() : reference_file_id(-1), type(CARTA::POINT), rotation(0) {}
RegionState(int ref_file_id_, CARTA::RegionType type_, const std::vector<CARTA::Point>& control_points_, float rotation_)
: reference_file_id(ref_file_id_), type(type_), control_points(control_points_), rotation(rotation_) {}

bool operator==(const RegionState& rhs) {
return (reference_file_id == rhs.reference_file_id) && (type == rhs.type) && !RegionChanged(rhs);
}

bool operator!=(const RegionState& rhs) {
return (reference_file_id != rhs.reference_file_id) || (type != rhs.type) || RegionChanged(rhs);
}

bool RegionDefined() {
return !control_points.empty();
}

bool RegionChanged(const RegionState& rhs) {
// Ignores annotation params (for interrupting region calculations)
return (rotation != rhs.rotation) || PointsChanged(rhs);
}
bool PointsChanged(const RegionState& rhs) {
// Points must be same size, order, and value to be unchanged
if (control_points.size() != rhs.control_points.size()) {
return true;
}
for (int i = 0; i < control_points.size(); ++i) {
float x(control_points[i].x()), y(control_points[i].y());
float rhs_x(rhs.control_points[i].x()), rhs_y(rhs.control_points[i].y());
if ((x != rhs_x) || (y != rhs_y)) {
return true;
}
}
return false;
}
};

class Region {
public:
Region(const RegionState& state, std::shared_ptr<casacore::CoordinateSystem> csys);

inline bool IsValid() { // control points validated
inline bool IsValid() {
return _valid;
};

// set new region parameters
inline bool RegionChanged() {
return _region_changed;
}

// Set new region parameters
bool UpdateRegion(const RegionState& state);

// state accessors
// RegionState accessors, including region type information
inline RegionState GetRegionState() {
std::lock_guard<std::mutex> guard(_region_state_mutex);
RegionState region_state = _region_state;
return region_state;
}

inline bool RegionChanged() { // reference image, type, points, or rotation changed
return _region_changed;
}

inline bool IsPoint() {
return GetRegionState().type == CARTA::POINT;
return GetRegionState().IsPoint();
}

inline bool IsLineType() {
// Not enclosed region defined by 2 or more points
std::vector<CARTA::RegionType> line_types{
CARTA::LINE, CARTA::POLYLINE, CARTA::ANNLINE, CARTA::ANNPOLYLINE, CARTA::ANNVECTOR, CARTA::ANNRULER};
auto type = GetRegionState().type;
return std::find(line_types.begin(), line_types.end(), type) != line_types.end();
return GetRegionState().IsLineType();
}

inline bool IsRotbox() {
RegionState rs = GetRegionState();
return ((rs.type == CARTA::RECTANGLE || rs.type == CARTA::ANNRECTANGLE) && (rs.rotation != 0.0));
inline bool IsInReferenceImage(int file_id) {
return file_id == GetRegionState().reference_file_id;
}

inline bool IsAnnotation() {
return GetRegionState().type > CARTA::POLYGON;
return GetRegionState().IsAnnotation();
}

inline std::shared_ptr<casacore::CoordinateSystem> CoordinateSystem() {
Expand All @@ -130,106 +71,53 @@ class Region {
// Communication
bool IsConnected();
void WaitForTaskCancellation();
std::shared_mutex& GetActiveTaskMutex();

// Converted region as approximate LCPolygon and its mask
std::shared_ptr<casacore::LCRegion> GetImageRegion(int file_id, std::shared_ptr<casacore::CoordinateSystem> image_csys,
const casacore::IPosition& image_shape, const StokesSource& stokes_source = StokesSource(), bool report_error = true);
// LCRegion and mask for region applied to image. Must be a closed region (not line) and not annotation.
std::shared_ptr<casacore::LCRegion> GetImageRegion(int file_id, std::shared_ptr<casacore::CoordinateSystem> csys,
const casacore::IPosition& shape, const StokesSource& stokes_source = StokesSource(), bool report_error = true);
casacore::ArrayLattice<casacore::Bool> GetImageRegionMask(int file_id);

// Converted region in Record for export
// Record for region applied to image, for export. Not for converting to LCRegion for analytics.
casacore::TableRecord GetImageRegionRecord(
int file_id, std::shared_ptr<casacore::CoordinateSystem> output_csys, const casacore::IPosition& output_shape);

std::shared_mutex& GetActiveTaskMutex();
int file_id, std::shared_ptr<casacore::CoordinateSystem> csys, const casacore::IPosition& shape);

private:
// check points: number required for region type, and values are finite
// Check points: number required for region type, and values are finite
bool CheckPoints(const std::vector<CARTA::Point>& points, CARTA::RegionType type);
bool PointsFinite(const std::vector<CARTA::Point>& points);

// Reset cache when region changes
// Cached LCRegion
void ResetRegionCache();
std::shared_ptr<casacore::LCRegion> GetCachedLCRegion(int file_id, const StokesSource& stokes_source);

// Check if reference region is set successfully
bool ReferenceRegionValid();

// Apply region to reference image, set WCRegion and wcs control points.
void SetReferenceRegion();
bool RectanglePointsToWorld(std::vector<CARTA::Point>& pixel_points, std::vector<casacore::Quantity>& wcs_points);
void RectanglePointsToCorners(std::vector<CARTA::Point>& pixel_points, float rotation, casacore::Vector<casacore::Double>& x,
casacore::Vector<casacore::Double>& y);
bool EllipsePointsToWorld(std::vector<CARTA::Point>& pixel_points, std::vector<casacore::Quantity>& wcs_points, float& rotation);

// Reference region as approximate polygon converted to image coordinates; used for data streams
bool UseApproximatePolygon(std::shared_ptr<casacore::CoordinateSystem> output_csys);
std::vector<CARTA::Point> GetRectangleMidpoints();
std::shared_ptr<casacore::LCRegion> GetCachedPolygonRegion(int file_id);
std::shared_ptr<casacore::LCRegion> GetAppliedPolygonRegion(
int file_id, std::shared_ptr<casacore::CoordinateSystem> output_csys, const casacore::IPosition& output_shape);
std::vector<std::vector<CARTA::Point>> GetReferencePolygonPoints(int num_vertices);
std::vector<std::vector<CARTA::Point>> GetApproximatePolygonPoints(int num_vertices);
std::vector<CARTA::Point> GetApproximateEllipsePoints(int num_vertices);
double GetTotalSegmentLength(std::vector<CARTA::Point>& points);
bool ConvertPointsToImagePixels(const std::vector<CARTA::Point>& points, std::shared_ptr<casacore::CoordinateSystem> output_csys,
casacore::Vector<casacore::Double>& x, casacore::Vector<casacore::Double>& y);
void RemoveHorizontalPolygonPoints(casacore::Vector<casacore::Double>& x, casacore::Vector<casacore::Double>& y);
bool ValuesNear(float val1, float val2);

// Region applied to any image; used for export
std::shared_ptr<casacore::LCRegion> GetCachedLCRegion(int file_id);
std::shared_ptr<casacore::LCRegion> GetConvertedLCRegion(int file_id, std::shared_ptr<casacore::CoordinateSystem> output_csys,
const casacore::IPosition& output_shape, const StokesSource& stokes_source = StokesSource(), bool report_error = true);

// Control points converted to pixel coords in output image, returned in LCRegion Record format for export
casacore::TableRecord GetRegionPointsRecord(
int file_id, std::shared_ptr<casacore::CoordinateSystem> output_csys, const casacore::IPosition& output_shape);
// Record in pixel coordinates from control points, for reference image
casacore::TableRecord GetControlPointsRecord(const casacore::IPosition& shape);
void CompleteLCRegionRecord(casacore::TableRecord& record, const casacore::IPosition& shape);
casacore::TableRecord GetPointRecord(std::shared_ptr<casacore::CoordinateSystem> output_csys, const casacore::IPosition& output_shape);
casacore::TableRecord GetLineRecord(
int file_id, std::shared_ptr<casacore::CoordinateSystem> image_csys, const casacore::IPosition& image_shape);
casacore::TableRecord GetPolygonRecord(std::shared_ptr<casacore::CoordinateSystem> output_csys);
casacore::TableRecord GetRotboxRecord(std::shared_ptr<casacore::CoordinateSystem> output_csys);
casacore::TableRecord GetEllipseRecord(std::shared_ptr<casacore::CoordinateSystem> output_csys);
casacore::TableRecord GetRotboxRecordForLCRegion(const casacore::IPosition& shape);
void CompleteRegionRecord(casacore::TableRecord& record, const casacore::IPosition& image_shape);

// Utilities to convert control points
// Input: CARTA::Point. Returns: point (x, y) in reference world coords
bool ConvertCartaPointToWorld(const CARTA::Point& point, std::vector<casacore::Quantity>& world_point);
// Input: point (x,y) in reference world coords. Returns: point (x,y) in output pixel coords
bool ConvertWorldToPixel(std::vector<casacore::Quantity>& world_point, std::shared_ptr<casacore::CoordinateSystem> output_csys,
casacore::Vector<casacore::Double>& pixel_point);

// region parameters struct
RegionState _region_state;

// coord sys and shape of reference image
// Coordinate system of reference image
std::shared_ptr<casacore::CoordinateSystem> _coord_sys;

// Reference region cache
std::mutex _region_mutex; // creation of casacore regions is not threadsafe
std::mutex _region_approx_mutex;
// Region parameters
RegionState _region_state;
std::mutex _region_state_mutex;

// Use a shared lock for long time calculations, use an exclusive lock for the object destruction
mutable std::shared_mutex _active_task_mutex;

// Region cached as original type
std::shared_ptr<casacore::WCRegion> _reference_region; // 2D region applied to reference image
std::vector<casacore::Quantity> _wcs_control_points; // for manual region conversion
// Region flags
bool _valid; // RegionState set properly
bool _region_changed; // control points or rotation changed

// Converted regions
// Reference region converted to image; key is file_id
std::unordered_map<int, std::shared_ptr<casacore::LCRegion>> _applied_regions;
// Polygon approximation region converted to image; key is file_id
std::unordered_map<int, std::shared_ptr<casacore::LCRegion>> _polygon_regions;
// Region applied to reference image
std::shared_ptr<casacore::LCRegion> _lcregion;
std::mutex _lcregion_mutex;
bool _lcregion_set; // may be nullptr if outside image

// region flags
bool _valid; // RegionState set properly
bool _region_changed; // control points or rotation changed
bool _reference_region_set; // indicates attempt was made; may be null wcregion outside image
// Converter to handle region applied to matched image
std::unique_ptr<RegionConverter> _region_converter;

// Communication
// Communication:
// Use a shared lock for long time calculations, use an exclusive lock for the object destruction
mutable std::shared_mutex _active_task_mutex;
volatile bool _connected = true;
};

Expand Down
Loading