# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1484250015 -3600
#      Thu Jan 12 20:40:15 2017 +0100
# Node ID afa9f0e6adbdc58a428b128348eb49760a4966d0
# Parent  29ea25593dd71b92e59386a73f6c25113ce5c179
wip, Add new constraints (finite_type).

diff -r 29ea25593dd7 -r afa9f0e6adbd libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Tue Jan 10 09:39:56 2017 +0100
+++ b/libinterp/corefcn/graphics.cc	Thu Jan 12 20:40:15 2017 +0100
@@ -1461,6 +1461,54 @@
         }
     }
 
+  if (xok)
+    {
+      Matrix v_mat = v.matrix_value ();
+      // Check min and max
+      if (! octave::math::isnan (minval.first))
+        {
+          for (octave_idx_type i = 0; i < v_mat.numel (); i++)
+            if (minval.second && minval.first > v_mat(i))
+              error ("set: \"%s\" must be greater than or equal to %g",
+                     get_name ().c_str (), minval.first);
+            else if (! minval.second && minval.first >= v_mat(i))
+              error ("set: \"%s\" must be greater than %g",
+                     get_name ().c_str (), minval.first);
+        }
+
+      if (! octave::math::isnan (maxval.first))
+        {
+          for (octave_idx_type i = 0; i < v_mat.numel (); i++)
+            if (maxval.second && maxval.first < v_mat(i))
+              error ("set: \"%s\" must be less than or equal to %g",
+                     get_name ().c_str (), maxval.first);
+            else if (! maxval.second && maxval.first <= v_mat(i))
+              error ("set: \"%s\" must be less than %g",
+                     get_name ().c_str (), maxval.first);
+        }
+
+      if (finite_constraint == NO_CHECK) { /* do nothing */ }
+      else if (finite_constraint == FINITE)
+        {
+          for (octave_idx_type i = 0; i < v_mat.numel (); i++)
+            if (! octave::math::finite (v_mat(i)))
+              error ("set: \"%s\" must be finite", get_name ().c_str ());
+        }
+      else if (finite_constraint == NOT_NAN)
+        {
+          for (octave_idx_type i = 0; i < v_mat.numel (); i++)
+            if (octave::math::isnan (v_mat(i)))
+              error ("set: \"%s\" must not be nan", get_name ().c_str ());
+        }
+      else if (finite_constraint == NOT_INF)
+        {
+          for (octave_idx_type i = 0; i < v_mat.numel (); i++)
+            if (octave::math::isinf (v_mat(i)))
+              error ("set: \"%s\" must not be infinite", get_name ().c_str ());
+        }
+
+    }
+
   return xok;
 }
 
@@ -4520,28 +4568,43 @@
   looseinset.add_constraint (dim_vector (1, 4));
   colororder.add_constraint (dim_vector (-1, 3));
   dataaspectratio.add_constraint (dim_vector (1, 3));
+  dataaspectratio.add_constraint ("min", 0, false);
+  dataaspectratio.add_constraint (FINITE);
   plotboxaspectratio.add_constraint (dim_vector (1, 3));
+  plotboxaspectratio.add_constraint ("min", 0, false);
+  plotboxaspectratio.add_constraint (FINITE);
   // FIXME: Should these use dimension vectors?  Currently can set 'xlim' to
   // any matrix size, but only first two elements are used.
   alim.add_constraint (2);
+  alim.add_constraint (NOT_NAN);
   clim.add_constraint (2);
+  clim.add_constraint (NOT_NAN);
   xlim.add_constraint (2);
+  xlim.add_constraint (NOT_NAN);
   ylim.add_constraint (2);
+  ylim.add_constraint (NOT_NAN);
   zlim.add_constraint (2);
+  zlim.add_constraint (NOT_NAN);
   xtick.add_constraint (dim_vector (1, -1));
+  xtick.add_constraint (FINITE);
   ytick.add_constraint (dim_vector (1, -1));
+  ytick.add_constraint (FINITE);
   ztick.add_constraint (dim_vector (1, -1));
+  ztick.add_constraint (FINITE);
   ticklength.add_constraint (dim_vector (1, 2));
   Matrix vw (1, 2, 0);
   vw(1) = 90;
   view = vw;
   view.add_constraint (dim_vector (1, 2));
   cameraposition.add_constraint (dim_vector (1, 3));
