65 def read(cls, fileName):
66 """Read a ds9 region file, returning a ObjectMaskCatalog object
67
68 The files should be structured as follows:
69
70 # Description of catalogue as a comment
71 # CATALOG: catalog-id-string
72 # TRACT: 0
73 # PATCH: 5,4
74 # FILTER: HSC-I
75
76 wcs; fk5
77
78 circle(RA, DEC, RADIUS) # ID: 1, mag: 12.34
79 box(RA, DEC, XSIZE, YSIZE, THETA) # ID: 2, mag: 23.45
80 ...
81
82 The ", mag: XX.YY" is optional
83
84 The commented lines must be present, with the relevant fields such as
85 tract patch and filter filled in. The coordinate system must be listed
86 as above. Each patch is specified as a box or circle, with RA, DEC,
87 and dimensions specified in decimal degrees (with or without an
88 explicit "d").
89
90 Only (axis-aligned) boxes and circles are currently supported as
91 region definitions.
92 """
93
94 log = logging.getLogger("lsst.ObjectMaskCatalog")
95
96 brightObjects = cls()
97 checkedWcsIsFk5 = False
98 NaN = float("NaN")*geom.degrees
99
100 nFormatError = 0
101 with open(fileName) as fd:
102 for lineNo, line in enumerate(fd.readlines(), 1):
103 line = line.rstrip()
104
105 if re.search(r"^\s*#", line):
106
107
108
109
110
111
112
113
114 mat = re.search(r"^\s*#\s*([a-zA-Z][a-zA-Z0-9_]+)\s*:\s*(.*)", line)
115 if mat:
116 key, value = mat.group(1).lower(), mat.group(2)
117 if key == "tract":
118 value = int(value)
119
120 brightObjects.table.getMetadata().
set(key, value)
121
122 line = re.sub(r"^\s*#.*", "", line)
123 if not line:
124 continue
125
126 if re.search(r"^\s*wcs\s*;\s*fk5\s*$", line, re.IGNORECASE):
127 checkedWcsIsFk5 = True
128 continue
129
130
131
132 mat = re.search(r"^\s*(box|circle)"
133 r"(?:\s+|\s*\(\s*)"
134 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
135 r"(?:\s+|\s*,\s*)"
136 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
137 r"(?:\s+|\s*,\s*)"
138 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
139 r"(?:"
140 r"(?:\s+|\s*,\s*)"
141 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
142 r"(?:"
143 r"(?:\s+|\s*,\s*)"
144 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
145 ")?"
146 ")?"
147 r"(?:\s*|\s*\)\s*)"
148 r"#\s*ID:[\w\s]*(\d+)"
149 r"(?:\s*,?\s*mag:\s*([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?))?"
150 r"\s*$", line)
151 if mat:
152 _type, ra, raUnit, dec, decUnit, \
153 param1, param1Unit, param2, param2Unit, param3, param3Unit, \
154 _id, mag = mat.groups()
155
156 _id = int(_id)
157 if mag is None:
158 mag = NaN
159 else:
160 mag = float(mag)
161
162 ra = convertToAngle(ra, raUnit, "ra", fileName, lineNo)
163 dec = convertToAngle(dec, decUnit, "dec", fileName, lineNo)
164
165 radius = NaN
166 width = NaN
167 height = NaN
168 angle = 0.0*geom.degrees
169
170 if _type == "box":
171 width = convertToAngle(param1, param1Unit, "width", fileName, lineNo)
172 height = convertToAngle(param2, param2Unit, "height", fileName, lineNo)
173 if param3 is not None:
174 angle = convertToAngle(param3, param3Unit, "angle", fileName, lineNo)
175
176 if angle != 0.0:
177 log.warning("Rotated boxes are not supported: \"%s\" at %s:%d",
178 line, fileName, lineNo)
179 nFormatError += 1
180 elif _type == "circle":
181 radius = convertToAngle(param1, param1Unit, "radius", fileName, lineNo)
182
183 if not (param2 is None and param3 is None):
184 log.warning("Extra parameters for circle: \"%s\" at %s:%d",
185 line, fileName, lineNo)
186 nFormatError += 1
187
188 rec = brightObjects.addNew()
189
190 rec["type"] = _type
191 rec["id"] = _id
192 rec["mag"] = mag
194
195 rec["angle"] = angle
196 rec["height"] = height
197 rec["width"] = width
198 rec["radius"] = radius
199 else:
200 log.warning("Unexpected line \"%s\" at %s:%d", line, fileName, lineNo)
201 nFormatError += 1
202
203 if nFormatError > 0:
204 raise RuntimeError("Saw %d formatting errors in %s" % (nFormatError, fileName))
205
206 if not checkedWcsIsFk5:
207 raise RuntimeError("Expected to see a line specifying an fk5 wcs in %s" % fileName)
208
209
210 brightObjects._catalog = brightObjects._catalog.copy(True)
211
212 return brightObjects
213
214
Point in an unspecified spherical coordinate system.
daf::base::PropertySet * set
std::shared_ptr< table::io::Persistable > read(table::io::InputArchive const &archive, table::io::CatalogVector const &catalogs) const override