// ------------------------------------------------------------------
// qpatchmath.h
//
// This file contains the class used for math operations on 
// bezier patches.
// ------------------------------------------------------------------
// Author: Stephen A. Vavasis
// Copyright (c) 1999 by Cornell University.  All rights reserved.
// 
// See the accompanying file 'Copyright' for authorship information,
// the terms of the license governing this software, and disclaimers
// concerning this software.
// ------------------------------------------------------------------
// This file is part of the QMG software.  
// Version 2.0 of QMG, release date September 3, 1999.
// ------------------------------------------------------------------

#ifndef QPATCHMATH_H
#define QPATCHMATH_H

#include "qnamesp.h"
#include "qpoint.h"
#include "doubledouble2.h"



// ------------------------------------------------------------------
// Abstract base class PatchMath.
// Derived class must provide an implementation of control_point_coord_
// to specify the patch's control points.

class QMG::PatchMath {
public:
  struct IntersectRecord {
    Point realcoord;
    Point paramcoord;
    Real dist;
    Real param_uncertainty;
    Real param_uncertainty_seg;
    bool degen;
    IntersectRecord() { }
    ~IntersectRecord() { }
  };
  class Bezier_Helper;
  friend class Bezier_Helper;

  class Workspace {
  private:
    vector<Real> rwkspa_;
    vector<std::complex<double> > cwkspa_;
    vector<doubledouble> ddwkspa_;
    int marker_active_;
    // no copying, no assignment
    Workspace(const Workspace&)  { }
    void operator=(const Workspace&) { }
  public:
    Workspace() : marker_active_(false) { }
    ~Workspace() { }

    // All of the following are in qpatchmath.cpp.
    class DoubleDoubleVector;
    class ComplexVector;
    class RealVector;
    class ComplexMatrix;
    class RealMatrix;
    class StartPosMarker;
    friend class DoubleDoubleVector;
    friend class ComplexVector;
    friend class RealVector;
    friend class ComplexMatrix;
    friend class RealMatrix;
    friend class StartPosMarker;
  };

private:

  virtual Real control_point_coord_(int cpindex, int d) const = 0;
  PatchType ptype_;
  int degree1_;
  int degree2_;
  int gdim_;
  int di_;
  bool is_forward_;

public:
  PatchMath(PatchType ptype, 
    int degree1, 
    int degree2, 
    int intrinsic_dim,
    int embedded_dim,
    bool is_forward) :
  ptype_(ptype),
    degree1_(degree1),
    degree2_(degree2),
    gdim_(intrinsic_dim),
    di_(embedded_dim),
    is_forward_(is_forward)
  { }
  virtual ~PatchMath() { }

  // 

  // Intersect a segment with a patch (or curve in 2D)

  void intersect_seg(vector<IntersectRecord>& output_stack,
    Workspace& workspace,
    const Point& startpoint,
    const Point& endpoint,
    double scfac,
    double tol,
    bool newton_improve) const;

  
  // Intersect a line with a patch (or curve in 2D).

  void intersect_line(vector<IntersectRecord>& output_stack,
    Workspace& workspace,
    const Matrix& lineeq,
    const Point& linerhs,
    double scfac,
    double tol,
    bool newton_improve) const;

  // Intersect a plane with a curve.
  void intersect_plane(vector<IntersectRecord>& output_stack,
    Workspace& workspace,
    const Point& plane_normal,
    Real rhs,
    double scfac,
    double tol,
    bool newton_improve) const;

  // Get extreme points in a certain direction.
  void get_extreme_points(vector<IntersectRecord>& output_stack,
    Workspace& workspace,
    const Point& direc,
    double scfac,
    double tol) const;

  // Get the real coordinates from parametric coordinates.
  Point get_real_point(const Point& paramcoord) const;

  // Get the patch normal.
  Point normal(const Point& paramcoord) const;

  // Get the patch directional derivative.
  Point direc_deriv(const Point& paramcoord, 
    const Point& direc) const;
  
  // Get the normal at the barycenter.
  Point normal_at_barycenter() const;

  // Get the parametric coordinates of the barycenter.
  Point barycenter_param() const;

  // Get the patch number of control points.
  int num_control_points() const;
};

#endif