+  cameraposition.add_constraint (FINITE);
   cameratarget.add_constraint (dim_vector (1, 3));
+  cameratarget.add_constraint (FINITE);
   Matrix upv (1, 3, 0.0);
   upv(2) = 1.0;
   cameraupvector = upv;
   cameraupvector.add_constraint (dim_vector (1, 3));
+  cameraupvector.add_constraint (FINITE);
   currentpoint.add_constraint (dim_vector (2, 3));
 
   // Range constraints for double properties
diff -r 29ea25593dd7 -r afa9f0e6adbd libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Tue Jan 10 09:39:56 2017 +0100
+++ b/libinterp/corefcn/graphics.in.h	Thu Jan 12 20:40:15 2017 +0100
@@ -1149,18 +1149,26 @@
 
 // ---------------------------------------------------------------------
 
+enum finite_type
+{
+  NO_CHECK,
+  FINITE,
+  NOT_NAN,
+  NOT_INF
+};
 class double_property : public base_property
 {
 public:
   double_property (const std::string& nm, const graphics_handle& h,
                    double d = 0)
     : base_property (nm, h),
-      current_val (d),
+      current_val (d), finite_constraint (NO_CHECK),
       minval (std::pair<double, bool> (octave_NaN, true)),
       maxval (std::pair<double, bool> (octave_NaN, true)) { }
 
   double_property (const double_property& p)
     : base_property (p), current_val (p.current_val),
+      finite_constraint (NO_CHECK),
       minval (std::pair<double, bool> (octave_NaN, true)),
       maxval (std::pair<double, bool> (octave_NaN, true)) { }
 
@@ -1174,7 +1182,16 @@
     return *this;
   }
 
-  base_property* clone (void) const { return new double_property (*this); }
+  base_property* clone (void) const
+  {
+    double_property *p = new double_property (*this);
+
+    p->finite_constraint = finite_constraint;
+    p->minval = minval;
+    p->maxval = maxval;
+
+    return p;
+  }
 
   void add_constraint (const std::string& type, double val, bool inclusive)
   {
@@ -1184,6 +1201,10 @@
       maxval = std::pair<double, bool> (val, inclusive);
   }
 
+  void add_constraint (const finite_type finite)
+  { finite_constraint = finite; }
+
+
 protected:
   bool do_set (const octave_value& v)
   {
@@ -1214,6 +1235,23 @@
                  get_name ().c_str (), maxval.first);
       }
 
+      if (finite_constraint == NO_CHECK) { /* do nothing */ }
+      else if (finite_constraint == FINITE)
+        {
+          if (! octave::math::finite (new_val))
+            error ("set: \"%s\" must be finite", get_name ().c_str ());
+        }
+      else if (finite_constraint == NOT_NAN)
+        {
+          if (octave::math::isnan (new_val))
+            error ("set: \"%s\" must not be nan", get_name ().c_str ());
+        }
+      else if (finite_constraint == NOT_INF)
+        {
+          if (octave::math::isinf (new_val))
+            error ("set: \"%s\" must not be infinite", get_name ().c_str ());
+        }
+
     if (new_val != current_val)
       {
         current_val = new_val;
@@ -1225,6 +1263,9 @@
 
 private:
   double current_val;
+
+protected:
+  finite_type finite_constraint;
   std::pair<double, bool> minval, maxval;
 };
 
@@ -1318,7 +1359,9 @@
   array_property (void)
     : base_property ("", graphics_handle ()), data (Matrix ()),
       xmin (), xmax (), xminp (), xmaxp (),
-      type_constraints (), size_constraints ()
+      type_constraints (), size_constraints (), finite_constraint (NO_CHECK),
+      minval (std::pair<double, bool> (octave_NaN, true)),
+      maxval (std::pair<double, bool> (octave_NaN, true))
   {
     get_data_limits ();
   }
@@ -1327,7 +1370,9 @@
                   const octave_value& m)
     : base_property (nm, h), data (m.is_sparse_type () ? m.full_value () : m),
       xmin (), xmax (), xminp (), xmaxp (),
