/****************************************************************************
** GMAF - The Geometry Modeling Algorithms Framework
**
** Created : 04092000
**
** Copyright (C) 2000 by Le-Jeng Shiue.  All rights reserved.
**
****************************************************************************/
#ifndef gmafCCSEdgeValueIterator_H
#define gmafCCSEdgeValueIterator_H

#include "BlitzExtension/blitzConfig.h"
#include "gmafQuad.h"

#include "gmafEdgeValueIterator.h"
/**
   gmafEdgeValueIterator: It will calculate the value of the edge by 
   CC subdivision sabin rule. It will traverse the vertical edge vertices 
   first and horizontal then.
   Ex. QuadArray = 1 2 3 4 (Assume 1,4 are valid corners)
                   5 6 7 8
		   9 a b c
		   d e f g
   This itr will traverse this quad in following order: 
   e26 : (ref. to sabin rules -- see Siggraph proceedings 99, page 62)
   e37 : ...
   e59 : ...
   e6a :
   e7b :
   e8c :
*/
class gmafCCSEdgeValueIterator : public gmafEdgeValueIterator {
// ENUMS
public:

// VARIABLES
/**@name Class Variables */
//@{
protected:
private:

//@}

// METHODS
/**@name Class Methods */
//@{
public:
  /**
     Constructor of gmafCCSEdgeValueIterator
     it will traverse the 4 corners if they are valance 4
  */    
  gmafCCSEdgeValueIterator(gmafQuad* q);
  /**
     Destructor of gmafCCSEdgeValueIterator
  */
  virtual ~gmafCCSEdgeValueIterator();
  
  inline virtual const Vertex3D& current() const; // return the edge value
  
protected:
  
private:
  // if return -1, it's not adjacent to any corner
  // if return 0,1,2,3, c will contain the corner vertex
  inline int adjacentCorner(Position2D& pos, Vertex3D& c) const;
};

//---------------------------------------------------------
inline gmafCCSEdgeValueIterator::gmafCCSEdgeValueIterator(gmafQuad* q) 
  : gmafEdgeValueIterator(q) {
}

inline gmafCCSEdgeValueIterator::~gmafCCSEdgeValueIterator() {
}

inline int gmafCCSEdgeValueIterator::
adjacentCorner(Position2D& pos, Vertex3D& c) const {
  int h = mQM.rows();
  int w = mQM.cols();
  if (mVCurPos < mVEndPos) {
    if (pos(0) == 1 && pos(1) == 1)
      { c = mQM(1,1); return 0; }// ul 
    else if (pos(0) == h-3 && pos(1) == 1)
      { c = mQM(h-2, 1);  return 1; }// ll
    else if (pos(0) == h-3 && pos(1) == w-2) 
      { c = mQM(h-2, w-2);  return 2; }// lr
    else if (pos(0) == 1 && pos(1) == w-2) 
      { c = mQM(1, w-2);  return 3; }// ur
  } else {
    if (pos(0) == 1 && pos(1) == 1)
      { c = mQM(1,1); return 0; }// ul 
    else if (pos(0) == h-2 && pos(1) == 1) 
      { c = mQM(h-2, 1);  return 1; }// ll
    else if (pos(0) == h-2 && pos(1) == w-3)
      { c = mQM(h-2, w-2);  return 2; }// lr
    else if (pos(0) == 1 && pos(1) == w-3) 
      { c = mQM(1, w-2);  return 3; }// ur
  }
  return -1;
}


inline const Vertex3D& gmafCCSEdgeValueIterator::current() const {
  const static double Wn[8] = {0, 0, 0, 1.236068, 1.0, 0.7185, 0.5223333, 0.391842565};
  gmafCCSEdgeValueIterator* me = (gmafCCSEdgeValueIterator*)this;
  Vertex3D f, e;
  Position2D pos;
  VertexMatrix2D vm;
  if (mVCurPos < mVEndPos) {
    pos = mVCurItr.position();
    pos(1) += 1;
    Range r1(pos(0), pos(0)+1);
    Range r2(pos(1)-1, pos(1)+1);
    vm.reference(mQM(r1,r2));
    e = vm(0,1) + vm(1,1);
    f = vm(0,0) + vm(0,2) + vm(1,0) + vm(1,2);
  } else {
    pos = mHCurItr.position();
    pos(0) += 1;
    Range r1(pos(0)-1, pos(0)+1);
    Range r2(pos(1), pos(1)+1);
    vm.reference(mQM(r1,r2));
    e = vm(1,0) + vm(1,1);
    f = vm(0,0) + vm(0,1) + vm(2,0) + vm(2,1);
  }

  Vertex3D corner;
  int c = adjacentCorner(pos, corner);
  if (c != -1 && mpQuad->getCornerValance(c) != 4) {
    double w = Wn[mpQuad->getCornerValance(c)];
    e -= corner;
    e += (w*corner);
    me->mCurValue = (e*6 + f)/(4 + 6*(1+w));
  } else me->mCurValue = (e*6 + f) / 16;
  return mCurValue;
}

#endif gmafCCSEdgeValueIterator_H

