[gimp-gap] fixes from test with gimp-2.9.2 DetailTracking fixes



commit 52f57cdc840648d15cd534b0badd593cc07f3551
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date:   Sun Mar 27 20:47:00 2016 +0200

    fixes from test with gimp-2.9.2 DetailTracking fixes

 ChangeLog                      |   41 ++-
 gap/gap_detail_tracking_exec.c | 1312 +++++++++++++++++++++++++++++++++-------
 gap/gap_detail_tracking_exec.h |   32 +-
 gap/gap_filter_foreach.c       |    7 +-
 gap/gap_filter_pdb.c           |   34 -
 gap/gap_filter_pdb.h           |    1 -
 gap/gap_lib.c                  |   50 +-
 gap/gap_locate2.c              |  228 +++++---
 8 files changed, 1325 insertions(+), 380 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f54d510..7fee62f 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,43 @@
-2015-19-19 Wolfgang Hofer <hof gimp org>
+2016-03-27 Wolfgang Hofer <hof gimp org>
+
+- Fixed issues from test with GIMP-2.9.2 
+  Replaced explicite pdb call to "gimp_xcf_save" procedure by
+  by  gimp_file_save that shall do the same (since .xcf extension is used)
+  Note that gimp-2.9.2 now performs checks for a valid drawale_id provided to the save procedure
+  (even in case saving to XCF that should ignore the drawable_id as gimp-2.8.x did)
+  that behavior caused GIMP-GAP automatic save to XCF fail ....
+  The implented fix now picks the active layer (or the layer on stackposition 0 in case there is no active 
layer)
+  for the gimp_file_save call and makes GIMP-GAP automatic save now work both with gimp-2.8.x and 2.9.x
+  (but still fails in gimp-2.9.x when the image has no layer at all)
+   
+
+
+- DetailTracking now provides the option to track more details
+  (up to 12 points are captured from the active path) 
+   and the best matching one (or two) points are picked for logging to the XML file
+
+  DetailTracking configure dialog supports the new parameter numPointsSelect
+  that can be set to 1 (for simple movement x/y compensation)
+  or set to 2 (for movemnet, scale and rotation compensation)
+
+- Detail Tracking renders reference and tracked points as vectors object path 
+  Hidden experimental feature to save tracked frames as sequence of frame images
+  (using the extension .XCF instead of .xml for the xml logging file triggers this feature)
+
+- DetailAlign filter extended for parsing additional XML attributes 
+  recorded by DetailTracking.
+  
+ 
+ * gap/gap_detail_align_exec.c
+ * gap/gap_detail_tracking_exec.c [.h]
+ * gap/gap_detail_tracking_main.c
+ * gap/gap_filter_foreach.c
+ * gap/gap_filter_pdb.c [.h]
+ * gap/gap_lib.c
+ * gap/gap_locate2.c
+
+
+2015-09-19 Wolfgang Hofer <hof gimp org>
 
 Merged MovePath dialog resize fix from gap-2.8 branch to master.
 
diff --git a/gap/gap_detail_tracking_exec.c b/gap/gap_detail_tracking_exec.c
index c44725b..9caf4bf 100644
--- a/gap/gap_detail_tracking_exec.c
+++ b/gap/gap_detail_tracking_exec.c
@@ -42,6 +42,7 @@ extern int gap_debug;
 
 #include "gap_base.h"
 #include "gap_libgapbase.h"
+#include "gap_lib.h"
 #include "gap_locate.h"
 #include "gap_locate2.h"
 #include "gap_colordiff.h"
@@ -62,6 +63,46 @@ extern int gap_debug;
 #define DEFAULT_removeMidlayers           TRUE
 #define DEFAULT_bgLayerIsReference        TRUE
 
+#define NUMBER_OF_COORDS 12
+
+static gdouble   p_calculate_angle_in_degree(gint p1x, gint p1y, gint p2x, gint p2y);
+static gdouble   p_calculate_scale_factor(gint p1x, gint p1y, gint p2x, gint p2y
+                       , gint p3x, gint p3y, gint p4x, gint p4y);
+static gdouble   p_calculateSqrDist(PixelCoords *coordA, PixelCoords *coordB);
+static gdouble   p_getPixelCoordsQuality(PixelCoords *coords);
+static void      p_capture_n_vector_points(gint32 imageId, PixelCoordsArray *pixelCoordsArray, gint 
ncoordsToCapture, gchar *vectorsName);
+static void      p_copy_src_to_dst_coords(PixelCoords *srcCoords, PixelCoords *dstCoords);
+static void      p_copy_src_to_dst_coords_array(PixelCoordsArray *srcCoordsArray, PixelCoordsArray 
*dstCoordsArray);
+static void      p_locate_target(gint32 refLayerId, PixelCoords *refCoords
+                    , gint32 targetLayerId, PixelCoords *targetCoords
+                    , gint32 locateOffsetX, gint32 locateOffsetY
+                    , FilterValues *valPtr);
+static void      p_write_xml_header(FILE *l_fp, gboolean center, gint width, gint height, gint numFrames);
+static void      p_write_xml_footer(FILE *l_fp);
+static gboolean  p_log_to_file(const char *filename, const char *logString
+                    , gint32 frameNr, gboolean center, gint width, gint height);
+static void      p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoords2
+                    , PixelCoords *startCoords, PixelCoords *startCoords2, FilterValues *valPtr
+                    , gint32 imageId
+                    );
+static void     p_select_best_coords(gint32 frameNr, PixelCoordsArray *currCoordsArray
+                   , PixelCoordsArray *startCoordsArray, FilterValues *valPtr
+                   , gint32 *bestIdx1
+                   , gint32 *bestIdx2
+                   );
+static gint32  p_selective_coords_logging(gint32 frameNr 
+                    , PixelCoordsArray *currCoordsArray
+                    , PixelCoordsArray *startCoordsArray
+                    , FilterValues *valPtr
+                    , gint32 imageId
+                    );
+static gint32    p_parse_frame_nr_from_layer_name(gint32 layerId);
+static void      p_get_frameHistInfo(FrameHistInfo *frameHistInfo);
+static void      p_set_frameHistInfo(FrameHistInfo *frameHistInfo);
+static void      p_set_n_vector_points(gint32 imageId, PixelCoordsArray *targetCoordsArray, gchar 
*vectorsName
+                    , gboolean setVisible, gboolean setGuides, gint32 guideIdx);
+
+
 /* -----------------------------------
  * p_calculate_angle_in_degree
  * -----------------------------------
@@ -146,26 +187,99 @@ p_calculate_scale_factor(gint p1x, gint p1y, gint p2x, gint p2y
 
 
 
+/* ----------------------------
+ * p_calculateSqrDist
+ * ----------------------------
+ * returns the square distance between coordA and coordB
+ *
+ */
+static gdouble
+p_calculateSqrDist(PixelCoords *coordA, PixelCoords *coordB)
+{
+  gdouble lenX;
+  gdouble lenY;
+  gdouble sqrDist;
+  
+  lenX = coordA->px - coordB->px;
+  lenY = coordA->py - coordB->py;
+  
+  sqrDist = (lenX * lenX) + (lenY * lenY);
+  return sqrDist;
+
+} /* end p_calculateSqrDist */
+
+/* ----------------------------
+ * p_getPixelCoordsQuality
+ * ----------------------------
+ * log the best 2 coordinates to stdout
+ * or to move-path controlpoint XML file.
+ *
+ * weight depends on average colordiff (while locating the coordinate)
+ * and distance (the longer the better for good precision 
+ *  while calcualting rotation angle and scaling)
+ */
+static gdouble
+p_getPixelCoordsQuality(PixelCoords *coords) 
+{
+  gdouble qaulity;
+  if (coords->valid)
+  {
+    qaulity = CLAMP((1.0 - coords->avgColorDiff), 0.0, 1.0);
+  }
+  else
+  {
+    qaulity = 0.0; 
+  }
+  return qaulity;
+
+}  /* end p_getPixelCoordsQuality */
+
+
+
+
 
 /* ------------------------------------------
- * p_capture_2_vector_points
+ * p_capture_n_vector_points
  * ------------------------------------------
- * capture the first 2 points of the 1st stroke in the active path vectors
+ * capture the first n coords of the 1st stroke in the named path vectors
+ *  (or active path vectors when vectorsName is null or not found)
  */
 static void
