home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / VDLib / source / ParameterCurve.cpp < prev   
Encoding:
C/C++ Source or Header  |  2006-10-28  |  6.1 KB  |  247 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2006 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "stdafx.h"
  19. #include <vd2/VDLib/ParameterCurve.h>
  20.  
  21. VDParameterCurve::VDParameterCurve()
  22.     : mMinVal(-1e+30f)
  23.     , mMaxVal(1e+30f)
  24.     , mRefCount(0)
  25. {
  26. }
  27.  
  28. VDParameterCurve::~VDParameterCurve() {
  29. }
  30.  
  31. int VDParameterCurve::AddRef() {
  32.     return ++mRefCount;
  33. }
  34.  
  35. int VDParameterCurve::Release() {
  36.     int rv = --mRefCount;
  37.     if (!rv)
  38.         delete this;
  39.     return rv;
  40. }
  41.  
  42. VDParameterCurvePoint VDParameterCurve::operator()(double x) const {
  43.     VDParameterCurvePoint interpPt;
  44.     interpPt.mX = x;
  45.     interpPt.mY = 0;
  46.     interpPt.mbLinear = false;
  47.  
  48.     // check for totally bogus empty case
  49.     if (mPoints.empty())
  50.         return interpPt;
  51.  
  52.     // find enclosing points
  53.     PointList::const_iterator it2(UpperBound(x));
  54.  
  55.     // check if requested sample is prior to first point
  56.     if (it2 == mPoints.begin()) {
  57.         interpPt.mY = it2->mY;
  58.         interpPt.mbLinear = it2->mbLinear;
  59.         return interpPt;
  60.     }
  61.  
  62.     // compute lower point
  63.     PointList::const_iterator it1(it2);
  64.     --it1;
  65.  
  66.     // check if requested sample is after last point
  67.     const Point& p1 = *it1;
  68.     if (it2 == mPoints.end()) {
  69.         interpPt.mY = p1.mY;
  70.         interpPt.mbLinear = p1.mbLinear;
  71.         return interpPt;
  72.     }
  73.  
  74.     // interpolate
  75.     const Point& p2 = *it2;
  76.  
  77.     if (p1.mbLinear || fabs(p1.mX - p2.mX) < 0.01f) {
  78.         double t = 0.0f;
  79.         double xdel = p2.mX - p1.mX;
  80.         double ydel = p2.mY - p1.mY;
  81.  
  82.         if (fabs(xdel) > 1e-5)
  83.             t = (x - p1.mX) / xdel;
  84.  
  85.         interpPt.mY = p1.mY + ydel*t;
  86.         interpPt.mbLinear = true;
  87.     } else {
  88.         // grab two outer points
  89.         PointList::const_iterator it0(it1);
  90.         if (it0 != mPoints.begin())
  91.             --it0;
  92.  
  93.         PointList::const_iterator it3(it2);
  94.         ++it3;
  95.         if (it3 == mPoints.end())
  96.             --it3;
  97.  
  98.         const Point& p0 = *it0;
  99.         const Point& p3 = *it3;
  100.  
  101.         double x0 = p0.mX;
  102.         double x1 = p1.mX;
  103.         double x2 = p2.mX;
  104.         double x3 = p3.mX;
  105.  
  106.         double y0 = p0.mY;
  107.         double y1 = p1.mY;
  108.         double y2 = p2.mY;
  109.         double y3 = p3.mY;
  110.  
  111.         if (fabs(x0 - x1) < 0.01f)
  112.             x0 = x1 - 0.01f;
  113.  
  114.         if (fabs(x2 - x3) < 0.01f)
  115.             x3 = x2 + 0.01f;
  116.  
  117.         // Rebias points by p0. Not only does this simplify the solve, but it also reduces numerical
  118.         // accuracy issues.
  119.  
  120.         double dx2 = x2 - x1;
  121.         double dy2 = y2 - y1;
  122.         double m1 = (y2-y0)/(x2-x0);
  123.         double m2 = (y3-y1)/(x3-x1);
  124.  
  125.         double YA = (m2 + m1 - dy2/dx2*2)/dx2/dx2;
  126.         double YB = (3*dy2/dx2 - 2*m1 - m2)/dx2;
  127.         double YC = m1;
  128.         double YD = y1;
  129.  
  130.         double t = x - x1;
  131.  
  132.         interpPt.mY = ((YA*t+YB)*t+YC)*t+YD;
  133.         if (interpPt.mY < mMinVal)
  134.             interpPt.mY = mMinVal;
  135.         if (interpPt.mY > mMaxVal)
  136.             interpPt.mY = mMaxVal;
  137.         interpPt.mbLinear = false;
  138.     }
  139.  
  140.     return interpPt;
  141. }
  142.  
  143. VDParameterCurve::PointList::iterator VDParameterCurve::GetNearestPointX(double x) {
  144.     return mPoints.begin() + (static_cast<const VDParameterCurve *>(this)->GetNearestPointX(x) - mPoints.begin());
  145. }
  146.  
  147. VDParameterCurve::PointList::const_iterator VDParameterCurve::GetNearestPointX(double x) const {
  148.     PointList::const_iterator it1(LowerBound(x));
  149.  
  150.     if (it1 == mPoints.end())
  151.         return it1;
  152.  
  153.     PointList::const_iterator it2(it1);
  154.     ++it2;
  155.  
  156.     if (it2 != mPoints.end()) {
  157.         const Point& pt1 = *it1;
  158.         const Point& pt2 = *it2;
  159.  
  160.         if ((pt2.mX - x) < (x - pt1.mX))
  161.             it1 = it2;
  162.     }
  163.  
  164.     return it1;
  165. }
  166.  
  167. VDParameterCurve::PointList::iterator VDParameterCurve::GetNearestPoint2D(double x, double y, double xRadius, double yScale) {
  168.     return mPoints.begin() + (static_cast<const VDParameterCurve *>(this)->GetNearestPoint2D(x, y, xRadius, yScale) - mPoints.begin());    
  169. }
  170.  
  171. VDParameterCurve::PointList::const_iterator VDParameterCurve::GetNearestPoint2D(double x, double y, double xRadius, double yScale) const {
  172.     PointList::const_iterator it1(LowerBound(x - xRadius));
  173.     PointList::const_iterator it2(LowerBound(x + xRadius));
  174.  
  175.     if (it2 != mPoints.end())
  176.         ++it2;
  177.  
  178.     PointList::const_iterator itBest(mPoints.end());
  179.     double bestDist2 = xRadius * xRadius;
  180.     for(; it1!=it2; ++it1) {
  181.         const Point& pt = *it1;
  182.  
  183.         double distX = (pt.mX - x);
  184.         double distY = (pt.mY - y) * yScale;
  185.         double dist2 = distX*distX + distY*distY;
  186.  
  187.         if (dist2 < bestDist2) {
  188.             bestDist2 = dist2;
  189.             itBest = it1;
  190.         }
  191.     }
  192.  
  193.     return itBest;
  194. }
  195.  
  196. VDParameterCurve::PointList::iterator VDParameterCurve::LowerBound(double x) {
  197.     return mPoints.begin() + (static_cast<const VDParameterCurve *>(this)->LowerBound(x) - mPoints.begin());
  198. }
  199.  
  200. VDParameterCurve::PointList::const_iterator VDParameterCurve::LowerBound(double x) const {
  201.     int lo = 0;
  202.     if (!mPoints.empty()) {
  203.         int hi = (uint32)mPoints.size() - 1;
  204.  
  205.         while(lo < hi) {
  206.             uint32 mid = (lo + hi) >> 1;
  207.             double xmid = mPoints[mid].mX;
  208.  
  209.             if (xmid < x)
  210.                 lo = mid+1;
  211.             else if (xmid >= x)
  212.                 hi = mid;
  213.         }
  214.  
  215.         if (mPoints[lo].mX < x)
  216.             ++lo;
  217.     }
  218.  
  219.     return mPoints.begin() + lo;
  220. }
  221.  
  222. VDParameterCurve::PointList::iterator VDParameterCurve::UpperBound(double x) {
  223.     return mPoints.begin() + (static_cast<const VDParameterCurve *>(this)->UpperBound(x) - mPoints.begin());
  224. }
  225.  
  226. VDParameterCurve::PointList::const_iterator VDParameterCurve::UpperBound(double x) const {
  227.     int lo = 0;
  228.     if (!mPoints.empty()) {
  229.         int hi = (uint32)mPoints.size() - 1;
  230.  
  231.         while(lo < hi) {
  232.             uint32 mid = (lo + hi) >> 1;
  233.             double xmid = mPoints[mid].mX;
  234.  
  235.             if (xmid <= x)
  236.                 lo = mid+1;
  237.             else if (xmid > x)
  238.                 hi = mid;
  239.         }
  240.  
  241.         if (mPoints[lo].mX <= x)
  242.             ++lo;
  243.     }
  244.  
  245.     return mPoints.begin() + lo;
  246. }
  247.