1 //*******************************************************************
2 // Copyright (C) 2000 ImageLinks Inc.
3 //
4 // License:  LGPL
5 //
6 // See LICENSE.txt file in the top level directory for more details.
7 //
8 // Author: Garrett Potts
9 //
10 //*************************************************************************
11 // $Id: ossim2dTo2dTransform.cpp 15766 2009-10-20 12:37:09Z gpotts $
12 
13 #include <cstdlib>
14 #include <sstream>
15 #include <ossim/base/ossim2dTo2dTransform.h>
16 
17 
18 RTTI_DEF1(ossim2dTo2dTransform, "ossim2dTo2dTransform", ossimObject);
19 
20 #include <ossim/base/ossimKeywordNames.h>
21 #include <ossim/base/ossimKeywordlist.h>
22 #include <ossim/base/ossimNotifyContext.h>
23 
24 // ### CREATE_COPY ###
25 // Implementation of static factory method createCopy() requires includes here of ALL 2D-to-2D
26 // transform types that need a deep copy capability:
27 #include <ossim/base/ossimAffineTransform.h>
28 #include <ossim/projection/ossimImageViewAffineTransform.h>
29 #include <ossim/projection/ossimImageViewProjectionTransform.h>
30 #include <ossim/projection/ossimMeanRadialLensDistortion.h>
31 #include <ossim/base/ossimQuadTreeWarp.h>
32 #include <ossim/projection/ossimRadialDecentLensDistortion.h>
33 
34 //***
35 // Define Trace flags for use within this file:
36 //***
37 #include <ossim/base/ossimTrace.h>
38 static ossimTrace traceExec  ("ossim2dTo2dTransform:exec");
39 static ossimTrace traceDebug ("ossim2dTo2dTransform:debug");
40 
41 static const double DEFAULT_THRESHOLD      = 1000.0*DBL_EPSILON;
42 static const int    DEFAULT_MAX_ITERATIONS = 10;
43 
44 //*****************************************************************************
45 //  CONSTRUCTOR:
46 //*****************************************************************************
ossim2dTo2dTransform()47 ossim2dTo2dTransform::ossim2dTo2dTransform()
48    :
49       theConvergenceThreshold (DEFAULT_THRESHOLD),
50       theMaxIterations        (DEFAULT_MAX_ITERATIONS),
51       theDxDy(1.0, 1.0)
52 {
53 }
54 
55 //*****************************************************************************
56 //  METHOD:
57 //*****************************************************************************
inverse(const ossimDpt & input,ossimDpt & output) const58 void ossim2dTo2dTransform::inverse(const ossimDpt& input,
59                                    ossimDpt&       output) const
60 {
61    static const char MODULE[] = "ossim2dTo2dTransform::inverse";
62    if (traceExec())  ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG: " << MODULE << ", entering...\n";
63 
64    //***
65    // Begin with guess. Forward transform is defined as trasforming left to
66    // right. We are therefore solving for left:
67    //***
68    ossimDpt left = getOrigin();
69    ossimDpt left_dx;
70    ossimDpt left_dy;
71    ossimDpt right;
72    ossimDpt right_dx;
73    ossimDpt right_dy;
74    ossimDpt dr_dx;
75    ossimDpt dr_dy;
76    ossimDpt r_diff;
77    ossimDpt l_diff;
78    double inverse_norm;
79    int iters=0;
80    //***
81    // Begin iterations:
82    //***
83    do
84    {
85       //***
86       // establish perturbed image points about the guessed point:
87       //***
88       left_dx.x = left.x + theDxDy.x;
89       left_dx.y = left.y;
90       left_dy.x = left.x;
91       left_dy.y = left.y + theDxDy.y;
92 
93       //***
94       // Compute numerical partials at current guessed point:
95       //***
96       forward(left,    right);
97       forward(left_dx, right_dx);
98       forward(left_dy, right_dy);
99 
100       dr_dx.x = (right_dx.x - right.x)/theDxDy.x; //e
101       dr_dx.y = (right_dx.y - right.y)/theDxDy.y; //g
102       dr_dy.x = (right_dy.x - right.x)/theDxDy.x; //f
103       dr_dy.y = (right_dy.y - right.y)/theDxDy.y; //h
104 
105       //***
106       // Test for convergence:
107       //***
108       r_diff = input - right;
109 
110       //***
111       // Compute linearized estimate of image point given gp delta:
112       //***
113       inverse_norm = dr_dy.x*dr_dx.y - dr_dx.x*dr_dy.y; // fg-eh
114 
115       if (inverse_norm != 0)
116       {
117          l_diff.x = (-dr_dy.y*r_diff.x + dr_dy.x*r_diff.y)/inverse_norm;
118          l_diff.y = ( dr_dx.y*r_diff.x - dr_dx.x*r_diff.y)/inverse_norm;
119 
120          left += l_diff;
121       }
122       else
123       {
124          l_diff.x = 0;
125          l_diff.y = 0;
126       }
127 
128       iters++;
129 
130    } while (((fabs(l_diff.x) > theConvergenceThreshold) ||
131              (fabs(l_diff.y) > theConvergenceThreshold)) &&
132             (iters < theMaxIterations));
133 
134    //***
135    // Note that this error mesage appears only if max count was reached while
136    // iterating. A linear (no iteration) solution would finish with iters =
137    // MAX_NUM_ITERATIONS + 1:
138    //***
139     if (iters == theMaxIterations)
140     {
141        ossimNotify(ossimNotifyLevel_WARN) << "WARNING: " << MODULE << ", exceeded max number of iterations computing inverse "
142                                           << "transform for point: " << input << "\n";
143     }
144 
145    output = left;
146    if (traceExec())  ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG: " << MODULE << ", returning...\n";
147    return;
148 
149 }
150 
151 //*****************************************************************************
152 //  METHOD:
153 //*****************************************************************************
saveState(ossimKeywordlist & kwl,const char * prefix) const154 bool ossim2dTo2dTransform::saveState(ossimKeywordlist& kwl,
155                                      const char* prefix) const
156 {
157    kwl.add(prefix,
158            ossimKeywordNames::CONVERGENCE_THRESHOLD_KW,
159            theConvergenceThreshold,
160            true);
161    kwl.add(prefix,
162            ossimKeywordNames::MAX_ITERATIONS_KW,
163            theMaxIterations,
164            true);
165    kwl.add(prefix,
166            "dxdy",
167            ossimString::toString(theDxDy.x) + " " +
168            ossimString::toString(theDxDy.y),
169            true);
170 
171    return ossimObject::saveState(kwl, prefix);
172 }
173 
174 //*****************************************************************************
175 //  METHOD:
176 //*****************************************************************************
loadState(const ossimKeywordlist & kwl,const char * prefix)177 bool ossim2dTo2dTransform::loadState(const ossimKeywordlist& kwl,
178                const char* prefix)
179 {
180   bool result = true;
181 
182    const char* buf;
183 
184    buf= kwl.find(prefix, ossimKeywordNames::CONVERGENCE_THRESHOLD_KW);
185 
186    if (buf)
187    {
188       theConvergenceThreshold = atof(buf);
189    }
190    else
191    {
192       theConvergenceThreshold = .00000000000002;
193    }
194 
195    buf= kwl.find(prefix, ossimKeywordNames::MAX_ITERATIONS_KW);
196    if(buf)
197    {
198       theMaxIterations = atoi(buf);
199    }
200    else
201    {
202       theMaxIterations = 10;
203    }
204    const char* dxdy = kwl.find(prefix, "dxdy");
205    if(dxdy)
206    {
207       ossimString tempString(dxdy);
208       std::vector<ossimString> splitArray;
209       tempString = tempString.trim();
210       tempString.split(splitArray, " ");
211       if(splitArray.size()==2)
212       {
213          theDxDy.x = splitArray[0].toDouble();
214          theDxDy.y = splitArray[1].toDouble();
215       }
216    }
217    if(result)
218    {
219       ossimObject::loadState(kwl, prefix);
220    }
221 
222    return result;
223 }
224 
forward(ossimDpt & modify_this) const225 void ossim2dTo2dTransform::forward(ossimDpt&  modify_this) const
226 {
227    ossimDpt output;
228    forward(modify_this, output);
229    modify_this = output;
230 }
231 
inverse(ossimDpt & modify_this) const232 void ossim2dTo2dTransform::inverse(ossimDpt&  modify_this) const
233 {
234    ossimDpt output;
235    inverse(modify_this, output);
236    modify_this = output;
237 }
238 
getOrigin() const239 ossimDpt ossim2dTo2dTransform::getOrigin()const
240 {
241    return ossimDpt(0,0);
242 }
243 
setConvergenceThreshold(const double & new_threshold)244 void ossim2dTo2dTransform::setConvergenceThreshold(const double& new_threshold)
245 {
246    theConvergenceThreshold = new_threshold;
247 }
248 
setMaxIterations(int new_max_iters)249 void ossim2dTo2dTransform::setMaxIterations(int new_max_iters)
250 {
251    theMaxIterations = new_max_iters;
252 }
253 
setDxDy(const ossimDpt & dxdy)254 void ossim2dTo2dTransform::setDxDy(const ossimDpt& dxdy)
255 {
256    theDxDy.x = dxdy.x;
257    theDxDy.y = dxdy.y;
258 }
259 
operator =(const ossim2dTo2dTransform & rhs)260 const ossim2dTo2dTransform& ossim2dTo2dTransform::operator=(const ossim2dTo2dTransform&  rhs )
261 {
262    if (this != &rhs)
263    {
264       ossimObject::operator = (rhs);
265 
266       theConvergenceThreshold = rhs.theConvergenceThreshold;
267       theMaxIterations        = rhs.theMaxIterations;
268       theDxDy                 = rhs.theDxDy;
269    }
270    return *this;
271 }
272 
print(std::ostream & out) const273 std::ostream& ossim2dTo2dTransform::print(std::ostream& out) const
274 {
275    out << "convergenceThreshold: " << theConvergenceThreshold << "\n"
276    << "maxIterations:        " << theMaxIterations << "\n"
277    << "dxdy:                 " << theDxDy << "\n";
278    return out;
279 }
280 
281