-      type_constraints (), size_constraints ()
+      type_constraints (), size_constraints (), finite_constraint (NO_CHECK),
+      minval (std::pair<double, bool> (octave_NaN, true)),
+      maxval (std::pair<double, bool> (octave_NaN, true))
   {
     get_data_limits ();
   }
@@ -1338,7 +1383,9 @@
   array_property (const array_property& p)
     : base_property (p), data (p.data),
       xmin (p.xmin), xmax (p.xmax), xminp (p.xminp), xmaxp (p.xmaxp),
-      type_constraints (), size_constraints ()
+      type_constraints (), size_constraints (), finite_constraint (NO_CHECK),
+      minval (std::pair<double, bool> (octave_NaN, true)),
+      maxval (std::pair<double, bool> (octave_NaN, true))
   { }
 
   octave_value get (void) const { return data; }
@@ -1349,6 +1396,17 @@
   void add_constraint (const dim_vector& dims)
   { size_constraints.push_back (dims); }
 
+  void add_constraint (const finite_type finite)
+  { finite_constraint = finite; }
+
+  void add_constraint (const std::string& type, double val, bool inclusive)
+  {
+    if (type == "min")
+      minval = std::pair<double, bool> (val, inclusive);
+    else if (type == "max")
+      maxval = std::pair<double, bool> (val, inclusive);
+  }
+
   double min_val (void) const { return xmin; }
   double max_val (void) const { return xmax; }
   double min_pos (void) const { return xminp; }
@@ -1378,6 +1436,9 @@
 
     p->type_constraints = type_constraints;
     p->size_constraints = size_constraints;
+    p->finite_constraint = finite_constraint;
+    p->minval = minval;
+    p->maxval = maxval;
 
     return p;
   }
@@ -1419,6 +1480,8 @@
   double xmaxp;
   std::set<std::string> type_constraints;
   std::list<dim_vector> size_constraints;
+  finite_type finite_constraint;
+  std::pair<double, bool> minval, maxval;
 };
 
 class row_vector_property : public array_property
@@ -1451,6 +1514,16 @@
     array_property::add_constraint (dims);
   }
 
+  void add_constraint (const finite_type finite)
+  {
+    array_property::add_constraint (finite);
+  }
+
+  void add_constraint (const std::string& type, double val, bool inclusive)
+  {
+    array_property::add_constraint (type, val, inclusive);
+  }
+
   void add_constraint (octave_idx_type len)
   {
     size_constraints.remove (dim_vector (1, -1));
@@ -3492,11 +3565,15 @@
       alphamap.add_constraint (dim_vector (-1, 1));
       colormap.add_constraint (dim_vector (-1, 3));
       outerposition.add_constraint (dim_vector (1, 4));
+      outerposition.add_constraint (FINITE);
       paperposition.add_constraint (dim_vector (1, 4));
+      paperposition.add_constraint (FINITE);
       papersize.add_constraint (dim_vector (1, 2));
+      papersize.add_constraint (FINITE);
       pointershapecdata.add_constraint (dim_vector (16, 16));
       pointershapehotspot.add_constraint (dim_vector (1, 2));
       position.add_constraint (dim_vector (1, 4));
+      position.add_constraint (FINITE);
     }
 
   private:
@@ -3867,7 +3944,7 @@
       array_property colororder , default_colororder ()
       double_property colororderindex , 1.0
       array_property currentpoint , Matrix (2, 3, 0.0)
-      array_property dataaspectratio mu , Matrix (1, 3, 1.0)
+      row_vector_property dataaspectratio mu , Matrix (1, 3, 1.0)
       radio_property dataaspectratiomode u , "{auto}|manual"
       radio_property drawmode , "{normal}|fast"
       radio_property fontangle u , "{normal}|italic"
@@ -3894,7 +3971,7 @@
       radio_property minorgridlinestyle , "{:}|-|--|-.|none"
       radio_property nextplot , "{replace}|add|replacechildren"
       array_property outerposition u , default_axes_outerposition ()
-      array_property plotboxaspectratio mu , Matrix (1, 3, 1.0)
+      row_vector_property plotboxaspectratio mu , Matrix (1, 3, 1.0)
       radio_property plotboxaspectratiomode u , "{auto}|manual"
       radio_property pickableparts , "{visible}|all|none"
       array_property position u , default_axes_position ()
