13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           RRRR    EEEEE   SSSSS   AAA   M   M  PPPP   L      EEEEE          %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           R   R   E       SS     A   A  MM MM  P   P  L      E              %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           RRRR    EEE      SSS   AAAAA  M M M  PPPP   L      EEE            %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           R R     E          SS  A   A  M   M  P      L      E              %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           R  R    EEEEE   SSSSS  A   A  M   M  P      LLLLL  EEEEE          %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                      MagickCore Pixel Resampling Methods                    %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Software Design                                %
16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy%                                   Cristy                                    %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Anthony Thyssen                                %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                August 2007                                  %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
217ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Include declarations.
423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
434c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
444c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/artifact.h"
454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h"
464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h"
474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/draw.h"
484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h"
494c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h"
504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h"
514c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h"
524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/log.h"
534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h"
544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h"
554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel.h"
564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h"
574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum.h"
584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/random_.h"
594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resample.h"
604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resize.h"
614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resize-private.h"
62ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h"
6363a81879d3568083e4ee4f78ebcae2bc831cb764cristy#include "MagickCore/token.h"
644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/transform.h"
654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/signature-private.h"
664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h"
67d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/utility-private.h"
689cb63ccb02272521283da6d251068d91196cc5bfanthony#include "MagickCore/option.h"
693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
70490ab03a4e81aa0943087243055c77e3794d75d9anthony  EWA Resampling Options
71490ab03a4e81aa0943087243055c77e3794d75d9anthony*/
72c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
73c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* select ONE resampling method */
74c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA 1                 /* Normal EWA handling - raw or clamped */
75c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                              /* if 0 then use "High Quality EWA" */
76c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA_CLAMP 1           /* EWA Clamping from Nicolas Robidoux */
77c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
785b697cdb1ed6e391b98953aafd362bddad51b453anthony#define FILTER_LUT 1          /* Use a LUT rather then direct filter calls */
795b697cdb1ed6e391b98953aafd362bddad51b453anthony
80c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* output debugging information */
81490ab03a4e81aa0943087243055c77e3794d75d9anthony#define DEBUG_ELLIPSE 0       /* output ellipse info for debug */
822e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_HIT_MISS 0      /* output hit/miss pixels (as gnuplot commands) */
832e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_NO_PIXEL_HIT 0  /* Make pixels that fail to hit anything - RED */
84490ab03a4e81aa0943087243055c77e3794d75d9anthony
855b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_DIRECT
865b697cdb1ed6e391b98953aafd362bddad51b453anthony#define WLUT_WIDTH 1024       /* size of the filter cache */
875b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
885b697cdb1ed6e391b98953aafd362bddad51b453anthony
89490ab03a4e81aa0943087243055c77e3794d75d9anthony/*
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Typedef declarations.
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristystruct _ResampleFilter
933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *view;
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
97c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  Image
98c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image;
99c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *exception;
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    debug;
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Information about image being resampled */
107bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image_area;
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1105c4e2586d27d4299a742d170d41105de1689aa46cristy  PixelInterpolateMethod
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    interpolate;
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  VirtualPixelMethod
1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    virtual_pixel;
1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1168b9f21cab4c50eb7d6e558a7a43a68833fe0b55ddirk  FilterType
1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    filter;
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* processing settings needed */
1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    limit_reached,
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    do_interpolate,
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_defined;
1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1254c08aed51c5899665ade97263692328eea4af106cristy  PixelInfo
1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_pixel;
1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* current ellipitical area being resampled around center point */
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    A, B, C,
131d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Vlimit, Ulimit, Uwidth, slope;
1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
133175defe3237b2e7bab13c9649a837500af6a82c7anthony#if FILTER_LUT
1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* LUT of weights for filtered average in elliptical area */
1353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1365b697cdb1ed6e391b98953aafd362bddad51b453anthony    filter_lut[WLUT_WIDTH];
1375b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1385b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* Use a Direct call to the filter functions */
1395b697cdb1ed6e391b98953aafd362bddad51b453anthony  ResizeFilter
1405b697cdb1ed6e391b98953aafd362bddad51b453anthony    *filter_def;
141582b6d79fc381d6c9455f3f1b3e26923950161ebanthony
142582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  double
143582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    F;
1445b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
1455b697cdb1ed6e391b98953aafd362bddad51b453anthony
1465b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* the practical working support of the filter */
1475b697cdb1ed6e391b98953aafd362bddad51b453anthony  double
1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    support;
1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
150bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    signature;
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy};
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   A c q u i r e R e s a m p l e I n f o                                     %
1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  AcquireResampleFilter() initializes the information resample needs do to a
1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  scaled lookup of a color from an image, using area sampling.
1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The algorithm is based on a Elliptical Weighted Average, where the pixels
1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  found in a large elliptical area is averaged together according to a
1703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  weighting (filter) function.  For more details see "Fundamentals of Texture
1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Mapping and Image Warping" a master's thesis by Paul.S.Heckbert, June 17,
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  1989.  Available for free from, http://www.cs.cmu.edu/~ph/
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As EWA resampling (or any sort of resampling) can require a lot of
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculations to produce a distorted scaling of the source image for each
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  output pixel, the ResampleFilter structure generated holds that information
1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  between individual image resampling.
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This function will make the appropriate AcquireCacheView() calls
1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  to view the image, calling functions do not need to open a cache view.
1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Usage Example...
1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      resample_filter=AcquireResampleFilter(image,exception);
1849cb63ccb02272521283da6d251068d91196cc5bfanthony%      SetResampleFilter(resample_filter, GaussianFilter);
185bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      for (y=0; y < (ssize_t) image->rows; y++) {
186bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%        for (x=0; x < (ssize_t) image->columns; x++) {
187c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          u= ....;   v= ....;
1883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ScaleResampleFilter(resample_filter, ... scaling vectors ...);
189c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          (void) ResamplePixelColor(resample_filter,u,v,&pixel);
1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ... assign resampled pixel value ...
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        }
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      }
1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      DestroyResampleFilter(resample_filter);
1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the AcquireResampleFilter method is:
1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     ResampleFilter *AcquireResampleFilter(const Image *image,
1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       ExceptionInfo *exception)
1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *AcquireResampleFilter(const Image *image,
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo *exception)
2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register ResampleFilter
2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *resample_filter;
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
214e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception != (ExceptionInfo *) NULL);
218e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
2195c1c858705bf277d750185e970740084cd3f8e68cristy  resample_filter=(ResampleFilter *) AcquireMagickMemory(sizeof(
2205c1c858705bf277d750185e970740084cd3f8e68cristy    *resample_filter));
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter == (ResampleFilter *) NULL)
2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(resample_filter,0,sizeof(*resample_filter));
2242ab242ec7c723f9f95558b30f1275011aa582ca9cristy  resample_filter->exception=exception;
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=ReferenceImage((Image *) image);
2265c1c858705bf277d750185e970740084cd3f8e68cristy  resample_filter->view=AcquireVirtualCacheView(resample_filter->image,
2275c1c858705bf277d750185e970740084cd3f8e68cristy    exception);
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->debug=IsEventLogging();
2295b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->image_area=(ssize_t) (image->columns*image->rows);
2305c1c858705bf277d750185e970740084cd3f8e68cristy  resample_filter->average_defined=MagickFalse;
231e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  resample_filter->signature=MagickCoreSignature;
2325c1c858705bf277d750185e970740084cd3f8e68cristy  SetResampleFilter(resample_filter,image->filter);
233aa2c16cb5e695053aa78e40f66bc36fbef4b1ed1cristy  (void) SetResampleFilterInterpolateMethod(resample_filter,image->interpolate);
23482fea938ea2a766e32daddb7f2f69d66958e9d45cristy  (void) SetResampleFilterVirtualPixelMethod(resample_filter,
23572949796e01f8b94a0976e74cb8eb3f86af280eaanthony    GetImageVirtualPixelMethod(image));
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   D e s t r o y R e s a m p l e I n f o                                     %
2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DestroyResampleFilter() finalizes and cleans up the resampling
2513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  resample_filter as returned by AcquireResampleFilter(), freeing any memory
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  or other information as needed.
2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DestroyResampleFilter method is:
2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      ResampleFilter *DestroyResampleFilter(ResampleFilter *resample_filter)
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling information structure
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *DestroyResampleFilter(
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter)
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
267e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(resample_filter->signature == MagickCoreSignature);
2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->view=DestroyCacheView(resample_filter->view);
2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=DestroyImage(resample_filter->image);
2745b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_LUT
2755b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->filter_def=DestroyResizeFilter(resample_filter->filter_def);
2765b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
277e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  resample_filter->signature=(~MagickCoreSignature);
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter=(ResampleFilter *) RelinquishMagickMemory(resample_filter);
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e s a m p l e P i x e l C o l o r                                       %
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ResamplePixelColor() samples the pixel values surrounding the location
2943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  given using an elliptical weighted average, at the scale previously
2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated, and in the most efficent manner possible for the
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  VirtualPixelMethod setting.
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ResamplePixelColor method is:
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter,
301db070957cf6bf959df9283a482377e8854c3d4d2cristy%       const double u0,const double v0,PixelInfo *pixel,
302db070957cf6bf959df9283a482377e8854c3d4d2cristy%       ExceptionInfo *exception)
3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o u0,v0: A double representing the center of the area to resample,
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        The distortion transformed transformed x,y coordinate.
3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o pixel: the resampled pixel is returned here.
3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
313db070957cf6bf959df9283a482377e8854c3d4d2cristy%    o exception: return any errors or warnings in this structure.
314db070957cf6bf959df9283a482377e8854c3d4d2cristy%
3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType ResamplePixelColor(
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const double u0,const double v0,
318db070957cf6bf959df9283a482377e8854c3d4d2cristy  PixelInfo *pixel,ExceptionInfo *exception)
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
323490ab03a4e81aa0943087243055c77e3794d75d9anthony  ssize_t u,v, v1, v2, uw, hit;
3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double u1;
3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double U,V,Q,DQ,DDQ;
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double divisor_c,divisor_m;
3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register double weight;
3284c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum *pixels;
3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
330e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(resample_filter->signature == MagickCoreSignature);
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
3334c08aed51c5899665ade97263692328eea4af106cristy  /* GetPixelInfo(resample_filter->image,pixel); */
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->do_interpolate ) {
335f931f0708bbd917a0b880912396f5128994f9137cristy    status=InterpolatePixelInfo(resample_filter->image,resample_filter->view,
336f931f0708bbd917a0b880912396f5128994f9137cristy      resample_filter->interpolate,u0,v0,pixel,resample_filter->exception);
3373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3402e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#if DEBUG_ELLIPSE
3415acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "u0=%lf; v0=%lf;\n", u0, v0);
3422e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#endif
3432e6ab68e6538e73abd8d77f505bc9f033c742f1canthony
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
345c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    Does resample area Miss the image Proper?
346c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    If and that area a simple solid color - then simply return that color!
347c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    This saves a lot of calculation when resampling outside the bounds of
348c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    the source image.
349c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony
350c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    However it probably should be expanded to image bounds plus the filters
351c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    scaled support size.
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch ( resample_filter->virtual_pixel ) {
3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BackgroundVirtualPixelMethod:
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TransparentVirtualPixelMethod:
3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BlackVirtualPixelMethod:
3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case GrayVirtualPixelMethod:
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case WhiteVirtualPixelMethod:
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MaskVirtualPixelMethod:
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( resample_filter->limit_reached
362d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 + resample_filter->Ulimit < 0.0
363c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0
364d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 + resample_filter->Vlimit < 0.0
365c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case UndefinedVirtualPixelMethod:
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case EdgeVirtualPixelMethod:
372d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < 0.0 && v0 + resample_filter->Vlimit < 0.0 )
373d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < 0.0
374c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0 )
375c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0
376d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < 0.0 )
377c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0
378c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0 )
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileVirtualPixelMethod:
383d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    v0 + resample_filter->Vlimit < 0.0
384c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the horizontally tiled images. */
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileVirtualPixelMethod:
389d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    u0 + resample_filter->Ulimit < 0.0
390c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the vertically tiled images. */
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case DitherVirtualPixelMethod:
395d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < -32.0 && v0 + resample_filter->Vlimit < -32.0 )
396d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < -32.0
397c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+31.0 )
398c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+31.0
399d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < -32.0 )
400c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+31.0
401c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+31.0 )
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TileVirtualPixelMethod:
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MirrorVirtualPixelMethod:
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case RandomVirtualPixelMethod:
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileEdgeVirtualPixelMethod:
4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileEdgeVirtualPixelMethod:
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case CheckerTileVirtualPixelMethod:
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* resampling of area is always needed - no VP limits */
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( hit ) {
415c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    /* The area being resampled is simply a solid color
416c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony     * just return a single lookup color.
417c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony     *
418c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony     * Should this return the users requested interpolated color?
419c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony     */
4205c1c858705bf277d750185e970740084cd3f8e68cristy    status=InterpolatePixelInfo(resample_filter->image,resample_filter->view,
4215c1c858705bf277d750185e970740084cd3f8e68cristy      IntegerInterpolatePixel,u0,v0,pixel,resample_filter->exception);
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
426c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony    When Scaling limits reached, return an 'averaged' result.
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->limit_reached ) {
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch ( resample_filter->virtual_pixel ) {
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*  This is always handled by the above, so no need.
4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case BackgroundVirtualPixelMethod:
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case ConstantVirtualPixelMethod:
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case TransparentVirtualPixelMethod:
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case GrayVirtualPixelMethod,
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case WhiteVirtualPixelMethod
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case MaskVirtualPixelMethod:
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case UndefinedVirtualPixelMethod:
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case EdgeVirtualPixelMethod:
4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case DitherVirtualPixelMethod:
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileEdgeVirtualPixelMethod:
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileEdgeVirtualPixelMethod:
4439b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony        /* We need an average edge pixel, from the correct edge!
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           How should I calculate an average edge color?
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           Just returning an averaged neighbourhood,
4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           works well in general, but falls down for TileEdge methods.
4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           This needs to be done properly!!!!!!
4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
4494c08aed51c5899665ade97263692328eea4af106cristy        status=InterpolatePixelInfo(resample_filter->image,
450d76c51ed30cf4084f4434ba08925d16001d1e340cristy          resample_filter->view,AverageInterpolatePixel,u0,v0,pixel,
451d76c51ed30cf4084f4434ba08925d16001d1e340cristy          resample_filter->exception);
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileVirtualPixelMethod:
4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileVirtualPixelMethod:
4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* just return the background pixel - Is there more direct way? */
4564c08aed51c5899665ade97263692328eea4af106cristy        status=InterpolatePixelInfo(resample_filter->image,
457d76c51ed30cf4084f4434ba08925d16001d1e340cristy          resample_filter->view,IntegerInterpolatePixel,-1.0,-1.0,pixel,
458d76c51ed30cf4084f4434ba08925d16001d1e340cristy          resample_filter->exception);
4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case TileVirtualPixelMethod:
4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case MirrorVirtualPixelMethod:
4623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case RandomVirtualPixelMethod:
4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case CheckerTileVirtualPixelMethod:
4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* generate a average color of the WHOLE image */
4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if ( resample_filter->average_defined == MagickFalse ) {
4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Image
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_image;
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          CacheView
4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_view;
4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4734c08aed51c5899665ade97263692328eea4af106cristy          GetPixelInfo(resample_filter->image,(PixelInfo *)
474065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy            &resample_filter->average_pixel);
475065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy          resample_filter->average_defined=MagickTrue;
4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /* Try to get an averaged pixel color of whole image */
478aa2c16cb5e695053aa78e40f66bc36fbef4b1ed1cristy          average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,
479065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy            resample_filter->exception);
4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (average_image == (Image *) NULL)
4813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              *pixel=resample_filter->average_pixel; /* FAILED */
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
48546ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy          average_view=AcquireVirtualCacheView(average_image,exception);
4864c08aed51c5899665ade97263692328eea4af106cristy          pixels=GetCacheViewVirtualPixels(average_view,0,0,1,1,
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            resample_filter->exception);
4884c08aed51c5899665ade97263692328eea4af106cristy          if (pixels == (const Quantum *) NULL) {
4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_view=DestroyCacheView(average_view);
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_image=DestroyImage(average_image);
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *pixel=resample_filter->average_pixel; /* FAILED */
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            break;
4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
494803640d20a6a664315eddfff6f8531d0c5e0871dcristy          GetPixelInfoPixel(resample_filter->image,pixels,
4953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            &(resample_filter->average_pixel));
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_view=DestroyCacheView(average_view);
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_image=DestroyImage(average_image);
498490ab03a4e81aa0943087243055c77e3794d75d9anthony
499490ab03a4e81aa0943087243055c77e3794d75d9anthony          if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod )
500490ab03a4e81aa0943087243055c77e3794d75d9anthony            {
5019cb63ccb02272521283da6d251068d91196cc5bfanthony              /* CheckerTile is a alpha blend of the image's average pixel
5029cb63ccb02272521283da6d251068d91196cc5bfanthony                 color and the current background color */
503490ab03a4e81aa0943087243055c77e3794d75d9anthony
5049cb63ccb02272521283da6d251068d91196cc5bfanthony              /* image's average pixel color */
505a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy              weight = QuantumScale*((double)
5064c08aed51c5899665ade97263692328eea4af106cristy                resample_filter->average_pixel.alpha);
507490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red *= weight;
508490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green *= weight;
509490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue *= weight;
510490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c = weight;
511490ab03a4e81aa0943087243055c77e3794d75d9anthony
5129cb63ccb02272521283da6d251068d91196cc5bfanthony              /* background color */
513a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy              weight = QuantumScale*((double)
5144c08aed51c5899665ade97263692328eea4af106cristy                resample_filter->image->background_color.alpha);
515490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red +=
516490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.red;
517490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green +=
518490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.green;
519490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue +=
520490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.blue;
5214c08aed51c5899665ade97263692328eea4af106cristy              resample_filter->average_pixel.alpha +=
5224c08aed51c5899665ade97263692328eea4af106cristy                      resample_filter->image->background_color.alpha;
523490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c += weight;
524490ab03a4e81aa0943087243055c77e3794d75d9anthony
5259cb63ccb02272521283da6d251068d91196cc5bfanthony              /* alpha blend */
526490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red /= divisor_c;
527490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green /= divisor_c;
528490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue /= divisor_c;
5299cb63ccb02272521283da6d251068d91196cc5bfanthony              resample_filter->average_pixel.alpha /= 2; /* 50% blend */
530490ab03a4e81aa0943087243055c77e3794d75d9anthony
531490ab03a4e81aa0943087243055c77e3794d75d9anthony            }
5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *pixel=resample_filter->average_pixel;
5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
5373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize weighted average data collection
5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 0.0;
5443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 0.0;
5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->red = pixel->green = pixel->blue = 0.0;
5464c08aed51c5899665ade97263692328eea4af106cristy  if (pixel->colorspace == CMYKColorspace)
5474c08aed51c5899665ade97263692328eea4af106cristy    pixel->black = 0.0;
54817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy  if (pixel->alpha_trait != UndefinedPixelTrait)
5494c08aed51c5899665ade97263692328eea4af106cristy    pixel->alpha = 0.0;
5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Determine the parellelogram bounding box fitted to the ellipse
5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    centered at u0,v0.  This area is bounding by the lines...
5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
555490ab03a4e81aa0943087243055c77e3794d75d9anthony  v1 = (ssize_t)ceil(v0 - resample_filter->Vlimit);  /* range of scan lines */
556490ab03a4e81aa0943087243055c77e3794d75d9anthony  v2 = (ssize_t)floor(v0 + resample_filter->Vlimit);
557490ab03a4e81aa0943087243055c77e3794d75d9anthony
558490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* scan line start and width accross the parallelogram */
559490ab03a4e81aa0943087243055c77e3794d75d9anthony  u1 = u0 + (v1-v0)*resample_filter->slope - resample_filter->Uwidth;
560490ab03a4e81aa0943087243055c77e3794d75d9anthony  uw = (ssize_t)(2.0*resample_filter->Uwidth)+1;
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
562490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
5635acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "v1=%ld; v2=%ld\n", (long)v1, (long)v2);
5645acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "u1=%ld; uw=%ld\n", (long)u1, (long)uw);
565490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
566490ab03a4e81aa0943087243055c77e3794d75d9anthony# define DEBUG_HIT_MISS 0 /* only valid if DEBUG_ELLIPSE is enabled */
567490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Do weighted resampling of all pixels,  within the scaled ellipse,
5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    bound by a Parellelogram fitted to the ellipse.
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DDQ = 2*resample_filter->A;
574490ab03a4e81aa0943087243055c77e3794d75d9anthony  for( v=v1; v<=v2;  v++ ) {
575490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
576490ab03a4e81aa0943087243055c77e3794d75d9anthony    long uu = ceil(u1);   /* actual pixel location (for debug only) */
5775acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy    (void) FormatLocaleFile(stderr, "# scan line from pixel %ld, %ld\n", (long)uu, (long)v);
578490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
579490ab03a4e81aa0943087243055c77e3794d75d9anthony    u = (ssize_t)ceil(u1);        /* first pixel in scanline */
580490ab03a4e81aa0943087243055c77e3794d75d9anthony    u1 += resample_filter->slope; /* start of next scan line */
581490ab03a4e81aa0943087243055c77e3794d75d9anthony
582490ab03a4e81aa0943087243055c77e3794d75d9anthony
583490ab03a4e81aa0943087243055c77e3794d75d9anthony    /* location of this first pixel, relative to u0,v0 */
584490ab03a4e81aa0943087243055c77e3794d75d9anthony    U = (double)u-u0;
5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    V = (double)v-v0;
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* Q = ellipse quotent ( if Q<F then pixel is inside ellipse) */
588490ab03a4e81aa0943087243055c77e3794d75d9anthony    Q = (resample_filter->A*U + resample_filter->B*V)*U + resample_filter->C*V*V;
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    DQ = resample_filter->A*(2.0*U+1) + resample_filter->B*V;
5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* get the scanline of pixels for this v */
592bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    pixels=GetCacheViewVirtualPixels(resample_filter->view,u,v,(size_t) uw,
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      1,resample_filter->exception);
5944c08aed51c5899665ade97263692328eea4af106cristy    if (pixels == (const Quantum *) NULL)
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* count up the weighted pixel colors */
5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    for( u=0; u<uw; u++ ) {
5995b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* Note that the ellipse has been pre-scaled so F = WLUT_WIDTH */
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( Q < (double)WLUT_WIDTH ) {
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        weight = resample_filter->filter_lut[(int)Q];
6035b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
6045b697cdb1ed6e391b98953aafd362bddad51b453anthony      /* Note that the ellipse has been pre-scaled so F = support^2 */
605582b6d79fc381d6c9455f3f1b3e26923950161ebanthony      if ( Q < (double)resample_filter->F ) {
606582b6d79fc381d6c9455f3f1b3e26923950161ebanthony        weight = GetResizeFilterWeight(resample_filter->filter_def,
607582b6d79fc381d6c9455f3f1b3e26923950161ebanthony             sqrt(Q));    /* a SquareRoot!  Arrggghhhhh... */
6085b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6104c08aed51c5899665ade97263692328eea4af106cristy        pixel->alpha  += weight*GetPixelAlpha(resample_filter->image,pixels);
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_m += weight;
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
61317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy        if (pixel->alpha_trait != UndefinedPixelTrait)
614a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy          weight *= QuantumScale*((double) GetPixelAlpha(resample_filter->image,pixels));
6154c08aed51c5899665ade97263692328eea4af106cristy        pixel->red   += weight*GetPixelRed(resample_filter->image,pixels);
6164c08aed51c5899665ade97263692328eea4af106cristy        pixel->green += weight*GetPixelGreen(resample_filter->image,pixels);
6174c08aed51c5899665ade97263692328eea4af106cristy        pixel->blue  += weight*GetPixelBlue(resample_filter->image,pixels);
6182ab242ec7c723f9f95558b30f1275011aa582ca9cristy        if (pixel->colorspace == CMYKColorspace)
6194c08aed51c5899665ade97263692328eea4af106cristy          pixel->black += weight*GetPixelBlack(resample_filter->image,pixels);
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_c += weight;
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
623490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
624490ab03a4e81aa0943087243055c77e3794d75d9anthony        /* mark the pixel according to hit/miss of the ellipse */
6255acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
626490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
6275acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
628490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
629490ab03a4e81aa0943087243055c77e3794d75d9anthony      } else {
6305acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
631490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
6325acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
633490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
634490ab03a4e81aa0943087243055c77e3794d75d9anthony      }
635490ab03a4e81aa0943087243055c77e3794d75d9anthony      uu++;
636490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
638490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
639ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      pixels+=GetPixelChannels(resample_filter->image);
6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Q += DQ;
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      DQ += DDQ;
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
644490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
6455acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "Hit=%ld;  Total=%ld;\n", (long)hit, (long)uw*(v2-v1) );
646490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
6473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Result sanity check -- this should NOT happen
6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
6517d2553e6f4849f937e3b32fcac096a23932a6f64anthony  if ( hit == 0 || divisor_m <= MagickEpsilon || divisor_c <= MagickEpsilon ) {
6527d2553e6f4849f937e3b32fcac096a23932a6f64anthony    /* not enough pixels, or bad weighting in resampling,
6537d2553e6f4849f937e3b32fcac096a23932a6f64anthony       resort to direct interpolation */
654490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_NO_PIXEL_HIT
6554c08aed51c5899665ade97263692328eea4af106cristy    pixel->alpha = pixel->red = pixel->green = pixel->blue = 0;
6569b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony    pixel->red = QuantumRange; /* show pixels for which EWA fails */
6579b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#else
6584c08aed51c5899665ade97263692328eea4af106cristy    status=InterpolatePixelInfo(resample_filter->image,
659d76c51ed30cf4084f4434ba08925d16001d1e340cristy      resample_filter->view,resample_filter->interpolate,u0,v0,pixel,
660d76c51ed30cf4084f4434ba08925d16001d1e340cristy      resample_filter->exception);
6619b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#endif
6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return status;
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Finialize results of resampling
6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 1.0/divisor_m;
66926323143e202e9d0c23a394934bc48067a5ddf41cristy  if (pixel->alpha_trait != UndefinedPixelTrait)
67026323143e202e9d0c23a394934bc48067a5ddf41cristy    pixel->alpha = (double) ClampToQuantum(divisor_m*pixel->alpha);
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 1.0/divisor_c;
672a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  pixel->red   = (double) ClampToQuantum(divisor_c*pixel->red);
673a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  pixel->green = (double) ClampToQuantum(divisor_c*pixel->green);
674a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy  pixel->blue  = (double) ClampToQuantum(divisor_c*pixel->blue);
6752ab242ec7c723f9f95558b30f1275011aa582ca9cristy  if (pixel->colorspace == CMYKColorspace)
676a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy    pixel->black = (double) ClampToQuantum(divisor_c*pixel->black);
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
680c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA && EWA_CLAMP
681c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/*
682c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
684c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
685c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
686c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony-   C l a m p U p A x e s                                                     %
687c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
688c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
689c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
690c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
692c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ClampUpAxes() function converts the input vectors into a major and
69340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% minor axis unit vectors, and their magnitude.  This allows us to
69440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% ensure that the ellipse generated is never smaller than the unit
695c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% circle and thus never too small for use in EWA resampling.
696c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
697c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% This purely mathematical 'magic' was provided by Professor Nicolas
698c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% Robidoux and his Masters student Chantal Racette.
699c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
70040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: "We Recommend Singular Value Decomposition", David Austin
701c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%   http://www.ams.org/samplings/feature-column/fcarc-svd
702c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
70340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% By generating major and minor axis vectors, we can actually use the
704c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ellipse in its "canonical form", by remapping the dx,dy of the
705c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% sampled point into distances along the major and minor axis unit
706c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% vectors.
70740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas%
70840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: http://en.wikipedia.org/wiki/Ellipse#Canonical_form
709c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony*/
710c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthonystatic inline void ClampUpAxes(const double dux,
711c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       const double dvx,
712c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       const double duy,
713c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       const double dvy,
714c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       double *major_mag,
715c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       double *minor_mag,
716c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       double *major_unit_x,
717c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       double *major_unit_y,
718c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       double *minor_unit_x,
719c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony			       double *minor_unit_y)
720c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony{
721c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
722c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes takes an input 2x2 matrix
723c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
724c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ a b ] = [ dux duy ]
725c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ c d ] = [ dvx dvy ]
726c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
727c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * and computes from it the major and minor axis vectors [major_x,
728c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_y] and [minor_x,minor_y] of the smallest ellipse containing
729c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * both the unit disk and the ellipse which is the image of the unit
730c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * disk by the linear transformation
731c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
732c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dux duy ] [S] = [s]
733c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dvx dvy ] [T] = [t]
734c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
735c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * (The vector [S,T] is the difference between a position in output
736c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * space and [X,Y]; the vector [s,t] is the difference between a
737c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * position in input space and [x,y].)
738c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
739c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
740082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * Output:
741c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
742c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_mag is the half-length of the major axis of the "new"
74340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ellipse.
744c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
745c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_mag is the half-length of the minor axis of the "new"
74640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ellipse.
747c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
748c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_x is the x-coordinate of the major axis direction vector
749c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of both the "old" and "new" ellipses.
750c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
751c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_y is the y-coordinate of the major axis direction vector.
752c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
753c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_x is the x-coordinate of the minor axis direction vector.
754c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
755c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_y is the y-coordinate of the minor axis direction vector.
756c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
757c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Unit vectors are useful for computing projections, in particular,
758c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * to compute the distance between a point in output space and the
759082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * center of a unit disk in output space, using the position of the
760082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * corresponding point [s,t] in input space. Following the clamping,
761082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * the square of this distance is
762082f7e49118ae53d297a46feb7ed147f159263b0nicolas   *
763082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * ( ( s * major_unit_x + t * major_unit_y ) / major_mag )^2
764082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * +
765082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * ( ( s * minor_unit_x + t * minor_unit_y ) / minor_mag )^2
766082f7e49118ae53d297a46feb7ed147f159263b0nicolas   *
767082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * If such distances will be computed for many [s,t]'s, it makes
768082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * sense to actually compute the reciprocal of major_mag and
769082f7e49118ae53d297a46feb7ed147f159263b0nicolas   * minor_mag and multiply them by the above unit lengths.
770c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
771c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Now, if you want to modify the input pair of tangent vectors so
772c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it defines the modified ellipse, all you have to do is set
773c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
7748b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdux = major_mag * major_unit_x
7758b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvx = major_mag * major_unit_y
7768b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newduy = minor_mag * minor_unit_x = minor_mag * -major_unit_y
7778b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvy = minor_mag * minor_unit_y = minor_mag *  major_unit_x
778c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
779932ef8479742364640c1aed64b795c528afab45cnicolas   * and use these tangent vectors as if they were the original ones.
78040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Usually, this is a drastic change in the tangent vectors even if
781c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * the singular values are not clamped; for example, the minor axis
782c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * vector always points in a direction which is 90 degrees
783c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * counterclockwise from the direction of the major axis vector.
784c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
785c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
786c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Discussion:
787c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
788c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * GOAL: Fix things so that the pullback, in input space, of a disk
789c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of radius r in output space is an ellipse which contains, at
790c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * least, a disc of radius r. (Make this hold for any r>0.)
791c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
79240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ESSENCE OF THE METHOD: Compute the product of the first two
79340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * factors of an SVD of the linear transformation defining the
794f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * ellipse and make sure that both its columns have norm at least 1.
795f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * Because rotations and reflexions map disks to themselves, it is
79640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * not necessary to compute the third (rightmost) factor of the SVD.
797f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   *
798f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * DETAILS: Find the singular values and (unit) left singular
799f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * vectors of Jinv, clampling up the singular values to 1, and
800932ef8479742364640c1aed64b795c528afab45cnicolas   * multiply the unit left singular vectors by the new singular
801f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * values in order to get the minor and major ellipse axis vectors.
802c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
80340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Image resampling context:
804c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
805c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The Jacobian matrix of the transformation at the output point
806c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * under consideration is defined as follows:
807c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
808c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Consider the transformation (x,y) -> (X,Y) from input locations
8098b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * to output locations. (Anthony Thyssen, elsewhere in resample.c,
81040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * uses the notation (u,v) -> (x,y).)
811c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
81240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * The Jacobian matrix of the transformation at (x,y) is equal to
813c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
81440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   J = [ A, B ] = [ dX/dx, dX/dy ]
81540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *       [ C, D ]   [ dY/dx, dY/dy ]
816c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
81740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * that is, the vector [A,C] is the tangent vector corresponding to
81840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * input changes in the horizontal direction, and the vector [B,D]
81940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * is the tangent vector corresponding to input changes in the
82040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * vertical direction.
821c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
82240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * In the context of resampling, it is natural to use the inverse
82340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Jacobian matrix Jinv because resampling is generally performed by
82440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * pulling pixel locations in the output image back to locations in
82540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * the input image. Jinv is
826c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
827d0026353a2b71306fc279a94596a7935982d9064nicolas   *   Jinv = [ a, b ] = [ dx/dX, dx/dY ]
82840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *          [ c, d ]   [ dy/dX, dy/dY ]
829c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
830c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Note: Jinv can be computed from J with the following matrix
831c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * formula:
832c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
833c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = 1/(A*D-B*C) [  D, -B ]
834c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *                      [ -C,  A ]
835c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
83640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * What we do is modify Jinv so that it generates an ellipse which
83740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * is as close as possible to the original but which contains the
83840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * unit disk. This can be accomplished as follows:
839c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
840c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Let
841c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
842c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U Sigma V^T
843c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
844932ef8479742364640c1aed64b795c528afab45cnicolas   * be an SVD decomposition of Jinv. (The SVD is not unique, but the
84540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * final ellipse does not depend on the particular SVD.)
846cb18092ccb044a899ad125e794ff30067fb42416cristy   *
84740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * We could clamp up the entries of the diagonal matrix Sigma so
84840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * that they are at least 1, and then set
849c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
850c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U newSigma V^T.
851c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
85240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * However, we do not need to compute V for the following reason:
85340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * V^T is an orthogonal matrix (that is, it represents a combination
85440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * of rotations and reflexions) so that it maps the unit circle to
85540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * itself. For this reason, the exact value of V does not affect the
85640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * final ellipse, and we can choose V to be the identity
85740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * matrix. This gives
858c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
85940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   Jinv = U newSigma.
860c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
86140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * In the end, we return the two diagonal entries of newSigma
86240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * together with the two columns of U.
863c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
864c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
865c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes was written by Nicolas Robidoux and Chantal Racette
86647b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * of Laurentian University with insightful suggestions from Anthony
86747b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Thyssen and funding from the National Science and Engineering
86847b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Research Council of Canada. It is distinguished from its
86947b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * predecessors by its efficient handling of degenerate cases.
870703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   *
8718c741cc65e33be2570284c0217701c72c719aecbnicolas   * The idea of clamping up the EWA ellipse's major and minor axes so
8728c741cc65e33be2570284c0217701c72c719aecbnicolas   * that the result contains the reconstruction kernel filter support
87347b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * is taken from Andreas Gustaffson's Masters thesis "Interactive
87447b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Image Warping", Helsinki University of Technology, Faculty of
87547b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Information Technology, 59 pages, 1993 (see Section 3.6).
8768c741cc65e33be2570284c0217701c72c719aecbnicolas   *
87747b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * The use of the SVD to clamp up the singular values of the
87847b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Jacobian matrix of the pullback transformation for EWA resampling
87947b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * is taken from the astrophysicist Craig DeForest.  It is
88047b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * implemented in his PDL::Transform code (PDL = Perl Data
88147b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Language).
882c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
883c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double a = dux;
884c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double b = duy;
885c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double c = dvx;
886c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double d = dvy;
887c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
888c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * n is the matrix Jinv * transpose(Jinv). Eigenvalues of n are the
889c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * squares of the singular values of Jinv.
890c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
891c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double aa = a*a;
892c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double bb = b*b;
893c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double cc = c*c;
894c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double dd = d*d;
895c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
896c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Eigenvectors of n are left singular vectors of Jinv.
897c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
898c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n11 = aa+bb;
899c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n12 = a*c+b*d;
900c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n21 = n12;
901c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n22 = cc+dd;
902c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double det = a*d-b*c;
903c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double twice_det = det+det;
904c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double frobenius_squared = n11+n22;
905c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double discriminant =
906c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    (frobenius_squared+twice_det)*(frobenius_squared-twice_det);
907564e05ecd66ac304817909c9ed31a6eca3a71714nicolas  /*
908564e05ecd66ac304817909c9ed31a6eca3a71714nicolas   * In exact arithmetic, discriminant can't be negative. In floating
909564e05ecd66ac304817909c9ed31a6eca3a71714nicolas   * point, it can, because of the bad conditioning of SVD
910564e05ecd66ac304817909c9ed31a6eca3a71714nicolas   * decompositions done through the associated normal matrix.
911564e05ecd66ac304817909c9ed31a6eca3a71714nicolas   */
91293c8f1606f63ab2bac5d044f5174dfee75da57cacristy  const double sqrt_discriminant =
913bb89b9227e797258cc59dfa6fd449989109e22b2nicolas    sqrt(discriminant > 0.0 ? discriminant : 0.0);
914c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
915c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1 is the largest singular value of the inverse Jacobian
916c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. In other words, its reciprocal is the smallest singular
917c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * value of the Jacobian matrix itself.
918c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * If s1 = 0, both singular values are 0, and any orthogonal pair of
919c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * left and right factors produces a singular decomposition of Jinv.
920c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
921c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
9228b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * Initially, we only compute the squares of the singular values.
923c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
924c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1 = 0.5*(frobenius_squared+sqrt_discriminant);
925c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
926c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s2 the smallest singular value of the inverse Jacobian
927c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. Its reciprocal is the largest singular value of the
928c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Jacobian matrix itself.
929c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
930c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s2s2 = 0.5*(frobenius_squared-sqrt_discriminant);
931c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11 = s1s1-n11;
932c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22 = s1s1-n22;
933c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
934c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * u1, the first column of the U factor of a singular decomposition
935c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of Jinv, is a (non-normalized) left singular vector corresponding
936c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * to s1. It has entries u11 and u21. We compute u1 from the fact
937c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it is an eigenvector of n corresponding to the eigenvalue
938c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * s1^2.
939c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
940c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11_squared = s1s1minusn11*s1s1minusn11;
941c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22_squared = s1s1minusn22*s1s1minusn22;
942c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
943c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The following selects the largest row of n-s1^2 I as the one
944c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * which is used to find the eigenvector. If both s1^2-n11 and
945c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1^2-n22 are zero, n-s1^2 I is the zero matrix.  In that case,
946c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * any vector is an eigenvector; in addition, norm below is equal to
947c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * zero, and, in exact arithmetic, this is the only case in which
948c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * norm = 0. So, setting u1 to the simple but arbitrary vector [1,0]
949c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * if norm = 0 safely takes care of all cases.
950c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
951c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u11 =
952c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? n12 : s1s1minusn22 );
953c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u21 =
954c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? s1s1minusn11 : n21 );
955c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double norm = sqrt(temp_u11*temp_u11+temp_u21*temp_u21);
956c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
957c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Finalize the entries of first left singular vector (associated
958c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * with the largest singular value).
959c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
960c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u11 = ( (norm>0.0) ? temp_u11/norm : 1.0 );
961c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u21 = ( (norm>0.0) ? temp_u21/norm : 0.0 );
962c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
963c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Clamp the singular values up to 1.
964c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
965ed22721389b8ff2983982914d29db84731825a8fnicolas  *major_mag = ( (s1s1<=1.0) ? 1.0 : sqrt(s1s1) );
966ed22721389b8ff2983982914d29db84731825a8fnicolas  *minor_mag = ( (s2s2<=1.0) ? 1.0 : sqrt(s2s2) );
967c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
968c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Return the unit major and minor axis direction vectors.
969c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
970c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_x = u11;
971c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_y = u21;
972c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_x = -u21;
973c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_y = u11;
974c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony}
975c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
976c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S c a l e R e s a m p l e F i l t e r                                     %
9833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ScaleResampleFilter() does all the calculations needed to resample an image
9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  at a specific scale, defined by two scaling vectors.  This not using
9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  a orthogonal scaling, but two distorted scaling vectors, to allow the
9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  generation of a angled ellipse.
9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As only two deritive scaling vectors are used the center of the ellipse
9943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  must be the center of the lookup.  That is any curvature that the
9953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion may produce is discounted.
9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The input vectors are produced by either finding the derivitives of the
9983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion function, or the partial derivitives from a distortion mapping.
9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  They do not need to be the orthogonal dx,dy scaling vectors, but can be
10003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated from other derivatives.  For example you could use  dr,da/r
10013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  polar coordinate vector scaling vectors
10023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1003c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If   u,v =  DistortEquation(x,y)   OR   u = Fu(x,y); v = Fv(x,y)
1004c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Then the scaling vectors are determined from the deritives...
10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      du/dx, dv/dx     and    du/dy, dv/dy
1006c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If the resulting scaling vectors is othogonally aligned then...
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      dv/dx = 0   and   du/dy  =  0
1008c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Producing an othogonally alligned ellipse in source space for the area to
1009c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  be resampled.
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Note that scaling vectors are different to argument order.  Argument order
10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  is the general order the deritives are extracted from the distortion
1013c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  equations, and not the scaling vectors. As such the middle two vaules
1014c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  may be swapped from what you expect.  Caution is advised.
10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10163ebea1e232532895681cd50101ddad0856e9a1d3anthony%  WARNING: It is assumed that any SetResampleFilter() method call will
10173ebea1e232532895681cd50101ddad0856e9a1d3anthony%  always be performed before the ScaleResampleFilter() method, so that the
10183ebea1e232532895681cd50101ddad0856e9a1d3anthony%  size of the ellipse will match the support for the resampling filter being
10193ebea1e232532895681cd50101ddad0856e9a1d3anthony%  used.
1020490ab03a4e81aa0943087243055c77e3794d75d9anthony%
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ScaleResampleFilter method is:
10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     void ScaleResampleFilter(const ResampleFilter *resample_filter,
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       const double dux,const double duy,const double dvx,const double dvy)
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resampling resample_filterrmation defining the
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      image being resampled
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o dux,duy,dvx,dvy:
1032c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The deritives or scaling vectors defining the EWA ellipse.
1033c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         NOTE: watch the order, which is based on the order deritives
1034c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         are usally determined from distortion equations (see above).
1035c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The middle two values may need to be swapped if you are thinking
1036c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         in terms of scaling vectors.
10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
10393ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
10403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double dux,const double duy,const double dvx,const double dvy)
10413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1042d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  double A,B,C,F;
10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
1045e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(resample_filter->signature == MagickCoreSignature);
10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->limit_reached = MagickFalse;
10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1049b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  /* A 'point' filter forces use of interpolation instead of area sampling */
1050b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  if ( resample_filter->filter == PointFilter )
1051b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    return; /* EWA turned off - nothing to do */
1052b821aafe132291d46e0fb0c2b24e6e467aa17640anthony
1053c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
10545acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "# -----\n" );
10555acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "dux=%lf; dvx=%lf;   duy=%lf; dvy=%lf;\n",
1056c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony       dux, dvx, duy, dvy);
1057c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
10583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Find Ellipse Coefficents such that
10603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        A*u^2 + B*u*v + C*v^2 = F
10613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     With u,v relative to point around which we are resampling.
10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     And the given scaling dx,dy vectors in u,v space
10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy         du/dx,dv/dx   and  du/dy,dv/dy
10643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1065c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1066d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /* Direct conversion of derivatives into elliptical coefficients
1067b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     However when magnifying images, the scaling vectors will be small
1068b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     resulting in a ellipse that is too small to sample properly.
1069b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     As such we need to clamp the major/minor axis to a minumum of 1.0
1070b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     to prevent it getting too small.
10713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1072c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA_CLAMP
1073c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  { double major_mag,
1074c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_mag,
1075c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_x,
1076c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_y,
1077c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_x,
1078c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_y;
1079c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1080c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  ClampUpAxes(dux,dvx,duy,dvy, &major_mag, &minor_mag,
1081c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                &major_x, &major_y, &minor_x, &minor_y);
1082bdfddb0056c20dba73d299334525256fa6a99986anthony  major_x *= major_mag;  major_y *= major_mag;
1083bdfddb0056c20dba73d299334525256fa6a99986anthony  minor_x *= minor_mag;  minor_y *= minor_mag;
1084c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
10855acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "major_x=%lf; major_y=%lf;  minor_x=%lf; minor_y=%lf;\n",
1086c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony        major_x, major_y, minor_x, minor_y);
1087c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
1088c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  A = major_y*major_y+minor_y*minor_y;
1089c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  B = -2.0*(major_x*major_y+minor_x*minor_y);
1090c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  C = major_x*major_x+minor_x*minor_x;
1091eaa08628db6764fa5cb6802eaf9bb5753c25eb1fnicolas  F = major_mag*minor_mag;
1092c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F *= F; /* square it */
1093c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  }
10945b697cdb1ed6e391b98953aafd362bddad51b453anthony#else /* raw unclamped EWA */
10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy;
1096d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy;
1098c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F = dux*dvy-duy*dvx;
10995708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  F *= F; /* square it */
11005b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* EWA_CLAMP */
1101d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1102490ab03a4e81aa0943087243055c77e3794d75d9anthony#else /* HQ_EWA */
1103d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
1104c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    This Paul Heckbert's "Higher Quality EWA" formula, from page 60 in his
1105c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    thesis, which adds a unit circle to the elliptical area so as to do both
1106c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    Reconstruction and Prefiltering of the pixels in the resampling.  It also
1107c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    means it is always likely to have at least 4 pixels within the area of the
1108c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ellipse, for weighted averaging.  No scaling will result with F == 4.0 and
1109c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    a circle of radius 2.0, and F smaller than this means magnification is
1110c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    being used.
1111c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1112c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    NOTE: This method produces a very blury result at near unity scale while
1113bdfddb0056c20dba73d299334525256fa6a99986anthony    producing perfect results for strong minitification and magnifications.
1114490ab03a4e81aa0943087243055c77e3794d75d9anthony
1115c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    However filter support is fixed to 2.0 (no good for Windowed Sinc filters)
11163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy+1;
1118d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
11193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy+1;
11203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  F = A*C - B*B/4;
11213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
11223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1123490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
11245acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "A=%lf; B=%lf; C=%lf; F=%lf\n", A,B,C,F);
11253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1126c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /* Figure out the various information directly about the ellipse.
11273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     This information currently not needed at this time, but may be
11283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     needed later for better limit determination.
1129d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1130d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony     It is also good to have as a record for future debugging
11313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { double alpha, beta, gamma, Major, Minor;
1133490ab03a4e81aa0943087243055c77e3794d75d9anthony    double Eccentricity, Ellipse_Area, Ellipse_Angle;
1134d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
11353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha = A+C;
11363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    beta  = A-C;
11373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    gamma = sqrt(beta*beta + B*B );
11383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if ( alpha - gamma <= MagickEpsilon )
11400283b31ed43486c1b3c6d903f6992b6402419c40cristy      Major=MagickMaximumValue;
11413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
11420283b31ed43486c1b3c6d903f6992b6402419c40cristy      Major=sqrt(2*F/(alpha - gamma));
11433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Minor = sqrt(2*F/(alpha + gamma));
11443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11455acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy    (void) FormatLocaleFile(stderr, "# Major=%lf; Minor=%lf\n", Major, Minor );
11463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* other information about ellipse include... */
11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Eccentricity = Major/Minor;
11493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Ellipse_Area = MagickPI*Major*Minor;
1150e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas    Ellipse_Angle = atan2(B, A-C);
11513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11525acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy    (void) FormatLocaleFile(stderr, "# Angle=%lf   Area=%lf\n",
1153c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony         (double) RadiansToDegrees(Ellipse_Angle), Ellipse_Area);
11543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
11553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
115715c331b918b9c7b71e876965897b66ff6118a269nicolas  /* If one or both of the scaling vectors is impossibly large
115815c331b918b9c7b71e876965897b66ff6118a269nicolas     (producing a very large raw F value), we may as well not bother
115915c331b918b9c7b71e876965897b66ff6118a269nicolas     doing any form of resampling since resampled area is very large.
116015c331b918b9c7b71e876965897b66ff6118a269nicolas     In this case some alternative means of pixel sampling, such as
116115c331b918b9c7b71e876965897b66ff6118a269nicolas     the average of the whole image is needed to get a reasonable
116215c331b918b9c7b71e876965897b66ff6118a269nicolas     result. Calculate only as needed.
11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1164fe181a767c3b3e61b9133829c504e75e34916de8cristy  if ( (4*A*C - B*B) > MagickMaximumValue ) {
11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1169582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  /* Scale ellipse to match the filters support
11709cb63ccb02272521283da6d251068d91196cc5bfanthony     (that is, multiply F by the square of the support)
11719cb63ccb02272521283da6d251068d91196cc5bfanthony     Simplier to just multiply it by the support twice!
1172e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  */
1173490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
1174490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1176e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Orthogonal bounds of the ellipse */
1177c120ce3e122ce1c110efd35b31c4083f192a7209cristy  resample_filter->Ulimit = sqrt(C*F/(A*C-0.25*B*B));
1178c120ce3e122ce1c110efd35b31c4083f192a7209cristy  resample_filter->Vlimit = sqrt(A*F/(A*C-0.25*B*B));
11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1180e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Horizontally aligned parallelogram fitted to Ellipse */
1181e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  resample_filter->Uwidth = sqrt(F/A); /* Half of the parallelogram width */
1182c120ce3e122ce1c110efd35b31c4083f192a7209cristy  resample_filter->slope = -B/(2.0*A); /* Reciprocal slope of the parallelogram */
1183490ab03a4e81aa0943087243055c77e3794d75d9anthony
1184490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
11855acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy  (void) FormatLocaleFile(stderr, "Ulimit=%lf; Vlimit=%lf; UWidth=%lf; Slope=%lf;\n",
1186490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Ulimit, resample_filter->Vlimit,
1187490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Uwidth, resample_filter->slope );
1188490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
11893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1190e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Check the absolute area of the parallelogram involved.
1191e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas   * This limit needs more work, as it is too slow for larger images
1192e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas   * with tiled views of the horizon.
1193e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  */
119439f347aa142535ededfff86309cc2bb4cf222373cristy  if ( (resample_filter->Uwidth * resample_filter->Vlimit)
119539f347aa142535ededfff86309cc2bb4cf222373cristy         > (4.0*resample_filter->image_area)) {
11963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12005708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  /* Scale ellipse formula to directly index the Filter Lookup Table */
12013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { register double scale;
12025b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
1203582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* scale so that F = WLUT_WIDTH; -- hardcoded */
1204490ab03a4e81aa0943087243055c77e3794d75d9anthony    scale = (double)WLUT_WIDTH/F;
12055b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1206582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* scale so that F = resample_filter->F (support^2) */
1207582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    scale = resample_filter->F/F;
12085b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->A = A*scale;
12103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->B = B*scale;
12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->C = C*scale;
12123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r                                         %
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
12243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilter() set the resampling filter lookup table based on a
12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  specific filter.  Note that the filter is used as a radial filter not as a
12283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  two pass othogonally aligned resampling filter.
12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilter method is:
12313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    void SetResampleFilter(ResampleFilter *resample_filter,
12338b9f21cab4c50eb7d6e558a7a43a68833fe0b55ddirk%      const FilterType filter)
12343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling resample_filterrmation structure
12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o filter: the resize filter for elliptical weighting LUT
12403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
12413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
12423ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void SetResampleFilter(ResampleFilter *resample_filter,
12438b9f21cab4c50eb7d6e558a7a43a68833fe0b55ddirk  const FilterType filter)
12443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
12453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResizeFilter
12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     *resize_filter;
12473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
1249e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(resample_filter->signature == MagickCoreSignature);
12503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12512e6ab68e6538e73abd8d77f505bc9f033c742f1canthony  resample_filter->do_interpolate = MagickFalse;
12523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->filter = filter;
12533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12549cb63ccb02272521283da6d251068d91196cc5bfanthony  /* Default cylindrical filter is a Cubic Keys filter */
1255490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( filter == UndefinedFilter )
1256853d6979aa2981592af7020163b5030aa7185783anthony    resample_filter->filter = RobidouxFilter;
1257490ab03a4e81aa0943087243055c77e3794d75d9anthony
12589cb63ccb02272521283da6d251068d91196cc5bfanthony  if ( resample_filter->filter == PointFilter ) {
12599cb63ccb02272521283da6d251068d91196cc5bfanthony    resample_filter->do_interpolate = MagickTrue;
12609cb63ccb02272521283da6d251068d91196cc5bfanthony    return;  /* EWA turned off - nothing more to do */
12619cb63ccb02272521283da6d251068d91196cc5bfanthony  }
12629cb63ccb02272521283da6d251068d91196cc5bfanthony
1263490ab03a4e81aa0943087243055c77e3794d75d9anthony  resize_filter = AcquireResizeFilter(resample_filter->image,
1264aa2c16cb5e695053aa78e40f66bc36fbef4b1ed1cristy    resample_filter->filter,MagickTrue,resample_filter->exception);
12659cb63ccb02272521283da6d251068d91196cc5bfanthony  if (resize_filter == (ResizeFilter *) NULL) {
12669cb63ccb02272521283da6d251068d91196cc5bfanthony    (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
12679cb63ccb02272521283da6d251068d91196cc5bfanthony         ModuleError, "UnableToSetFilteringValue",
12689cb63ccb02272521283da6d251068d91196cc5bfanthony         "Fall back to Interpolated 'Point' filter");
12699cb63ccb02272521283da6d251068d91196cc5bfanthony    resample_filter->filter = PointFilter;
12709cb63ccb02272521283da6d251068d91196cc5bfanthony    resample_filter->do_interpolate = MagickTrue;
12719cb63ccb02272521283da6d251068d91196cc5bfanthony    return;  /* EWA turned off - nothing more to do */
12729cb63ccb02272521283da6d251068d91196cc5bfanthony  }
1273490ab03a4e81aa0943087243055c77e3794d75d9anthony
127410b8bc801774c852503dfc90a706dfa942f9cc2eanthony  /* Get the practical working support for the filter,
127510b8bc801774c852503dfc90a706dfa942f9cc2eanthony   * after any API call blur factors have been accoded for.
127610b8bc801774c852503dfc90a706dfa942f9cc2eanthony   */
1277c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1278490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->support = GetResizeFilterSupport(resize_filter);
1279c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#else
1280c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  resample_filter->support = 2.0;  /* fixed support size for HQ-EWA */
1281490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
1282490ab03a4e81aa0943087243055c77e3794d75d9anthony
12835b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
12845b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* Fill the LUT with the weights from the selected filter function */
12855b697cdb1ed6e391b98953aafd362bddad51b453anthony  { register int
12865b697cdb1ed6e391b98953aafd362bddad51b453anthony       Q;
12875b697cdb1ed6e391b98953aafd362bddad51b453anthony    double
12885b697cdb1ed6e391b98953aafd362bddad51b453anthony       r_scale;
12899cb63ccb02272521283da6d251068d91196cc5bfanthony
12905b697cdb1ed6e391b98953aafd362bddad51b453anthony    /* Scale radius so the filter LUT covers the full support range */
12915b697cdb1ed6e391b98953aafd362bddad51b453anthony    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
12925b697cdb1ed6e391b98953aafd362bddad51b453anthony    for(Q=0; Q<WLUT_WIDTH; Q++)
12935b697cdb1ed6e391b98953aafd362bddad51b453anthony      resample_filter->filter_lut[Q] = (double)
12945b697cdb1ed6e391b98953aafd362bddad51b453anthony           GetResizeFilterWeight(resize_filter,sqrt((double)Q)*r_scale);
12955b697cdb1ed6e391b98953aafd362bddad51b453anthony
12965b697cdb1ed6e391b98953aafd362bddad51b453anthony    /* finished with the resize filter */
12975b697cdb1ed6e391b98953aafd362bddad51b453anthony    resize_filter = DestroyResizeFilter(resize_filter);
12985b697cdb1ed6e391b98953aafd362bddad51b453anthony  }
12995b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1300582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  /* save the filter and the scaled ellipse bounds needed for filter */
13015b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->filter_def = resize_filter;
1302582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  resample_filter->F = resample_filter->support*resample_filter->support;
13035b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
1304490ab03a4e81aa0943087243055c77e3794d75d9anthony
13053ebea1e232532895681cd50101ddad0856e9a1d3anthony  /*
13063ebea1e232532895681cd50101ddad0856e9a1d3anthony    Adjust the scaling of the default unit circle
13073ebea1e232532895681cd50101ddad0856e9a1d3anthony    This assumes that any real scaling changes will always
13083ebea1e232532895681cd50101ddad0856e9a1d3anthony    take place AFTER the filter method has been initialized.
13093ebea1e232532895681cd50101ddad0856e9a1d3anthony  */
13103ebea1e232532895681cd50101ddad0856e9a1d3anthony  ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
13113ebea1e232532895681cd50101ddad0856e9a1d3anthony
13125708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#if 0
1313d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
13149cb63ccb02272521283da6d251068d91196cc5bfanthony    This is old code kept as a reference only. Basically it generates
13159cb63ccb02272521283da6d251068d91196cc5bfanthony    a Gaussian bell curve, with sigma = 0.5 if the support is 2.0
13169cb63ccb02272521283da6d251068d91196cc5bfanthony
1317d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Create Normal Gaussian 2D Filter Weighted Lookup Table.
1318d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    A normal EWA guassual lookup would use   exp(Q*ALPHA)
1319d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    where  Q = distance squared from 0.0 (center) to 1.0 (edge)
1320d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    and    ALPHA = -4.0*ln(2.0)  ==>  -2.77258872223978123767
13215b697cdb1ed6e391b98953aafd362bddad51b453anthony    The table is of length 1024, and equates to support radius of 2.0
1322d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    thus needs to be scaled by  ALPHA*4/1024 and any blur factor squared
1323d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
13249cb63ccb02272521283da6d251068d91196cc5bfanthony    The it comes from reference code provided by Fred Weinhaus.
1325d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  */
1326d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur);
1327d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  for(Q=0; Q<WLUT_WIDTH; Q++)
1328d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    resample_filter->filter_lut[Q] = exp((double)Q*r_scale);
1329d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  resample_filter->support = WLUT_WIDTH;
13305708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#endif
1331490ab03a4e81aa0943087243055c77e3794d75d9anthony
13325b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
1333e06e4c180324bebbd41bce9ea4898642f380b614anthony#if defined(MAGICKCORE_OPENMP_SUPPORT)
133472949796e01f8b94a0976e74cb8eb3f86af280eaanthony  #pragma omp single
1335e06e4c180324bebbd41bce9ea4898642f380b614anthony#endif
13369cb63ccb02272521283da6d251068d91196cc5bfanthony  {
1337972c2e42a2171341bbf55a48cb36882616a591b1dirk    if (IsStringTrue(GetImageArtifact(resample_filter->image,
1338972c2e42a2171341bbf55a48cb36882616a591b1dirk        "resample:verbose")) != MagickFalse)
1339e06e4c180324bebbd41bce9ea4898642f380b614anthony      {
13409cb63ccb02272521283da6d251068d91196cc5bfanthony        register int
13419cb63ccb02272521283da6d251068d91196cc5bfanthony          Q;
13429cb63ccb02272521283da6d251068d91196cc5bfanthony        double
13439cb63ccb02272521283da6d251068d91196cc5bfanthony          r_scale;
13449cb63ccb02272521283da6d251068d91196cc5bfanthony
1345e06e4c180324bebbd41bce9ea4898642f380b614anthony        /* Debug output of the filter weighting LUT
13469cb63ccb02272521283da6d251068d91196cc5bfanthony          Gnuplot the LUT data, the x scale index has been adjusted
13479cb63ccb02272521283da6d251068d91196cc5bfanthony            plot [0:2][-.2:1] "lut.dat" with lines
13489cb63ccb02272521283da6d251068d91196cc5bfanthony          The filter values should be normalized for comparision
1349e06e4c180324bebbd41bce9ea4898642f380b614anthony        */
1350d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("#\n");
13519cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("# Resampling Filter LUT (%d values) for '%s' filter\n",
13529cb63ccb02272521283da6d251068d91196cc5bfanthony                   WLUT_WIDTH, CommandOptionToMnemonic(MagickFilterOptions,
13539cb63ccb02272521283da6d251068d91196cc5bfanthony                   resample_filter->filter) );
1354e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("#\n");
1355d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("# Note: values in table are using a squared radius lookup.\n");
13569cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("# As such its distribution is not uniform.\n");
13579cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("#\n");
13589cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("# The X value is the support distance for the Y weight\n");
13599cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("# so you can use gnuplot to plot this cylindrical filter\n");
13609cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("#    plot [0:2][-.2:1] \"lut.dat\" with lines\n");
13619cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("#\n");
13629cb63ccb02272521283da6d251068d91196cc5bfanthony
13639cb63ccb02272521283da6d251068d91196cc5bfanthony        /* Scale radius so the filter LUT covers the full support range */
13649cb63ccb02272521283da6d251068d91196cc5bfanthony        r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
1365e06e4c180324bebbd41bce9ea4898642f380b614anthony        for(Q=0; Q<WLUT_WIDTH; Q++)
1366d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony          printf("%8.*g %.*g\n",
13679cb63ccb02272521283da6d251068d91196cc5bfanthony              GetMagickPrecision(),sqrt((double)Q)*r_scale,
13689cb63ccb02272521283da6d251068d91196cc5bfanthony              GetMagickPrecision(),resample_filter->filter_lut[Q] );
13699cb63ccb02272521283da6d251068d91196cc5bfanthony        printf("\n\n"); /* generate a 'break' in gnuplot if multiple outputs */
1370e06e4c180324bebbd41bce9ea4898642f380b614anthony      }
13719cb63ccb02272521283da6d251068d91196cc5bfanthony    /* Output the above once only for each image, and each setting
137272949796e01f8b94a0976e74cb8eb3f86af280eaanthony    (void) DeleteImageArtifact(resample_filter->image,"resample:verbose");
13739cb63ccb02272521283da6d251068d91196cc5bfanthony    */
137472949796e01f8b94a0976e74cb8eb3f86af280eaanthony  }
13755b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* FILTER_LUT */
13763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return;
13773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
13783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
13803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r I n t e r p o l a t e M e t h o d       %
13853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
13883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13902ab242ec7c723f9f95558b30f1275011aa582ca9cristy%  SetResampleFilterInterpolateMethod() sets the resample filter interpolation
13912ab242ec7c723f9f95558b30f1275011aa582ca9cristy%  method.
13923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterInterpolateMethod method is:
13943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterInterpolateMethod(
13963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const InterpolateMethod method)
13973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
13983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
13993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
14013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the interpolation method.
14033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
14053ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterInterpolateMethod(
14065c4e2586d27d4299a742d170d41105de1689aa46cristy  ResampleFilter *resample_filter,const PixelInterpolateMethod method)
14073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
14083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
1409e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(resample_filter->signature == MagickCoreSignature);
14103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
14113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
14123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
14133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
14143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->interpolate=method;
14152ab242ec7c723f9f95558b30f1275011aa582ca9cristy  return(MagickTrue);
14162ab242ec7c723f9f95558b30f1275011aa582ca9cristy}
14172ab242ec7c723f9f95558b30f1275011aa582ca9cristy
14182ab242ec7c723f9f95558b30f1275011aa582ca9cristy/*
14192ab242ec7c723f9f95558b30f1275011aa582ca9cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14202ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
14212ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
14222ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
14233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r V i r t u a l P i x e l M e t h o d     %
14243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilterVirtualPixelMethod() changes the virtual pixel method
14303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  associated with the specified resample filter.
14313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterVirtualPixelMethod method is:
14333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterVirtualPixelMethod(
14353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const VirtualPixelMethod method)
14363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
14383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
14403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the virtual pixel method.
14423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
14443ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterVirtualPixelMethod(
14453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const VirtualPixelMethod method)
14463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
14473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
1448e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(resample_filter->signature == MagickCoreSignature);
14493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
14503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
14513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
14523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
14533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->virtual_pixel=method;
14542d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy  if (method != UndefinedVirtualPixelMethod)
14552d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy    (void) SetCacheViewVirtualPixelMethod(resample_filter->view,method);
14563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
14573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1458