resample.c revision c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24b
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                                %
163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                John Cristy                                  %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Anthony Thyssen                                %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                August 2007                                  %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2116af1cbdffcc02e7239d432e5fb51734fcf9f9ffcristy%  Copyright 1999-2010 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*/
433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/studio.h"
443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/artifact.h"
453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/color-private.h"
463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/cache.h"
473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/draw.h"
483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/exception-private.h"
493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/gem.h"
503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/image.h"
513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/image-private.h"
523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/log.h"
53d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony#include "magick/magick.h"
543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/memory_.h"
553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/pixel-private.h"
563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/quantum.h"
573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/random_.h"
583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/resample.h"
593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/resize.h"
603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/resize-private.h"
613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/transform.h"
623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/signature-private.h"
6328ad1d779b6ca95852e860514185a7a97e06af77anthony#include "magick/utility.h"
643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
65490ab03a4e81aa0943087243055c77e3794d75d9anthony  EWA Resampling Options
66490ab03a4e81aa0943087243055c77e3794d75d9anthony*/
67c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
68c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* select ONE resampling method */
69c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA 1                 /* Normal EWA handling - raw or clamped */
70c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                              /* if 0 then use "High Quality EWA" */
71c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA_CLAMP 1           /* EWA Clamping from Nicolas Robidoux */
72c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
735b697cdb1ed6e391b98953aafd362bddad51b453anthony#define FILTER_LUT 1          /* Use a LUT rather then direct filter calls */
745b697cdb1ed6e391b98953aafd362bddad51b453anthony
75c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* output debugging information */
76490ab03a4e81aa0943087243055c77e3794d75d9anthony#define DEBUG_ELLIPSE 0       /* output ellipse info for debug */
772e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_HIT_MISS 0      /* output hit/miss pixels (as gnuplot commands) */
782e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_NO_PIXEL_HIT 0  /* Make pixels that fail to hit anything - RED */
79490ab03a4e81aa0943087243055c77e3794d75d9anthony
805b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_DIRECT
815b697cdb1ed6e391b98953aafd362bddad51b453anthony#define WLUT_WIDTH 1024       /* size of the filter cache */
825b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
835b697cdb1ed6e391b98953aafd362bddad51b453anthony
84490ab03a4e81aa0943087243055c77e3794d75d9anthony/*
853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Typedef declarations.
863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
873ed852eea50f9d4cd633efb8c2b054b8e33c253cristystruct _ResampleFilter
883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *view;
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
92c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  Image
93c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image;
94c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *exception;
973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    debug;
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Information about image being resampled */
102bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image_area;
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  InterpolatePixelMethod
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    interpolate;
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  VirtualPixelMethod
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    virtual_pixel;
1103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FilterTypes
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    filter;
1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* processing settings needed */
1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    limit_reached,
1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    do_interpolate,
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_defined;
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_pixel;
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* current ellipitical area being resampled around center point */
1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    A, B, C,
126d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Vlimit, Ulimit, Uwidth, slope;
1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
128175defe3237b2e7bab13c9649a837500af6a82c7anthony#if FILTER_LUT
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* LUT of weights for filtered average in elliptical area */
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1315b697cdb1ed6e391b98953aafd362bddad51b453anthony    filter_lut[WLUT_WIDTH];
1325b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1335b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* Use a Direct call to the filter functions */
1345b697cdb1ed6e391b98953aafd362bddad51b453anthony  ResizeFilter
1355b697cdb1ed6e391b98953aafd362bddad51b453anthony    *filter_def;
136582b6d79fc381d6c9455f3f1b3e26923950161ebanthony
137582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  double
138582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    F;
1395b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
1405b697cdb1ed6e391b98953aafd362bddad51b453anthony
1415b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* the practical working support of the filter */
1425b697cdb1ed6e391b98953aafd362bddad51b453anthony  double
1433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    support;
1443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
145bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
1463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    signature;
1473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy};
1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   A c q u i r e R e s a m p l e I n f o                                     %
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  AcquireResampleFilter() initializes the information resample needs do to a
1613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  scaled lookup of a color from an image, using area sampling.
1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The algorithm is based on a Elliptical Weighted Average, where the pixels
1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  found in a large elliptical area is averaged together according to a
1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  weighting (filter) function.  For more details see "Fundamentals of Texture
1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Mapping and Image Warping" a master's thesis by Paul.S.Heckbert, June 17,
1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  1989.  Available for free from, http://www.cs.cmu.edu/~ph/
1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As EWA resampling (or any sort of resampling) can require a lot of
1703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculations to produce a distorted scaling of the source image for each
1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  output pixel, the ResampleFilter structure generated holds that information
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  between individual image resampling.
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This function will make the appropriate AcquireCacheView() calls
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  to view the image, calling functions do not need to open a cache view.
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Usage Example...
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      resample_filter=AcquireResampleFilter(image,exception);
179c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%      SetResampleFilter(resample_filter, GaussianFilter, 1.0);
180bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      for (y=0; y < (ssize_t) image->rows; y++) {
181bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%        for (x=0; x < (ssize_t) image->columns; x++) {
182c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          u= ....;   v= ....;
1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ScaleResampleFilter(resample_filter, ... scaling vectors ...);
184c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          (void) ResamplePixelColor(resample_filter,u,v,&pixel);
1853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ... assign resampled pixel value ...
1863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        }
1873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      }
1883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      DestroyResampleFilter(resample_filter);
1893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the AcquireResampleFilter method is:
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     ResampleFilter *AcquireResampleFilter(const Image *image,
1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       ExceptionInfo *exception)
1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *AcquireResampleFilter(const Image *image,
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo *exception)
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register ResampleFilter
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *resample_filter;
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image->signature == MagickSignature);
2103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception != (ExceptionInfo *) NULL);
2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception->signature == MagickSignature);
2143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter=(ResampleFilter *) AcquireMagickMemory(
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sizeof(*resample_filter));
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter == (ResampleFilter *) NULL)
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(resample_filter,0,sizeof(*resample_filter));
2203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=ReferenceImage((Image *) image);
2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->view=AcquireCacheView(resample_filter->image);
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->exception=exception;
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->debug=IsEventLogging();
2263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->signature=MagickSignature;
2273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2285b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->image_area=(ssize_t) (image->columns*image->rows);
2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->average_defined = MagickFalse;
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* initialise the resampling filter settings */
2325b697cdb1ed6e391b98953aafd362bddad51b453anthony  SetResampleFilter(resample_filter, image->filter, image->blur);
23382fea938ea2a766e32daddb7f2f69d66958e9d45cristy  (void) SetResampleFilterInterpolateMethod(resample_filter,
23482fea938ea2a766e32daddb7f2f69d66958e9d45cristy    image->interpolate);
23582fea938ea2a766e32daddb7f2f69d66958e9d45cristy  (void) SetResampleFilterVirtualPixelMethod(resample_filter,
23672949796e01f8b94a0976e74cb8eb3f86af280eaanthony    GetImageVirtualPixelMethod(image));
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   D e s t r o y R e s a m p l e I n f o                                     %
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DestroyResampleFilter() finalizes and cleans up the resampling
2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  resample_filter as returned by AcquireResampleFilter(), freeing any memory
2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  or other information as needed.
2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DestroyResampleFilter method is:
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      ResampleFilter *DestroyResampleFilter(ResampleFilter *resample_filter)
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling information structure
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *DestroyResampleFilter(
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter)
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
2743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->view=DestroyCacheView(resample_filter->view);
2753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=DestroyImage(resample_filter->image);
2765b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_LUT
2775b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->filter_def=DestroyResizeFilter(resample_filter->filter_def);
2785b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->signature=(~MagickSignature);
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter=(ResampleFilter *) RelinquishMagickMemory(resample_filter);
2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   I n t e r p o l a t e R e s a m p l e F i l t e r                         %
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  InterpolateResampleFilter() applies bi-linear or tri-linear interpolation
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  between a floating point coordinate and the pixels surrounding that
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  coordinate.  No pixel area resampling, or scaling of the result is
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  performed.
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the InterpolateResampleFilter method is:
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType InterpolateResampleFilter(
3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleInfo *resample_filter,const InterpolatePixelMethod method,
3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        const double x,const double y,MagickPixelPacket *pixel)
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the pixel clor interpolation method.
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o x,y: A double representing the current (x,y) position of the pixel.
3133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o pixel: return the interpolated pixel here.
3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline double MagickMax(const double x,const double y)
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (x > y)
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(x);
3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(y);
3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void BicubicInterpolate(const MagickPixelPacket *pixels,const double dx,
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket *pixel)
3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickRealType
3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    dx2,
3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p,
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q,
3323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    r,
3333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    s;
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  dx2=dx*dx;
3363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].red-pixels[2].red)-(pixels[0].red-pixels[1].red);
3373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].red-pixels[1].red)-p;
3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].red-pixels[0].red;
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].red;
3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->red=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].green-pixels[2].green)-(pixels[0].green-pixels[1].green);
3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].green-pixels[1].green)-p;
3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].green-pixels[0].green;
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].green;
3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->green=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].blue-pixels[2].blue)-(pixels[0].blue-pixels[1].blue);
3473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].blue-pixels[1].blue)-p;
3483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].blue-pixels[0].blue;
3493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].blue;
3503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->blue=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].opacity-pixels[2].opacity)-(pixels[0].opacity-pixels[1].opacity);
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].opacity-pixels[1].opacity)-p;
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].opacity-pixels[0].opacity;
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].opacity;
3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->opacity=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (pixel->colorspace == CMYKColorspace)
3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=(pixels[3].index-pixels[2].index)-(pixels[0].index-pixels[1].index);
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      q=(pixels[0].index-pixels[1].index)-p;
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      r=pixels[2].index-pixels[0].index;
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      s=pixels[1].index;
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->index=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline MagickRealType CubicWeightingFunction(const MagickRealType x)
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickRealType
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha,
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    gamma;
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+2.0,0.0);
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma=1.0*alpha*alpha*alpha;
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+1.0,0.0);
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma-=4.0*alpha*alpha*alpha;
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+0.0,0.0);
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma+=6.0*alpha*alpha*alpha;
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x-1.0,0.0);
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma-=4.0*alpha*alpha*alpha;
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(gamma/6.0);
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline double MeshInterpolate(const PointInfo *delta,const double p,
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double x,const double y)
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(delta->x*x+delta->y*y+(1.0-delta->x-delta->y)*p);
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
389bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic inline ssize_t NearestNeighbor(MagickRealType x)
3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (x >= 0.0)
392bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    return((ssize_t) (x+0.5));
393bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  return((ssize_t) (x-0.5));
3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3963ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType InterpolateResampleFilter(
3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const InterpolatePixelMethod method,
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double x,const double y,MagickPixelPacket *pixel)
3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const IndexPacket
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *indexes;
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const PixelPacket
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
409bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
4152e6ab68e6538e73abd8d77f505bc9f033c742f1canthony
4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch (method)
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case AverageInterpolatePixel:
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
4213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16];
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16],
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
42754ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
42854ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 16L; i++)
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
44246f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (resample_filter->image->colorspace == CMYKColorspace)
4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
4493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma=alpha[i];
4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->red+=gamma*0.0625*pixels[i].red;
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->green+=gamma*0.0625*pixels[i].green;
4533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->blue+=gamma*0.0625*pixels[i].blue;
4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->opacity+=0.0625*pixels[i].opacity;
4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->colorspace == CMYKColorspace)
4563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->index+=gamma*0.0625*pixels[i].index;
4573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BicubicInterpolatePixel:
4623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16],
4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        u[4];
4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16];
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta;
4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
47354ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
47454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
4783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
4793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
4813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 16L; i++)
4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
48846f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (resample_filter->image->colorspace == CMYKColorspace)
4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
4943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
4953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
4983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
4993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        BicubicInterpolate(pixels+4*i,delta.x,u+i);
5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      BicubicInterpolate(u,delta.y,pixel);
5023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BilinearInterpolatePixel:
5053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    default:
5063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
5083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[4];
5093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
5113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[4],
5123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
5133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
5153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta,
5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        epsilon;
5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
51854ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
51954ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),2,2,resample_filter->exception);
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
5233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].red=(MagickRealType) p[i].red;
5293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].green=(MagickRealType) p[i].green;
5303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].blue=(MagickRealType) p[i].blue;
5313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].opacity=(MagickRealType) p[i].opacity;
5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (resample_filter->image->matte != MagickFalse)
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (i=0; i < 4L; i++)
5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p[i].opacity);
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].red*=alpha[i];
5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].green*=alpha[i];
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].blue*=alpha[i];
5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (indexes != (IndexPacket *) NULL)
5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (i=0; i < 4L; i++)
5443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].index=(MagickRealType) indexes[i];
5463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->colorspace == CMYKColorspace)
5473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].index*=alpha[i];
5483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      epsilon.x=1.0-delta.x;
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      epsilon.y=1.0-delta.y;
5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (epsilon.x*alpha[2]+delta.x*alpha[3])));
5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
5603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].green));
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].blue));
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->opacity=(epsilon.y*(epsilon.x*pixels[0].opacity+delta.x*
5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].opacity)+delta.y*(epsilon.x*pixels[2].opacity+delta.x*
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].opacity));
5673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (resample_filter->image->colorspace == CMYKColorspace)
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->index=gamma*(epsilon.y*(epsilon.x*pixels[0].index+delta.x*
5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[1].index)+delta.y*(epsilon.x*pixels[2].index+delta.x*
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[3].index));
5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case FilterInterpolatePixel:
5743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
57554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      CacheView
57654ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        *filter_view;
57754ffe7c6780ec1e33f8707e228b962d1accf58f8cristy
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Image
5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *excerpt_image,
5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *filter_image;
5813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
5833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
5843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      RectangleInfo
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        geometry;
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      geometry.width=4L;
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      geometry.height=4L;
590bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      geometry.x=(ssize_t) floor(x)-1L;
591bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      geometry.y=(ssize_t) floor(y)-1L;
5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      excerpt_image=ExcerptImage(resample_filter->image,&geometry,
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->exception);
5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (excerpt_image == (Image *) NULL)
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_image=ResizeImage(excerpt_image,1,1,resample_filter->image->filter,
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->image->blur,resample_filter->exception);
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      excerpt_image=DestroyImage(excerpt_image);
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (filter_image == (Image *) NULL)
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_view=AcquireCacheView(filter_image);
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,
6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->exception);
6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p != (const PixelPacket *) NULL)
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          indexes=GetVirtualIndexQueue(filter_image);
6103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetMagickPixelPacket(resample_filter->image,pixels);
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_view=DestroyCacheView(filter_view);
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_image=DestroyImage(filter_image);
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case IntegerInterpolatePixel:
6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
62254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
62354ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),1,1,resample_filter->exception);
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GetMagickPixelPacket(resample_filter->image,pixels);
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MeshInterpolatePixel:
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[4];
6383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[4],
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
6443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta,
6453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        luminance;
6463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
64754ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
64854ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),2,2,resample_filter->exception);
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
6563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
6573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
6593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
66246f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (resample_filter->image->colorspace == CMYKColorspace)
6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
6693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
6733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      luminance.x=MagickPixelLuminance(pixels+0)-MagickPixelLuminance(pixels+3);
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      luminance.y=MagickPixelLuminance(pixels+1)-MagickPixelLuminance(pixels+2);
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (fabs(luminance.x) < fabs(luminance.y))
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Diagonal 0-3 NW-SE.
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (delta.x <= delta.y)
6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Bottom-left triangle  (pixel:2, diagonal: 0-3).
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.y=1.0-delta.y;
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[2].red,
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].red,pixels[0].red);
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[2].green,
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].green,pixels[0].green);
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[2].blue,
6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].blue,pixels[0].blue);
6943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[2].opacity,
6953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].opacity,pixels[0].opacity);
6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[2].index,
6983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[3].index,pixels[0].index);
6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Top-right triangle (pixel:1, diagonal: 0-3).
7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.x=1.0-delta.x;
7063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[1].red,
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].red,pixels[3].red);
7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[1].green,
7113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].green,pixels[3].green);
7123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[1].blue,
7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].blue,pixels[3].blue);
7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[1].opacity,
7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].opacity,pixels[3].opacity);
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[1].index,
7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[0].index,pixels[3].index);
7193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      else
7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
7243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Diagonal 1-2 NE-SW.
7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (delta.x <= (1.0-delta.y))
7273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Top-left triangle (pixel 0, diagonal: 1-2).
7303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[0].red,
7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].red,pixels[2].red);
7353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[0].green,
7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].green,pixels[2].green);
7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[0].blue,
7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].blue,pixels[2].blue);
7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[0].opacity,
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].opacity,pixels[2].opacity);
7413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
7423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[0].index,
7433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[1].index,pixels[2].index);
7443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
7463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Bottom-right triangle (pixel: 3, diagonal: 1-2).
7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.x=1.0-delta.x;
7513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.y=1.0-delta.y;
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
7533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[3].red,
7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].red,pixels[1].red);
7563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[3].green,
7573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].green,pixels[1].green);
7583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[3].blue,
7593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].blue,pixels[1].blue);
7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[3].opacity,
7613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].opacity,pixels[1].opacity);
7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
7633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[3].index,
7643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[2].index,pixels[1].index);
7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
7683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case NearestNeighborInterpolatePixel:
7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
7723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
7733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=GetCacheViewVirtualPixels(resample_filter->view,NearestNeighbor(x),
7753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        NearestNeighbor(y),1,1,resample_filter->exception);
7763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
7773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
7793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
7823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GetMagickPixelPacket(resample_filter->image,pixels);
7833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
7843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
7853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case SplineInterpolatePixel:
7873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
7893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16];
7903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
7923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16],
7933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dx,
7943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dy,
7953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
7963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
7983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta;
7993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
80054ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      ssize_t
80154ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        j,
80254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        n;
80354ffe7c6780ec1e33f8707e228b962d1accf58f8cristy
80454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
80554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
8063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
8073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
8083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
8093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
8113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
8123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      n=0;
8133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
8143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
8153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=(-1); i < 3L; i++)
8163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dy=CubicWeightingFunction((MagickRealType) i-delta.y);
8183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (j=(-1); j < 3L; j++)
8193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetMagickPixelPacket(resample_filter->image,pixels+n);
8213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,p,indexes+n,pixels+n);
8223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          alpha[n]=1.0;
8233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->matte != MagickFalse)
8243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
82554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy              alpha[n]=QuantumScale*((MagickRealType)
82654ffe7c6780ec1e33f8707e228b962d1accf58f8cristy                GetAlphaPixelComponent(p));
8273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].red*=alpha[n];
8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].green*=alpha[n];
8293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].blue*=alpha[n];
8303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[n].index*=alpha[n];
8323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
8333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          dx=CubicWeightingFunction(delta.x-(MagickRealType) j);
8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          gamma=alpha[n];
8353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
8363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->red+=gamma*dx*dy*pixels[n].red;
8373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->green+=gamma*dx*dy*pixels[n].green;
8383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->blue+=gamma*dx*dy*pixels[n].blue;
8393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->matte != MagickFalse)
8403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixel->opacity+=dx*dy*pixels[n].opacity;
8413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->colorspace == CMYKColorspace)
8423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixel->index+=gamma*dx*dy*pixels[n].index;
8433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          n++;
8443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          p++;
8453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
8463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
8473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
8483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
8503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
8513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
8543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e s a m p l e P i x e l C o l o r                                       %
8593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ResamplePixelColor() samples the pixel values surrounding the location
8653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  given using an elliptical weighted average, at the scale previously
8663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated, and in the most efficent manner possible for the
8673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  VirtualPixelMethod setting.
8683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ResamplePixelColor method is:
8703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter,
8723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       const double u0,const double v0,MagickPixelPacket *pixel)
8733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
8773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o u0,v0: A double representing the center of the area to resample,
8793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        The distortion transformed transformed x,y coordinate.
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o pixel: the resampled pixel is returned here.
8823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
8843ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType ResamplePixelColor(
8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const double u0,const double v0,
8863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket *pixel)
8873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
8893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
8903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
891490ab03a4e81aa0943087243055c77e3794d75d9anthony  ssize_t u,v, v1, v2, uw, hit;
8923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double u1;
8933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double U,V,Q,DQ,DDQ;
8943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double divisor_c,divisor_m;
8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register double weight;
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const PixelPacket *pixels;
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const IndexPacket *indexes;
8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
8993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
9023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GetMagickPixelPacket(resample_filter->image,pixel);
9033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->do_interpolate ) {
9043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,
9053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->interpolate,u0,v0,pixel);
9063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
9073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9092e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#if DEBUG_ELLIPSE
9102e6ab68e6538e73abd8d77f505bc9f033c742f1canthony  fprintf(stderr, "u0=%lf; v0=%lf;\n", u0, v0);
9112e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#endif
9122e6ab68e6538e73abd8d77f505bc9f033c742f1canthony
9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
9143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Does resample area Miss the image?
9153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    And is that area a simple solid color - then return that color
9163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
9173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
9183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch ( resample_filter->virtual_pixel ) {
9193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BackgroundVirtualPixelMethod:
9203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case ConstantVirtualPixelMethod:
9213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TransparentVirtualPixelMethod:
9223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BlackVirtualPixelMethod:
9233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case GrayVirtualPixelMethod:
9243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case WhiteVirtualPixelMethod:
9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MaskVirtualPixelMethod:
9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( resample_filter->limit_reached
927d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 + resample_filter->Ulimit < 0.0
928d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
929d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 + resample_filter->Vlimit < 0.0
930d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
9313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case UndefinedVirtualPixelMethod:
9363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case EdgeVirtualPixelMethod:
937d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < 0.0 && v0 + resample_filter->Vlimit < 0.0 )
938d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < 0.0
939d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
940d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
941d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < 0.0 )
942d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
943d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
9443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileVirtualPixelMethod:
948d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    v0 + resample_filter->Vlimit < 0.0
949d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
9503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the horizontally tiled images. */
9523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileVirtualPixelMethod:
954d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    u0 + resample_filter->Ulimit < 0.0
955d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
9563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the vertically tiled images. */
9583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case DitherVirtualPixelMethod:
960d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < -32.0 && v0 + resample_filter->Vlimit < -32.0 )
961d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < -32.0
962d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
963d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
964d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < -32.0 )
965d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
966d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
9673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TileVirtualPixelMethod:
9713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MirrorVirtualPixelMethod:
9723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case RandomVirtualPixelMethod:
9733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileEdgeVirtualPixelMethod:
9743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileEdgeVirtualPixelMethod:
9753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case CheckerTileVirtualPixelMethod:
9763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* resampling of area is always needed - no VP limits */
9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( hit ) {
9803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* whole area is a solid color -- just return that color */
9813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,IntegerInterpolatePixel,
9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      u0,v0,pixel);
9833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
9843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Scaling limits reached, return an 'averaged' result.
9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->limit_reached ) {
9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch ( resample_filter->virtual_pixel ) {
9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*  This is always handled by the above, so no need.
9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case BackgroundVirtualPixelMethod:
9933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case ConstantVirtualPixelMethod:
9943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case TransparentVirtualPixelMethod:
9953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case GrayVirtualPixelMethod,
9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case WhiteVirtualPixelMethod
9973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case MaskVirtualPixelMethod:
9983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case UndefinedVirtualPixelMethod:
10003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case EdgeVirtualPixelMethod:
10013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case DitherVirtualPixelMethod:
10023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileEdgeVirtualPixelMethod:
10033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileEdgeVirtualPixelMethod:
10049b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony        /* We need an average edge pixel, from the correct edge!
10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           How should I calculate an average edge color?
10063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           Just returning an averaged neighbourhood,
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           works well in general, but falls down for TileEdge methods.
10083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           This needs to be done properly!!!!!!
10093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=InterpolateResampleFilter(resample_filter,
10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          AverageInterpolatePixel,u0,v0,pixel);
10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
10133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileVirtualPixelMethod:
10143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileVirtualPixelMethod:
10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* just return the background pixel - Is there more direct way? */
10163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=InterpolateResampleFilter(resample_filter,
10173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           IntegerInterpolatePixel,(double)-1,(double)-1,pixel);
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case TileVirtualPixelMethod:
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case MirrorVirtualPixelMethod:
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case RandomVirtualPixelMethod:
10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case CheckerTileVirtualPixelMethod:
10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* generate a average color of the WHOLE image */
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if ( resample_filter->average_defined == MagickFalse ) {
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Image
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_image;
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          CacheView
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_view;
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1032065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy          GetMagickPixelPacket(resample_filter->image,(MagickPixelPacket *)
1033065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy            &resample_filter->average_pixel);
1034065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy          resample_filter->average_defined=MagickTrue;
10353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /* Try to get an averaged pixel color of whole image */
1037065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy          average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,1.0,
1038065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy            resample_filter->exception);
10393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (average_image == (Image *) NULL)
10403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
10413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              *pixel=resample_filter->average_pixel; /* FAILED */
10423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
10443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_view=AcquireCacheView(average_image);
10453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels=(PixelPacket *)GetCacheViewVirtualPixels(average_view,0,0,1,1,
10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            resample_filter->exception);
10473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (pixels == (const PixelPacket *) NULL) {
10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_view=DestroyCacheView(average_view);
10493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_image=DestroyImage(average_image);
10503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *pixel=resample_filter->average_pixel; /* FAILED */
10513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            break;
10523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
10533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          indexes=(IndexPacket *) GetCacheViewAuthenticIndexQueue(average_view);
10543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,pixels,indexes,
10553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            &(resample_filter->average_pixel));
10563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_view=DestroyCacheView(average_view);
10573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_image=DestroyImage(average_image);
1058490ab03a4e81aa0943087243055c77e3794d75d9anthony
1059490ab03a4e81aa0943087243055c77e3794d75d9anthony          if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod )
1060490ab03a4e81aa0943087243055c77e3794d75d9anthony            {
1061490ab03a4e81aa0943087243055c77e3794d75d9anthony              /* CheckerTile is avergae of image average half background */
1062490ab03a4e81aa0943087243055c77e3794d75d9anthony              /* FUTURE: replace with a 50% blend of both pixels */
1063490ab03a4e81aa0943087243055c77e3794d75d9anthony
1064490ab03a4e81aa0943087243055c77e3794d75d9anthony              weight = QuantumScale*((MagickRealType)(QuantumRange-
1065490ab03a4e81aa0943087243055c77e3794d75d9anthony                          resample_filter->average_pixel.opacity));
1066490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red *= weight;
1067490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green *= weight;
1068490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue *= weight;
1069490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c = weight;
1070490ab03a4e81aa0943087243055c77e3794d75d9anthony
1071490ab03a4e81aa0943087243055c77e3794d75d9anthony              weight = QuantumScale*((MagickRealType)(QuantumRange-
1072490ab03a4e81aa0943087243055c77e3794d75d9anthony                          resample_filter->image->background_color.opacity));
1073490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red +=
1074490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.red;
1075490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green +=
1076490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.green;
1077490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue +=
1078490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.blue;
1079bb66d9ce1d174e871ae1ac4ee9b300d1f0d5cdddcristy              resample_filter->average_pixel.opacity +=
1080490ab03a4e81aa0943087243055c77e3794d75d9anthony                      resample_filter->image->background_color.opacity;
1081490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c += weight;
1082490ab03a4e81aa0943087243055c77e3794d75d9anthony
1083490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red /= divisor_c;
1084490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green /= divisor_c;
1085490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue /= divisor_c;
1086bb66d9ce1d174e871ae1ac4ee9b300d1f0d5cdddcristy              resample_filter->average_pixel.opacity /= 2;
1087490ab03a4e81aa0943087243055c77e3794d75d9anthony
1088490ab03a4e81aa0943087243055c77e3794d75d9anthony            }
10893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
10903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *pixel=resample_filter->average_pixel;
10913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
10923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
10933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
10943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize weighted average data collection
10983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
10993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
11003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 0.0;
11013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 0.0;
11023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->red = pixel->green = pixel->blue = 0.0;
11033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->image->matte != MagickFalse) pixel->opacity = 0.0;
11043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->image->colorspace == CMYKColorspace) pixel->index = 0.0;
11053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Determine the parellelogram bounding box fitted to the ellipse
11083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    centered at u0,v0.  This area is bounding by the lines...
11093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1110490ab03a4e81aa0943087243055c77e3794d75d9anthony  v1 = (ssize_t)ceil(v0 - resample_filter->Vlimit);  /* range of scan lines */
1111490ab03a4e81aa0943087243055c77e3794d75d9anthony  v2 = (ssize_t)floor(v0 + resample_filter->Vlimit);
1112490ab03a4e81aa0943087243055c77e3794d75d9anthony
1113490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* scan line start and width accross the parallelogram */
1114490ab03a4e81aa0943087243055c77e3794d75d9anthony  u1 = u0 + (v1-v0)*resample_filter->slope - resample_filter->Uwidth;
1115490ab03a4e81aa0943087243055c77e3794d75d9anthony  uw = (ssize_t)(2.0*resample_filter->Uwidth)+1;
11163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1117490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1118490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "v1=%ld; v2=%ld\n", (long)v1, (long)v2);
1119490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "u1=%ld; uw=%ld\n", (long)u1, (long)uw);
1120490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
1121490ab03a4e81aa0943087243055c77e3794d75d9anthony# define DEBUG_HIT_MISS 0 /* only valid if DEBUG_ELLIPSE is enabled */
1122490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
11233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Do weighted resampling of all pixels,  within the scaled ellipse,
11263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    bound by a Parellelogram fitted to the ellipse.
11273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DDQ = 2*resample_filter->A;
1129490ab03a4e81aa0943087243055c77e3794d75d9anthony  for( v=v1; v<=v2;  v++ ) {
1130490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
1131490ab03a4e81aa0943087243055c77e3794d75d9anthony    long uu = ceil(u1);   /* actual pixel location (for debug only) */
1132490ab03a4e81aa0943087243055c77e3794d75d9anthony    fprintf(stderr, "# scan line from pixel %ld, %ld\n", (long)uu, (long)v);
1133490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
1134490ab03a4e81aa0943087243055c77e3794d75d9anthony    u = (ssize_t)ceil(u1);        /* first pixel in scanline */
1135490ab03a4e81aa0943087243055c77e3794d75d9anthony    u1 += resample_filter->slope; /* start of next scan line */
1136490ab03a4e81aa0943087243055c77e3794d75d9anthony
1137490ab03a4e81aa0943087243055c77e3794d75d9anthony
1138490ab03a4e81aa0943087243055c77e3794d75d9anthony    /* location of this first pixel, relative to u0,v0 */
1139490ab03a4e81aa0943087243055c77e3794d75d9anthony    U = (double)u-u0;
11403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    V = (double)v-v0;
11413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* Q = ellipse quotent ( if Q<F then pixel is inside ellipse) */
1143490ab03a4e81aa0943087243055c77e3794d75d9anthony    Q = (resample_filter->A*U + resample_filter->B*V)*U + resample_filter->C*V*V;
11443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    DQ = resample_filter->A*(2.0*U+1) + resample_filter->B*V;
11453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* get the scanline of pixels for this v */
1147bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    pixels=GetCacheViewVirtualPixels(resample_filter->view,u,v,(size_t) uw,
11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      1,resample_filter->exception);
11493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (pixels == (const PixelPacket *) NULL)
11503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
11513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
11523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* count up the weighted pixel colors */
11543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    for( u=0; u<uw; u++ ) {
11555b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* Note that the ellipse has been pre-scaled so F = WLUT_WIDTH */
11573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( Q < (double)WLUT_WIDTH ) {
11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        weight = resample_filter->filter_lut[(int)Q];
11595b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
11605b697cdb1ed6e391b98953aafd362bddad51b453anthony      /* Note that the ellipse has been pre-scaled so F = support^2 */
1161582b6d79fc381d6c9455f3f1b3e26923950161ebanthony      if ( Q < (double)resample_filter->F ) {
1162582b6d79fc381d6c9455f3f1b3e26923950161ebanthony        weight = GetResizeFilterWeight(resample_filter->filter_def,
1163582b6d79fc381d6c9455f3f1b3e26923950161ebanthony             sqrt(Q));    /* a SquareRoot!  Arrggghhhhh... */
11645b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->opacity  += weight*pixels->opacity;
11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_m += weight;
11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
11703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          weight *= QuantumScale*((MagickRealType)(QuantumRange-pixels->opacity));
11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->red   += weight*pixels->red;
11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->green += weight*pixels->green;
11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->blue  += weight*pixels->blue;
11743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->colorspace == CMYKColorspace)
11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->index += weight*(*indexes);
11763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_c += weight;
11773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
1179490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
1180490ab03a4e81aa0943087243055c77e3794d75d9anthony        /* mark the pixel according to hit/miss of the ellipse */
1181490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
1182490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
1183490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
1184490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
1185490ab03a4e81aa0943087243055c77e3794d75d9anthony      } else {
1186490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
1187490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
1188490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
1189490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
1190490ab03a4e81aa0943087243055c77e3794d75d9anthony      }
1191490ab03a4e81aa0943087243055c77e3794d75d9anthony      uu++;
1192490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
11933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
1194490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
11953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixels++;
11963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes++;
11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Q += DQ;
11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      DQ += DDQ;
11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
12003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1201490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1202490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "Hit=%ld;  Total=%ld;\n", (long)hit, (long)uw*(v2-v1) );
1203490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
12063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Result sanity check -- this should NOT happen
12073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1208490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( hit == 0 ) {
12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* not enough pixels in resampling, resort to direct interpolation */
1210490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_NO_PIXEL_HIT
12119b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony    pixel->opacity = pixel->red = pixel->green = pixel->blue = 0;
12129b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony    pixel->red = QuantumRange; /* show pixels for which EWA fails */
12139b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#else
12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,
12153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->interpolate,u0,v0,pixel);
12169b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#endif
12173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return status;
12183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Finialize results of resampling
12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
12233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 1.0/divisor_m;
1224ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->opacity = (MagickRealType) ClampToQuantum(divisor_m*pixel->opacity);
12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 1.0/divisor_c;
1226ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->red   = (MagickRealType) ClampToQuantum(divisor_c*pixel->red);
1227ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->green = (MagickRealType) ClampToQuantum(divisor_c*pixel->green);
1228ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->blue  = (MagickRealType) ClampToQuantum(divisor_c*pixel->blue);
12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->image->colorspace == CMYKColorspace)
1230ce70c17bb6433add2eb069515a4f3105989e0662cristy    pixel->index = (MagickRealType) ClampToQuantum(divisor_c*pixel->index);
12313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1234c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA && EWA_CLAMP
1235c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/*
1236c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1237c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1238c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1239c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1240c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony-   C l a m p U p A x e s                                                     %
1241c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1242c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1243c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1244c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1246c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ClampUpAxes() function converts the input vectors into a major and
124740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% minor axis unit vectors, and their magnitude.  This allows us to
124840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% ensure that the ellipse generated is never smaller than the unit
1249c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% circle and thus never too small for use in EWA resampling.
1250c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1251c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% This purely mathematical 'magic' was provided by Professor Nicolas
1252c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% Robidoux and his Masters student Chantal Racette.
1253c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
125440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: "We Recommend Singular Value Decomposition", David Austin
1255c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%   http://www.ams.org/samplings/feature-column/fcarc-svd
1256c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
125740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% By generating major and minor axis vectors, we can actually use the
1258c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ellipse in its "canonical form", by remapping the dx,dy of the
1259c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% sampled point into distances along the major and minor axis unit
1260c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% vectors.
126140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas%
126240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: http://en.wikipedia.org/wiki/Ellipse#Canonical_form
1263c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony*/
126415c331b918b9c7b71e876965897b66ff6118a269nicolasstatic inline void ClampUpAxes(const double dux,
126515c331b918b9c7b71e876965897b66ff6118a269nicolas			       const double dvx,
126615c331b918b9c7b71e876965897b66ff6118a269nicolas			       const double duy,
126715c331b918b9c7b71e876965897b66ff6118a269nicolas			       const double dvy,
126815c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *major_mag,
126915c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *minor_mag,
127015c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *major_unit_x,
127115c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *major_unit_y,
127215c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *minor_unit_x,
127315c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *minor_unit_y)
1274c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony{
1275c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1276c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes takes an input 2x2 matrix
1277c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1278c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ a b ] = [ dux duy ]
1279c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ c d ] = [ dvx dvy ]
1280c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1281c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * and computes from it the major and minor axis vectors [major_x,
1282c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_y] and [minor_x,minor_y] of the smallest ellipse containing
1283c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * both the unit disk and the ellipse which is the image of the unit
1284c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * disk by the linear transformation
1285c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1286c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dux duy ] [S] = [s]
1287c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dvx dvy ] [T] = [t]
1288c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1289c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * (The vector [S,T] is the difference between a position in output
1290c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * space and [X,Y]; the vector [s,t] is the difference between a
1291c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * position in input space and [x,y].)
1292c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1293c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1294c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Outputs:
1295c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1296c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_mag is the half-length of the major axis of the "new"
129740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ellipse.
1298c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1299c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_mag is the half-length of the minor axis of the "new"
130040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ellipse.
1301c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1302c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_x is the x-coordinate of the major axis direction vector
1303c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of both the "old" and "new" ellipses.
1304c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1305c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_y is the y-coordinate of the major axis direction vector.
1306c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1307c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_x is the x-coordinate of the minor axis direction vector.
1308c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1309c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_y is the y-coordinate of the minor axis direction vector.
1310c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1311c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Unit vectors are useful for computing projections, in particular,
1312c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * to compute the distance between a point in output space and the
1313c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * center (of a disk) from the position of the corresponding point
1314c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * in input space.
1315c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1316c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Now, if you want to modify the input pair of tangent vectors so
1317c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it defines the modified ellipse, all you have to do is set
1318c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
13198b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdux = major_mag * major_unit_x
13208b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvx = major_mag * major_unit_y
13218b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newduy = minor_mag * minor_unit_x = minor_mag * -major_unit_y
13228b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvy = minor_mag * minor_unit_y = minor_mag *  major_unit_x
1323c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1324932ef8479742364640c1aed64b795c528afab45cnicolas   * and use these tangent vectors as if they were the original ones.
132540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Usually, this is a drastic change in the tangent vectors even if
1326c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * the singular values are not clamped; for example, the minor axis
1327c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * vector always points in a direction which is 90 degrees
1328c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * counterclockwise from the direction of the major axis vector.
1329c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1330c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1331c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Discussion:
1332c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1333c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * GOAL: Fix things so that the pullback, in input space, of a disk
1334c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of radius r in output space is an ellipse which contains, at
1335c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * least, a disc of radius r. (Make this hold for any r>0.)
1336c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
133740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ESSENCE OF THE METHOD: Compute the product of the first two
133840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * factors of an SVD of the linear transformation defining the
1339f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * ellipse and make sure that both its columns have norm at least 1.
1340f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * Because rotations and reflexions map disks to themselves, it is
134140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * not necessary to compute the third (rightmost) factor of the SVD.
1342f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   *
1343f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * DETAILS: Find the singular values and (unit) left singular
1344f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * vectors of Jinv, clampling up the singular values to 1, and
1345932ef8479742364640c1aed64b795c528afab45cnicolas   * multiply the unit left singular vectors by the new singular
1346f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * values in order to get the minor and major ellipse axis vectors.
1347c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
134840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Image resampling context:
1349c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1350c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The Jacobian matrix of the transformation at the output point
1351c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * under consideration is defined as follows:
1352c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1353c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Consider the transformation (x,y) -> (X,Y) from input locations
13548b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * to output locations. (Anthony Thyssen, elsewhere in resample.c,
135540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * uses the notation (u,v) -> (x,y).)
1356c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
135740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * The Jacobian matrix of the transformation at (x,y) is equal to
1358c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
135940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   J = [ A, B ] = [ dX/dx, dX/dy ]
136040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *       [ C, D ]   [ dY/dx, dY/dy ]
1361c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
136240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * that is, the vector [A,C] is the tangent vector corresponding to
136340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * input changes in the horizontal direction, and the vector [B,D]
136440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * is the tangent vector corresponding to input changes in the
136540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * vertical direction.
1366c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
136740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * In the context of resampling, it is natural to use the inverse
136840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Jacobian matrix Jinv because resampling is generally performed by
136940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * pulling pixel locations in the output image back to locations in
137040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * the input image. Jinv is
1371c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
137240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   Jinb = [ a, b ] = [ dx/dX, dx/dY ]
137340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *          [ c, d ]   [ dy/dX, dy/dY ]
1374c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1375c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Note: Jinv can be computed from J with the following matrix
1376c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * formula:
1377c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1378c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = 1/(A*D-B*C) [  D, -B ]
1379c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *                      [ -C,  A ]
1380c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
138140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * What we do is modify Jinv so that it generates an ellipse which
138240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * is as close as possible to the original but which contains the
138340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * unit disk. This can be accomplished as follows:
1384c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1385c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Let
1386c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1387c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U Sigma V^T
1388c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1389932ef8479742364640c1aed64b795c528afab45cnicolas   * be an SVD decomposition of Jinv. (The SVD is not unique, but the
139040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * final ellipse does not depend on the particular SVD.)
139140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *
139240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * We could clamp up the entries of the diagonal matrix Sigma so
139340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * that they are at least 1, and then set
1394c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1395c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U newSigma V^T.
1396c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
139740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * However, we do not need to compute V for the following reason:
139840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * V^T is an orthogonal matrix (that is, it represents a combination
139940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * of rotations and reflexions) so that it maps the unit circle to
140040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * itself. For this reason, the exact value of V does not affect the
140140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * final ellipse, and we can choose V to be the identity
140240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * matrix. This gives
1403c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
140440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   Jinv = U newSigma.
1405c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
140640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * In the end, we return the two diagonal entries of newSigma
140740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * together with the two columns of U.
1408c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1409c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1410c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes was written by Nicolas Robidoux and Chantal Racette
1411c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * of Laurentian University with funding from the National Science
1412c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * and Engineering Research Council of Canada.
1413703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   *
1414b059768d3a0ca98ad6da9377b1658015ce0013a6nicolas   * The astrophysicist Craig DeForest pioneered the use of the SVD to
1415b059768d3a0ca98ad6da9377b1658015ce0013a6nicolas   * clamp up the singular values of the Jacobian matrix of the
141656238dc2b8ff1734a830ecefdfbf69065f3a5f6anicolas   * pullback transformation for EWA resampling. It is implemented in
141756238dc2b8ff1734a830ecefdfbf69065f3a5f6anicolas   * his PDL::Transform code (PDL = Perl Data Language).
1418c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1419c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double a = dux;
1420c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double b = duy;
1421c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double c = dvx;
1422c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double d = dvy;
1423c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1424c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * n is the matrix Jinv * transpose(Jinv). Eigenvalues of n are the
1425c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * squares of the singular values of Jinv.
1426c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1427c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double aa = a*a;
1428c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double bb = b*b;
1429c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double cc = c*c;
1430c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double dd = d*d;
1431c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1432c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Eigenvectors of n are left singular vectors of Jinv.
1433c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1434c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n11 = aa+bb;
1435c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n12 = a*c+b*d;
1436c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n21 = n12;
1437c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n22 = cc+dd;
1438c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double det = a*d-b*c;
1439c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double twice_det = det+det;
1440c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double frobenius_squared = n11+n22;
1441c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double discriminant =
1442c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    (frobenius_squared+twice_det)*(frobenius_squared-twice_det);
1443c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double sqrt_discriminant = sqrt(discriminant);
1444c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1445c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1 is the largest singular value of the inverse Jacobian
1446c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. In other words, its reciprocal is the smallest singular
1447c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * value of the Jacobian matrix itself.
1448c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * If s1 = 0, both singular values are 0, and any orthogonal pair of
1449c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * left and right factors produces a singular decomposition of Jinv.
1450c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
1451c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
14528b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * Initially, we only compute the squares of the singular values.
1453c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1454c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1 = 0.5*(frobenius_squared+sqrt_discriminant);
1455c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1456c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s2 the smallest singular value of the inverse Jacobian
1457c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. Its reciprocal is the largest singular value of the
1458c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Jacobian matrix itself.
1459c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1460c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s2s2 = 0.5*(frobenius_squared-sqrt_discriminant);
1461c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11 = s1s1-n11;
1462c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22 = s1s1-n22;
1463c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1464c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * u1, the first column of the U factor of a singular decomposition
1465c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of Jinv, is a (non-normalized) left singular vector corresponding
1466c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * to s1. It has entries u11 and u21. We compute u1 from the fact
1467c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it is an eigenvector of n corresponding to the eigenvalue
1468c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * s1^2.
1469c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1470c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11_squared = s1s1minusn11*s1s1minusn11;
1471c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22_squared = s1s1minusn22*s1s1minusn22;
1472c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1473c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The following selects the largest row of n-s1^2 I as the one
1474c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * which is used to find the eigenvector. If both s1^2-n11 and
1475c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1^2-n22 are zero, n-s1^2 I is the zero matrix.  In that case,
1476c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * any vector is an eigenvector; in addition, norm below is equal to
1477c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * zero, and, in exact arithmetic, this is the only case in which
1478c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * norm = 0. So, setting u1 to the simple but arbitrary vector [1,0]
1479c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * if norm = 0 safely takes care of all cases.
1480c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1481c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u11 =
1482c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? n12 : s1s1minusn22 );
1483c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u21 =
1484c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? s1s1minusn11 : n21 );
1485c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double norm = sqrt(temp_u11*temp_u11+temp_u21*temp_u21);
1486c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1487c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Finalize the entries of first left singular vector (associated
1488c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * with the largest singular value).
1489c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1490c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u11 = ( (norm>0.0) ? temp_u11/norm : 1.0 );
1491c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u21 = ( (norm>0.0) ? temp_u21/norm : 0.0 );
1492c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1493c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Clamp the singular values up to 1.
1494c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1495ed22721389b8ff2983982914d29db84731825a8fnicolas  *major_mag = ( (s1s1<=1.0) ? 1.0 : sqrt(s1s1) );
1496ed22721389b8ff2983982914d29db84731825a8fnicolas  *minor_mag = ( (s2s2<=1.0) ? 1.0 : sqrt(s2s2) );
1497c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
1498c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Return the unit major and minor axis direction vectors.
1499c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
1500c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_x = u11;
1501c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_y = u21;
1502c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_x = -u21;
1503c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_y = u11;
1504c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony}
1505c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1506c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
15073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
15083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S c a l e R e s a m p l e F i l t e r                                     %
15133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ScaleResampleFilter() does all the calculations needed to resample an image
15193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  at a specific scale, defined by two scaling vectors.  This not using
15203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  a orthogonal scaling, but two distorted scaling vectors, to allow the
15213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  generation of a angled ellipse.
15223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As only two deritive scaling vectors are used the center of the ellipse
15243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  must be the center of the lookup.  That is any curvature that the
15253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion may produce is discounted.
15263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The input vectors are produced by either finding the derivitives of the
15283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion function, or the partial derivitives from a distortion mapping.
15293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  They do not need to be the orthogonal dx,dy scaling vectors, but can be
15303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated from other derivatives.  For example you could use  dr,da/r
15313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  polar coordinate vector scaling vectors
15323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1533c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If   u,v =  DistortEquation(x,y)   OR   u = Fu(x,y); v = Fv(x,y)
1534c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Then the scaling vectors are determined from the deritives...
15353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      du/dx, dv/dx     and    du/dy, dv/dy
1536c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If the resulting scaling vectors is othogonally aligned then...
15373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      dv/dx = 0   and   du/dy  =  0
1538c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Producing an othogonally alligned ellipse in source space for the area to
1539c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  be resampled.
15403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Note that scaling vectors are different to argument order.  Argument order
15423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  is the general order the deritives are extracted from the distortion
1543c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  equations, and not the scaling vectors. As such the middle two vaules
1544c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  may be swapped from what you expect.  Caution is advised.
15453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15463ebea1e232532895681cd50101ddad0856e9a1d3anthony%  WARNING: It is assumed that any SetResampleFilter() method call will
15473ebea1e232532895681cd50101ddad0856e9a1d3anthony%  always be performed before the ScaleResampleFilter() method, so that the
15483ebea1e232532895681cd50101ddad0856e9a1d3anthony%  size of the ellipse will match the support for the resampling filter being
15493ebea1e232532895681cd50101ddad0856e9a1d3anthony%  used.
1550490ab03a4e81aa0943087243055c77e3794d75d9anthony%
15513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ScaleResampleFilter method is:
15523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     void ScaleResampleFilter(const ResampleFilter *resample_filter,
15543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       const double dux,const double duy,const double dvx,const double dvy)
15553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
15573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resampling resample_filterrmation defining the
15593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      image being resampled
15603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o dux,duy,dvx,dvy:
1562c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The deritives or scaling vectors defining the EWA ellipse.
1563c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         NOTE: watch the order, which is based on the order deritives
1564c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         are usally determined from distortion equations (see above).
1565c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The middle two values may need to be swapped if you are thinking
1566c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         in terms of scaling vectors.
15673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
15693ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
15703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double dux,const double duy,const double dvx,const double dvy)
15713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1572d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  double A,B,C,F;
15733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
15753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
15763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->limit_reached = MagickFalse;
15783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1579b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  /* A 'point' filter forces use of interpolation instead of area sampling */
1580b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  if ( resample_filter->filter == PointFilter )
1581b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    return; /* EWA turned off - nothing to do */
1582b821aafe132291d46e0fb0c2b24e6e467aa17640anthony
1583c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
1584c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "# -----\n" );
1585c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "dux=%lf; dvx=%lf;   duy=%lf; dvy=%lf;\n",
1586c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony       dux, dvx, duy, dvy);
1587c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
15883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Find Ellipse Coefficents such that
15903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        A*u^2 + B*u*v + C*v^2 = F
15913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     With u,v relative to point around which we are resampling.
15923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     And the given scaling dx,dy vectors in u,v space
15933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy         du/dx,dv/dx   and  du/dy,dv/dy
15943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1595c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1596d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /* Direct conversion of derivatives into elliptical coefficients
1597b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     However when magnifying images, the scaling vectors will be small
1598b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     resulting in a ellipse that is too small to sample properly.
1599b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     As such we need to clamp the major/minor axis to a minumum of 1.0
1600b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     to prevent it getting too small.
16013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1602c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA_CLAMP
1603c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  { double major_mag,
1604c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_mag,
1605c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_x,
1606c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_y,
1607c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_x,
1608c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_y;
1609c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1610c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  ClampUpAxes(dux,dvx,duy,dvy, &major_mag, &minor_mag,
1611c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                &major_x, &major_y, &minor_x, &minor_y);
1612bdfddb0056c20dba73d299334525256fa6a99986anthony  major_x *= major_mag;  major_y *= major_mag;
1613bdfddb0056c20dba73d299334525256fa6a99986anthony  minor_x *= minor_mag;  minor_y *= minor_mag;
1614c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
1615c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "major_x=%lf; major_y=%lf;  minor_x=%lf; minor_y=%lf;\n",
1616c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony        major_x, major_y, minor_x, minor_y);
1617c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
1618c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  A = major_y*major_y+minor_y*minor_y;
1619c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  B = -2.0*(major_x*major_y+minor_x*minor_y);
1620c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  C = major_x*major_x+minor_x*minor_x;
1621eaa08628db6764fa5cb6802eaf9bb5753c25eb1fnicolas  F = major_mag*minor_mag;
1622c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F *= F; /* square it */
1623c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  }
16245b697cdb1ed6e391b98953aafd362bddad51b453anthony#else /* raw unclamped EWA */
16253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy;
1626d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
16273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy;
1628c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F = dux*dvy-duy*dvx;
16295708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  F *= F; /* square it */
16305b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* EWA_CLAMP */
1631d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1632490ab03a4e81aa0943087243055c77e3794d75d9anthony#else /* HQ_EWA */
1633d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
1634c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    This Paul Heckbert's "Higher Quality EWA" formula, from page 60 in his
1635c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    thesis, which adds a unit circle to the elliptical area so as to do both
1636c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    Reconstruction and Prefiltering of the pixels in the resampling.  It also
1637c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    means it is always likely to have at least 4 pixels within the area of the
1638c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ellipse, for weighted averaging.  No scaling will result with F == 4.0 and
1639c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    a circle of radius 2.0, and F smaller than this means magnification is
1640c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    being used.
1641c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1642c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    NOTE: This method produces a very blury result at near unity scale while
1643bdfddb0056c20dba73d299334525256fa6a99986anthony    producing perfect results for strong minitification and magnifications.
1644490ab03a4e81aa0943087243055c77e3794d75d9anthony
1645c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    However filter support is fixed to 2.0 (no good for Windowed Sinc filters)
16463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
16473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy+1;
1648d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
16493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy+1;
16503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  F = A*C - B*B/4;
16513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
16523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1653490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
16543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fprintf(stderr, "A=%lf; B=%lf; C=%lf; F=%lf\n", A,B,C,F);
16553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1656c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /* Figure out the various information directly about the ellipse.
16573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     This information currently not needed at this time, but may be
16583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     needed later for better limit determination.
1659d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1660d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony     It is also good to have as a record for future debugging
16613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
16623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { double alpha, beta, gamma, Major, Minor;
1663490ab03a4e81aa0943087243055c77e3794d75d9anthony    double Eccentricity, Ellipse_Area, Ellipse_Angle;
1664d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
16653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha = A+C;
16663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    beta  = A-C;
16673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    gamma = sqrt(beta*beta + B*B );
16683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if ( alpha - gamma <= MagickEpsilon )
16703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Major = MagickHuge;
16713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
16723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Major = sqrt(2*F/(alpha - gamma));
16733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Minor = sqrt(2*F/(alpha + gamma));
16743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1675490ab03a4e81aa0943087243055c77e3794d75d9anthony    fprintf(stderr, "# Major=%lf; Minor=%lf\n", Major, Minor );
16763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* other information about ellipse include... */
16783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Eccentricity = Major/Minor;
16793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Ellipse_Area = MagickPI*Major*Minor;
1680e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas    Ellipse_Angle = atan2(B, A-C);
16813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1682c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    fprintf(stderr, "# Angle=%lf   Area=%lf\n",
1683e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas         RadiansToDegrees(Ellipse_Angle), Ellipse_Area);
16843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
16853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
16863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
168715c331b918b9c7b71e876965897b66ff6118a269nicolas  /* If one or both of the scaling vectors is impossibly large
168815c331b918b9c7b71e876965897b66ff6118a269nicolas     (producing a very large raw F value), we may as well not bother
168915c331b918b9c7b71e876965897b66ff6118a269nicolas     doing any form of resampling since resampled area is very large.
169015c331b918b9c7b71e876965897b66ff6118a269nicolas     In this case some alternative means of pixel sampling, such as
169115c331b918b9c7b71e876965897b66ff6118a269nicolas     the average of the whole image is needed to get a reasonable
169215c331b918b9c7b71e876965897b66ff6118a269nicolas     result. Calculate only as needed.
16933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1694490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( (4*A*C - B*B) > MagickHuge ) {
16953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
16963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
16973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
16983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1699582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  /* Scale ellipse to match the filters support
1700582b6d79fc381d6c9455f3f1b3e26923950161ebanthony     (that is, multiply F by the square of the support).
1701e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  */
1702490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
1703490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
17043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1705e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Orthogonal bounds of the ellipse */
1706490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->Ulimit = sqrt(4*C*F/(4*A*C-B*B));
1707490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->Vlimit = sqrt(4*A*F/(4*A*C-B*B));
17083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1709e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Horizontally aligned parallelogram fitted to Ellipse */
1710e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  resample_filter->Uwidth = sqrt(F/A); /* Half of the parallelogram width */
1711e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  resample_filter->slope = -B/(2*A); /* Reciprocal slope of the parallelogram */
1712490ab03a4e81aa0943087243055c77e3794d75d9anthony
1713490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1714490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "Ulimit=%lf; Vlimit=%lf; UWidth=%lf; Slope=%lf;\n",
1715490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Ulimit, resample_filter->Vlimit,
1716490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Uwidth, resample_filter->slope );
1717490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
17183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1719e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Check the absolute area of the parallelogram involved.
1720e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas   * This limit needs more work, as it is too slow for larger images
1721e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas   * with tiled views of the horizon.
1722e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  */
172339f347aa142535ededfff86309cc2bb4cf222373cristy  if ( (resample_filter->Uwidth * resample_filter->Vlimit)
172439f347aa142535ededfff86309cc2bb4cf222373cristy         > (4.0*resample_filter->image_area)) {
17253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
17263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
17273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
17283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17295708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  /* Scale ellipse formula to directly index the Filter Lookup Table */
17303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { register double scale;
17315b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
1732582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* scale so that F = WLUT_WIDTH; -- hardcoded */
1733490ab03a4e81aa0943087243055c77e3794d75d9anthony    scale = (double)WLUT_WIDTH/F;
17345b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1735582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* scale so that F = resample_filter->F (support^2) */
1736582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    scale = resample_filter->F/F;
17375b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
17383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->A = A*scale;
17393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->B = B*scale;
17403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->C = C*scale;
17413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
17423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
17433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
17453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r                                         %
17503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilter() set the resampling filter lookup table based on a
17563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  specific filter.  Note that the filter is used as a radial filter not as a
17573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  two pass othogonally aligned resampling filter.
17583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The default Filter, is Gaussian, which is the standard filter used by the
17603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  original paper on the Elliptical Weighted Everage Algorithm. However other
17613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  filters can also be used.
17623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilter method is:
17643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    void SetResampleFilter(ResampleFilter *resample_filter,
17663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      const FilterTypes filter,const double blur)
17673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
17693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling resample_filterrmation structure
17713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o filter: the resize filter for elliptical weighting LUT
17733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o blur: filter blur factor (radial scaling) for elliptical weighting LUT
17753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
17773ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void SetResampleFilter(ResampleFilter *resample_filter,
17783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const FilterTypes filter,const double blur)
17793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
17803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResizeFilter
17813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     *resize_filter;
17823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
17843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
17853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17862e6ab68e6538e73abd8d77f505bc9f033c742f1canthony  resample_filter->do_interpolate = MagickFalse;
17873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->filter = filter;
17883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1789490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( filter == PointFilter )
1790b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    {
1791b821aafe132291d46e0fb0c2b24e6e467aa17640anthony      resample_filter->do_interpolate = MagickTrue;
1792b821aafe132291d46e0fb0c2b24e6e467aa17640anthony      return;  /* EWA turned off - nothing more to do */
1793b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    }
17943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
179561b5ddd7008c09f611076719e86f6f65ef5a9a4danthony  /* Set a default cylindrical filter of a 'low blur' Jinc windowed Jinc */
1796490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( filter == UndefinedFilter )
1797853d6979aa2981592af7020163b5030aa7185783anthony    resample_filter->filter = RobidouxFilter;
1798490ab03a4e81aa0943087243055c77e3794d75d9anthony
1799490ab03a4e81aa0943087243055c77e3794d75d9anthony  resize_filter = AcquireResizeFilter(resample_filter->image,
1800490ab03a4e81aa0943087243055c77e3794d75d9anthony       resample_filter->filter,blur,MagickTrue,resample_filter->exception);
1801bdfddb0056c20dba73d299334525256fa6a99986anthony  if (resize_filter == (ResizeFilter *) NULL)
1802490ab03a4e81aa0943087243055c77e3794d75d9anthony    {
18033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
18043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           ModuleError, "UnableToSetFilteringValue",
18053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           "Fall back to default EWA gaussian filter");
1806490ab03a4e81aa0943087243055c77e3794d75d9anthony      resample_filter->filter = PointFilter;
18073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1808490ab03a4e81aa0943087243055c77e3794d75d9anthony
180910b8bc801774c852503dfc90a706dfa942f9cc2eanthony  /* Get the practical working support for the filter,
181010b8bc801774c852503dfc90a706dfa942f9cc2eanthony   * after any API call blur factors have been accoded for.
181110b8bc801774c852503dfc90a706dfa942f9cc2eanthony   */
1812c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1813490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->support = GetResizeFilterSupport(resize_filter);
1814c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#else
1815c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  resample_filter->support = 2.0;  /* fixed support size for HQ-EWA */
1816490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
1817490ab03a4e81aa0943087243055c77e3794d75d9anthony
18185b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
18195b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* Fill the LUT with the weights from the selected filter function */
18205b697cdb1ed6e391b98953aafd362bddad51b453anthony  { register int
18215b697cdb1ed6e391b98953aafd362bddad51b453anthony       Q;
18225b697cdb1ed6e391b98953aafd362bddad51b453anthony    double
18235b697cdb1ed6e391b98953aafd362bddad51b453anthony       r_scale;
18245b697cdb1ed6e391b98953aafd362bddad51b453anthony    /* Scale radius so the filter LUT covers the full support range */
18255b697cdb1ed6e391b98953aafd362bddad51b453anthony    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
18265b697cdb1ed6e391b98953aafd362bddad51b453anthony    for(Q=0; Q<WLUT_WIDTH; Q++)
18275b697cdb1ed6e391b98953aafd362bddad51b453anthony      resample_filter->filter_lut[Q] = (double)
18285b697cdb1ed6e391b98953aafd362bddad51b453anthony           GetResizeFilterWeight(resize_filter,sqrt((double)Q)*r_scale);
18295b697cdb1ed6e391b98953aafd362bddad51b453anthony
18305b697cdb1ed6e391b98953aafd362bddad51b453anthony    /* finished with the resize filter */
18315b697cdb1ed6e391b98953aafd362bddad51b453anthony    resize_filter = DestroyResizeFilter(resize_filter);
18325b697cdb1ed6e391b98953aafd362bddad51b453anthony  }
18335b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1834582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  /* save the filter and the scaled ellipse bounds needed for filter */
18355b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->filter_def = resize_filter;
1836582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  resample_filter->F = resample_filter->support*resample_filter->support;
18375b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
1838490ab03a4e81aa0943087243055c77e3794d75d9anthony
18393ebea1e232532895681cd50101ddad0856e9a1d3anthony  /*
18403ebea1e232532895681cd50101ddad0856e9a1d3anthony    Adjust the scaling of the default unit circle
18413ebea1e232532895681cd50101ddad0856e9a1d3anthony    This assumes that any real scaling changes will always
18423ebea1e232532895681cd50101ddad0856e9a1d3anthony    take place AFTER the filter method has been initialized.
18433ebea1e232532895681cd50101ddad0856e9a1d3anthony  */
18443ebea1e232532895681cd50101ddad0856e9a1d3anthony  ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
18453ebea1e232532895681cd50101ddad0856e9a1d3anthony
18465708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#if 0
18475b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* This is old code kept as a reference only.  It is very wrong,
18485b697cdb1ed6e391b98953aafd362bddad51b453anthony     and I don't understand exactly what it was attempting to do.
18495b697cdb1ed6e391b98953aafd362bddad51b453anthony  */
1850d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
1851d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Create Normal Gaussian 2D Filter Weighted Lookup Table.
1852d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    A normal EWA guassual lookup would use   exp(Q*ALPHA)
1853d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    where  Q = distance squared from 0.0 (center) to 1.0 (edge)
1854d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    and    ALPHA = -4.0*ln(2.0)  ==>  -2.77258872223978123767
18555b697cdb1ed6e391b98953aafd362bddad51b453anthony    The table is of length 1024, and equates to support radius of 2.0
1856d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    thus needs to be scaled by  ALPHA*4/1024 and any blur factor squared
1857d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1858c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    The above came from some reference code provided by Fred Weinhaus
1859c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    and seems to have been a guess that was appropriate for its use
1860c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    in a 3d perspective landscape mapping program.
1861d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  */
1862d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur);
1863d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  for(Q=0; Q<WLUT_WIDTH; Q++)
1864d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    resample_filter->filter_lut[Q] = exp((double)Q*r_scale);
1865d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  resample_filter->support = WLUT_WIDTH;
1866d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  break;
18675708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#endif
1868490ab03a4e81aa0943087243055c77e3794d75d9anthony
18695b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
1870e06e4c180324bebbd41bce9ea4898642f380b614anthony#if defined(MAGICKCORE_OPENMP_SUPPORT)
187172949796e01f8b94a0976e74cb8eb3f86af280eaanthony  #pragma omp single
1872e06e4c180324bebbd41bce9ea4898642f380b614anthony#endif
1873582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  { register int
1874582b6d79fc381d6c9455f3f1b3e26923950161ebanthony       Q;
1875582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    double
1876582b6d79fc381d6c9455f3f1b3e26923950161ebanthony       r_scale;
187728ad1d779b6ca95852e860514185a7a97e06af77anthony
1878582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* Scale radius so the filter LUT covers the full support range */
1879582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
188028ad1d779b6ca95852e860514185a7a97e06af77anthony    if (IsMagickTrue(GetImageArtifact(resample_filter->image,"resample:verbose")) )
1881e06e4c180324bebbd41bce9ea4898642f380b614anthony      {
1882e06e4c180324bebbd41bce9ea4898642f380b614anthony        /* Debug output of the filter weighting LUT
1883e06e4c180324bebbd41bce9ea4898642f380b614anthony          Gnuplot the LUT with hoizontal adjusted to 'r' using...
1884e06e4c180324bebbd41bce9ea4898642f380b614anthony            plot [0:2][-.2:1] "lut.dat" using (sqrt($0/1024)*2):1 with lines
1885e06e4c180324bebbd41bce9ea4898642f380b614anthony          The filter values is normalized for comparision
1886e06e4c180324bebbd41bce9ea4898642f380b614anthony        */
1887d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("#\n");
1888e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("# Resampling Filter LUT (%d values)\n", WLUT_WIDTH);
1889e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("#\n");
1890d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("# Note: values in table are using a squared radius lookup.\n");
1891d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("# And the whole table represents the filters support.\n");
189261b5ddd7008c09f611076719e86f6f65ef5a9a4danthony        printf("\n"); /* generates a 'break' in gnuplot if multiple outputs */
1893e06e4c180324bebbd41bce9ea4898642f380b614anthony        for(Q=0; Q<WLUT_WIDTH; Q++)
1894d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony          printf("%8.*g %.*g\n",
1895d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony               GetMagickPrecision(),sqrt((double)Q)*r_scale,
1896d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony               GetMagickPrecision(),resample_filter->filter_lut[Q] );
1897e06e4c180324bebbd41bce9ea4898642f380b614anthony      }
189872949796e01f8b94a0976e74cb8eb3f86af280eaanthony    /* output the above once only for each image, and each setting */
189972949796e01f8b94a0976e74cb8eb3f86af280eaanthony    (void) DeleteImageArtifact(resample_filter->image,"resample:verbose");
190072949796e01f8b94a0976e74cb8eb3f86af280eaanthony  }
19015b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* FILTER_LUT */
19023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return;
19033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
19043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
19063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   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       %
19113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilterInterpolateMethod() changes the interpolation method
19173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  associated with the specified resample filter.
19183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterInterpolateMethod method is:
19203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterInterpolateMethod(
19223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const InterpolateMethod method)
19233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
19253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
19273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the interpolation method.
19293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
19313ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterInterpolateMethod(
19323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const InterpolatePixelMethod method)
19333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
19343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
19353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
19363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
1937d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
19383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
19393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
19403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
1941d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
19423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->interpolate=method;
1943d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
19443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
19453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
19463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
19483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   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     %
19533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilterVirtualPixelMethod() changes the virtual pixel method
19593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  associated with the specified resample filter.
19603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterVirtualPixelMethod method is:
19623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterVirtualPixelMethod(
19643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const VirtualPixelMethod method)
19653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
19673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
19693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the virtual pixel method.
19713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
19733ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterVirtualPixelMethod(
19743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const VirtualPixelMethod method)
19753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
19763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
19773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
19783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
19793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
19803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
19813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
19823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->virtual_pixel=method;
19832d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy  if (method != UndefinedVirtualPixelMethod)
19842d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy    (void) SetCacheViewVirtualPixelMethod(resample_filter->view,method);
19853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
19863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1987