Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# 

2# LSST Data Management System 

3# Copyright 2008, 2009, 2010 LSST Corporation. 

4# 

5# This product includes software developed by the 

6# LSST Project (http://www.lsst.org/). 

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22 

23import functools 

24import numpy 

25 

26import lsst.geom 

27from lsst.pex.config import Config, ListField, makeRegistry, \ 

28 ConfigDictField, ConfigurableField 

29from .transformFactory import makeTransform, makeIdentityTransform, \ 

30 makeRadialTransform 

31 

32__all__ = ["transformRegistry", "OneTransformConfig", "TransformConfig", 

33 "IdentityTransformConfig", "AffineTransformConfig", "RadialTransformConfig", 

34 "MultiTransformConfig"] 

35 

36transformRegistry = makeRegistry( 

37 """"A registry of ``Transform`` factories 

38 

39 A ``Transform`` factory is a function that obeys these rules: 

40 - has an attribute ``ConfigClass`` 

41 - takes one argument, ``config`` (an instance of ``ConfigClass``) by name 

42 - returns a ``Transform`` 

43 """ 

44) 

45 

46 

47class IdentityTransformConfig(Config): 

48 """A Config representing a ``Transform`` that does nothing. 

49 

50 See Also 

51 -------- 

52 lsst.afw.geom.makeIdentityTransform 

53 """ 

54 pass 

55 

56 

57def identityFactory(config): 

58 """Make an identity ``Transform`` 

59 """ 

60 return makeIdentityTransform() 

61 

62 

63identityFactory.ConfigClass = IdentityTransformConfig 

64transformRegistry.register("identity", identityFactory) 

65 

66 

67class OneTransformConfig(Config): 

68 """A Config representing a single ``Transform`` in a compound ``Transform``. 

69 

70 See Also 

71 -------- 

72 lsst.afw.geom.MultiTransformConfig 

73 """ 

74 transform = ConfigurableField( 

75 doc="Transform factory", 

76 target=identityFactory, 

77 ) 

78 

79 

80def invertingFactory(config): 

81 """Invert a ``Transform`` specified by config. 

82 """ 

83 return config.transform.apply().inverted() 

84 

85 

86invertingFactory.ConfigClass = OneTransformConfig 

87transformRegistry.register("inverted", invertingFactory) 

88 

89 

90class AffineTransformConfig(Config): 

91 """A Config representing an affine ``Transform``. 

92 

93 See Also 

94 -------- 

95 lsst.afw.geom.makeTransform 

96 """ 

97 linear = ListField( 

98 doc="2x2 linear matrix in the usual numpy order; " 

99 "to rotate a vector by theta use: cos(theta), sin(theta), " 

100 "-sin(theta), cos(theta)", 

101 dtype=float, 

102 length=4, 

103 default=(1, 0, 0, 1), 

104 ) 

105 translation = ListField( 

106 doc="x, y translation vector", 

107 dtype=float, 

108 length=2, 

109 default=(0, 0), 

110 ) 

111 

112 

113def affineFactory(config): 

114 """Make an affine ``Transform`` 

115 """ 

116 linear = numpy.array(config.linear) 

117 linear.shape = (2, 2) 

118 translation = numpy.array(config.translation) 

119 return makeTransform(lsst.geom.AffineTransform(linear, translation)) 

120 

121 

122affineFactory.ConfigClass = AffineTransformConfig 

123transformRegistry.register("affine", affineFactory) 

124 

125 

126class RadialTransformConfig(Config): 

127 """A Config representing a radially symmetric ``Transform``. 

128 

129 See Also 

130 -------- 

131 lsst.afw.geom.makeRadialTransform 

132 """ 

133 coeffs = ListField( 

134 doc="Coefficients for the radial polynomial; coeff[0] must be 0", 

135 dtype=float, 

136 minLength=1, 

137 optional=False, 

138 ) 

139 

140 def validate(self): 

141 if len(self.coeffs) == 0: 

142 return 

143 if len(self.coeffs) == 1 or self.coeffs[0] != 0 or self.coeffs[1] == 0: 

144 raise RuntimeError( 

145 f"invalid radial transform coeffs {self.coeffs}: " 

146 "need len(coeffs)=0 or len(coeffs)>1, coeffs[0]==0, " 

147 "and coeffs[1]!=0") 

148 

149 

150def radialFactory(config): 

151 """Make a radial ``Transform`` 

152 """ 

153 return makeRadialTransform(config.coeffs._list) 

154 

155 

156radialFactory.ConfigClass = RadialTransformConfig 

157transformRegistry.register("radial", radialFactory) 

158 

159 

160class MultiTransformConfig(Config): 

161 """A Config representing a chain of consecutive ``Transforms``. 

162 """ 

163 transformDict = ConfigDictField( 

164 doc="Dict of index: OneTransformConfig (a transform wrapper); " 

165 "key order is transform order", 

166 keytype=int, 

167 itemtype=OneTransformConfig, 

168 ) 

169 

170 

171def multiFactory(config): 

172 """Concatenate multiple ``Transforms`` 

173 """ 

174 transformKeys = sorted(config.transformDict.keys()) 

175 transformList = [config.transformDict[key].transform.apply() 

176 for key in transformKeys] 

177 

178 # Can't use then(self, other) directly because no single Transform class 

179 def concat(transform1, transform2): 

180 return transform1.then(transform2) 

181 

182 return functools.reduce(concat, transformList) 

183 

184 

185multiFactory.ConfigClass = MultiTransformConfig 

186transformRegistry.register("multi", multiFactory) 

187 

188 

189class TransformConfig(Config): 

190 """Config that identifies ``Transforms`` by keyword. 

191 

192 Supported configs: 

193 

194 ``"identity"`` 

195 `IdentityTransformConfig` 

196 ``"inverted"`` 

197 `OneTransformConfig` 

198 ``"affine"`` 

199 `AffineTransformConfig` 

200 ``"radial"`` 

201 `RadialTransformConfig` 

202 ``"multi"`` 

203 `MultiTransformConfig` 

204 """ 

205 transform = transformRegistry.makeField( 

206 doc="a Transform from the registry" 

207 )