-p_capture_2_vector_points(gint32 imageId, PixelCoords *coordPtr, PixelCoords *coordPtr2) {
+p_capture_n_vector_points(gint32 imageId, PixelCoordsArray *pixelCoordsArray, gint ncoordsToCapture, gchar 
*vectorsName)
+{
+  gint nCoords;
+  gint idx;
   gint32  activeVectorsId;
   gint32  gx1;
   gint32  gy1;
-  gint32  gx2;
-  gint32  gy2;
+  PixelCoords *coordPtr;
 
   gx1 = -1;
   gy1 = -1;
-  gx2 = -1;
-  gy2 = -1;
+  
+  nCoords = CLAMP(ncoordsToCapture, 0, MAX_PIXEL_COORDS_ARRAY);
+  pixelCoordsArray->numberOfCoords = 0;
+  for(idx = 0; idx < nCoords; idx++) 
+  {
+     coordPtr = &pixelCoordsArray->pixCoord[idx];
+     coordPtr->valid = FALSE;
+     coordPtr->avgColorDiff = 1.0;  /* worst for invalid coords */
+  }
+
+  activeVectorsId = -1;
+  if (vectorsName != NULL)
+  {
+    if (*vectorsName != '\0')
+    {
+       activeVectorsId = gimp_image_get_vectors_by_name(imageId, vectorsName);
+    }
+  }
+  if (activeVectorsId < 0)
+  {
+    activeVectorsId = gimp_image_get_active_vectors(imageId);
+  }
+
 
-  activeVectorsId = gimp_image_get_active_vectors(imageId);
   if(activeVectorsId >= 0)
   {
     gint num_strokes;
@@ -196,16 +310,39 @@ p_capture_2_vector_points(gint32 imageId, PixelCoords *coordPtr, PixelCoords *co
 
         if (type == GIMP_VECTORS_STROKE_TYPE_BEZIER)
         {
-          if(num_points >= 6)
+          /* attempt to pick the first nCoords from the vectors path */
+          for(idx = 0; idx < nCoords; idx++)
           {
-            gx1 = points[0];
-            gy1 = points[1];
-          }
-          if(num_points >= 12)
-          {
-            gx2 = points[6];
-            gy2 = points[7];
+            /* for GIMP_VECTORS_STROKE_TYPE_BEZIER there are 6 points per coordinate
+             * where 
+             *   point[0] is the x coordinate of the 1st pathpoint,  point[6] holds x coordinate of the 2nd 
pathpoint
+             *   point[1] is the y coordinate of the 1st pathpoint,  point[7] holds y coordinate of the 2nd 
pathpoint
+             *   point[2] [3] [4] [5] contain other information that is not used here.
+             */
+            if(num_points > idx * 6) 
+            {
+              gint idxOffset;
+              
+              idxOffset = idx *6;
+              gx1 = points[0 + idxOffset];
+              gy1 = points[1 + idxOffset];
+              if((gx1 >= 0) && (gy1 >= 0))
+              {
+                coordPtr = &pixelCoordsArray->pixCoord[idx];
+                coordPtr->px = gx1;
+                coordPtr->py = gy1;
+                coordPtr->valid = TRUE;
+                coordPtr->avgColorDiff = 0.0;     /* best for reference coords */
+                pixelCoordsArray->numberOfCoords++;
+              }
+              else
+              {
+                break;  /* stop at the first invalid point */
+              }
+            }
+            
           }
+          
         }
         if(points)
         {
@@ -219,38 +356,24 @@ p_capture_2_vector_points(gint32 imageId, PixelCoords *coordPtr, PixelCoords *co
   }
 
 
-  coordPtr->valid = FALSE;
-  coordPtr2->valid = FALSE;
-
-  if((gx1 >= 0) && (gy1 >= 0))
+  if(gap_debug)
   {
-    if(gap_debug)
-    {
-      printf("\nPathPoints: x1=%d; y1=%d x2=%d; y2=%d\n"
-          , gx1
-          , gy1
-          , gx2
-          , gy2
+     printf("\np_capture_n_vector_points  PathPoints: %d\n", pixelCoordsArray->numberOfCoords);
+     for(idx = 0; idx < pixelCoordsArray->numberOfCoords; idx++)
+     {
+       coordPtr = &pixelCoordsArray->pixCoord[idx];
+       printf("x[%d]=%d; y[%d]=%d\n"
+          , idx
+          , coordPtr->px 
+          , idx
+          , coordPtr->py
           );
-    }
-
-    coordPtr->px = gx1;
-    coordPtr->py = gy1;
-    coordPtr->valid = TRUE;
-
-    if((gx2 != gx1) || (gy2 != gy1))
-    {
-      if ((gx2 >= 0) && (gy2 >= 0))
-      {
-        coordPtr2->px = gx2;
-        coordPtr2->py = gy2;
-        coordPtr2->valid = TRUE;
-      }
-    }
-
+     }
+     printf("  numberOfCoords:%d\n", pixelCoordsArray->numberOfCoords);
   }
 
-}  /* end p_capture_2_vector_points */
+
+}  /* end p_capture_n_vector_points */
 
 
 /* ------------------------------------
@@ -261,10 +384,35 @@ static void
 p_copy_src_to_dst_coords(PixelCoords *srcCoords, PixelCoords *dstCoords)
 {
   dstCoords->valid = srcCoords->valid;
+  dstCoords->avgColorDiff = srcCoords->avgColorDiff;
   dstCoords->px = srcCoords->px;
   dstCoords->py = srcCoords->py;
 }
 
+
+/* ------------------------------------
+ * p_copy_src_to_dst_coords_array
+ * ------------------------------------
+ */
+static void
+p_copy_src_to_dst_coords_array(PixelCoordsArray *srcCoordsArray, PixelCoordsArray *dstCoordsArray)
+{
+  gint idx;
+  gint numberOfCoords;
+  
+  numberOfCoords = CLAMP(srcCoordsArray->numberOfCoords, 0, MAX_PIXEL_COORDS_ARRAY);
+  dstCoordsArray->numberOfCoords = numberOfCoords;
+  
+  for(idx = 0; idx < numberOfCoords; idx++)
+  {
+    p_copy_src_to_dst_coords(&srcCoordsArray->pixCoord[idx]
+                            ,&dstCoordsArray->pixCoord[idx]
+                            );
+  }
+}
+
+
+
 /* ------------------------------------
  * p_locate_target
  * ------------------------------------
@@ -273,7 +421,7 @@ static void
 p_locate_target(gint32 refLayerId, PixelCoords *refCoords
    , gint32 targetLayerId, PixelCoords *targetCoords
    , gint32 locateOffsetX, gint32 locateOffsetY
-   , FilterValues *valPtr, gint32 *lostTraceCount)
+   , FilterValues *valPtr)
 {
   gdouble colordiffLocate;
   gint          ref_offset_x;
@@ -291,6 +439,7 @@ p_locate_target(gint32 refLayerId, PixelCoords *refCoords
   gimp_drawable_offsets (targetLayerId, &target_offset_x, &target_offset_y);
 
   targetCoords->valid = FALSE;
+
   refX = refCoords->px - ref_offset_x;
   refY = refCoords->py - ref_offset_y;
   colordiffLocate =
@@ -305,6 +454,7 @@ p_locate_target(gint32 refLayerId, PixelCoords *refCoords
                                     , locateOffsetX
                                     , locateOffsetY
                                     );
+  targetCoords->avgColorDiff = colordiffLocate;  /* 0.0 indicates the best. 1.0 the worst locating quality 
of the target coordinate */
 
   targetCoords->px = targetX + target_offset_x;
   targetCoords->py = targetY + target_offset_y;
@@ -317,12 +467,8 @@ p_locate_target(gint32 refLayerId, PixelCoords *refCoords
      */
     targetCoords->valid = TRUE;
   }
-  else
-  {
-    (*lostTraceCount) += 1;
-  }
 
-  if(gap_debug)
+  //if(gap_debug)
   {
     printf("p_locate_target: refX:%d refY:%d locateOffsetX:%d locateOffsetY:%d\n"
             "                targetX:%d targetY:%d targetCoords->px:%d py:%d  avgColodiff:%.5f valid:%d\n"
@@ -334,7 +480,7 @@ p_locate_target(gint32 refLayerId, PixelCoords *refCoords
         ,(int)targetY
         ,(int)targetCoords->px
         ,(int)targetCoords->py
-        ,(float)colordiffLocate
+        ,(float)targetCoords->avgColorDiff
         , targetCoords->valid
         );
   }
@@ -609,6 +755,7 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
   py = py1 + valPtr->offsY;
 
   if ((valPtr->coordsRelToFrame1)
+  &&  (valPtr->numPointsSelect > 1)
   &&  (startCoords2->valid == TRUE))
   {
     px2 = startCoords2->px -px2;
@@ -617,6 +764,7 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
   }
 
   if((currCoords2->valid  == TRUE)
+  &&  (valPtr->numPointsSelect > 1)
   && (startCoords2->valid == TRUE)
   && (startCoords->valid  == TRUE))
   {
@@ -663,7 +811,8 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
 
   logString = NULL;
 
-  if(currCoords2->valid == TRUE)
+  if((currCoords2->valid == TRUE)
+  && (valPtr->numPointsSelect > 1))
   {
     /* double point detail coordinate tracking (allows calculation of rotate and scale factors) */
     gchar *scaleValueAsString;
@@ -676,7 +825,7 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
 
     if(valPtr->enableScaling == TRUE)
     {
-      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\" rotation=\"%s\" 
width_resize=\"%s\" height_resize=\"%s\" keyframe_abs=\"%d\" p1x=\"%04d\"  p1y=\"%04d\"  p2x=\"%04d\" 
p2y=\"%04d\"/>"
+      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\" rotation=\"%s\" 
width_resize=\"%s\" height_resize=\"%s\" keyframe_abs=\"%d\" p1x=\"%04d\"  p1y=\"%04d\"  p2x=\"%04d\" 
p2y=\"%04d\" s1x=\"%04d\" s1y=\"%04d\" s2x=\"%04d\" s2y=\"%04d\"/>"
        , px
        , py
        , rotValueAsString
@@ -687,11 +836,15 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
        , currCoords->py
        , currCoords2->px
        , currCoords2->py
+       , startCoords->px
+       , startCoords->py
+       , startCoords2->px
+       , startCoords2->py
        );
     }
     else
     {
-      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\" rotation=\"%s\" 
keyframe_abs=\"%d\" p1x=\"%04d\"  p1y=\"%04d\"  p2x=\"%04d\" p2y=\"%04d\"/>"
+      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\" rotation=\"%s\" 
keyframe_abs=\"%d\" p1x=\"%04d\"  p1y=\"%04d\"  p2x=\"%04d\" p2y=\"%04d\" s1x=\"%04d\" s1y=\"%04d\" 
s2x=\"%04d\" s2y=\"%04d\"/>"
        , px
        , py
        , rotValueAsString
@@ -700,6 +853,10 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
        , currCoords->py
        , currCoords2->px
        , currCoords2->py
+       , startCoords->px
+       , startCoords->py
+       , startCoords2->px
+       , startCoords2->py
        );
     }
 
@@ -712,12 +869,15 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
     /* single point detail coordinate tracking */
     if (valPtr->offsRotate == 0.0)
     {
-      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\"  keyframe_abs=\"%d\" 
p1x=\"%04d\"  p1y=\"%04d\"/>"
+      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\"  keyframe_abs=\"%d\" 
p1x=\"%04d\"  p1y=\"%04d\" s1x=\"%04d\"  s1y=\"%04d\"/>"
          , px
          , py
          , frameNr
          , currCoords->px
          , currCoords->py
+       
+         , startCoords->px
+         , startCoords->py
          );
     }
     else
@@ -725,13 +885,15 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
       rotValueAsString = gap_base_gdouble_to_ascii_string(valPtr->offsRotate, precision_digits);
       precision_digits = 7;
 
-      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\"  rotation=\"%s\" 
keyframe_abs=\"%d\" p1x=\"%04d\"  p1y=\"%04d\"/>"
+      logString = g_strdup_printf("    <controlpoint px=\"%04d\" py=\"%04d\"  rotation=\"%s\" 
keyframe_abs=\"%d\" p1x=\"%04d\"  p1y=\"%04d\" s1x=\"%04d\"  s1y=\"%04d\"/>"
          , px
          , py
          , rotValueAsString
          , frameNr
          , currCoords->px
          , currCoords->py
+         , startCoords->px
+         , startCoords->py
          );
       g_free(rotValueAsString);
     }
@@ -762,13 +924,363 @@ p_coords_logging(gint32 frameNr, PixelCoords *currCoords,  PixelCoords *currCoor
 }  /* end p_coords_logging */
 
 
+/* ----------------------------
+ * p_select_best_coords
+ * ----------------------------
+ * pick the two best matching coordinates.
+ *
+ * weight depends on average colordiff (while locating the coordinate)
+ * and distance (the longer the better for good precision 
+ *  while calcualting rotation angle and scaling)
+ */
+static void
+p_select_best_coords(gint32 frameNr, PixelCoordsArray *currCoordsArray
+  , PixelCoordsArray *startCoordsArray, FilterValues *valPtr
+  , gint32 *bestIdx1
+  , gint32 *bestIdx2
+  )
+{
+#define MAX_AVG_LOOPS 4
+  gint idx1;
+  gint idx2;
+  gint soloPickIdx1;
+  gint pickIdx1;
+  gint pickIdx2;
+  gint numPoints;
+  gdouble sqrDistance;
+  gdouble quality;          /* 1.0 is best 0.0 is worst quality */
+  gdouble soloQuality;      /* 1.0 is best 0.0 is worst quality */
+  gdouble weight;
+  gdouble maxWeight;
+  gdouble maxSoloQuality;
+  gint32 sumOffsX;
+  gint32 sumOffsY;
+  gint32 numValidOffsets;
+  gdouble avgOffsX;
+  gdouble avgOffsY;
+  gint32 numValidOffsets1;
+  gdouble avgOffsX1;
+  gdouble avgOffsY1;
+  gint32  pixelMovementTolerance;
+  PixelCoords  *currCoords;
+  PixelCoords  *startCoords;
+  gint32 moveOffsetX;
+  gint32 moveOffsetY;
+  gint32 validPointsCount;
+        
+  maxWeight = 0.0;
+  maxSoloQuality = 0.0;
+  
+  soloPickIdx1 = 0;
+  pickIdx1 = 0;
+  pickIdx2 = 1;
+  numPoints = MIN(currCoordsArray->numberOfCoords , startCoordsArray->numberOfCoords);
+
+  /* calculate average offsets (movemnet of x and y axis) 
+   * in the 2nd and further outer loops eliminate extreme values
+   */
+  pixelMovementTolerance = MAX(5, valPtr->targetMoveRadius / 8);
+  avgOffsX = 0.0;
+  avgOffsY = 0.0;
+  for(idx2 = 0; idx2 < MAX_AVG_LOOPS; idx2++)
+  {
+    sumOffsX = 0;
+    sumOffsY = 0;
+    numValidOffsets = 0;
+    validPointsCount = 0;
+    for(idx1 = 0; idx1 < numPoints; idx1++)
+    {
 
-/* -------------------------------
- * p_parse_frame_nr_from_layerId
- * -------------------------------
+      currCoords = &currCoordsArray->pixCoord[idx1];
+      startCoords = &startCoordsArray->pixCoord[idx1];
+      if (startCoords->valid)
+      {
+        if(currCoords->valid)
+        {
+          gboolean isPlausible;
+          moveOffsetX = currCoords->px - startCoords->px;
+          moveOffsetY = currCoords->py - startCoords->py;
+          
+          validPointsCount++;
+          isPlausible = FALSE;
+          if (idx2 == 0) 
+          {
+            /* in the 1st outer loop all valid coords are plausible
+             * for calculation of an an initial average value
+             */
+            isPlausible = TRUE; 
+          }
+          else if ( (abs(moveOffsetX - avgOffsX) < pixelMovementTolerance)
+               &&   (abs(moveOffsetY - avgOffsY) < pixelMovementTolerance))
+          {
+            /* only coordinates that have similar movement vektors as the average
+             * are part of the final average calculation (that eliminates extreme values)
+             */
+            isPlausible = TRUE; 
+          }
+        
+          if (isPlausible)
+          {
+            sumOffsX += moveOffsetX;
+            sumOffsY += moveOffsetY;
+            numValidOffsets++;
+          }
+        }
+      }  
+    }
+    if (numValidOffsets > 0)
+    {
+      avgOffsX = (gdouble)sumOffsX / (gdouble)numValidOffsets;
+      avgOffsY = (gdouble)sumOffsY / (gdouble)numValidOffsets;
+      
+      if (idx2 == 0)
+      {
+        avgOffsX1 = avgOffsX;
+        avgOffsY1 = avgOffsY;
+        numValidOffsets1 = numValidOffsets;
+      }
+      else if (numValidOffsets > 2)
+      {
+        /* we have average X/Y values based on more than 2 points
+         * that shall be sufficient to detect points with extreme movement
+         */
+        break;
+      }
+      else if (idx2 == MAX_AVG_LOOPS -1)
+      {
+        /* no more attempts planed, therefore keep the current pixelMovementTolerance */
+        break;
+      }
+      else
+      {
+        /* the average offsets is based on just one or two points.
+         * which is not a good base for detection of extreme movement values.
+         * in this case try another loop with increased tolerance
+         * to get more points involved in the average calculation.
+         */
+        pixelMovementTolerance += (pixelMovementTolerance /2);
+      }
+    }
+    else
+    {
+      /* no points are available for average movement calculation */
+      if (validPointsCount > 1)
+      {
+         /* none of the valid points has movement vektor near the average value
+          * therefore try another loop with increased tolerance
+          */
+        pixelMovementTolerance += (pixelMovementTolerance /2);
+      }
+      else
+      {
+        break;  /* escape from loop because less than 2 valid point are available */
+      }
+    }
+  }
+
+  currCoordsArray->numValidOffsets = numValidOffsets;
+  currCoordsArray->avgOffsX = avgOffsX;
+  currCoordsArray->avgOffsY = avgOffsY;
+  
+  /* weight calculation loops to select best matching coordinates */
+  for(idx1 = 0; idx1 < numPoints; idx1++)
+  {
+  
+    soloQuality = p_getPixelCoordsQuality(&currCoordsArray->pixCoord[idx1])
+                * p_getPixelCoordsQuality(&startCoordsArray->pixCoord[idx1]);
+    if (soloQuality <= 0.0)
+    {
+      continue;
+    }
+
+    if (numValidOffsets > 1)
+    {
+      /* there are 2 or more valid coords available
+       * in this case eliminate coords with extreme different movement vektors
+       */
+      currCoords = &currCoordsArray->pixCoord[idx1];
+      startCoords = &startCoordsArray->pixCoord[idx1];
+      moveOffsetX = currCoords->px - startCoords->px;
+      moveOffsetY = currCoords->py - startCoords->py;
+      if ( (abs(moveOffsetX - avgOffsX) > pixelMovementTolerance)
+      ||   (abs(moveOffsetY - avgOffsY) > pixelMovementTolerance))
+      {
+        continue;
+      }
+    }
+
+
+
+    if (soloQuality > maxSoloQuality) 
+    {
+      maxSoloQuality = soloQuality;
+      soloPickIdx1 = idx1;
+    }
+    
+    if (currCoordsArray->pixCoord[idx1].valid != TRUE)
+    {
+      continue;  /* skip further weight checks when invalid points are involved */
+    }
+
+    for(idx2 = idx1 + 1; idx2 < numPoints; idx2++)
+    {
+       if (currCoordsArray->pixCoord[idx2].valid)
+       {
+         if (numValidOffsets > 1)
+         {
+           /* there are 2 or more valid coords available
+            * in this case eliminate coords with extreme different movement vektors
+            */
+           currCoords = &currCoordsArray->pixCoord[idx2];
+           startCoords = &startCoordsArray->pixCoord[idx2];
+           moveOffsetX = currCoords->px - startCoords->px;
+           moveOffsetY = currCoords->py - startCoords->py;
+           if ( (abs(moveOffsetX - avgOffsX) > pixelMovementTolerance)
+           ||   (abs(moveOffsetY - avgOffsY) > pixelMovementTolerance))
+           {
+             continue;
+           }
+         }
+
+
+
+         quality = soloQuality * p_getPixelCoordsQuality(&currCoordsArray->pixCoord[idx2])
+               * p_getPixelCoordsQuality(&startCoordsArray->pixCoord[idx2]);
+         sqrDistance = p_calculateSqrDist(&currCoordsArray->pixCoord[idx1], 
&currCoordsArray->pixCoord[idx2]);
+       
+         /* operate with the square distance for performance reason
+          * therfore also use square quality to compensate..
+          */
+         weight = sqrDistance * quality * quality;
+         if (weight > maxWeight)
+         {
+           maxWeight = weight;
+           pickIdx1 = idx1;
+           pickIdx2 = idx2;
+         }
+       }
+    }
+  }
+  
+  if (maxWeight <= 0.0)
+  {
+    pickIdx1 = soloPickIdx1;
+  }
+  
+
+  *bestIdx1 = pickIdx1;
+  *bestIdx2 = pickIdx2;
+
+  // if(gap_debug)
+  {
+    for(idx1 = 0; idx1 < numPoints; idx1++)
+    {
+      gdouble qp1;
+      gdouble qs1;
+      qp1 = p_getPixelCoordsQuality(&currCoordsArray->pixCoord[idx1]);
+      qs1 = p_getPixelCoordsQuality(&startCoordsArray->pixCoord[idx1]);
+           
+      currCoords = &currCoordsArray->pixCoord[idx1];
+      startCoords = &startCoordsArray->pixCoord[idx1];
+      moveOffsetX = currCoords->px - startCoords->px;
+      moveOffsetY = currCoords->py - startCoords->py;
+
+      printf("p_select_best_coords [%d] curr[].px:%d curr[].py:%d curr[].quality:%.4f "
+             "  start[].px:%d start[].py:%d start[].quality:%.4f mvX:%d mvY:%d"
+        , (int) idx1
+        , currCoordsArray->pixCoord[idx1].px
+        , currCoordsArray->pixCoord[idx1].py
+        , (float)qp1
+        , startCoordsArray->pixCoord[idx1].px
+        , startCoordsArray->pixCoord[idx1].py
+        , (float)qs1
+        , (int)moveOffsetX
+        , (int)moveOffsetY
+        );
+      
+      if ((qp1 <= 0.0) || (qs1 <= 0.0))
+      {
+        printf("\n");
+      }
+      else if ( (abs(moveOffsetX - avgOffsX) > pixelMovementTolerance)
+      ||   (abs(moveOffsetY - avgOffsY) > pixelMovementTolerance))
+      {
+        printf("(Movement extremeValue > Tolerance: %d) \n"
+          ,(int)pixelMovementTolerance
+          );
+      }
+      else
+      {
+        printf("(Movement typical) \n");
+      }
+
+    }
+    
+    printf("p_select_best_coords: frameNr:%d bestIdx1:%d bestIdx2:%d maxWeight:%.4f avgOffst1 X:%.4f Y:%.4f 
numValidOffsets:%d avgOffst X:%.4f Y:%.4f\n"
+      , (int)frameNr
+      , (int)pickIdx1
+      , (int)pickIdx2
+      , (float)maxWeight
+      , (float)avgOffsX1
+      , (float)avgOffsY1
+      , (int)numValidOffsets
+      , (float)avgOffsX
+      , (float)avgOffsY
+      );
+  }
+  
+}  /* end p_select_best_coords */
+
+
+/* ----------------------------
+ * p_selective_coords_logging
+ * ----------------------------
+ * log the best 2 coordinates to stdout
+ * or to move-path controlpoint XML file.
+ *
+ * weight depends on average colordiff (while locating the coordinate)
+ * and distance (the longer the better for good precision 
+ *  while calcualting rotation angle and scaling)
  */
 static gint32
