resample.c revision 8b1d981efa1bdef504b79420d43936c49eeecd3d
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"
633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
64490ab03a4e81aa0943087243055c77e3794d75d9anthony  EWA Resampling Options
65490ab03a4e81aa0943087243055c77e3794d75d9anthony*/
66490ab03a4e81aa0943087243055c77e3794d75d9anthony#define WLUT_WIDTH 1024       /* size of the filter cache */
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
73c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* output debugging information */
74490ab03a4e81aa0943087243055c77e3794d75d9anthony#define DEBUG_ELLIPSE 0       /* output ellipse info for debug */
752e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_HIT_MISS 0      /* output hit/miss pixels (as gnuplot commands) */
762e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_NO_PIXEL_HIT 0  /* Make pixels that fail to hit anything - RED */
77490ab03a4e81aa0943087243055c77e3794d75d9anthony
78490ab03a4e81aa0943087243055c77e3794d75d9anthony/*
793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Typedef declarations.
803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
813ed852eea50f9d4cd633efb8c2b054b8e33c253cristystruct _ResampleFilter
823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *view;
853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
86c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  Image
87c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image;
88c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *exception;
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    debug;
943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Information about image being resampled */
96bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image_area;
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  InterpolatePixelMethod
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    interpolate;
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  VirtualPixelMethod
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    virtual_pixel;
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FilterTypes
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    filter;
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* processing settings needed */
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
1103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    limit_reached,
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    do_interpolate,
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_defined;
1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket
1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_pixel;
1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* current ellipitical area being resampled around center point */
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    A, B, C,
120d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Vlimit, Ulimit, Uwidth, slope;
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* LUT of weights for filtered average in elliptical area */
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    filter_lut[WLUT_WIDTH],
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    support;
1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
127bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    signature;
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy};
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   A c q u i r e R e s a m p l e I n f o                                     %
1373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  AcquireResampleFilter() initializes the information resample needs do to a
1433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  scaled lookup of a color from an image, using area sampling.
1443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The algorithm is based on a Elliptical Weighted Average, where the pixels
1463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  found in a large elliptical area is averaged together according to a
1473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  weighting (filter) function.  For more details see "Fundamentals of Texture
1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Mapping and Image Warping" a master's thesis by Paul.S.Heckbert, June 17,
1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  1989.  Available for free from, http://www.cs.cmu.edu/~ph/
1503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As EWA resampling (or any sort of resampling) can require a lot of
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculations to produce a distorted scaling of the source image for each
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  output pixel, the ResampleFilter structure generated holds that information
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  between individual image resampling.
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This function will make the appropriate AcquireCacheView() calls
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  to view the image, calling functions do not need to open a cache view.
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Usage Example...
1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      resample_filter=AcquireResampleFilter(image,exception);
161c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%      SetResampleFilter(resample_filter, GaussianFilter, 1.0);
162bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      for (y=0; y < (ssize_t) image->rows; y++) {
163bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%        for (x=0; x < (ssize_t) image->columns; x++) {
164c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          u= ....;   v= ....;
1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ScaleResampleFilter(resample_filter, ... scaling vectors ...);
166c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          (void) ResamplePixelColor(resample_filter,u,v,&pixel);
1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ... assign resampled pixel value ...
1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        }
1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      }
1703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      DestroyResampleFilter(resample_filter);
1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the AcquireResampleFilter method is:
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     ResampleFilter *AcquireResampleFilter(const Image *image,
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       ExceptionInfo *exception)
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
1823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1843ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *AcquireResampleFilter(const Image *image,
1853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo *exception)
1863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register ResampleFilter
1883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *resample_filter;
1893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image->signature == MagickSignature);
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception != (ExceptionInfo *) NULL);
1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception->signature == MagickSignature);
1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter=(ResampleFilter *) AcquireMagickMemory(
1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sizeof(*resample_filter));
1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter == (ResampleFilter *) NULL)
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(resample_filter,0,sizeof(*resample_filter));
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=ReferenceImage((Image *) image);
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->view=AcquireCacheView(resample_filter->image);
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->exception=exception;
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->debug=IsEventLogging();
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->signature=MagickSignature;
2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
210eaedf06777741da32408da72c1e512975c600c48cristy  resample_filter->image_area=(ssize_t) (resample_filter->image->columns*
211eaedf06777741da32408da72c1e512975c600c48cristy    resample_filter->image->rows);
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->average_defined = MagickFalse;
2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* initialise the resampling filter settings */
2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  SetResampleFilter(resample_filter, resample_filter->image->filter,
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->image->blur);
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->interpolate = resample_filter->image->interpolate;
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->virtual_pixel=GetImageVirtualPixelMethod(image);
2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   D e s t r o y R e s a m p l e I n f o                                     %
2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DestroyResampleFilter() finalizes and cleans up the resampling
2353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  resample_filter as returned by AcquireResampleFilter(), freeing any memory
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  or other information as needed.
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DestroyResampleFilter method is:
2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      ResampleFilter *DestroyResampleFilter(ResampleFilter *resample_filter)
2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling information structure
2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *DestroyResampleFilter(
2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter)
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
2513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->view=DestroyCacheView(resample_filter->view);
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=DestroyImage(resample_filter->image);
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->signature=(~MagickSignature);
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter=(ResampleFilter *) RelinquishMagickMemory(resample_filter);
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   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                         %
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  InterpolateResampleFilter() applies bi-linear or tri-linear interpolation
2753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  between a floating point coordinate and the pixels surrounding that
2763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  coordinate.  No pixel area resampling, or scaling of the result is
2773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  performed.
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the InterpolateResampleFilter method is:
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType InterpolateResampleFilter(
2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleInfo *resample_filter,const InterpolatePixelMethod method,
2833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        const double x,const double y,MagickPixelPacket *pixel)
2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the pixel clor interpolation method.
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o x,y: A double representing the current (x,y) position of the pixel.
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o pixel: return the interpolated pixel here.
2943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline double MagickMax(const double x,const double y)
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (x > y)
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(x);
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(y);
3023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void BicubicInterpolate(const MagickPixelPacket *pixels,const double dx,
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket *pixel)
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickRealType
3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    dx2,
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p,
3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q,
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    r,
3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    s;
3133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  dx2=dx*dx;
3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].red-pixels[2].red)-(pixels[0].red-pixels[1].red);
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].red-pixels[1].red)-p;
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].red-pixels[0].red;
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].red;
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->red=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].green-pixels[2].green)-(pixels[0].green-pixels[1].green);
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].green-pixels[1].green)-p;
3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].green-pixels[0].green;
3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].green;
3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->green=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].blue-pixels[2].blue)-(pixels[0].blue-pixels[1].blue);
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].blue-pixels[1].blue)-p;
3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].blue-pixels[0].blue;
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].blue;
3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->blue=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].opacity-pixels[2].opacity)-(pixels[0].opacity-pixels[1].opacity);
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].opacity-pixels[1].opacity)-p;
3323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].opacity-pixels[0].opacity;
3333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].opacity;
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->opacity=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (pixel->colorspace == CMYKColorspace)
3363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=(pixels[3].index-pixels[2].index)-(pixels[0].index-pixels[1].index);
3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      q=(pixels[0].index-pixels[1].index)-p;
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      r=pixels[2].index-pixels[0].index;
3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      s=pixels[1].index;
3413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->index=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline MagickRealType CubicWeightingFunction(const MagickRealType x)
3463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickRealType
3483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha,
3493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    gamma;
3503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+2.0,0.0);
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma=1.0*alpha*alpha*alpha;
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+1.0,0.0);
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma-=4.0*alpha*alpha*alpha;
3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+0.0,0.0);
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma+=6.0*alpha*alpha*alpha;
3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x-1.0,0.0);
3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma-=4.0*alpha*alpha*alpha;
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(gamma/6.0);
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline double MeshInterpolate(const PointInfo *delta,const double p,
3633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double x,const double y)
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(delta->x*x+delta->y*y+(1.0-delta->x-delta->y)*p);
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
368bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic inline ssize_t NearestNeighbor(MagickRealType x)
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (x >= 0.0)
371bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    return((ssize_t) (x+0.5));
372bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  return((ssize_t) (x-0.5));
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType InterpolateResampleFilter(
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const InterpolatePixelMethod method,
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double x,const double y,MagickPixelPacket *pixel)
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const IndexPacket
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *indexes;
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const PixelPacket
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
388bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
3942e6ab68e6538e73abd8d77f505bc9f033c742f1canthony
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch (method)
3963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case AverageInterpolatePixel:
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16];
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16],
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
40654ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
40754ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 16L; i++)
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
42146f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (resample_filter->image->colorspace == CMYKColorspace)
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma=alpha[i];
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->red+=gamma*0.0625*pixels[i].red;
4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->green+=gamma*0.0625*pixels[i].green;
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->blue+=gamma*0.0625*pixels[i].blue;
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->opacity+=0.0625*pixels[i].opacity;
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->colorspace == CMYKColorspace)
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->index+=gamma*0.0625*pixels[i].index;
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BicubicInterpolatePixel:
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16],
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        u[4];
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16];
4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta;
4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
45254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
45354ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
4563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
4573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 16L; i++)
4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
46746f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (resample_filter->image->colorspace == CMYKColorspace)
4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
4733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
4783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        BicubicInterpolate(pixels+4*i,delta.x,u+i);
4793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      BicubicInterpolate(u,delta.y,pixel);
4813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BilinearInterpolatePixel:
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    default:
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[4];
4883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[4],
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
4943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta,
4953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        epsilon;
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
49754ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
49854ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),2,2,resample_filter->exception);
4993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
5023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
5053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
5063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].red=(MagickRealType) p[i].red;
5083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].green=(MagickRealType) p[i].green;
5093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].blue=(MagickRealType) p[i].blue;
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].opacity=(MagickRealType) p[i].opacity;
5113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
5123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (resample_filter->image->matte != MagickFalse)
5143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (i=0; i < 4L; i++)
5153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p[i].opacity);
5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].red*=alpha[i];
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].green*=alpha[i];
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].blue*=alpha[i];
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (indexes != (IndexPacket *) NULL)
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (i=0; i < 4L; i++)
5233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].index=(MagickRealType) indexes[i];
5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->colorspace == CMYKColorspace)
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].index*=alpha[i];
5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
5293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
5303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      epsilon.x=1.0-delta.x;
5313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      epsilon.y=1.0-delta.y;
5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (epsilon.x*alpha[2]+delta.x*alpha[3])));
5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
5373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].green));
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].blue));
5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->opacity=(epsilon.y*(epsilon.x*pixels[0].opacity+delta.x*
5443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].opacity)+delta.y*(epsilon.x*pixels[2].opacity+delta.x*
5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].opacity));
5463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (resample_filter->image->colorspace == CMYKColorspace)
5473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->index=gamma*(epsilon.y*(epsilon.x*pixels[0].index+delta.x*
5483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[1].index)+delta.y*(epsilon.x*pixels[2].index+delta.x*
5493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[3].index));
5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case FilterInterpolatePixel:
5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
55454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      CacheView
55554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        *filter_view;
55654ffe7c6780ec1e33f8707e228b962d1accf58f8cristy
5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Image
5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *excerpt_image,
5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *filter_image;
5603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      RectangleInfo
5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        geometry;
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      geometry.width=4L;
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      geometry.height=4L;
569bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      geometry.x=(ssize_t) floor(x)-1L;
570bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      geometry.y=(ssize_t) floor(y)-1L;
5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      excerpt_image=ExcerptImage(resample_filter->image,&geometry,
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->exception);
5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (excerpt_image == (Image *) NULL)
5743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
5763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_image=ResizeImage(excerpt_image,1,1,resample_filter->image->filter,
5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->image->blur,resample_filter->exception);
5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      excerpt_image=DestroyImage(excerpt_image);
5813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (filter_image == (Image *) NULL)
5823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
5833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_view=AcquireCacheView(filter_image);
5843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,
5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->exception);
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p != (const PixelPacket *) NULL)
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          indexes=GetVirtualIndexQueue(filter_image);
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetMagickPixelPacket(resample_filter->image,pixels);
5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_view=DestroyCacheView(filter_view);
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_image=DestroyImage(filter_image);
5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case IntegerInterpolatePixel:
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
60154ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
60254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),1,1,resample_filter->exception);
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GetMagickPixelPacket(resample_filter->image,pixels);
6103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MeshInterpolatePixel:
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[4];
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[4],
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta,
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        luminance;
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
62654ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
62754ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),2,2,resample_filter->exception);
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
6293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
6363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
6383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
64146f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
6443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
6453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            if (resample_filter->image->colorspace == CMYKColorspace)
6463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
6473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
6513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      luminance.x=MagickPixelLuminance(pixels+0)-MagickPixelLuminance(pixels+3);
6533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      luminance.y=MagickPixelLuminance(pixels+1)-MagickPixelLuminance(pixels+2);
6543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (fabs(luminance.x) < fabs(luminance.y))
6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
6573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Diagonal 0-3 NW-SE.
6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
6593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (delta.x <= delta.y)
6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Bottom-left triangle  (pixel:2, diagonal: 0-3).
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.y=1.0-delta.y;
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[2].red,
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].red,pixels[0].red);
6693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[2].green,
6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].green,pixels[0].green);
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[2].blue,
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].blue,pixels[0].blue);
6733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[2].opacity,
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].opacity,pixels[0].opacity);
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[2].index,
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[3].index,pixels[0].index);
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Top-right triangle (pixel:1, diagonal: 0-3).
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.x=1.0-delta.x;
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[1].red,
6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].red,pixels[3].red);
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[1].green,
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].green,pixels[3].green);
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[1].blue,
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].blue,pixels[3].blue);
6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[1].opacity,
6943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].opacity,pixels[3].opacity);
6953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[1].index,
6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[0].index,pixels[3].index);
6983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      else
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Diagonal 1-2 NE-SW.
7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (delta.x <= (1.0-delta.y))
7063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Top-left triangle (pixel 0, diagonal: 1-2).
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
7113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[0].red,
7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].red,pixels[2].red);
7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[0].green,
7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].green,pixels[2].green);
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[0].blue,
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].blue,pixels[2].blue);
7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[0].opacity,
7193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].opacity,pixels[2].opacity);
7203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[0].index,
7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[1].index,pixels[2].index);
7233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Bottom-right triangle (pixel: 3, diagonal: 1-2).
7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.x=1.0-delta.x;
7303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.y=1.0-delta.y;
7313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[3].red,
7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].red,pixels[1].red);
7353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[3].green,
7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].green,pixels[1].green);
7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[3].blue,
7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].blue,pixels[1].blue);
7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[3].opacity,
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].opacity,pixels[1].opacity);
7413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
7423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[3].index,
7433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[2].index,pixels[1].index);
7443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case NearestNeighborInterpolatePixel:
7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
7513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=GetCacheViewVirtualPixels(resample_filter->view,NearestNeighbor(x),
7543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        NearestNeighbor(y),1,1,resample_filter->exception);
7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
7563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
7583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
7613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GetMagickPixelPacket(resample_filter->image,pixels);
7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
7633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
7643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case SplineInterpolatePixel:
7663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
7683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16];
7693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
7713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16],
7723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dx,
7733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dy,
7743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
7753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
7773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta;
7783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
77954ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      ssize_t
78054ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        j,
78154ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        n;
78254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy
78354ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
78454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
7853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
7863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
7883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
7913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      n=0;
7923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
7933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
7943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=(-1); i < 3L; i++)
7953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
7963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dy=CubicWeightingFunction((MagickRealType) i-delta.y);
7973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (j=(-1); j < 3L; j++)
7983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetMagickPixelPacket(resample_filter->image,pixels+n);
8003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,p,indexes+n,pixels+n);
8013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          alpha[n]=1.0;
8023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->matte != MagickFalse)
8033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
80454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy              alpha[n]=QuantumScale*((MagickRealType)
80554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy                GetAlphaPixelComponent(p));
8063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].red*=alpha[n];
8073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].green*=alpha[n];
8083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].blue*=alpha[n];
8093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (resample_filter->image->colorspace == CMYKColorspace)
8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[n].index*=alpha[n];
8113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
8123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          dx=CubicWeightingFunction(delta.x-(MagickRealType) j);
8133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          gamma=alpha[n];
8143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
8153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->red+=gamma*dx*dy*pixels[n].red;
8163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->green+=gamma*dx*dy*pixels[n].green;
8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->blue+=gamma*dx*dy*pixels[n].blue;
8183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->matte != MagickFalse)
8193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixel->opacity+=dx*dy*pixels[n].opacity;
8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (resample_filter->image->colorspace == CMYKColorspace)
8213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixel->index+=gamma*dx*dy*pixels[n].index;
8223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          n++;
8233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          p++;
8243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
8253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
8263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
8273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
8293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
8303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
8333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e s a m p l e P i x e l C o l o r                                       %
8383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ResamplePixelColor() samples the pixel values surrounding the location
8443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  given using an elliptical weighted average, at the scale previously
8453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated, and in the most efficent manner possible for the
8463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  VirtualPixelMethod setting.
8473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ResamplePixelColor method is:
8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter,
8513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       const double u0,const double v0,MagickPixelPacket *pixel)
8523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
8543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
8563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o u0,v0: A double representing the center of the area to resample,
8583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        The distortion transformed transformed x,y coordinate.
8593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o pixel: the resampled pixel is returned here.
8613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
8633ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType ResamplePixelColor(
8643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const double u0,const double v0,
8653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket *pixel)
8663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
8683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
870490ab03a4e81aa0943087243055c77e3794d75d9anthony  ssize_t u,v, v1, v2, uw, hit;
8713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double u1;
8723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double U,V,Q,DQ,DDQ;
8733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double divisor_c,divisor_m;
8743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register double weight;
8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const PixelPacket *pixels;
8763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const IndexPacket *indexes;
8773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
8783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
8793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
8813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GetMagickPixelPacket(resample_filter->image,pixel);
8823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->do_interpolate ) {
8833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,
8843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->interpolate,u0,v0,pixel);
8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
8863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
8873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8882e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#if DEBUG_ELLIPSE
8892e6ab68e6538e73abd8d77f505bc9f033c742f1canthony  fprintf(stderr, "u0=%lf; v0=%lf;\n", u0, v0);
8902e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#endif
8912e6ab68e6538e73abd8d77f505bc9f033c742f1canthony
8923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
8933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Does resample area Miss the image?
8943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    And is that area a simple solid color - then return that color
8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch ( resample_filter->virtual_pixel ) {
8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BackgroundVirtualPixelMethod:
8993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case ConstantVirtualPixelMethod:
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TransparentVirtualPixelMethod:
9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BlackVirtualPixelMethod:
9023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case GrayVirtualPixelMethod:
9033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case WhiteVirtualPixelMethod:
9043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MaskVirtualPixelMethod:
9053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( resample_filter->limit_reached
906d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 + resample_filter->Ulimit < 0.0
907d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
908d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 + resample_filter->Vlimit < 0.0
909d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
9103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case UndefinedVirtualPixelMethod:
9153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case EdgeVirtualPixelMethod:
916d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < 0.0 && v0 + resample_filter->Vlimit < 0.0 )
917d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < 0.0
918d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
919d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
920d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < 0.0 )
921d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
922d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
9233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileVirtualPixelMethod:
927d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    v0 + resample_filter->Vlimit < 0.0
928d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
9293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the horizontally tiled images. */
9313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileVirtualPixelMethod:
933d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    u0 + resample_filter->Ulimit < 0.0
934d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
9353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the vertically tiled images. */
9373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case DitherVirtualPixelMethod:
939d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < -32.0 && v0 + resample_filter->Vlimit < -32.0 )
940d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < -32.0
941d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
942d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
943d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < -32.0 )
944d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
945d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
9463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TileVirtualPixelMethod:
9503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MirrorVirtualPixelMethod:
9513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case RandomVirtualPixelMethod:
9523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileEdgeVirtualPixelMethod:
9533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileEdgeVirtualPixelMethod:
9543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case CheckerTileVirtualPixelMethod:
9553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* resampling of area is always needed - no VP limits */
9563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( hit ) {
9593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* whole area is a solid color -- just return that color */
9603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,IntegerInterpolatePixel,
9613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      u0,v0,pixel);
9623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
9633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
9663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Scaling limits reached, return an 'averaged' result.
9673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
9683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->limit_reached ) {
9693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch ( resample_filter->virtual_pixel ) {
9703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*  This is always handled by the above, so no need.
9713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case BackgroundVirtualPixelMethod:
9723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case ConstantVirtualPixelMethod:
9733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case TransparentVirtualPixelMethod:
9743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case GrayVirtualPixelMethod,
9753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case WhiteVirtualPixelMethod
9763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case MaskVirtualPixelMethod:
9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case UndefinedVirtualPixelMethod:
9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case EdgeVirtualPixelMethod:
9803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case DitherVirtualPixelMethod:
9813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileEdgeVirtualPixelMethod:
9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileEdgeVirtualPixelMethod:
9839b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony        /* We need an average edge pixel, from the correct edge!
9843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           How should I calculate an average edge color?
9853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           Just returning an averaged neighbourhood,
9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           works well in general, but falls down for TileEdge methods.
9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           This needs to be done properly!!!!!!
9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=InterpolateResampleFilter(resample_filter,
9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          AverageInterpolatePixel,u0,v0,pixel);
9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileVirtualPixelMethod:
9933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileVirtualPixelMethod:
9943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* just return the background pixel - Is there more direct way? */
9953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=InterpolateResampleFilter(resample_filter,
9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           IntegerInterpolatePixel,(double)-1,(double)-1,pixel);
9973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
9983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case TileVirtualPixelMethod:
9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case MirrorVirtualPixelMethod:
10003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case RandomVirtualPixelMethod:
10013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case CheckerTileVirtualPixelMethod:
10023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
10033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* generate a average color of the WHOLE image */
10043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if ( resample_filter->average_defined == MagickFalse ) {
10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Image
10063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_image;
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          CacheView
10093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_view;
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetMagickPixelPacket(resample_filter->image,
10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                (MagickPixelPacket *)&(resample_filter->average_pixel));
10133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          resample_filter->average_defined = MagickTrue;
10143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /* Try to get an averaged pixel color of whole image */
10163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,1.0,
10173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           resample_filter->exception);
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (average_image == (Image *) NULL)
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              *pixel=resample_filter->average_pixel; /* FAILED */
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_view=AcquireCacheView(average_image);
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels=(PixelPacket *)GetCacheViewVirtualPixels(average_view,0,0,1,1,
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            resample_filter->exception);
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (pixels == (const PixelPacket *) NULL) {
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_view=DestroyCacheView(average_view);
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_image=DestroyImage(average_image);
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *pixel=resample_filter->average_pixel; /* FAILED */
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            break;
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
10323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          indexes=(IndexPacket *) GetCacheViewAuthenticIndexQueue(average_view);
10333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,pixels,indexes,
10343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            &(resample_filter->average_pixel));
10353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_view=DestroyCacheView(average_view);
10363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_image=DestroyImage(average_image);
1037490ab03a4e81aa0943087243055c77e3794d75d9anthony
1038490ab03a4e81aa0943087243055c77e3794d75d9anthony          if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod )
1039490ab03a4e81aa0943087243055c77e3794d75d9anthony            {
1040490ab03a4e81aa0943087243055c77e3794d75d9anthony              /* CheckerTile is avergae of image average half background */
1041490ab03a4e81aa0943087243055c77e3794d75d9anthony              /* FUTURE: replace with a 50% blend of both pixels */
1042490ab03a4e81aa0943087243055c77e3794d75d9anthony
1043490ab03a4e81aa0943087243055c77e3794d75d9anthony              weight = QuantumScale*((MagickRealType)(QuantumRange-
1044490ab03a4e81aa0943087243055c77e3794d75d9anthony                          resample_filter->average_pixel.opacity));
1045490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red *= weight;
1046490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green *= weight;
1047490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue *= weight;
1048490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c = weight;
1049490ab03a4e81aa0943087243055c77e3794d75d9anthony
1050490ab03a4e81aa0943087243055c77e3794d75d9anthony              weight = QuantumScale*((MagickRealType)(QuantumRange-
1051490ab03a4e81aa0943087243055c77e3794d75d9anthony                          resample_filter->image->background_color.opacity));
1052490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red +=
1053490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.red;
1054490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green +=
1055490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.green;
1056490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue +=
1057490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.blue;
1058490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.matte +=
1059490ab03a4e81aa0943087243055c77e3794d75d9anthony                      resample_filter->image->background_color.opacity;
1060490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c += weight;
1061490ab03a4e81aa0943087243055c77e3794d75d9anthony
1062490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red /= divisor_c;
1063490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green /= divisor_c;
1064490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue /= divisor_c;
1065490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.matte /= 2;
1066490ab03a4e81aa0943087243055c77e3794d75d9anthony
1067490ab03a4e81aa0943087243055c77e3794d75d9anthony            }
10683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
10693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *pixel=resample_filter->average_pixel;
10703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
10713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
10723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
10733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
10743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
10763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize weighted average data collection
10773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
10783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
10793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 0.0;
10803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 0.0;
10813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->red = pixel->green = pixel->blue = 0.0;
10823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->image->matte != MagickFalse) pixel->opacity = 0.0;
10833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->image->colorspace == CMYKColorspace) pixel->index = 0.0;
10843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
10863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Determine the parellelogram bounding box fitted to the ellipse
10873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    centered at u0,v0.  This area is bounding by the lines...
10883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1089490ab03a4e81aa0943087243055c77e3794d75d9anthony  v1 = (ssize_t)ceil(v0 - resample_filter->Vlimit);  /* range of scan lines */
1090490ab03a4e81aa0943087243055c77e3794d75d9anthony  v2 = (ssize_t)floor(v0 + resample_filter->Vlimit);
1091490ab03a4e81aa0943087243055c77e3794d75d9anthony
1092490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* scan line start and width accross the parallelogram */
1093490ab03a4e81aa0943087243055c77e3794d75d9anthony  u1 = u0 + (v1-v0)*resample_filter->slope - resample_filter->Uwidth;
1094490ab03a4e81aa0943087243055c77e3794d75d9anthony  uw = (ssize_t)(2.0*resample_filter->Uwidth)+1;
10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1096490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1097490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "v1=%ld; v2=%ld\n", (long)v1, (long)v2);
1098490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "u1=%ld; uw=%ld\n", (long)u1, (long)uw);
1099490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
1100490ab03a4e81aa0943087243055c77e3794d75d9anthony# define DEBUG_HIT_MISS 0 /* only valid if DEBUG_ELLIPSE is enabled */
1101490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
11023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Do weighted resampling of all pixels,  within the scaled ellipse,
11053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    bound by a Parellelogram fitted to the ellipse.
11063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DDQ = 2*resample_filter->A;
1108490ab03a4e81aa0943087243055c77e3794d75d9anthony  for( v=v1; v<=v2;  v++ ) {
1109490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
1110490ab03a4e81aa0943087243055c77e3794d75d9anthony    long uu = ceil(u1);   /* actual pixel location (for debug only) */
1111490ab03a4e81aa0943087243055c77e3794d75d9anthony    fprintf(stderr, "# scan line from pixel %ld, %ld\n", (long)uu, (long)v);
1112490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
1113490ab03a4e81aa0943087243055c77e3794d75d9anthony    u = (ssize_t)ceil(u1);        /* first pixel in scanline */
1114490ab03a4e81aa0943087243055c77e3794d75d9anthony    u1 += resample_filter->slope; /* start of next scan line */
1115490ab03a4e81aa0943087243055c77e3794d75d9anthony
1116490ab03a4e81aa0943087243055c77e3794d75d9anthony
1117490ab03a4e81aa0943087243055c77e3794d75d9anthony    /* location of this first pixel, relative to u0,v0 */
1118490ab03a4e81aa0943087243055c77e3794d75d9anthony    U = (double)u-u0;
11193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    V = (double)v-v0;
11203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* Q = ellipse quotent ( if Q<F then pixel is inside ellipse) */
1122490ab03a4e81aa0943087243055c77e3794d75d9anthony    Q = (resample_filter->A*U + resample_filter->B*V)*U + resample_filter->C*V*V;
11233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    DQ = resample_filter->A*(2.0*U+1) + resample_filter->B*V;
11243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* get the scanline of pixels for this v */
1126bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    pixels=GetCacheViewVirtualPixels(resample_filter->view,u,v,(size_t) uw,
11273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      1,resample_filter->exception);
11283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (pixels == (const PixelPacket *) NULL)
11293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
11303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
11313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* count up the weighted pixel colors */
11333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    for( u=0; u<uw; u++ ) {
11343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* Note that the ellipse has been pre-scaled so F = WLUT_WIDTH */
11353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( Q < (double)WLUT_WIDTH ) {
11363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        weight = resample_filter->filter_lut[(int)Q];
11373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->opacity  += weight*pixels->opacity;
11393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_m += weight;
11403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->matte != MagickFalse)
11423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          weight *= QuantumScale*((MagickRealType)(QuantumRange-pixels->opacity));
11433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->red   += weight*pixels->red;
11443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->green += weight*pixels->green;
11453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->blue  += weight*pixels->blue;
11463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (resample_filter->image->colorspace == CMYKColorspace)
11473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->index += weight*(*indexes);
11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_c += weight;
11493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
1151490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
1152490ab03a4e81aa0943087243055c77e3794d75d9anthony        /* mark the pixel according to hit/miss of the ellipse */
1153490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
1154490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
1155490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
1156490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
1157490ab03a4e81aa0943087243055c77e3794d75d9anthony      } else {
1158490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
1159490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
1160490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
1161490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
1162490ab03a4e81aa0943087243055c77e3794d75d9anthony      }
1163490ab03a4e81aa0943087243055c77e3794d75d9anthony      uu++;
1164490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
1166490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixels++;
11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes++;
11693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Q += DQ;
11703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      DQ += DDQ;
11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1173490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1174490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "Hit=%ld;  Total=%ld;\n", (long)hit, (long)uw*(v2-v1) );
1175490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
11763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Result sanity check -- this should NOT happen
11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1180490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( hit == 0 ) {
11813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* not enough pixels in resampling, resort to direct interpolation */
1182490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_NO_PIXEL_HIT
11839b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony    pixel->opacity = pixel->red = pixel->green = pixel->blue = 0;
11849b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony    pixel->red = QuantumRange; /* show pixels for which EWA fails */
11859b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#else
11863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,
11873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->interpolate,u0,v0,pixel);
11889b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#endif
11893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return status;
11903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
11913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Finialize results of resampling
11943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 1.0/divisor_m;
1196ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->opacity = (MagickRealType) ClampToQuantum(divisor_m*pixel->opacity);
11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 1.0/divisor_c;
1198ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->red   = (MagickRealType) ClampToQuantum(divisor_c*pixel->red);
1199ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->green = (MagickRealType) ClampToQuantum(divisor_c*pixel->green);
1200ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->blue  = (MagickRealType) ClampToQuantum(divisor_c*pixel->blue);
12013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->image->colorspace == CMYKColorspace)
1202ce70c17bb6433add2eb069515a4f3105989e0662cristy    pixel->index = (MagickRealType) ClampToQuantum(divisor_c*pixel->index);
12033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1206c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA && EWA_CLAMP
1207c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/*
1208c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1210c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1211c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1212c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony-   C l a m p U p A x e s                                                     %
1213c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1214c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1215c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1216c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1217c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1218c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ClampUpAxes() function converts the input vectors into a major and
1219c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% minor axis unit vectors, and their magnatude.  This form allows us
1220c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% to ensure that the ellipse generated is never smaller than the unit
1221c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% circle and thus never too small for use in EWA resampling.
1222c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1223c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% This purely mathematical 'magic' was provided by Professor Nicolas
1224c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% Robidoux and his Masters student Chantal Racette.
1225c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1226c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% See Reference: "We Recommend Singular Value Decomposition", David Austin
1227c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%   http://www.ams.org/samplings/feature-column/fcarc-svd
1228c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1229c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% By generating Major and Minor Axis vectors, we can actually use the
1230c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ellipse in its "canonical form", by remapping the dx,dy of the
1231c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% sampled point into distances along the major and minor axis unit
1232c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% vectors.
1233c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%    http://en.wikipedia.org/wiki/Ellipse#Canonical_form
1234c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony*/
1235c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthonystatic void ClampUpAxes(const double dux,
1236c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        const double dvx,
1237c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        const double duy,
1238c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        const double dvy,
1239c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        double *major_mag,
1240c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        double *minor_mag,
1241c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        double *major_unit_x,
1242c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        double *major_unit_y,
1243c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        double *minor_unit_x,
1244c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                        double *minor_unit_y)
1245c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony{
1246c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1247c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes takes an input 2x2 matrix
1248c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1249c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ a b ] = [ dux duy ]
1250c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ c d ] = [ dvx dvy ]
1251c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1252c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * and computes from it the major and minor axis vectors [major_x,
1253c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_y] and [minor_x,minor_y] of the smallest ellipse containing
1254c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * both the unit disk and the ellipse which is the image of the unit
1255c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * disk by the linear transformation
1256c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1257c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dux duy ] [S] = [s]
1258c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dvx dvy ] [T] = [t]
1259c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1260c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * (The vector [S,T] is the difference between a position in output
1261c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * space and [X,Y]; the vector [s,t] is the difference between a
1262c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * position in input space and [x,y].)
1263c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1264c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1265c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Outputs:
1266c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1267c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_mag is the half-length of the major axis of the "new"
1268c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ellipse (in input space).
1269c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1270c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_mag is the half-length of the minor axis of the "new"
1271c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ellipse (in input space).
1272c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1273c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_x is the x-coordinate of the major axis direction vector
1274c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of both the "old" and "new" ellipses.
1275c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1276c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_y is the y-coordinate of the major axis direction vector.
1277c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1278c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_x is the x-coordinate of the minor axis direction vector.
1279c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1280c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_y is the y-coordinate of the minor axis direction vector.
1281c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1282c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Unit vectors are useful for computing projections, in particular,
1283c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * to compute the distance between a point in output space and the
1284c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * center (of a disk) from the position of the corresponding point
1285c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * in input space.
1286c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1287c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Now, if you want to modify the input pair of tangent vectors so
1288c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it defines the modified ellipse, all you have to do is set
1289c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
12908b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdux = major_mag * major_unit_x
12918b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvx = major_mag * major_unit_y
12928b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newduy = minor_mag * minor_unit_x = minor_mag * -major_unit_y
12938b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvy = minor_mag * minor_unit_y = minor_mag *  major_unit_x
1294c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1295c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * and use these new tangent vectors "as if" they were the original
1296c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * ones.  Most of the time this is a rather drastic change in the
1297c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * tangent vectors (even if the singular values are large enough not
1298c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * to be clampled). A technical explanation of why things still work
1299c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * is found at the end of the discussion below.
1300c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1301c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1302c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1303c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Discussion:
1304c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1305c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * GOAL: Fix things so that the pullback, in input space, of a disk
1306c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of radius r in output space is an ellipse which contains, at
1307c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * least, a disc of radius r. (Make this hold for any r>0.)
1308c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1309c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * METHOD: Find the singular values and (unit) left singular vectors
1310c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of Jinv, clampling up the singular values to 1, and multiplying
1311c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * the unit left singular vectors by the new singular values in
1312c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * order to get the minor and major ellipse axis vectors.
1313c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1314c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Inputs:
1315c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1316c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The Jacobian matrix of the transformation at the output point
1317c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * under consideration is defined as follows:
1318c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1319c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Consider the transformation (x,y) -> (X,Y) from input locations
13208b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * to output locations. (Anthony Thyssen, elsewhere in resample.c,
13218b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * uses the notation (u,v) -> (x,y) instead of (x,y) -> (X,Y).)
1322c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1323c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The Jacobian matrix J is equal to
1324c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1325c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   [ A, B ] = [ dX/dx, dX/dy ]
1326c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   [ C, D ] = [ dY/dx, dY/dy ]
1327c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1328c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Consequently, the vector [A,C] is the tangent vector
1329c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * corresponding to input changes in the horizontal direction, and
1330c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * the vector [B,D] is the tangent vector corresponding to input
1331c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * changes in the vertical direction.
1332c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1333c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * In the context of resampling, it is more natural to use the
1334c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * inverse Jacobian matrix Jinv. Jinv is
1335c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1336c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   [ a, b ] = [ dx/dX, dx/dY ]
1337c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   [ c, d ] = [ dy/dX, dy/dY ]
1338c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1339c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Note: Jinv can be computed from J with the following matrix
1340c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * formula:
1341c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1342c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = 1/(A*D-B*C) [  D, -B ]
1343c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *                      [ -C,  A ]
1344c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1345703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * What we (implicitly) want to do is replace Jinv by a new Jinv
1346c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * which generates an ellipse which is as close as possible to the
1347703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * original but which contains the unit disk. This is accomplished
1348703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * as follows:
1349c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1350c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Let
1351c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1352c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U Sigma V^T
1353c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1354703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * be an SVD decomposition of Jinv. (The SVD is not unique. The
1355703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * final ellipse does not depend on the particular SVD.) In
1356c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * principle, what we want is to clamp up the entries of the
1357c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * diagonal matrix Sigma so that they are at least 1, and then set
1358c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1359c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U newSigma V^T.
1360c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1361c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * However, we do not need to compute V^T for the following reason:
1362c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * V is an orthogonal matrix (that is, it represents a combination
1363c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * of a rotation and a reflexion). Consequently, V maps the unit
1364c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * circle to itself. For this reason, the exact value of V does not
1365703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * affect the final ellipse, and we choose the identity matrix.
1366703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * That is, we simply set
1367c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1368c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U newSigma,
1369c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1370703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * omitting the V^T factor altogether. In the end, we return the two
1371703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * diagonal entries of newSigma together with the two columns of U,
1372703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * for a total of six returned quantities.
1373c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1374c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1375c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes was written by Nicolas Robidoux and Chantal Racette
1376c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * of Laurentian University with funding from the National Science
1377c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * and Engineering Research Council of Canada.
1378703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   *
1379553b36ed9da8ada2eb4dbca68b827e95c33feb97nicolas   * The idea of using the SVD to clamp the singular values of the
1380553b36ed9da8ada2eb4dbca68b827e95c33feb97nicolas   * linear part of the affine approximation of the pullback
1381553b36ed9da8ada2eb4dbca68b827e95c33feb97nicolas   * transformation comes from the astrophysicist Craig DeForest, who
1382553b36ed9da8ada2eb4dbca68b827e95c33feb97nicolas   * implemented it for use with (approximate) Gaussian filtering in
13838b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * his PDL::Transform code (PDL = Perl Data Language).
1384703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   *
1385703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * The only (possibly) new math in the following is the selection of
1386703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * the largest row of the eigen matrix system in order to stabilize
1387703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * the computation in near rank-deficient cases, and the
1388703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * corresponding efficient repair of degenerate cases using the norm
1389703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * of this largest row. Omitting the "V^T" factor of the SVD may
1390703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   * also be a new "trick."
1391c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1392c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double a = dux;
1393c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double b = duy;
1394c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double c = dvx;
1395c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double d = dvy;
1396c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1397c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * n is the matrix Jinv * transpose(Jinv). Eigenvalues of n are the
1398c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * squares of the singular values of Jinv.
1399c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1400c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double aa = a*a;
1401c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double bb = b*b;
1402c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double cc = c*c;
1403c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double dd = d*d;
1404c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1405c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Eigenvectors of n are left singular vectors of Jinv.
1406c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1407c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n11 = aa+bb;
1408c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n12 = a*c+b*d;
1409c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n21 = n12;
1410c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n22 = cc+dd;
1411c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double det = a*d-b*c;
1412c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double twice_det = det+det;
1413c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double frobenius_squared = n11+n22;
1414c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double discriminant =
1415c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    (frobenius_squared+twice_det)*(frobenius_squared-twice_det);
1416c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double sqrt_discriminant = sqrt(discriminant);
1417c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1418c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1 is the largest singular value of the inverse Jacobian
1419c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. In other words, its reciprocal is the smallest singular
1420c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * value of the Jacobian matrix itself.
1421c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * If s1 = 0, both singular values are 0, and any orthogonal pair of
1422c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * left and right factors produces a singular decomposition of Jinv.
1423c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
1424c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
14258b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * Initially, we only compute the squares of the singular values.
1426c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1427c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1 = 0.5*(frobenius_squared+sqrt_discriminant);
1428c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1429c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s2 the smallest singular value of the inverse Jacobian
1430c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. Its reciprocal is the largest singular value of the
1431c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Jacobian matrix itself.
1432c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1433c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s2s2 = 0.5*(frobenius_squared-sqrt_discriminant);
1434c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11 = s1s1-n11;
1435c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22 = s1s1-n22;
1436c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1437c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * u1, the first column of the U factor of a singular decomposition
1438c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of Jinv, is a (non-normalized) left singular vector corresponding
1439c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * to s1. It has entries u11 and u21. We compute u1 from the fact
1440c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it is an eigenvector of n corresponding to the eigenvalue
1441c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * s1^2.
1442c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1443c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11_squared = s1s1minusn11*s1s1minusn11;
1444c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22_squared = s1s1minusn22*s1s1minusn22;
1445c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1446c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The following selects the largest row of n-s1^2 I as the one
1447c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * which is used to find the eigenvector. If both s1^2-n11 and
1448c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1^2-n22 are zero, n-s1^2 I is the zero matrix.  In that case,
1449c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * any vector is an eigenvector; in addition, norm below is equal to
1450c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * zero, and, in exact arithmetic, this is the only case in which
1451c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * norm = 0. So, setting u1 to the simple but arbitrary vector [1,0]
1452c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * if norm = 0 safely takes care of all cases.
1453c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1454c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u11 =
1455c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? n12 : s1s1minusn22 );
1456c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u21 =
1457c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? s1s1minusn11 : n21 );
1458c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double norm = sqrt(temp_u11*temp_u11+temp_u21*temp_u21);
1459c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1460c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Finalize the entries of first left singular vector (associated
1461c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * with the largest singular value).
1462c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1463c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u11 = ( (norm>0.0) ? temp_u11/norm : 1.0 );
1464c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u21 = ( (norm>0.0) ? temp_u21/norm : 0.0 );
1465c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1466c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Clamp the singular values up to 1.
1467c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1468ed22721389b8ff2983982914d29db84731825a8fnicolas  *major_mag = ( (s1s1<=1.0) ? 1.0 : sqrt(s1s1) );
1469ed22721389b8ff2983982914d29db84731825a8fnicolas  *minor_mag = ( (s2s2<=1.0) ? 1.0 : sqrt(s2s2) );
1470c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
1471c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Return the unit major and minor axis direction vectors.
1472c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
1473c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_x = u11;
1474c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_y = u21;
1475c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_x = -u21;
1476c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_y = u11;
1477c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony}
1478c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1479c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
14803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
14813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S c a l e R e s a m p l e F i l t e r                                     %
14863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
14893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ScaleResampleFilter() does all the calculations needed to resample an image
14923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  at a specific scale, defined by two scaling vectors.  This not using
14933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  a orthogonal scaling, but two distorted scaling vectors, to allow the
14943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  generation of a angled ellipse.
14953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
14963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As only two deritive scaling vectors are used the center of the ellipse
14973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  must be the center of the lookup.  That is any curvature that the
14983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion may produce is discounted.
14993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The input vectors are produced by either finding the derivitives of the
15013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion function, or the partial derivitives from a distortion mapping.
15023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  They do not need to be the orthogonal dx,dy scaling vectors, but can be
15033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated from other derivatives.  For example you could use  dr,da/r
15043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  polar coordinate vector scaling vectors
15053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1506c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If   u,v =  DistortEquation(x,y)   OR   u = Fu(x,y); v = Fv(x,y)
1507c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Then the scaling vectors are determined from the deritives...
15083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      du/dx, dv/dx     and    du/dy, dv/dy
1509c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If the resulting scaling vectors is othogonally aligned then...
15103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      dv/dx = 0   and   du/dy  =  0
1511c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Producing an othogonally alligned ellipse in source space for the area to
1512c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  be resampled.
15133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Note that scaling vectors are different to argument order.  Argument order
15153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  is the general order the deritives are extracted from the distortion
1516c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  equations, and not the scaling vectors. As such the middle two vaules
1517c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  may be swapped from what you expect.  Caution is advised.
15183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15193ebea1e232532895681cd50101ddad0856e9a1d3anthony%  WARNING: It is assumed that any SetResampleFilter() method call will
15203ebea1e232532895681cd50101ddad0856e9a1d3anthony%  always be performed before the ScaleResampleFilter() method, so that the
15213ebea1e232532895681cd50101ddad0856e9a1d3anthony%  size of the ellipse will match the support for the resampling filter being
15223ebea1e232532895681cd50101ddad0856e9a1d3anthony%  used.
1523490ab03a4e81aa0943087243055c77e3794d75d9anthony%
15243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ScaleResampleFilter method is:
15253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     void ScaleResampleFilter(const ResampleFilter *resample_filter,
15273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       const double dux,const double duy,const double dvx,const double dvy)
15283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
15303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resampling resample_filterrmation defining the
15323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      image being resampled
15333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o dux,duy,dvx,dvy:
1535c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The deritives or scaling vectors defining the EWA ellipse.
1536c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         NOTE: watch the order, which is based on the order deritives
1537c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         are usally determined from distortion equations (see above).
1538c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The middle two values may need to be swapped if you are thinking
1539c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         in terms of scaling vectors.
15403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
15423ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
15433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double dux,const double duy,const double dvx,const double dvy)
15443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1545d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  double A,B,C,F;
15463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1547c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
15483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
15493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
15503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->limit_reached = MagickFalse;
15523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1553b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  /* A 'point' filter forces use of interpolation instead of area sampling */
1554b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  if ( resample_filter->filter == PointFilter )
1555b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    return; /* EWA turned off - nothing to do */
1556b821aafe132291d46e0fb0c2b24e6e467aa17640anthony
1557c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
1558c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "# -----\n" );
1559c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "dux=%lf; dvx=%lf;   duy=%lf; dvy=%lf;\n",
1560c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony       dux, dvx, duy, dvy);
1561c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
15623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Find Ellipse Coefficents such that
15643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        A*u^2 + B*u*v + C*v^2 = F
15653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     With u,v relative to point around which we are resampling.
15663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     And the given scaling dx,dy vectors in u,v space
15673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy         du/dx,dv/dx   and  du/dy,dv/dy
15683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1569c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1570d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /* Direct conversion of derivatives into elliptical coefficients
1571b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     However when magnifying images, the scaling vectors will be small
1572b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     resulting in a ellipse that is too small to sample properly.
1573b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     As such we need to clamp the major/minor axis to a minumum of 1.0
1574b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     to prevent it getting too small.
15753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1576c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA_CLAMP
1577c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  { double major_mag,
1578c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_mag,
1579c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_x,
1580c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_y,
1581c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_x,
1582c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_y;
1583c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1584c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  ClampUpAxes(dux,dvx,duy,dvy, &major_mag, &minor_mag,
1585c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                &major_x, &major_y, &minor_x, &minor_y);
1586c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  major_x *= major_mag;  major_y *= major_mag;
1587c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  minor_x *= minor_mag;  minor_y *= minor_mag;
1588c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
1589c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "major_x=%lf; major_y=%lf;  minor_x=%lf; minor_y=%lf;\n",
1590c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony        major_x, major_y, minor_x, minor_y);
1591c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
1592c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  A = major_y*major_y+minor_y*minor_y;
1593c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  B = -2.0*(major_x*major_y+minor_x*minor_y);
1594c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  C = major_x*major_x+minor_x*minor_x;
1595eaa08628db6764fa5cb6802eaf9bb5753c25eb1fnicolas  F = major_mag*minor_mag;
1596c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F *= F; /* square it */
1597c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  }
1598c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#else /* raw EWA */
15993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy;
1600d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
16013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy;
1602c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F = dux*dvy-duy*dvx;
16035708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  F *= F; /* square it */
1604c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
1605d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1606490ab03a4e81aa0943087243055c77e3794d75d9anthony#else /* HQ_EWA */
1607d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
1608c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    This Paul Heckbert's "Higher Quality EWA" formula, from page 60 in his
1609c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    thesis, which adds a unit circle to the elliptical area so as to do both
1610c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    Reconstruction and Prefiltering of the pixels in the resampling.  It also
1611c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    means it is always likely to have at least 4 pixels within the area of the
1612c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ellipse, for weighted averaging.  No scaling will result with F == 4.0 and
1613c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    a circle of radius 2.0, and F smaller than this means magnification is
1614c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    being used.
1615c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1616c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    NOTE: This method produces a very blury result at near unity scale while
1617490ab03a4e81aa0943087243055c77e3794d75d9anthony    producing perfect results for string minitification and magnifications.
1618490ab03a4e81aa0943087243055c77e3794d75d9anthony
1619c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    However filter support is fixed to 2.0 (no good for Windowed Sinc filters)
16203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
16213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy+1;
1622d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
16233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy+1;
16243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  F = A*C - B*B/4;
16253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
16263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1627490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
16283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fprintf(stderr, "A=%lf; B=%lf; C=%lf; F=%lf\n", A,B,C,F);
16293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1630c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /* Figure out the various information directly about the ellipse.
16313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     This information currently not needed at this time, but may be
16323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     needed later for better limit determination.
1633d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1634d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony     It is also good to have as a record for future debugging
16353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
16363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { double alpha, beta, gamma, Major, Minor;
1637490ab03a4e81aa0943087243055c77e3794d75d9anthony    double Eccentricity, Ellipse_Area, Ellipse_Angle;
1638d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
16393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha = A+C;
16403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    beta  = A-C;
16413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    gamma = sqrt(beta*beta + B*B );
16423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if ( alpha - gamma <= MagickEpsilon )
16443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Major = MagickHuge;
16453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
16463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Major = sqrt(2*F/(alpha - gamma));
16473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Minor = sqrt(2*F/(alpha + gamma));
16483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1649490ab03a4e81aa0943087243055c77e3794d75d9anthony    fprintf(stderr, "# Major=%lf; Minor=%lf\n", Major, Minor );
16503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* other information about ellipse include... */
16523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Eccentricity = Major/Minor;
16533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Ellipse_Area = MagickPI*Major*Minor;
1654490ab03a4e81aa0943087243055c77e3794d75d9anthony    Ellipse_Angle =  atan2(B, A-C);
16553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1656c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    fprintf(stderr, "# Angle=%lf   Area=%lf\n",
1657490ab03a4e81aa0943087243055c77e3794d75d9anthony         RadiansToDegrees(Ellipse_Angle), Ellipse_Area );
16583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
16593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
16603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1661490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* The scaling vectors is impossibly large (producing a very large raw F
1662490ab03a4e81aa0943087243055c77e3794d75d9anthony     value), we may as well not bother doing any form of resampling, as you
1663490ab03a4e81aa0943087243055c77e3794d75d9anthony     risk an near infinite resampled area.  In this case some alturnative
1664490ab03a4e81aa0943087243055c77e3794d75d9anthony     means of pixel sampling, such as the average of the whole image is needed
1665c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony     to get a reasonable result. Calculate only as needed.
16663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1667490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( (4*A*C - B*B) > MagickHuge ) {
16683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
16693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
16703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
16713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1672490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* Scale ellipse by the appropriate size */
1673490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
1674490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
16753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1676490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* Othogonal bounds of the Ellipse */
1677490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->Ulimit = sqrt(4*C*F/(4*A*C-B*B));
1678490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->Vlimit = sqrt(4*A*F/(4*A*C-B*B));
16793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1680490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* Horizontally aligned Parallelogram fitted to Ellipse */
1681490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->Uwidth = sqrt(F/A);   /* Parallelogram Width / 2 */
1682490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->slope = -B/(2*A);     /* Slope of the parallelogram */
1683490ab03a4e81aa0943087243055c77e3794d75d9anthony
1684490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1685490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "Ulimit=%lf; Vlimit=%lf; UWidth=%lf; Slope=%lf;\n",
1686490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Ulimit, resample_filter->Vlimit,
1687490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Uwidth, resample_filter->slope );
1688490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
16893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1690d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /* Check the absolute area of the Parallogram involved...
16913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   * This limit needs more work, as it gets too slow for
16923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   * larger images involved with tiled views of the horizon. */
169339f347aa142535ededfff86309cc2bb4cf222373cristy  if ( (resample_filter->Uwidth * resample_filter->Vlimit)
169439f347aa142535ededfff86309cc2bb4cf222373cristy         > (4.0*resample_filter->image_area)) {
16953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
16963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
16973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
16983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16995708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  /* Scale ellipse formula to directly index the Filter Lookup Table */
17003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { register double scale;
1701490ab03a4e81aa0943087243055c77e3794d75d9anthony    scale = (double)WLUT_WIDTH/F;
17023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->A = A*scale;
17033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->B = B*scale;
17043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->C = C*scale;
17053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* ..ple_filter->F = WLUT_WIDTH; -- hardcoded */
17063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
17073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
17083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
17103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r                                         %
17153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilter() set the resampling filter lookup table based on a
17213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  specific filter.  Note that the filter is used as a radial filter not as a
17223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  two pass othogonally aligned resampling filter.
17233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The default Filter, is Gaussian, which is the standard filter used by the
17253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  original paper on the Elliptical Weighted Everage Algorithm. However other
17263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  filters can also be used.
17273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilter method is:
17293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    void SetResampleFilter(ResampleFilter *resample_filter,
17313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      const FilterTypes filter,const double blur)
17323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
17343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling resample_filterrmation structure
17363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o filter: the resize filter for elliptical weighting LUT
17383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o blur: filter blur factor (radial scaling) for elliptical weighting LUT
17403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
17423ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void SetResampleFilter(ResampleFilter *resample_filter,
17433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const FilterTypes filter,const double blur)
17443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
17453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register int
17463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     Q;
17473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
17493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     r_scale;
17503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResizeFilter
17523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     *resize_filter;
17533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
17553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
17563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17572e6ab68e6538e73abd8d77f505bc9f033c742f1canthony  resample_filter->do_interpolate = MagickFalse;
17583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->filter = filter;
17593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1760490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( filter == PointFilter )
1761b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    {
1762b821aafe132291d46e0fb0c2b24e6e467aa17640anthony      resample_filter->do_interpolate = MagickTrue;
1763b821aafe132291d46e0fb0c2b24e6e467aa17640anthony      return;  /* EWA turned off - nothing more to do */
1764b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    }
17653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1766490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( filter == UndefinedFilter )
17672e6ab68e6538e73abd8d77f505bc9f033c742f1canthony    resample_filter->filter = MitchellFilter;  /* a far less blurry filter */
1768490ab03a4e81aa0943087243055c77e3794d75d9anthony
1769490ab03a4e81aa0943087243055c77e3794d75d9anthony  resize_filter = AcquireResizeFilter(resample_filter->image,
1770490ab03a4e81aa0943087243055c77e3794d75d9anthony       resample_filter->filter,blur,MagickTrue,resample_filter->exception);
1771490ab03a4e81aa0943087243055c77e3794d75d9anthony  if (resize_filter == (ResizeFilter *) NULL)
1772490ab03a4e81aa0943087243055c77e3794d75d9anthony    {
17733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
17743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           ModuleError, "UnableToSetFilteringValue",
17753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           "Fall back to default EWA gaussian filter");
1776490ab03a4e81aa0943087243055c77e3794d75d9anthony      resample_filter->filter = PointFilter;
17773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1778490ab03a4e81aa0943087243055c77e3794d75d9anthony
1779c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1780490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->support = GetResizeFilterSupport(resize_filter);
1781490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( resample_filter->filter == GaussianFilter )
1782c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    resample_filter->support = 2.0;  /* larger gaussian support */
1783c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#else
1784c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  resample_filter->support = 2.0;  /* fixed support size for HQ-EWA */
1785490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
1786490ab03a4e81aa0943087243055c77e3794d75d9anthony
1787490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* Scale radius so the filter LUT covers the full support range */
1788490ab03a4e81aa0943087243055c77e3794d75d9anthony  r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
1789490ab03a4e81aa0943087243055c77e3794d75d9anthony
1790490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* Fill the LUT with a 1D resize filter function */
1791490ab03a4e81aa0943087243055c77e3794d75d9anthony  for(Q=0; Q<WLUT_WIDTH; Q++)
1792490ab03a4e81aa0943087243055c77e3794d75d9anthony    resample_filter->filter_lut[Q] = (double)
1793490ab03a4e81aa0943087243055c77e3794d75d9anthony         GetResizeFilterWeight(resize_filter,sqrt((double)Q)*r_scale);
1794490ab03a4e81aa0943087243055c77e3794d75d9anthony
1795490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* finished with the resize filter */
1796490ab03a4e81aa0943087243055c77e3794d75d9anthony  resize_filter = DestroyResizeFilter(resize_filter);
1797490ab03a4e81aa0943087243055c77e3794d75d9anthony
17983ebea1e232532895681cd50101ddad0856e9a1d3anthony  /*
17993ebea1e232532895681cd50101ddad0856e9a1d3anthony    Adjust the scaling of the default unit circle
18003ebea1e232532895681cd50101ddad0856e9a1d3anthony    This assumes that any real scaling changes will always
18013ebea1e232532895681cd50101ddad0856e9a1d3anthony    take place AFTER the filter method has been initialized.
18023ebea1e232532895681cd50101ddad0856e9a1d3anthony  */
18033ebea1e232532895681cd50101ddad0856e9a1d3anthony
18043ebea1e232532895681cd50101ddad0856e9a1d3anthony  ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
18053ebea1e232532895681cd50101ddad0856e9a1d3anthony
18065708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#if 0
1807490ab03a4e81aa0943087243055c77e3794d75d9anthony  This is old code kept for reference only.  It is very wrong.
1808d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
1809d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Create Normal Gaussian 2D Filter Weighted Lookup Table.
1810d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    A normal EWA guassual lookup would use   exp(Q*ALPHA)
1811d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    where  Q = distance squared from 0.0 (center) to 1.0 (edge)
1812d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    and    ALPHA = -4.0*ln(2.0)  ==>  -2.77258872223978123767
1813d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    However the table is of length 1024, and equates to a radius of 2px
1814d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    thus needs to be scaled by  ALPHA*4/1024 and any blur factor squared
1815d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1816c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    The above came from some reference code provided by Fred Weinhaus
1817c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    and seems to have been a guess that was appropriate for its use
1818c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    in a 3d perspective landscape mapping program.
1819d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  */
1820d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur);
1821d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  for(Q=0; Q<WLUT_WIDTH; Q++)
1822d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    resample_filter->filter_lut[Q] = exp((double)Q*r_scale);
1823d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  resample_filter->support = WLUT_WIDTH;
1824d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  break;
18255708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#endif
1826490ab03a4e81aa0943087243055c77e3794d75d9anthony
1827e06e4c180324bebbd41bce9ea4898642f380b614anthony#if defined(MAGICKCORE_OPENMP_SUPPORT)
18289b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony  /* if( GetOpenMPThreadId() == 0 ) */
1829e06e4c180324bebbd41bce9ea4898642f380b614anthony#endif
1830e06e4c180324bebbd41bce9ea4898642f380b614anthony    if (GetImageArtifact(resample_filter->image,"resample:verbose")
1831e06e4c180324bebbd41bce9ea4898642f380b614anthony          != (const char *) NULL)
1832e06e4c180324bebbd41bce9ea4898642f380b614anthony      {
1833e06e4c180324bebbd41bce9ea4898642f380b614anthony        /* Debug output of the filter weighting LUT
1834e06e4c180324bebbd41bce9ea4898642f380b614anthony          Gnuplot the LUT with hoizontal adjusted to 'r' using...
1835e06e4c180324bebbd41bce9ea4898642f380b614anthony            plot [0:2][-.2:1] "lut.dat" using (sqrt($0/1024)*2):1 with lines
1836e06e4c180324bebbd41bce9ea4898642f380b614anthony          The filter values is normalized for comparision
1837e06e4c180324bebbd41bce9ea4898642f380b614anthony        */
1838d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("#\n");
1839e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("# Resampling Filter LUT (%d values)\n", WLUT_WIDTH);
1840e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("#\n");
1841d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("# Note: values in table are using a squared radius lookup.\n");
1842d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("# And the whole table represents the filters support.\n");
1843e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("#\n");
1844e06e4c180324bebbd41bce9ea4898642f380b614anthony        for(Q=0; Q<WLUT_WIDTH; Q++)
1845d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony          printf("%8.*g %.*g\n",
1846d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony               GetMagickPrecision(),sqrt((double)Q)*r_scale,
1847d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony               GetMagickPrecision(),resample_filter->filter_lut[Q] );
1848e06e4c180324bebbd41bce9ea4898642f380b614anthony      }
18493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return;
18503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
18513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
18533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
18543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   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       %
18583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
18623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
18633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilterInterpolateMethod() changes the interpolation method
18643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  associated with the specified resample filter.
18653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
18663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterInterpolateMethod method is:
18673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
18683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterInterpolateMethod(
18693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const InterpolateMethod method)
18703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
18713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
18723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
18733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
18743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
18753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the interpolation method.
18763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
18773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
18783ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterInterpolateMethod(
18793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const InterpolatePixelMethod method)
18803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
18813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
18823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
18833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
1884d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
18853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
18863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
18873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
1888d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
18893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->interpolate=method;
1890d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
18913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
18923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
18933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
18953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
18963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
18993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   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     %
19003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilterVirtualPixelMethod() changes the virtual pixel method
19063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  associated with the specified resample filter.
19073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterVirtualPixelMethod method is:
19093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterVirtualPixelMethod(
19113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const VirtualPixelMethod method)
19123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
19143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
19163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the virtual pixel method.
19183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
19203ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterVirtualPixelMethod(
19213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const VirtualPixelMethod method)
19223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
19233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
19243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
19253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
19263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
19273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
19283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
19293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->virtual_pixel=method;
19302d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy  if (method != UndefinedVirtualPixelMethod)
19312d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy    (void) SetCacheViewVirtualPixelMethod(resample_filter->view,method);
19323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
19333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1934