1 /* queryfeature.c
2    Feature querying functionality
3    See queryfeature.h
4 */
5 #include <assert.h>
6 #include <stdio.h>
7 #include <string.h>
8 
9 #include "version.h"
10 #include "queryfeature.h"
11 #include "filter.h"
12 
13 typedef struct {char* name; int value;}    TIntFeature;
14 typedef struct {char* name; double value;} TDoubleFeature;
15 typedef struct {char* name; char* value;}  TStringFeature;
16 
17 // Fulvio Senore June.2004 changed the check to work with microsoft compiler
18 #ifdef _MSC_VER
19 //#ifdef MSVS
20 #define snprintf _snprintf
21 #endif
22 
23 /***************** Feature tables: *************************/
24 TIntFeature intFeatures[] ={
25   {"CPErrorIsDistSphere",1},       // optimizer reports angular control point errors
26   {"NumLensTypes",5},              // source lens types 0..4
27   {"NumPanoTypes",8},              // pano lens types 0..7
28   {"CanCropOutside",1},
29   {"CanHaveNegativeCP",1},
30   {"AntiAliasingFilter",1},
31   {"NumFilter",24},
32   {"SetProgressFcn",1}             // setProgressFcn and setInfoDlgFcn are available
33 };
34 
35 TDoubleFeature doubleFeatures[] ={
36   {"MaxFFOV",MAX_FISHEYE_FOV}
37 };
38 
39 TStringFeature stringFeatures[]={
40   // Version info:
41   {PTVERSION_NAME_FILEVERSION,PTVERSION_FILEVERSION},         // "FileVersion"
42   {PTVERSION_NAME_LONG,LONGVERSION},                          // "LongVersion"
43   {PTVERSION_NAME_LEGALCOPYRIGHT,PTVERSION_LEGALCOPYRIGHT},   // "LegalCopyright"
44   {PTVERSION_NAME_COMMENT,PTVERSION_COMMENT},                 // "Comments"
45   // Source lens type names
46   // If a lens type is unavailable, set its name to ""
47   {"LensType0","Normal (rectilinear)"},
48   {"LensType1","Cylindrical"},
49   {"LensType2","Fisheye Equidistance Circular"},
50   {"LensType3","Fisheye Equidistance Full Frame"},
51   {"LensType4","Equirectangular"},
52   {"LensType5",""},//"_spherical_cp"},
53   {"LensType6",""},//"_spherical_tp"},
54   {"LensType7","Mirror"},
55   {"LensType8","Fisheye Orthographic"},
56   {"LensType9",""},//"_cubic"},
57   {"LensType10","Fisheye Stereographic"},  // fisheye stereographic
58   {"LensType11",""},//"_mercator"},
59   {"LensType12",""},//"_trans_mercator"},
60   {"LensType13",""},//"_trans_panorama"},
61   {"LensType14",""},//"_sinusoidal"},
62   {"LensType15",""},//"_lambert"},
63   {"LensType16",""},//"_lambertazimuthal"},
64   {"LensType17",""},//"_albersequalareaconic"},
65   {"LensType18",""},//"_millercylindrical"},
66   {"LensType19","Fisheye Equisolid"},
67 
68   // Source lens type crop format (C)ircle or (R)ectangle:
69   {"LensMask0","R"},
70   {"LensMask1","R"},
71   {"LensMask2","C"},
72   {"LensMask3","R"},
73   {"LensMask4","R"},
74   {"LensMask7","C"},
75   {"LensMask8","C"},
76   {"LensMask10","C"},
77   {"LensMask19","C"},
78   // Pano lens type names
79   // If a lens type is unavailable, set its name to ""
80   {"PanoType0","Normal (rectilinear)"},
81   {"PanoType1","Cylindrical"},
82   {"PanoType2","Equirectangular"},
83   {"PanoType3","Full Frame"},
84   {"PanoType4","Stereographic"},
85   {"PanoType5","Mercator"},
86   {"PanoType6","Transverse mercator"},
87   {"PanoType7","Sinusoidal"},
88   {"PanoType8","Lambert Cylindrical Equal Area"},
89   {"PanoType9","Lambert Azimuthal Equal Area"},
90   {"PanoType10","Albers Conical Equal Area"},
91   {"PanoType11","Miller Cylindrical"},
92   {"PanoType12","Panini"},
93   {"PanoType13","Architectural"},
94   {"PanoType14","Orthographic"},
95   {"PanoType15","Equisolid"},
96   {"PanoType16","Equirectangular Panini"},
97   {"PanoType17","Biplane"},
98   {"PanoType18","Triplane"},
99   {"PanoType19","Panini General"},
100   {"PanoType20", "Thoby Projection"},
101   {"PanoType21", "Hammer-Aitoff Equal Area"},
102 
103   // Filter Types
104 
105   //   fix: Fixed Windowsize
106   //   aa: Antialiasing filter with adaptive filter size
107   // Filter Names
108   {"FilterType0","fix"},
109   {"FilterName0","Poly3"},
110   {"FilterType1","fix"},
111   {"FilterName1","Spline16"},
112   {"FilterType2","fix"},
113   {"FilterName2","Spline36"},
114   {"FilterType2","fix"},
115   {"FilterName3","Sinc256"},
116   {"FilterType4","fix"},
117   {"FilterName4","Spline64"},
118   {"FilterType5","fix"},
119   {"FilterName5","Bilinear"},
120   {"FilterType6","fix"},
121   {"FilterName6","Nearest neighbor"},
122   {"FilterType7","fix"},
123   {"FilterName7","Sinc1024"},
124   {"FilterType8","aa"},
125   {"FilterName8","Box"},
126   {"FilterType9","aa"},
127   {"FilterName9","Bartlett/Triangle"},
128   {"FilterType10","aa"},
129   {"FilterName10","Hermite"},
130   {"FilterType11","aa"},
131   {"FilterName11","Hanning"},
132   {"FilterType12","aa"},
133   {"FilterName12","Hamming"},
134   {"FilterType13","aa"},
135   {"FilterName13","Blackmann"},
136   {"FilterType14","aa"},
137   {"FilterName14","Gaussian 1/sqrt(2)"},
138   {"FilterType15","aa"},
139   {"FilterName15","Gaussian 1/2"},
140   {"FilterType16","aa"},
141   {"FilterName16","Quadardic"},
142   {"FilterType17","aa"},
143   {"FilterName17","Cubic"},
144   {"FilterType18","aa"},
145   {"FilterName18","Catmull-Rom"},
146   {"FilterType19","aa"},
147   {"FilterName19","Mitchell"},
148   {"FilterType20","aa"},
149   {"FilterName20","Lanczos2"},
150   {"FilterType21","aa"},
151   {"FilterName21","Lanczos3"},
152   {"FilterType22","aa"},
153   {"FilterName22","Blackman/Bessel"},
154   {"FilterType23","aa"},
155   {"FilterName23","Blackman/sinc"},
156 #if 0
157   // WE NO longer support need to list them. It should be enough to list the version
158 
159   // Patches that have been applied
160   {"Patch200510a", "Rob Platt, Do not process unchanged color channels for CA correction"},
161   {"BMPrev", "Jim Watters, correctly open BMP files created with rows in reverse order"},
162   {"Tiff32", "Thomas Rauscher, Load and save TIFF 32-bit with IEEE floats, http://www.pano2qtvr.com/dll_patch/"},
163   {"AntiAliasing", "Thomas Rauscher, New antialiasing filter for adjust, http://www.pano2qtvr.com/dll_patch/"},
164   {"HDRFile", "Thomas Rauscher, Load and save Radiance HDR files, http://www.pano2qtvr.com/dll_patch/"},
165   {"Patch200505", "Douglas Wilkins, Correct behaviour when mode = _usedata"},
166 #ifdef HasJava
167   {"Patch200504a", "Douglas Wilkins, Java support enabled"},
168 #else
169   {"Patch200504a", "Douglas Wilkins, Java support disabled"},
170 #endif
171   {"Patch200502a", "Joost Nieuwenhuijse, Crop outside of image, http://www.ptgui.com"},
172   {"Patch200410a", "Jim Watters, JPEG optimization, http://photocreations.ca/panotools"},
173   {"FastTransform01", "Fulvio Senore, Fast transform, http://www.fsoft.it/panorama/pano12.htm"},
174   {"Patch200407a", "Rik Littlefield, Kevin Kratzke, & Jim Watters, Fix multiple bugs - PSD, 16bit"},
175   {"MaskFromFocus_001", "Rik Littlefield, added mask-from-focus, http://www.janrik.net/ptools/"},
176   {"Patch200405a", "Rik Littlefield, Improved optimizer, http://www.janrik.net/ptools/"},
177   {"Patch200403a", "Kevin Kratzke, Radial Shift fix, http://www.kekus.com"},
178   {"Patch200312a", "Jim Watters, Updated PSD format, http://photocreations.ca/panotools"},
179   {"Patch200309a", "Jim Watters, Allowed linking of y, p, & r values, http://photocreations.ca/panotools"},
180   {"Patch200308a", "Jim Watters, Improved Radial Luminance, http://photocreations.ca/panotools"}
181 #endif
182 };
183 /***************** end feature tables **********************/
184 
185 
queryFeatureInt(const char * name,int * result)186 int queryFeatureInt(const char *name, int *result)
187 {
188   int i;
189   int count = sizeof( intFeatures ) / sizeof( intFeatures[0] );
190   for(i=0; i < count; i++)
191   {
192     if(strcmp(name,intFeatures[i].name)==0)
193     {
194       *result=intFeatures[i].value;
195       return 1;
196     }
197   }
198   return 0;
199 }
200 
queryFeatureDouble(const char * name,double * result)201 int queryFeatureDouble(const char *name, double *result)
202 {
203   int i;
204   int count = sizeof( doubleFeatures ) / sizeof( doubleFeatures[0] );
205   for(i=0; i < count; i++)
206   {
207     if(strcmp(name,doubleFeatures[i].name)==0)
208     {
209       *result=doubleFeatures[i].value;
210       return 1;
211     }
212   }
213   return 0;
214 }
215 
queryFeatureString(const char * name,char * result,const int bufsize)216 int queryFeatureString(const char *name,char *result, const int bufsize)
217 {
218   int intvalue;
219   double doublevalue;
220   size_t i, length=0, count = (sizeof( stringFeatures ) / sizeof( stringFeatures[0] ));
221   const size_t tmp_len=200;
222 
223   // Fulvio Senore, August 2004
224   // allocates a dummy buffer for the calls to snprintf
225   // the original code passed NULL to snprintf() but it caused problems (asserts) when compiling
226   // with the microsoft compiler that links with the debug libraries to avoid crashes
227   char *cpTmp = malloc( tmp_len + 1 );
228   cpTmp[tmp_len] = '\0';
229 
230   for(i=0; i < count; i++)
231   {
232     if(strcmp(name,stringFeatures[i].name)==0)
233     {
234       if(result != NULL)
235       {
236         strncpy(result, stringFeatures[i].value, (size_t)bufsize);
237       }
238       length=strlen(stringFeatures[i].value);
239       break;
240     }
241   }
242   if(length <= 0)
243   {
244     // there's no string value with the specified name
245     // Let's check the int values too:
246     for(i=0; i < sizeof( intFeatures ) / sizeof( intFeatures[0] ); i++)
247     {
248       if(queryFeatureInt(name, &intvalue))
249       {
250         // length=snprintf(NULL,0,"%d",intvalue);
251         length=snprintf(cpTmp,tmp_len,"%d",intvalue);
252         if(result != NULL)
253         {
254           snprintf(result,(size_t)bufsize,"%d",intvalue);
255         }
256         break;
257       }
258     }
259   }
260   if(length <= 0)
261   {
262     // Let's check the double values too:
263     for(i=0; i < sizeof( doubleFeatures ) / sizeof( doubleFeatures[0] ); i++)
264     {
265       if(queryFeatureDouble(name, &doublevalue))
266       {
267 //        length=snprintf(NULL,0,"%0.f",doublevalue);
268         length=snprintf(cpTmp,tmp_len,"%0.f",doublevalue);
269         if(result != NULL)
270         {
271           snprintf(result,(size_t)bufsize,"%0.f",doublevalue);
272         }
273         break;
274       }
275     }
276   }
277   // make sure that the copied string always is NULL terminated, even if truncated
278   // (except if the buffer holds only zero bytes):
279   if( result && ((int)length >= bufsize) && (bufsize > 0) )
280   {
281     result[bufsize-1]=0;
282   }
283   free( cpTmp );
284   return length;
285 }
286 
queryFeatureCount()287 int queryFeatureCount()
288 {
289   return sizeof( intFeatures ) / sizeof( intFeatures[0] )+
290 	     sizeof( doubleFeatures ) / sizeof( doubleFeatures[0] ) +
291 		 sizeof( stringFeatures ) / sizeof( stringFeatures[0] );
292 }
293 
queryFeatures(int index,char ** name,Tp12FeatureType * type)294 void queryFeatures(int index,char** name,Tp12FeatureType* type)
295 {
296   if(index < (sizeof( intFeatures ) / sizeof( intFeatures[0] )))
297   {
298     if(name) *name=intFeatures[index].name;
299     if(type) *type=p12FeatureInt;
300   }
301   else
302   {
303     index -= sizeof( intFeatures ) / sizeof( intFeatures[0] );
304     if(index < sizeof( doubleFeatures ) / sizeof( doubleFeatures[0] ))
305     {
306       if(name) *name=doubleFeatures[index].name;
307       if(type) *type=p12FeatureDouble;
308     }
309     else
310     {
311       index -= sizeof( doubleFeatures ) / sizeof( doubleFeatures[0] );
312       if(index < sizeof( stringFeatures ) / sizeof( stringFeatures[0] ))
313       {
314         if(name) *name=stringFeatures[index].name;
315         if(type) *type=p12FeatureString;
316       }
317       else
318       {
319         if(type) *type=p12FeatureUnknown;
320       }
321     }
322   }
323 }
324 
325 //////////////////////////////////////////////////////////////////////
326 
327 
328 char *panoFormatNames[] = {
329     "Rectilinear",
330     "Cylindrical",
331     "Equirectangular",
332     "Fisheye",
333     "Stereographic",
334     "Mercator",
335     "Trans Mercator",
336     "Sinusoidal",
337     "Lambert Cylindrical Equal Area",
338     "Lambert Equal Area Azimuthal",
339     "Albers Equal Area Conic",
340     "Miller Cylindrical",
341     "Panini",
342     "Architectural",
343     "Orthographic",
344     "Equisolid",
345     "Equirectangular Panini",
346     "Biplane",
347     "Triplane",
348     "Panini General",
349     "Thoby Projection",
350     "Hammer-Aitoff Equal Area",
351 };
352 
353 static int panoFormatID[] = {
354     _rectilinear,
355     _panorama,
356     _equirectangular,
357     _fisheye_ff,
358     _stereographic,
359     _mercator,
360     _trans_mercator,
361     _sinusoidal,
362     _lambert,
363     _lambertazimuthal,
364     _albersequalareaconic,
365     _millercylindrical,
366     _panini,
367     _architectural,
368     _orthographic,
369     _equisolid,
370     _equipanini,
371     _biplane,
372     _triplane,
373     _panini_general,
374     _thoby,
375     _hammer,
376     };
377 
378 
panoProjectionFormatCount(void)379 int panoProjectionFormatCount(void)
380 {
381     // Return the number of Projection formats available in the library
382     assert(sizeof(panoFormatNames) == PANO_FORMAT_COUNT * sizeof(typeof (panoFormatNames[0])));
383     return PANO_FORMAT_COUNT;
384 }
385 
panoProjectionFeaturesQuery(int projection,pano_projection_features * features)386 int panoProjectionFeaturesQuery(int projection, pano_projection_features *features)
387 {
388     // Return static information on the characteristics of each of the projections
389     // in the library.  This now includes min, max and defualt parameter values.
390 	// All data are zero by default.
391 
392     int i;
393 
394     assert(features != NULL);
395     assert(sizeof(panoFormatNames) == PANO_FORMAT_COUNT * sizeof(char*));
396 
397 
398     if (projection < 0 || projection >= PANO_FORMAT_COUNT)
399 	return 0;
400 
401 
402     // Set defaults
403     bzero(features, sizeof (*features));
404 
405     features->projection = projection;
406     features->internalFormat = panoFormatID[projection];
407     features->maxHFOV = 360;
408     features->maxVFOV = 180;
409     features->name = panoFormatNames[projection];
410     switch (projection) {
411     case PANO_FORMAT_RECTILINEAR:
412 	features->maxVFOV = 179;
413 	features->maxHFOV = 179;
414 	break;
415     case PANO_FORMAT_PANORAMA:
416 	features->maxVFOV = 179;
417 	break;
418     case PANO_FORMAT_EQUIRECTANGULAR:
419     case PANO_FORMAT_MILLER_CYLINDRICAL:
420     case PANO_FORMAT_ARCHITECTURAL:
421 	break;
422     case PANO_FORMAT_PANINI:
423 	features->maxVFOV = 179;
424 	features->maxHFOV = 359;
425         break;
426     case PANO_FORMAT_EQUI_PANINI:
427 	features->maxVFOV = 179;
428 	features->maxHFOV = 359;
429         break;
430     case PANO_FORMAT_PANINI_GENERAL:
431 	features->maxVFOV = 160;
432 	features->maxHFOV = 320;
433 	features->numberOfParameters = 3;
434 	features->parm[0].name = "Cmpr";
435 	features->parm[1].name = "Tops";
436 	features->parm[2].name = "Bots";
437     features->parm[0].minValue = 0;
438     features->parm[0].maxValue = 150;
439 	features->parm[0].defValue = 100;
440     features->parm[1].minValue = -100;
441     features->parm[1].maxValue = 100;
442     features->parm[2].minValue = -100;
443     features->parm[2].maxValue = 100;
444 
445         break;
446     case PANO_FORMAT_FISHEYE_FF:
447     case PANO_FORMAT_THOBY:
448 	features->maxVFOV = 360;
449 	features->maxHFOV = 360;
450 	break;
451     case PANO_FORMAT_ORTHOGRAPHIC:
452 	features->maxVFOV = 180;
453 	features->maxHFOV = 180;
454 	break;
455     case PANO_FORMAT_EQUISOLID:
456 	features->maxVFOV = 360;
457 	features->maxHFOV = 360;
458 	break;
459     case PANO_FORMAT_STEREOGRAPHIC:
460 	features->maxHFOV = 359;
461 	features->maxVFOV = 359;
462 	break;
463     case PANO_FORMAT_MERCATOR:
464 	features->maxVFOV = 179;
465 	break;
466     case PANO_FORMAT_TRANS_MERCATOR:
467 	features->maxHFOV = 179;
468 	features->maxVFOV = 360;
469 	break;
470     case PANO_FORMAT_SINUSOIDAL:
471     case PANO_FORMAT_LAMBERT_EQUAL_AREA_CONIC:
472     case PANO_FORMAT_LAMBERT_AZIMUTHAL:
473     case PANO_FORMAT_HAMMER:
474 	break;
475     case PANO_FORMAT_ALBERS_EQUAL_AREA_CONIC:
476 	features->numberOfParameters = 2;
477 	features->parm[0].name = "phi1";
478 	features->parm[1].name = "phi2";
479 	for (i=0;i<2;i++) {
480 	    features->parm[i].minValue = -90;
481 	    features->parm[i].maxValue = +90;
482 	}
483 	features->parm[0].defValue = 0;
484 	features->parm[1].defValue = 60;
485 
486 	break;
487 	case PANO_FORMAT_BIPLANE:
488         features->maxVFOV = 179;
489         features->maxHFOV = 359;
490 		features->numberOfParameters = 2;
491 		features->parm[0].name = "alpha";
492 		features->parm[0].minValue=1;
493 		features->parm[0].maxValue=179;
494 		features->parm[0].defValue=45;
495 		features->parm[1].name = "corners";
496 		features->parm[1].minValue = 0;
497 		features->parm[1].maxValue = 1;
498 		features->parm[1].defValue = 0;
499 		break;
500 	case PANO_FORMAT_TRIPLANE:
501 	    features->maxVFOV = 179;
502         features->maxHFOV = 359;
503         features->numberOfParameters = 1;
504 		features->parm[0].name = "alpha";
505 		features->parm[0].minValue=1;
506 		features->parm[0].maxValue=120;
507 		features->parm[0].defValue=60;
508 		break;
509     default:
510 	assert(0); // A projection is missing!
511 	return 0;
512     }
513     return 1;
514 }
515 
queryFOVLimits(int projection,double * params,double * lims)516 int queryFOVLimits( int projection,		/* projection index */
517 				    double * params, /* length depends on projection */
518 					double * lims	/* [0] = maxhfov, [1] = maxvfov */
519 				  )
520 {
521 	pano_projection_features pf;
522 	int ok = panoProjectionFeaturesQuery(projection, &pf);
523 	lims[0] = lims[1] = 0;
524 	if( !ok ) return 0;
525   // default fixed values
526 	lims[0] = pf.maxHFOV;
527 	lims[1] = pf.maxVFOV;
528   // compute dynamic values
529     switch (projection) {
530     default:
531 	break;
532     case PANO_FORMAT_PANINI_GENERAL:
533 		maxFOVs_panini_general	(params, lims );
534     break;
535     case PANO_FORMAT_BIPLANE:
536         lims[0] = params[0] + 179;
537         break;
538     case PANO_FORMAT_TRIPLANE:
539         lims[0] = 2 * params[0] + 179;
540         break;
541     case PANO_FORMAT_ALBERS_EQUAL_AREA_CONIC:
542 	break;
543     }
544 
545 	return 1;
546 }
547 
548 
549 
550