-p_parse_frame_nr_from_layerId(gint32 layerId)
+p_selective_coords_logging(gint32 frameNr 
+  , PixelCoordsArray *currCoordsArray
+  , PixelCoordsArray *startCoordsArray
+  , FilterValues *valPtr
+  , gint32 imageId
+  )
+{
+  gint32 bestIdx1;
+  gint32 bestIdx2;
+
+  p_select_best_coords(frameNr
+  , currCoordsArray
+  , startCoordsArray
+  , valPtr
+  , &bestIdx1
+  , &bestIdx2
+  );
+
+  p_coords_logging(frameNr
+                  , &currCoordsArray->pixCoord[bestIdx1]
+                  , &currCoordsArray->pixCoord[bestIdx2]
+                  , &startCoordsArray->pixCoord[bestIdx1]
+                  , &startCoordsArray->pixCoord[bestIdx2]
+                  , valPtr
+                  , imageId
+                  );
+  
+  return (bestIdx1);
+  
+}  /* end p_selective_coords_logging */
+
+
+/* --------------------------------
+ * p_parse_frame_nr_from_layer_name
+ * --------------------------------
+ */
+static gint32
+p_parse_frame_nr_from_layer_name(gint32 layerId)
 {
   char     *layername;
   gint32    frameNr;
@@ -798,7 +1310,7 @@ p_parse_frame_nr_from_layerId(gint32 layerId)
 
   return (frameNr);
 
-}  /* end p_parse_frame_nr_from_layerId */
+}  /* end p_parse_frame_nr_from_layer_name */
 
 
 /* -------------------------------
@@ -809,13 +1321,19 @@ static void
 p_get_frameHistInfo(FrameHistInfo *frameHistInfo)
 {
   int l_len;
+  PixelCoords *startCoords;
+  
 
   frameHistInfo->workImageId = -1;
   frameHistInfo->frameNr = 0;
-  frameHistInfo->startCoords.valid = FALSE;
-  frameHistInfo->startCoords.px = 0;
-  frameHistInfo->startCoords.py = 0;
+  frameHistInfo->trackedFramesCount = 0;
   frameHistInfo->lostTraceCount = 0;
+  frameHistInfo->startCoordsArray.numberOfCoords = 0;
+
+  startCoords = &frameHistInfo->startCoordsArray.pixCoord[0];
+  startCoords->valid = FALSE;
+  startCoords->px = 0;
+  startCoords->py = 0;
 
   l_len = gimp_get_data_size (GAP_DETAIL_FRAME_HISTORY_INFO);
 
@@ -834,19 +1352,25 @@ p_get_frameHistInfo(FrameHistInfo *frameHistInfo)
 
     gimp_get_data(GAP_DETAIL_FRAME_HISTORY_INFO, frameHistInfo);
 
-    if(gap_debug)
+    //if(gap_debug)
     {
+      PixelCoords *prevCoords;
+      
+      startCoords = &frameHistInfo->startCoordsArray.pixCoord[0];
+      prevCoords  = &frameHistInfo->prevCoordsArray.pixCoord[0];
+
       printf("p_get_frameHistInfo: %s  frameNr:%d px:%d py:%d valid:%d\n"
-             "                     prevPx:%d prevPy:%d prevValid:%d lostTraceCount:%d\n"
+             "                     prevPx:%d prevPy:%d prevValid:%d lostTraceCount:%d  
trackedFramesCount:%d\n"
         , GAP_DETAIL_FRAME_HISTORY_INFO
         , (int)frameHistInfo->frameNr
-        , (int)frameHistInfo->startCoords.px
-        , (int)frameHistInfo->startCoords.py
-        , (int)frameHistInfo->startCoords.valid
-        , (int)frameHistInfo->prevCoords.px
-        , (int)frameHistInfo->prevCoords.py
-        , (int)frameHistInfo->prevCoords.valid
+        , (int)startCoords->px
+        , (int)startCoords->py
+        , (int)startCoords->valid
+        , (int)prevCoords->px
+        , (int)prevCoords->py
+        , (int)prevCoords->valid
         , (int)frameHistInfo->lostTraceCount
+        , (int)frameHistInfo->trackedFramesCount
         );
     }
 
@@ -866,15 +1390,21 @@ p_set_frameHistInfo(FrameHistInfo *frameHistInfo)
 {
   if(gap_debug)
   {
+      PixelCoords *startCoords;
+      PixelCoords *prevCoords;
+      
+      startCoords = &frameHistInfo->startCoordsArray.pixCoord[0];
+      prevCoords  = &frameHistInfo->prevCoordsArray.pixCoord[0];
+      
       printf("p_SET_frameHistInfo: %s  frameNr:%d px:%d py:%d valid:%d  prevPx:%d prevPy:%d prevValid:%d\n\n"
         , GAP_DETAIL_FRAME_HISTORY_INFO
         , (int)frameHistInfo->frameNr
-        , (int)frameHistInfo->startCoords.px
-        , (int)frameHistInfo->startCoords.py
-        , (int)frameHistInfo->startCoords.valid
-        , (int)frameHistInfo->prevCoords.px
-        , (int)frameHistInfo->prevCoords.py
-        , (int)frameHistInfo->prevCoords.valid
+        , (int)startCoords->px
+        , (int)startCoords->py
+        , (int)startCoords->valid
+        , (int)prevCoords->px
+        , (int)prevCoords->py
+        , (int)prevCoords->valid
 
         );
   }
@@ -886,88 +1416,155 @@ p_set_frameHistInfo(FrameHistInfo *frameHistInfo)
 
 
 /* -------------------------------
- * p_set_2_vector_points
+ * p_set_n_vector_points
  * -------------------------------
- * remove all strokes from the active path vectors
- * and set a new stroke containing targetCoords (one or 2 depend on the valid flag)
- * For better visualisation set guide lines crossing at the first target coords.
+ * if the image already contains a vectors object with the specified vectorsName
+ * then  remove all strokes from the vectors object and replace it with the 
+ * points in the targetCoordsArray.
+ * 
+ * in case there is no vectors object with the specified vectorsName create it and add it to the image.
+ *
+ * if setGuides is TRUE
+ * then set guide lines crossing at the target coords[guideIdx] for better visualisation.
+ *  (note that path vectors will be not visible in case the path contains just one single point)
  */
 static void
-p_set_2_vector_points(gint32 imageId, PixelCoords *targetCoords, PixelCoords *targetCoords2)
+p_set_n_vector_points(gint32 imageId, PixelCoordsArray *targetCoordsArray, gchar *vectorsName
+   , gboolean setVisible, gboolean setGuides, gint32 guideIdx)
 {
-  gint32  activeVectorsId;
+  gint32  vectorsId;
   /* gint    newStrokeId; */
 
+  gint32    showGuideIdx;
   gdouble  *points;
   gint      num_points;
+  gint      l_idx;
   gboolean  closed;
   GimpVectorsStrokeType type;
+  PixelCoords *targetCoords;
+  
+ 
+  showGuideIdx = CLAMP(guideIdx, 0, targetCoordsArray->numberOfCoords -1);
+  targetCoords  = &targetCoordsArray->pixCoord[showGuideIdx];
 
-
-  gimp_image_add_hguide(imageId, targetCoords->py);
-  gimp_image_add_vguide(imageId, targetCoords->px);
+  if(setGuides == TRUE)
+  {
+    gimp_image_add_hguide(imageId, targetCoords->py);
+    gimp_image_add_vguide(imageId, targetCoords->px);
+  }
 
 
-  activeVectorsId = gimp_image_get_active_vectors(imageId);
-  if(activeVectorsId >= 0)
+  //if(gap_debug)
+  if(setGuides)
   {
-    gint num_strokes;
-    gint *strokes;
-
-    strokes = gimp_vectors_get_strokes (activeVectorsId, &num_strokes);
-    if(strokes)
+    printf("\np_set_n_vector_points vectorsName:%s\n  numberOfCoords:%d  guideIdx:%d showGuideIdx:%d\n"
+        , vectorsName
+        , (int)targetCoordsArray->numberOfCoords
+        , (int)guideIdx
+        , (int)showGuideIdx
+        );
+    for(l_idx = 0; l_idx < targetCoordsArray->numberOfCoords; l_idx++)
     {
-      if(num_strokes > 0)
+      gdouble pdx;
+      gdouble pdy;
+      targetCoords  = &targetCoordsArray->pixCoord[l_idx];
+      if (targetCoords->valid)
       {
-        gint ii;
-        for(ii=0; ii < num_strokes; ii++)
-        {
-          gimp_vectors_remove_stroke(activeVectorsId, strokes[ii]);
-        }
+         pdx = targetCoords->px;
+         pdy = targetCoords->py;
       }
-      g_free(strokes);
-
+      else
+      {
+         pdx = 0;
+         pdy = 0;
+      }
+      
+      printf("pdx[%d] : %.2f  pdy[%d] : %.2f\n"
+        , l_idx
+        , (float)pdx
+        , l_idx
+        , (float)pdy
+        );
+    
     }
+  }
 
-    if (targetCoords->valid)
+  vectorsId = gimp_image_get_vectors_by_name(imageId, vectorsName);
+  if(vectorsId >= 0)
+  {
+//     gint num_strokes;
+//     gint *strokes;
+// 
+//     strokes = gimp_vectors_get_strokes (vectorsId, &num_strokes);
+//     if(strokes)
+//     {
+//       if(num_strokes > 0)
+//       {
+//         gint ii;
+//         for(ii=0; ii < num_strokes; ii++)
+//         {
+//           gimp_vectors_remove_stroke(vectorsId, strokes[ii]);
+//         }
+//       }
+//       g_free(strokes);
+// 
+//     }
+    gimp_image_remove_vectors(imageId, vectorsId);
+  } 
+
+  /* create new vectors path */
+  vectorsId = gimp_vectors_new(imageId, vectorsName);
+
+  
+  if(vectorsId >= 0)  
+  {
+    num_points = 6 * targetCoordsArray->numberOfCoords;
+    points = g_new (gdouble, num_points);
+    
+    for(l_idx = 0; l_idx < targetCoordsArray->numberOfCoords; l_idx++)
     {
-      closed = FALSE;
-      num_points = 6;
-      if (targetCoords2->valid)
+      gdouble pdx;
+      gdouble pdy;
+      gint    offset;
+      
+      offset = l_idx * 6;
+      targetCoords  = &targetCoordsArray->pixCoord[l_idx];
+      if (targetCoords->valid)
       {
-        num_points = 12;
+         pdx = targetCoords->px;
+         pdy = targetCoords->py;
       }
-      points = g_new (gdouble, num_points);
-      points[0] = targetCoords->px;
-      points[1] = targetCoords->py;
-      points[2] = targetCoords->px;
-      points[3] = targetCoords->py;
-      points[4] = targetCoords->px;
-      points[5] = targetCoords->py;
-      if(targetCoords2->valid)
+      else
       {
-        points[6] = targetCoords2->px;
-        points[7] = targetCoords2->py;
-        points[8] = targetCoords2->px;
-        points[9] = targetCoords2->py;
-        points[10] = targetCoords2->px;
-        points[11] = targetCoords2->py;
+         pdx = 0;
+         pdy = 0;
       }
+      points[0 + offset] = pdx;
+      points[1 + offset] = pdy;
+      points[2 + offset] = pdx;
+      points[3 + offset] = pdy;
+      points[4 + offset] = pdx;
+      points[5 + offset] = pdy;
+    }
 
-      type = GIMP_VECTORS_STROKE_TYPE_BEZIER;
-      /* newStrokeId = */ gimp_vectors_stroke_new_from_points (activeVectorsId
+    
+    closed = FALSE;
+    type = GIMP_VECTORS_STROKE_TYPE_BEZIER;
+    /* newStrokeId = */ gimp_vectors_stroke_new_from_points (vectorsId
                                      , type
                                      , num_points
                                      , points
                                      , closed
                                      );
-      g_free(points);
-    }
-
+    g_free(points);
+    
+    gimp_image_insert_vectors(imageId, vectorsId, -1, 0);
+    gimp_vectors_set_visible(vectorsId, setVisible);
 
   }
 
-}  /* end p_set_2_vector_points */
+}  /* end p_set_n_vector_points */
+
 
 
 /* -----------------------------------
@@ -978,34 +1575,53 @@ p_set_2_vector_points(gint32 imageId, PixelCoords *targetCoords, PixelCoords *ta
  * This image has one layer at the first snapshot
  * and each further snapshot adds one layer on top of the layerstack.
  *
- * The start is detected when the image has only one layer.
+ * The start is detected when frameHistInfo->trackedFramesCount == 0
+ * or whenever the imageId has changed ( frameHistInfo->workImageId )
+ * or whenever the image has exactly one layer. (typical at 1st snapshot or when the user has deleted other 
layers)
+ *
  * optionally the numer of layers can be limted
- * to 2 (or more) layers.
+ * to 2 (or 3) layers.
+ *
+ * Detail tracking output depends on the specified vlPtr->moveLogFile
+ * o) output coordinates offests and rotation information 
+ *    is written in XML format to the moveLogFile 
+ *       if filename is present and has not .xcf extension
+ * o) XML output is written to stdout  
+ *       if moveLogFile is empty or starts with the '-' character.
+ * o) is rendered as vectors path (with the name "TrackingPoints") 
+ *       and saved as frame image 
+ *       if the specified moveLogFile has .xcf extension
  */
 gint32
 gap_track_detail_on_top_layers(gint32 imageId, gboolean doProgress, FilterValues *valPtr)
 {
+  gint      l_idx;
   gint      l_nlayers;
   gint32   *l_layers_list;
 
   FrameHistInfo  frameHistInfoData;
   FrameHistInfo *frameHistInfo;
-  PixelCoords  currCoords;
-  PixelCoords  currCoords2;
-  PixelCoords  targetCoords;
-  PixelCoords  targetCoords2;
-  gint32       locateOffsetX;
-  gint32       locateOffsetY;
-  gint32       locateOffsetX2;
-  gint32       locateOffsetY2;
-  gint32       lostTraceCount;
-
-  if(gap_debug)
+  PixelCoordsArray currCoordsArray;
+  PixelCoordsArray targetCoordsArray;
+  gint32       locateOffsetX[MAX_PIXEL_COORDS_ARRAY];
+  gint32       locateOffsetY[MAX_PIXEL_COORDS_ARRAY];
+  gint32       successfulTracedPointsCount;
+  gint32       previousLostTraceCount;
+  gint32       currFrameNr;
+  gchar       *l_extension;
+  gboolean     isTrackingToFrameImage;
+  gint32       bestIdx1;
+  
+  
+  
+
+  //if(gap_debug)
   {
-      printf("gap_track_detail_on_top_layers: START\n"
-             "  refShapeRadius:%d targetMoveRadius:%d locateColordiff:%.4f\n"
+      printf("\ngap_track_detail_on_top_layers: START\n"
+             "  numPointsSelect:%d refShapeRadius:%d targetMoveRadius:%d locateColordiff:%.4f\n"
              "  coordsRelToFrame1:%d  offsX:%d offsY:%d removeMidlayers:%d bgLayerIsReference:%d\n"
              "  moveLogFile:%s\n"
+            , (int)valPtr->numPointsSelect 
             , (int)valPtr->refShapeRadius
             , (int)valPtr->targetMoveRadius
             , (float)valPtr->loacteColodiffThreshold
@@ -1020,84 +1636,158 @@ gap_track_detail_on_top_layers(gint32 imageId, gboolean doProgress, FilterValues
 
   frameHistInfo = &frameHistInfoData;
 
-  currCoords.valid = FALSE;
-  targetCoords.valid = FALSE;
+  successfulTracedPointsCount = 0;
+  previousLostTraceCount = 0;
+  bestIdx1 = 0;
+  currCoordsArray.numberOfCoords = 0;
+  currCoordsArray.numValidOffsets = 0;
+  targetCoordsArray.numValidOffsets = 0;
+  for (l_idx = 0; l_idx < MAX_PIXEL_COORDS_ARRAY; l_idx++)
+  {
+    currCoordsArray.pixCoord[l_idx].valid = FALSE;
+    targetCoordsArray.pixCoord[l_idx].valid = FALSE;
+    locateOffsetX[l_idx] = 0;
+    locateOffsetY[l_idx] = 0;
+  }
+  
+  /* check if detail tracking output is logged to an XML file valPtr->moveLogFile
+   * or is written as vectors path and saved as frame image to an .XCF file (if extension .XCF is specified)
+   */
+  isTrackingToFrameImage = FALSE;
+  l_extension = NULL;
+  if (valPtr->moveLogFile[0] != '\0')
+  {
+    l_extension = gap_lib_alloc_extension(&valPtr->moveLogFile[0]);
+  }
+  if(l_extension != NULL) 
+  {
+    if ((strcmp(".xcf", l_extension) == 0)
+    ||  (strcmp(".XCF", l_extension) == 0))
+    {
+      isTrackingToFrameImage = TRUE;
+    }
+    g_free(l_extension);
+    l_extension = NULL;
+  }  
+
+
+  p_capture_n_vector_points(imageId, &currCoordsArray, NUMBER_OF_COORDS, 
VECTORS_NAME_START_REFERENCE_POINTS);
+  if (currCoordsArray.numberOfCoords == 0)
+  {
+    //if(gap_debug)
+    {
+       printf("gap_track_detail_on_top_layers  NO tracking possible because No vectors path was found\n");
+    }  
+    return (imageId);
+  } 
+  
 
   l_layers_list = gimp_image_get_layers(imageId, &l_nlayers);
   if((l_layers_list != NULL)
   && (l_nlayers > 0))
   {
     gint32 topLayerId;
+    gint32 refLayerId;
 
     topLayerId = l_layers_list[0];
 
-    frameHistInfo->frameNr += 1;
+    refLayerId = l_layers_list[1];
+    if (valPtr->bgLayerIsReference == TRUE)
+    {
+      refLayerId = l_layers_list[l_nlayers -1];
+    }
+
+    /// frameHistInfo->frameNr += 1;
 
     p_get_frameHistInfo(frameHistInfo);
-    locateOffsetX = 0;
-    locateOffsetY = 0;
-    locateOffsetX2 = 0;
-    locateOffsetY2 = 0;
 
-    if (l_nlayers == 1)
-    {
-      p_capture_2_vector_points(imageId, &currCoords, &currCoords2);
 
+    if ((frameHistInfo->trackedFramesCount == 0)
+    || (frameHistInfo->workImageId != imageId)
+    || (l_nlayers == 1))
+    {
+      //if(gap_debug)
+      {
+        printf("(A) gap_track_detail_on_top_layers  BEGIN tracking l_nlayers:%d\n"
+               ,(int)l_nlayers
+               );
+      }  
+      /* start of detail tracking when no frame history available and whenever a new workImage was created */
       frameHistInfo->lostTraceCount = 0;
-      p_copy_src_to_dst_coords(&currCoords,  &frameHistInfo->startCoords);
-      p_copy_src_to_dst_coords(&currCoords2, &frameHistInfo->startCoords2);
-      p_copy_src_to_dst_coords(&currCoords,  &frameHistInfo->prevCoords);
-      p_copy_src_to_dst_coords(&currCoords2, &frameHistInfo->prevCoords2);
+      frameHistInfo->trackedFramesCount = 0;
+      p_copy_src_to_dst_coords_array(&currCoordsArray,  &frameHistInfo->startCoordsArray);
+      p_copy_src_to_dst_coords_array(&currCoordsArray,  &frameHistInfo->prevCoordsArray);
+
+      /* create (or replace) reference vectors objects */
+      p_set_n_vector_points(imageId, &currCoordsArray, VECTORS_NAME_START_REFERENCE_POINTS, FALSE, FALSE, 0);
+      p_set_n_vector_points(imageId, &currCoordsArray, VECTORS_NAME_REFERENCE_POINTS, TRUE, FALSE, 0);
+
 
       frameHistInfo->frameNr = 1;
-      p_coords_logging(frameHistInfo->frameNr
-                      , &currCoords
-                      , &currCoords2
-                      , &frameHistInfo->startCoords
-                      , &frameHistInfo->startCoords2
+      frameHistInfo->workImageId = imageId;
+      if (isTrackingToFrameImage != TRUE)
+      {
+        bestIdx1 = p_selective_coords_logging(frameHistInfo->frameNr
+                      , &currCoordsArray
+                      , &frameHistInfo->startCoordsArray
                       , valPtr
                       , imageId
                       );
+      }
     }
     else
     {
-      gint32 refLayerId;
 
-      refLayerId = l_layers_list[1];
-      if (valPtr->bgLayerIsReference == TRUE)
+      //if(gap_debug)
       {
-        refLayerId = l_layers_list[l_nlayers -1];
-      }
+        printf("(B) gap_track_detail_on_top_layers  CONTINUE tracking l_nlayers:%d\n"
+               ,(int)l_nlayers
+               );
+      }  
+
 
 
-      if(frameHistInfo->startCoords.valid != TRUE)
+      /* (re)inital capture vector points if the start coords of first processed frame are not valid 
+       *  TODO detecting by valid startCoordsArray [0] is no longer sufficient
+       *       for now re-init is hercoded disabled (not sure if that is needed ...)
+       */
+      if(FALSE) //// if (frameHistInfo->startCoordsArray.pixCoord[0].valid != TRUE)
       {
-        p_capture_2_vector_points(imageId, &currCoords, &currCoords2);
+        p_capture_n_vector_points(imageId, &currCoordsArray, NUMBER_OF_COORDS, 
VECTORS_NAME_START_REFERENCE_POINTS);
 
         frameHistInfo->lostTraceCount = 0;
-        p_copy_src_to_dst_coords(&currCoords,  &frameHistInfo->startCoords);
-        p_copy_src_to_dst_coords(&currCoords2, &frameHistInfo->startCoords2);
-        p_copy_src_to_dst_coords(&currCoords,  &frameHistInfo->prevCoords);
-        p_copy_src_to_dst_coords(&currCoords2, &frameHistInfo->prevCoords2);
-
-        frameHistInfo->frameNr = p_parse_frame_nr_from_layerId(refLayerId);
-        p_coords_logging(frameHistInfo->frameNr
-                      , &currCoords
-                      , &currCoords2
-                      , &frameHistInfo->startCoords
-                      , &frameHistInfo->startCoords2
+        p_copy_src_to_dst_coords_array(&currCoordsArray,  &frameHistInfo->startCoordsArray);
+        p_copy_src_to_dst_coords_array(&currCoordsArray,  &frameHistInfo->prevCoordsArray);
+
+        frameHistInfo->frameNr = p_parse_frame_nr_from_layer_name(refLayerId);
+        if (isTrackingToFrameImage != TRUE)
+        {
+          bestIdx1 = p_selective_coords_logging(frameHistInfo->frameNr
+                      , &currCoordsArray
+                      , &frameHistInfo->startCoordsArray
                       , valPtr
                       , imageId
                       );
+        }
       }
       else if (valPtr->bgLayerIsReference == TRUE)
       {
+        gint32 sumOffsX;
+        gint32 sumOffsY;
+        gint32 numValidOffsets;
+
+        //if(gap_debug)
+        {
+          printf("(Bb) gap_track_detail_on_top_layers  CONTINUE BG is referenence  l_nlayers:%d\n"
+                ,(int)l_nlayers
+                );
+        }  
+        
         /* when all trackings refere to initial BG layer (that is always kept as reference
-         * for all further frames), we do not capture currCoords
+         * for all further frames), we do not capture currCoordsArray
          * but copy the initial start values.
          */
-        p_copy_src_to_dst_coords(&frameHistInfo->startCoords, &currCoords);
-        p_copy_src_to_dst_coords(&frameHistInfo->startCoords2, &currCoords2);
+        p_copy_src_to_dst_coords_array(&frameHistInfo->startCoordsArray, &currCoordsArray);
 
         /* locate shall start investigations at matching coordinates of the previous processed frame
          * because the chance to find the detail near this postion is much greater than near
@@ -1106,77 +1796,163 @@ gap_track_detail_on_top_layers(gint32 imageId, gboolean doProgress, FilterValues
          * but without the locateOffsets we might loose track of the detail when it moves outside the 
targetRadius
          * and increasing the targetRadius would also result in siginificant longer processing time)
          */
-        if (frameHistInfo->prevCoords.valid)
+        sumOffsX = 0;
+       sumOffsY = 0;
+        numValidOffsets = 0;
+        for (l_idx = 0; l_idx < frameHistInfo->prevCoordsArray.numberOfCoords; l_idx++)
         {
-          locateOffsetX = frameHistInfo->prevCoords.px - frameHistInfo->startCoords.px;
-          locateOffsetY = frameHistInfo->prevCoords.py - frameHistInfo->startCoords.py;
-           }
-        if (frameHistInfo->prevCoords2.valid)
+          PixelCoords  *prevCoords;
+          PixelCoords  *startCoords;
+          
+          prevCoords = &frameHistInfo->prevCoordsArray.pixCoord[l_idx];
+          startCoords = &frameHistInfo->startCoordsArray.pixCoord[l_idx];
+          if (startCoords->valid)
+          {
+            if(prevCoords->valid)
+            {
+              locateOffsetX[l_idx] = prevCoords->px - startCoords->px;
+              locateOffsetY[l_idx] = prevCoords->py - startCoords->py;
+              
+              sumOffsX += locateOffsetX[l_idx];
+              sumOffsY += locateOffsetY[l_idx];
+              numValidOffsets++;
+            }
+          }
+        }
+        if ((frameHistInfo->prevCoordsArray.numberOfCoords > numValidOffsets)
+        &&  (numValidOffsets > 0))
         {
-          locateOffsetX2 = frameHistInfo->prevCoords2.px - frameHistInfo->startCoords2.px;
-          locateOffsetY2 = frameHistInfo->prevCoords2.py - frameHistInfo->startCoords2.py;
-           }
+          /* for invalid coordinates use the average offests of all valid points
+           * as guess. This shall increase the chances to pick up a coordinate
+           * that has lost trace some frames ago.
+           * (Another option would be to increase the search radius in such cases
+           * but this would also significant increase the processing time)
+           */
+          for (l_idx = 0; l_idx < frameHistInfo->prevCoordsArray.numberOfCoords; l_idx++)
+          {
+            PixelCoords  *prevCoords;
+            PixelCoords  *startCoords;
+          
+            prevCoords = &frameHistInfo->prevCoordsArray.pixCoord[l_idx];
+            startCoords = &frameHistInfo->startCoordsArray.pixCoord[l_idx];
+            if (startCoords->valid)
+            {
+              if(!prevCoords->valid)
+              {
+                locateOffsetX[l_idx] = sumOffsX / numValidOffsets;
+                locateOffsetY[l_idx] = sumOffsY / numValidOffsets;
+              }
+            }
+          }
+
+        }
+         
       }
       else
       {
-           /* tracking is done with reference to the previous layer
-            * therefore refresh capture. (currCoords are set to the targetCoords
-            * that were calculated in previous processing step)
-            */
-        p_capture_2_vector_points(imageId, &currCoords, &currCoords2);
+        //if(gap_debug)
+        {
+          printf("(Bp) gap_track_detail_on_top_layers  CONTINUE Previous Layer is referenence l_nlayers:%d\n"
+                ,(int)l_nlayers
+                );
+        }  
+        /* tracking is done with reference to the previous layer
+         * therefore refresh capture. (currCoordsArray are set to the targetCoordsArray
+         * that were calculated in previous processing step)
+         */
+        p_capture_n_vector_points(imageId, &currCoordsArray, NUMBER_OF_COORDS, 
VECTORS_NAME_REFERENCE_POINTS);
+
       }
+   
 
-      lostTraceCount = frameHistInfo->lostTraceCount;
 
-      if (currCoords.valid == TRUE)
+    }
+
+    /* ----  tracking requires at least 2 layers -------- */
+
+    if (l_nlayers > 1)
+    {
+      previousLostTraceCount = frameHistInfo->lostTraceCount;
+      targetCoordsArray.numberOfCoords = currCoordsArray.numberOfCoords;
+      
+      //if(gap_debug)
       {
-        p_locate_target(refLayerId
-                           , &currCoords
-                           , topLayerId
-                           , &targetCoords
-                           , locateOffsetX
-                           , locateOffsetY
-                           , valPtr
-                           , &frameHistInfo->lostTraceCount
-                           );
+        printf("DetailTrack before locating %d coordinates\n", currCoordsArray.numberOfCoords);
       }
-
-      if (currCoords2.valid == TRUE)
+      
+      for (l_idx = 0; l_idx < currCoordsArray.numberOfCoords; l_idx++)
       {
-        p_locate_target(refLayerId
-                           , &currCoords2
+        PixelCoords  *currCoordsPtr;
+        PixelCoords  *targetCoordsPtr;
+        
+        currCoordsPtr = &currCoordsArray.pixCoord[l_idx];
+        targetCoordsPtr = &targetCoordsArray.pixCoord[l_idx];
+        targetCoordsPtr->valid = FALSE;
+        targetCoordsPtr->px = 0;
+        targetCoordsPtr->py = 0;
+         
+        if (currCoordsPtr->valid == TRUE)
+        {
+          p_locate_target(refLayerId
+                           , currCoordsPtr
                            , topLayerId
-                           , &targetCoords2
-                           , locateOffsetX2
-                           , locateOffsetY2
+                           , targetCoordsPtr
+                           , locateOffsetX[l_idx]
+                           , locateOffsetY[l_idx]
                            , valPtr
-                           , &frameHistInfo->lostTraceCount
                            );
-      }
-
+          if (targetCoordsPtr->valid == TRUE)
+          {
+            successfulTracedPointsCount++;
+          }
+        }
 
+      }
+      if (successfulTracedPointsCount < valPtr->numPointsSelect)
+      {
+        /* the required number of successful traces was not detected
+         * therefore increase the lostTraceCount in the frame history
+         */
+        frameHistInfo->lostTraceCount += 1;
+      }
     }
 
-
-
-    if (targetCoords.valid == TRUE)
+    gap_image_remove_all_guides(imageId);
+    currFrameNr = p_parse_frame_nr_from_layer_name(topLayerId);
+    
+    /* here we could check if at least one points could be successfully located,
+     * but continue setting vectors and logging on the ivalid result may help
+     * analysis what went wrong when the xml includes the unusables results too.
+     * if ((successfulTracedPointsCount > 0) 
+     *  || (frameHistInfo->trackedFramesCount == 0))
+     */
+    if(TRUE)
     {
-      gap_image_remove_all_guides(imageId);
-      p_set_2_vector_points(imageId, &targetCoords, &targetCoords2);
-
-      p_copy_src_to_dst_coords(&targetCoords,  &frameHistInfo->prevCoords);
-      p_copy_src_to_dst_coords(&targetCoords2, &frameHistInfo->prevCoords2);
-
-      frameHistInfo->frameNr = p_parse_frame_nr_from_layerId(topLayerId);
-      p_coords_logging(frameHistInfo->frameNr
-                      , &targetCoords
-                      , &targetCoords2
-                      , &frameHistInfo->startCoords
-                      , &frameHistInfo->startCoords2
+      p_copy_src_to_dst_coords_array(&targetCoordsArray,  &frameHistInfo->prevCoordsArray);
+
+      frameHistInfo->frameNr = currFrameNr;
+      
+      if (isTrackingToFrameImage != TRUE)
+      {
+        bestIdx1 = p_selective_coords_logging(frameHistInfo->frameNr
+                      , &targetCoordsArray
+                      , &frameHistInfo->startCoordsArray
                       , valPtr
                       , imageId
                       );
-
+      }
+      else
+      {
+        gint32 bestIdx2;
+        p_select_best_coords(frameHistInfo->frameNr
+         , &targetCoordsArray
+         , &frameHistInfo->startCoordsArray
+         , valPtr
+         , &bestIdx1
+         , &bestIdx2
+        );
+      }
+      p_set_n_vector_points(imageId, &targetCoordsArray, VECTORS_NAME_TRACKING_POINTS, TRUE, TRUE, bestIdx1);
     }
 
     if (valPtr->removeMidlayers == TRUE)
@@ -1187,18 +1963,66 @@ gap_track_detail_on_top_layers(gint32 imageId, gboolean doProgress, FilterValues
                             );
     }
 
+
+    /* optional save image_id as frame */
+    if (isTrackingToFrameImage == TRUE)
+    {
+      l_extension = gap_lib_alloc_extension(&valPtr->moveLogFile[0]);
+      if (l_extension != NULL)
+      {
+        gchar *frame_filename;
+        gchar *basename;
+        long   number;
+        gint   l_rc;
+
+        basename = gap_lib_alloc_basename(&valPtr->moveLogFile[0], &number);
+        frame_filename = gap_lib_alloc_fname_fixed_digits(basename, currFrameNr, l_extension, 6 /* digits*/ 
);
+    
+        l_rc = gap_lib_save_named_frame(imageId, frame_filename);
+    
+        g_free(basename);
+        g_free(frame_filename);
+        
+      }
+      g_free(l_extension);
+      l_extension = NULL;
+
+    }
+
+    
+    if((valPtr->bgLayerIsReference != TRUE)
+    && (successfulTracedPointsCount >= valPtr->numPointsSelect))
+    {
+      /* after save image as frame set current target vectors
+       * as reference for processing of the next frame (next call of this procedure)
+       */
+      p_set_n_vector_points(imageId, &targetCoordsArray, VECTORS_NAME_REFERENCE_POINTS, TRUE, FALSE, 0);
+    }
+    
+    frameHistInfo->trackedFramesCount++;
     p_set_frameHistInfo(frameHistInfo);
     g_free(l_layers_list);
 
-    if ((lostTraceCount == 0)
-    &&  (frameHistInfo->lostTraceCount > 0))
+    if ((successfulTracedPointsCount < valPtr->numPointsSelect)
+    &&  (frameHistInfo->trackedFramesCount > 1)
+    &&  (previousLostTraceCount == 0))
     {
+      // if (gap_debug)
+      {
+        printf("Detail Tracking Stopped at frameNr:%d previousLostTraceCount:%d 
successfulTracedPointsCount:%d (required %d)\n"
+          , (int)frameHistInfo->frameNr
+          , (int)previousLostTraceCount
+          , (int)successfulTracedPointsCount
+          , (int)valPtr->numPointsSelect
+          );
+      }
       /* trace lost the 1st time, display warning */
       gap_arr_msg_popup(GIMP_RUN_INTERACTIVE
                        , _("Detail Tracking Stopped. (could not find corresponding detail)"));;
     }
   }
 
+ 
   return(imageId);
 
 }  /* end gap_track_detail_on_top_layers */
@@ -1313,10 +2137,11 @@ gboolean
 gap_detail_tracking_dialog(FilterValues *fiVals)
 {
 #define SPINBUTTON_ENTRY_WIDTH 80
-#define DETAIL_TRACKING_DIALOG_ARGC 12
+#define DETAIL_TRACKING_DIALOG_ARGC 13
 
   static GapArrArg  argv[DETAIL_TRACKING_DIALOG_ARGC];
   gint ii;
+  gint ii_numPointsSelect;
   gint ii_loacteColodiffThreshold;
   gint ii_refShapeRadius;
   gint ii_targetMoveRadius;
@@ -1334,6 +2159,22 @@ gap_detail_tracking_dialog(FilterValues *fiVals)
                         "to mark coordinate(s) to be tracked in the target frame(s)");
 
 
+  ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_INT_PAIR); ii_numPointsSelect = ii;
+  argv[ii].label_txt = _("Select Points:");
+  argv[ii].help_txt  = _("1: select only the best path point for movement detection, "
+                         "2: select the best 2 points for movement,scale and rotation detection.");
+  argv[ii].constraint = FALSE;
+  argv[ii].int_min   = 1;
+  argv[ii].int_max   = 4;
+  argv[ii].umin      = 1;
+  argv[ii].umax      = 4;
+  argv[ii].int_ret   = fiVals->numPointsSelect;
+  argv[ii].entry_width = SPINBUTTON_ENTRY_WIDTH;
+  argv[ii].has_default = TRUE;
+  argv[ii].int_default = 2;
+
+
+
   ii++; gap_arr_arg_init(&argv[ii], GAP_ARR_WGT_FLT_PAIR); ii_loacteColodiffThreshold = ii;
   argv[ii].constraint = TRUE;
   argv[ii].label_txt = _("Locate colordiff Thres:");
@@ -1478,6 +2319,7 @@ gap_detail_tracking_dialog(FilterValues *fiVals)
                             _("Settings :"),
                             DETAIL_TRACKING_DIALOG_ARGC, argv))
   {
+      fiVals->numPointsSelect          = (gint32)(argv[ii_numPointsSelect].int_ret); 
       fiVals->refShapeRadius           = (gint32)(argv[ii_refShapeRadius].int_ret);
       fiVals->targetMoveRadius         = (gint32)(argv[ii_targetMoveRadius].int_ret);
       fiVals->loacteColodiffThreshold  = (gdouble)(argv[ii_loacteColodiffThreshold].flt_ret);
diff --git a/gap/gap_detail_tracking_exec.h b/gap/gap_detail_tracking_exec.h
index d4fc144..a128827 100644
--- a/gap/gap_detail_tracking_exec.h
+++ b/gap/gap_detail_tracking_exec.h
@@ -55,10 +55,19 @@
 #define GAP_DETAIL_FRAME_HISTORY_INFO     "GAP_DETAIL_FRAME_HISTORY_INFO"
 #define GAP_DETAIL_TRACKING_PLUG_IN_NAME  "gap-detail-tracking"
 
+#define VECTORS_NAME_TRACKING_POINTS          "TrackingPoints"
+#define VECTORS_NAME_REFERENCE_POINTS         "ReferencePoints"
+#define VECTORS_NAME_START_REFERENCE_POINTS   "StartReferencePoints"
+
+
 typedef struct FilterValues {
    gint32     refShapeRadius;
    gint32     targetMoveRadius;
    gdouble    loacteColodiffThreshold;
+   gint32     numPointsSelect;     /* 1,2 or 4 maximum number of recorded controlpoints 
+                                    * (the best n points out of all available will be selected for 
+                                    * logging and camera shake compensation)
+                                    */
 
    gboolean   coordsRelToFrame1;   /* subtract coords of frame 1 when logging coords */
    gint32     offsX;               /* add this value when logging coords */
@@ -75,24 +84,33 @@ typedef struct PixelCoords
   gboolean  valid;
   gint32  px;
   gint32  py;
+  gdouble   avgColorDiff;    // 0 = best quality, 1 = worst quality
 } PixelCoords;
 
+#define MAX_PIXEL_COORDS_ARRAY 32
+
+typedef struct PixelCoordsArray
+{
+  PixelCoords  pixCoord[MAX_PIXEL_COORDS_ARRAY];
+  int          numberOfCoords;           /* number of used pixelCoord elements in the array */
+  gint32       numValidOffsets;          /* number of valid coords involved in average Offset calculation */
+  gdouble      avgOffsX;                 /* average horizontal movement vektor (extreme values are not 
included) */ 
+  gdouble      avgOffsY;                 /* average vertical movement vektor (extreme values are not 
included) */ 
+} PixelCoordsArray;
+
 
 typedef struct FrameHistInfo
 {
   gint32       workImageId;
   gint32       frameNr;      /* last handled frameNr */
-  PixelCoords  startCoords;  /* coords of first processed frame */
-  PixelCoords  startCoords2; /* 2nd detail coords of first processed frame */
-
-  PixelCoords  prevCoords;   /* coords of the previous processed frame */
-  PixelCoords  prevCoords2;  /* 2nd detail coords of the previous processed frame */
+  PixelCoordsArray startCoordsArray;  /* coords of first processed frame */
+  PixelCoordsArray prevCoordsArray;   /* coords of the previous processed frame */
 
-  gint32       lostTraceCount;
+  gint32       lostTraceCount;        /* count frames where the required number of detailspoints could not 
be located */
+  gint32       trackedFramesCount;
 } FrameHistInfo;
 
 
-
 /* -----------------------------------
  * gap_track_detail_on_top_layers
  * -----------------------------------
diff --git a/gap/gap_filter_foreach.c b/gap/gap_filter_foreach.c
index 8b7c942..d410b96 100644
--- a/gap/gap_filter_foreach.c
+++ b/gap/gap_filter_foreach.c
@@ -654,7 +654,12 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
              {
                printf ("Saving image to backupfile:%s step = %d\n",
                        l_step_backup_file, (int)l_idx);
-               gap_filt_pdb_save_xcf(image_id, l_step_backup_file);
+               gimp_file_save(GIMP_RUN_NONINTERACTIVE
+                             , image_id
+                             , gap_image_get_any_layer(image_id)
+                             , l_step_backup_file
+                             , l_step_backup_file
+                             );
              }
           }
 
diff --git a/gap/gap_filter_pdb.c b/gap/gap_filter_pdb.c
index e5beec1..009346e 100644
--- a/gap/gap_filter_pdb.c
+++ b/gap/gap_filter_pdb.c
@@ -234,40 +234,6 @@ gap_filt_pdb_call_plugin(char *plugin_name, gint32 image_id, gint32 layer_id, Gi
 
 
 /* ------------------------
- * gap_filt_pdb_save_xcf
- * ------------------------
- */
-int
-gap_filt_pdb_save_xcf(gint32 image_id, char *sav_name)
-{
-  GimpParam* l_params;
-  gint   l_retvals;
-  gint   l_rc;
-
-    /* save current image as xcf file
-     * xcf_save does operate on the complete image,
-     * the drawable is ignored. (we can supply a dummy value)
-     */
-    l_params = gimp_run_procedure ("gimp_xcf_save",
-                                 &l_retvals,
-                                 GIMP_PDB_INT32,    GIMP_RUN_NONINTERACTIVE,
-                                 GIMP_PDB_IMAGE,    image_id,
-                                 GIMP_PDB_DRAWABLE, 0,
-                                 GIMP_PDB_STRING, sav_name,
-                                 GIMP_PDB_STRING, sav_name, /* raw name ? */
-                                 GIMP_PDB_END);
-    l_rc = -1;
-    if (l_params[0].data.d_status == GIMP_PDB_SUCCESS) 
-    {
-      l_rc = 0;  /* OK */
-    }
-    gimp_destroy_params (l_params, l_retvals);
-    
-    return (l_rc);
-}  /* end gap_filt_pdb_save_xcf */
-
-
-/* ------------------------
  * gap_filt_pdb_get_data
  * ------------------------
  * gap_filt_pdb_get_data
diff --git a/gap/gap_filter_pdb.h b/gap/gap_filter_pdb.h
index d66fe36..3e53e5d 100644
--- a/gap/gap_filter_pdb.h
+++ b/gap/gap_filter_pdb.h
@@ -40,7 +40,6 @@ typedef enum
  */
 
 gint gap_filt_pdb_call_plugin(char *plugin_name, gint32 image_id, gint32 layer_id, GimpRunMode run_mode);
-int  gap_filt_pdb_save_xcf(gint32 image_id, char *sav_name);
 gint gap_filt_pdb_get_data(char *key);
 void gap_filt_pdb_set_data(char *key, gint plugin_data_len);
 gint gap_filt_pdb_procedure_available(char  *proc_name, GapFiltPdbProcType ptype);
diff --git a/gap/gap_lib.c b/gap/gap_lib.c
index 3a3ebbf..53ae3fc 100644
--- a/gap/gap_lib.c
+++ b/gap/gap_lib.c
@@ -277,7 +277,6 @@ gap_lib_layer_tracking(gint32 image_id
 
 }  /* end gap_lib_layer_tracking */
 
-
 /* ---------------------------------
  * p_set_or_pick_active_layer_by_pos
  * ---------------------------------
@@ -2868,19 +2867,17 @@ gap_lib_save_named_image(gint32 image_id, const char *sav_name, GimpRunMode run_
 int
 gap_lib_save_named_frame(gint32 image_id, char *sav_name)
 {
-  GimpParam *l_params;
   gchar     *l_ext;
   gchar     *l_lowerExt;
   char      *l_tmpname;
-  gint       l_retvals;
-  int        l_gzip;
-  int        l_xcf;
+  gboolean   isGzip;
+  gboolean   isXcf;
   int        l_rc;
 
   l_tmpname = NULL;
   l_rc   = -1;
-  l_gzip = 0;          /* dont zip */
-  l_xcf  = 0;          /* assume no xcf format (1==xcf, 0==any other) */
+  isGzip = FALSE;          /* dont zip */
+  isXcf  = FALSE;          /* assume no xcf format (1==xcf, 0==any other) */
 
   /* check extension to decide if saved file will be zipped */
   l_ext = gap_lib_alloc_extension(sav_name);
@@ -2897,16 +2894,16 @@ gap_lib_save_named_frame(gint32 image_id, char *sav_name)
 
   if(0 == strcmp(l_lowerExt, ".xcf"))
   {
-    l_xcf  = 1;
+    isXcf  = TRUE;
   }
   else if(0 == strcmp(l_lowerExt, ".xcfgz"))
   {
-    l_gzip = 1;          /* zip it */
-    l_xcf  = 1;
+    isGzip = TRUE;          /* zip it */
+    isXcf  = TRUE;
   }
   else if(0 == strcmp(l_lowerExt, ".gz"))
   {
-    l_gzip = 1;          /* zip it */
+    isGzip = TRUE;          /* zip it */
   }
 
   /* find a temp name
@@ -2937,37 +2934,38 @@ gap_lib_save_named_frame(gint32 image_id, char *sav_name)
   }
 
 
-  if(l_xcf != 0)
+  if(isXcf == TRUE)
   {
+    gboolean isSaveOk;
     if(gap_debug)
     {
-      printf("DEBUG: gap_lib_save_named_frame before gimp_xcf_save on file: '%s'\n"
+      printf("DEBUG: gap_lib_save_named_frame before XCF gimp_file_save on file: '%s'\n"
             , l_tmpname
             );
     }
 
     /* save current frame as xcf image
      * xcf_save does operate on the complete image,
-     * the drawable is ignored. (we can supply a dummy value)
+     * the drawable was is ignored in gimp-2.8.x 
+     * but is now checked for a valid id in gimp-2.9.2
+     * (we can't supply a dummy value but must provide a vaild id now!
+     *  therefore gap automatic save will fail for images without any layer with gimp-2.9.x)
      */
-    l_params = gimp_run_procedure ("gimp_xcf_save",
-                                 &l_retvals,
-                                 GIMP_PDB_INT32,    GIMP_RUN_NONINTERACTIVE,
-                                 GIMP_PDB_IMAGE,    image_id,
-                                 GIMP_PDB_DRAWABLE, 0,
-                                 GIMP_PDB_STRING, l_tmpname,
-                                 GIMP_PDB_STRING, l_tmpname, /* raw name ? */
-                                 GIMP_PDB_END);
+    isSaveOk = gimp_file_save(GIMP_RUN_NONINTERACTIVE
+                             , image_id
+                             , gap_image_get_any_layer(image_id)
+                             , l_tmpname
+                             , l_tmpname
+                             );
     if(gap_debug)
     {
       printf("DEBUG: after   xcf  gap_lib_save_named_frame: '%s'\n", l_tmpname);
     }
 
-    if (l_params[0].data.d_status == GIMP_PDB_SUCCESS)
+    if (isSaveOk == TRUE)
     {
        l_rc = image_id;
     }
-    gimp_destroy_params (l_params, l_retvals);
   }
   else
   {
@@ -3001,14 +2999,14 @@ gap_lib_save_named_frame(gint32 image_id, char *sav_name)
   {
      g_remove(l_tmpname);
      g_free(l_tmpname);  /* free temporary name */
-     if((l_xcf == 0) && (l_rc == SAVE_NON_XCF_FAKE_OK_FOR_READ_ONLY_TYPES))
+     if((isXcf != TRUE) && (l_rc == SAVE_NON_XCF_FAKE_OK_FOR_READ_ONLY_TYPES))
      {
        return (0); /* FAKE save OK  */
      }
      return l_rc;
   }
 
-  if(l_gzip == 0)
+  if(isGzip != TRUE)
   {
      /* remove sav_name, then rename tmpname ==> sav_name */
      g_remove(sav_name);
diff --git a/gap/gap_locate2.c b/gap/gap_locate2.c
index 8e6eb5b..5072932 100644
--- a/gap/gap_locate2.c
+++ b/gap/gap_locate2.c
@@ -51,10 +51,12 @@ typedef struct Context {
   gint32    bestY;
   gint32    px;
   gint32    py;
+  gint32    rowsProcessedCount;     /* debug information (for development/debug purpose) */
   gint32    cancelAttemptCount;     /* debug information (for development/debug purpose) */
-  gboolean  cancelAttemptFlag;      /* indicator to cancel current attempt */
+  gboolean  cancelAttemptFlag;      /* indicator to cancel current evaluation attempt */
   gboolean  isFinishedFlag;         /* indicator to cancel all further evaluations */
-  gint32  requiredPixelCount;       /* number of pixels minimum required for plausible area comparison  (1/4 
of full area size)*/
+  gint32  requiredPixelCount;       /* number of pixels minimum required for plausible area comparison  (30 
% of full area size)*/
+  gint32  almostFullAreaPixelCount; /* number of pixels  (90 % of full area size)*/
   gint32  involvedPixelCount;       /* number of pixels involved in current comparison attempt */
   gdouble sumDiffValue;             /* summ of the RGB channel differences of the involved pixels in the 
current attempt */
   gdouble currentDistance;          /* square distance from reference coords to the offset of the current 
attempt */
@@ -62,19 +64,25 @@ typedef struct Context {
   gdouble bestMatchingDistance;     /* square distance from reference coords to the offset of the best 
matching attempt */
   gdouble bestMatchingSumDiffValue; /* summ of the RGB channel differences of the best matching attempt */
   gdouble veryNearDistance;         /* square of near radius to stop evaluation when exactly matching area 
is detected */
-  gdouble bestMatchingAvgColordiff; /* average colordiff at best matching attempt */
   GimpDrawable *refDrawable;
   GimpDrawable *targetDrawable;
   
 } Context;
 
+static gdouble     p_calculate_average_colordiff(gdouble sumDiffValue, gint32 pixelCount);
+static void        p_compare_regions (const GimpPixelRgn *refPR
+                    ,const GimpPixelRgn *targetPR
+                    ,Context *context);
+static gdouble     p_calculate_distance_to_ref_coord(Context *context, gint32 px, gint32 py);
+static void        p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py);
+
 
 /* ---------------------------------
  * p_calculate_average_colordiff
  * ---------------------------------
  * calculate the average color difference for given sum of value differnces and pixel count
  */
-static inline gdouble
+static gdouble
 p_calculate_average_colordiff(gdouble sumDiffValue, gint32 pixelCount)
 {
   if (pixelCount > 0)
@@ -105,10 +113,16 @@ p_compare_regions (const GimpPixelRgn *refPR
   guint    row;
   guchar*  ref = refPR->data;   /* the reference drawable */
   guchar*  target = targetPR->data;   /* the target drawable */
+  
+  guint    commonWidth;
+  guint    commonHeight;
+
+  commonWidth = MIN(targetPR->w, refPR->w);
+  commonHeight = MIN(targetPR->h, refPR->h);
 
 //   if(gap_debug)
 //   {
-//     printf("region REF x:%d y:%d w:%d h:%d  TARGET x:%d y:%d w:%d h:%d   px:%d py:%d\n"
+//     printf("region REF x:%d y:%d w:%d h:%d  TARGET x:%d y:%d w:%d h:%d  Common w:%d h:%d px:%d py:%d\n"
 //        , (int)refPR->x
 //        , (int)refPR->y
 //        , (int)refPR->w
@@ -117,48 +131,37 @@ p_compare_regions (const GimpPixelRgn *refPR
 //        , (int)targetPR->y
 //        , (int)targetPR->w
 //        , (int)targetPR->h
+//        , (int)commonWidth
+//        , (int)commonHeight
 //        , (int)context->px
 //        , (int)context->py
 //        );
 //   }
 
 
-  for (row = 0; row < targetPR->h; row++)
+  for (row = 0; row < commonHeight; row++)
   {
     guint  col;
     guint  idxref;
     guint  idxtarget;
     
-    if (row >= refPR->h)
-    {
-      continue;
-    }
-
+//    context->rowsProcessedCount += 1;
     idxref = 0;
     idxtarget = 0;
-    for(col = 0; col < targetPR->w; col++)
+    for(col = 0; col < commonWidth; col++)
     {
       gboolean isCompareable;
       
       isCompareable = TRUE;
       
-      if (col < refPR->w)
+      if(refPR->bpp > 3)
       {
-        if(refPR->bpp > 3)
+        if(ref[idxref +3] < OPACITY_LEVEL_UCHAR)
         {
-          if(ref[idxref +3] < OPACITY_LEVEL_UCHAR)
-          {
-            /* transparent reference pixel is not compared */
-            isCompareable = FALSE;
-          }
+          /* transparent reference pixel is not compared */
+          isCompareable = FALSE;
         }
       }
-      else
-      {
-        isCompareable = FALSE;
-      }
-      
-
 
       if(targetPR->bpp > 3)
       {
@@ -176,23 +179,6 @@ p_compare_regions (const GimpPixelRgn *refPR
         context->sumDiffValue += abs(ref[idxref +1] - target[idxtarget +1]);
         context->sumDiffValue += abs(ref[idxref +2] - target[idxtarget +2]);
 
-        if (context->sumDiffValue > context->bestMatchingSumDiffValue)
-        {
-          gdouble avgColodiff;
-          
-          avgColodiff =
-              p_calculate_average_colordiff(context->sumDiffValue
-                                          , context->involvedPixelCount
-                                          );
-          if(avgColodiff > context->bestMatchingAvgColordiff)
-          {
-            /* stop evaluating area at current offset on worse results */
-            context->cancelAttemptFlag = TRUE;
-            context->cancelAttemptCount += 1;
-            return;
-          }                               
-        }
-
         
       }
 
@@ -200,6 +186,43 @@ p_compare_regions (const GimpPixelRgn *refPR
       idxtarget += targetPR->bpp;
     }
 
+    /* check for early escape possibilty when current sumDiffValue gets too large 
+     * Preformance note: 
+     *  we could do this check already in the inner column based loop to detect escape
+     *  possibilities a little earlier, but i guess
+     *  overall performance might be better when cecks are done only once per row.
+     */
+    if (context->sumDiffValue > context->bestMatchingSumDiffValue)
+    {
+      if (context->bestMatchingPixelCount >= context->almostFullAreaPixelCount)
+      {
+        /* The (so far best matching) result was based on comparison
+         * of almost all area pixels involved.
+         * (Less pixels may be involved when:
+         *   o) there are transparent pixels in the compared areas OR
+         *   o) the compared areas are clipped at layer borders
+         * )
+         * At this point there is nearly no more chance for a better matching
+         * average color diff in the current attempt, and we can
+         * stop evaluating area at current offset for performance reasons.
+         */
+        context->cancelAttemptFlag = TRUE;
+        //context->cancelAttemptCount += 1;
+        return;
+      }
+      else if (context->sumDiffValue >= (context->bestMatchingSumDiffValue + 
context->bestMatchingSumDiffValue) )
+      {
+        /* the sumDiffValue is now alredy 2 times worse then the best match.
+         * and the chances are low to get a better average color diff in the current attempt
+         */
+        context->cancelAttemptFlag = TRUE;
+        //context->cancelAttemptCount += 1;
+        return;
+      }
+    }
+
+
+
     ref += refPR->rowstride;
     target += targetPR->rowstride;
 
@@ -230,7 +253,7 @@ p_calculate_distance_to_ref_coord(Context *context, gint32 px, gint32 py)
  * p_attempt_locate_at_current_offset
  * --------------------------------------------
  */
-void
+static void
 p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
 {
   GimpPixelRgn refPR;
@@ -239,6 +262,8 @@ p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
   gint      rx1, ry1, rWidth, rHeight;
   gint      tx1, ty1, tWidth, tHeight;
   gint      commonAreaWidth, commonAreaHeight;
+  gint      fullShapeWidth,  fullShapeHeight;
+  gint      rWidthRequired, rHeightRequired;
   gboolean  isIntersect;
 
   gint    leftShapeRadius;
@@ -249,14 +274,17 @@ p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
   {
     return;
   }
+  
+  fullShapeWidth = (2 * context->refShapeRadius);
+  fullShapeHeight = (2 * context->refShapeRadius);
 
-  /* calculate processing relevant interecting reference / target rectangles */  
+  /* calculate processing relevant intersecting reference / target rectangles */  
 
   isIntersect =
    gimp_rectangle_intersect((context->refX - context->refShapeRadius)  /* origin1 */
                           , (context->refY - context->refShapeRadius)
-                          , (2 * context->refShapeRadius)               /*  width1 */
-                          , (2 * context->refShapeRadius)               /* height1 */
+                          , fullShapeWidth               /*  width1 */
+                          , fullShapeHeight              /* height1 */
                           ,0
                           ,0
                           ,context->refDrawable->width
@@ -270,7 +298,7 @@ p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
   {
     return;
   }
-
+  
   leftShapeRadius = context->refX - rx1;
   upperShapeRadius = context->refY - ry1;
 
@@ -292,9 +320,25 @@ p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
   {
     return;
   }
-
+  
   commonAreaWidth = tWidth;
   commonAreaHeight = tHeight;
+
+  // TODO test if 2/3 of the fullShapeWidth and fullShapeHeight is sufficient for usable results.
+  // alternative1: maybe require  rWidth and rHeight
+  // alternative2: maybe require  fullShapeWidth and fullShapeHeight
+  rWidthRequired = (fullShapeWidth * 2) / 3;
+  rHeightRequired = (fullShapeHeight * 2) / 3;
+  
+  if ((commonAreaWidth < rWidthRequired) 
+  ||  (commonAreaHeight < rHeightRequired))
+  {
+    /* the common area is significant smaller than the reference shape 
+     * skip the compare attempt in this case to avoid unpredictable results (near borders)
+     */
+    return;
+  }
+
   
 
 //   if(gap_debug)
@@ -360,7 +404,7 @@ p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
       * early escaping from the loop with pr != NULL
       * leads to memory leaks due to unbalanced tile ref/unref calls.
       * the call to gap_gimp_pixel_rgns_unref cals unref on the current tile
-      * (in th same way as gimp_pixel_rgns_process does)
+      * (in the same way as gimp_pixel_rgns_process does)
       * but does not ref another available tile.
       */
     gap_gimp_pixel_rgns_unref (pr);
@@ -380,13 +424,14 @@ p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
       context->bestMatchingPixelCount = context->involvedPixelCount;
       context->bestX = px;
       context->bestY = py;
-      context->bestMatchingAvgColordiff = 
-        p_calculate_average_colordiff(context->bestMatchingSumDiffValue
-                                    , context->bestMatchingPixelCount
-                                    );
-
+ 
       if(gap_debug)
       {
+        gdouble bestMatchingAvgColordiff;
+        
+        bestMatchingAvgColordiff = p_calculate_average_colordiff(context->bestMatchingSumDiffValue
+                                    , context->bestMatchingPixelCount
+                                    );
         printf("FOUND: bestX:%d bestY:%d squareDist:%d\n"
                "             sumDiffValues:%d pixelCount:%d bestMatchingAvgColordiff:%.5f\n"
           , (int)context->bestX
@@ -394,7 +439,7 @@ p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
           , (int)context->bestMatchingDistance
           , (int)context->bestMatchingSumDiffValue
           , (int)context->bestMatchingPixelCount
-          , (float)context->bestMatchingAvgColordiff
+          , (float)bestMatchingAvgColordiff
           );
       }
        
@@ -439,14 +484,19 @@ gap_locateAreaWithinRadiusWithOffset(gint32  refDrawableId
   Context *context;
   gdouble averageColorDiff;
   gboolean isFinishedFlag;
-  gint    idx;
-  gint    idy;
   gdouble maxPixelCount;
+  gint32  shapeDiameter;
+  gint32  fullAreaPixelCount;
+  gint32  dx;
+  gint32  dy;
   
   
   *targetX = refX;
   *targetY = refY;
   
+  shapeDiameter = 1 + (refShapeRadius + refShapeRadius);
+  fullAreaPixelCount = (shapeDiameter) * (shapeDiameter);
+  
   /* init Context */
   context = &contextData;
   context->refShapeRadius = refShapeRadius;
@@ -455,9 +505,11 @@ gap_locateAreaWithinRadiusWithOffset(gint32  refDrawableId
   context->bestX = refX;
   context->bestY = refY;
   context->cancelAttemptCount = 0;
+  context->rowsProcessedCount = 0;
   context->cancelAttemptFlag = FALSE;
   context->isFinishedFlag = FALSE;
-  context->requiredPixelCount = MAX(1, ((refShapeRadius * refShapeRadius) / 4));
+  context->requiredPixelCount = (fullAreaPixelCount * 30) / 100;
+  context->almostFullAreaPixelCount = (fullAreaPixelCount * 90) / 100;
   context->involvedPixelCount = 0;
   context->sumDiffValue = 0;
   context->currentDistance = 0;
@@ -472,51 +524,63 @@ gap_locateAreaWithinRadiusWithOffset(gint32  refDrawableId
                 
   context->bestMatchingSumDiffValue = maxPixelCount * MAX_DIFF_VALUE_PER_PIXEL;
   context->bestMatchingDistance = maxPixelCount;
-  context->bestMatchingAvgColordiff = 1.0;
   
   averageColorDiff = 1.0;
   
-  for(idx = 0; idx <= targetMoveRadius; idx ++)
+  if(gap_debug)
+  {
+      printf("gap_locateAreaWithinRadiusWithOffset START: refDrawableId:%d targetDrawableId:%d\n"
+             "                           refX:%d refY:%d refShapeRadius:%d\n"
+             "                           requiredPixelCount:%d almostFullAreaPixelCount:%d  
fullAreaPixelCount:%d\n"
+        , (int)refDrawableId
+        , (int)targetDrawableId
+        , (int)context->refX
+        , (int)context->refY
+        , (int)refShapeRadius
+        , (int)context->requiredPixelCount
+        , (int)context->almostFullAreaPixelCount
+        , (int)fullAreaPixelCount
+        );
+  }
+  
+  
+  for(dx = 0; dx <= targetMoveRadius; dx ++)
   {
     if (context->isFinishedFlag) 
     { 
       break; 
     }
 
-    for(idy = 0; idy <= targetMoveRadius; idy++)
+    for(dy = 0; dy <= targetMoveRadius; dy++)
     {
-      gint32 dx;
-      gint32 dy;
-      
-      dx = idx;
-      dy = idy;
-      p_attempt_locate_at_current_offset(context, (offsetX + refX) + dx, (offsetY + refY) +dy);
+ 
+      p_attempt_locate_at_current_offset(context, (offsetX + refX) + dx, (offsetY + refY) + dy);
       if (isFinishedFlag)
       { 
         break;
       }
       
-      if (idx > 0)
+      if (dx > 0)
       {
-        p_attempt_locate_at_current_offset(context, (offsetX + refX) - dx, (offsetY + refY) +dy);
+        p_attempt_locate_at_current_offset(context, (offsetX + refX) - dx, (offsetY + refY) + dy);
         if (context->isFinishedFlag) 
         {
           break; 
         }
       }
       
-      if (idy > 0)
+      if (dy > 0)
       {
-        p_attempt_locate_at_current_offset(context, (offsetX + refX) + dx, (offsetY + refY) -dy);
+        p_attempt_locate_at_current_offset(context, (offsetX + refX) + dx, (offsetY + refY) - dy);
         if (context->isFinishedFlag) 
         {
           break; 
         }
       }
       
-      if ((idx > 0) && (idy > 0))
+      if ((dx > 0) && (dy > 0))
       {
-        p_attempt_locate_at_current_offset(context, (offsetX + refX) - dx, (offsetY + refY) -dy);
+        p_attempt_locate_at_current_offset(context, (offsetX + refX) - dx, (offsetY + refY) - dy);
         if (context->isFinishedFlag) 
         {
           break; 
@@ -530,13 +594,17 @@ gap_locateAreaWithinRadiusWithOffset(gint32  refDrawableId
   {
     *targetX = context->bestX;
     *targetY = context->bestY;
-    averageColorDiff = context->bestMatchingAvgColordiff;
+    averageColorDiff = p_calculate_average_colordiff(context->bestMatchingSumDiffValue
+                                    , context->bestMatchingPixelCount
+                                    );
+
     
     if(gap_debug)
     {
       printf("gap_locateAreaWithinRadiusWithOffset Result: bestX:%d bestY:%d averageColorDiff:%.5f\n"
              "                           sumDiffValues:%d pixelCount:%d\n"
-             "                           refX:%d refY:%d  cancelAttemptCount:%d\n"
+             "                           refX:%d refY:%d  cancelAttemptCount:%d rowsProcessedCount:%d\n"
+             "                           requiredPixelCount:%d almostFullAreaPixelCount:%d\n"
         , (int)context->bestX
         , (int)context->bestY
         , (float)averageColorDiff
@@ -545,9 +613,19 @@ gap_locateAreaWithinRadiusWithOffset(gint32  refDrawableId
         , (int)context->refX
         , (int)context->refY
         , (int)context->cancelAttemptCount
+        , (int)context->rowsProcessedCount
+        , (int)context->requiredPixelCount
+        , (int)context->almostFullAreaPixelCount
         );
     }
   }
+  else
+  {
+    if(gap_debug)
+    {
+      printf("gap_locateAreaWithinRadiusWithOffset * NOTHING FOUND *\n");
+    }
+  }
 
 
   if(context->refDrawable != NULL)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]