<commit_before>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

    Lasercake is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Lasercake is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_BBOX_COLLISION_DETECTOR_HPP__
#define LASERCAKE_BBOX_COLLISION_DETECTOR_HPP__

#include <boost/integer.hpp>
#include <unordered_map>
#include <unordered_set>
#include <array>
#include <cassert>
#include <cstdlib>

using std::unordered_map;
using std::unordered_set;

typedef size_t num_bits_type;
typedef size_t num_coordinates_type;

// ObjectIdentifier needs hash and == and to be freely copiable. So, ints will do, pointers will do...
// coordinate_bits should usually be 32 or 64. I don't know if it works for other values.
template<typename ObjectIdentifier, num_bits_type coordinate_bits, num_coordinates_type num_dimensions>
class bbox_collision_detector {
  static_assert(num_dimensions >= 0, "You can't make a space with negative dimensions!");
  static_assert(coordinate_bits >= 0, "You can't have an int type with negative bits!");
  friend class zbox_tester;

public:
  typedef typename boost::uint_t<coordinate_bits>::fast Coordinate;
  struct bounding_box {
    std::array<Coordinate, num_dimensions> min, size;
    bool overlaps(bounding_box const& other)const {
      for (num_coordinates_type i = 0; i < num_dimensions; ++i) {
        // this should correctly handle zboxes' "size=0" when all bits are ignored
        if (other.min[i] + (other.size[i] - 1) <       min[i]) return false;
        if (      min[i] + (      size[i] - 1) < other.min[i]) return false;
      }
      return true;
    }
  };

  bbox_collision_detector():objects_tree(nullptr){}

private:
  static const num_bits_type total_bits = coordinate_bits * num_dimensions;

  static Coordinate safe_left_shift_one(num_bits_type shift) {
    if (shift >= 8*sizeof(Coordinate)) return 0;
    return Coordinate(1) << shift; // TODO address the fact that this could put bits higher than the appropriate amount if coordinate_bits isn't the number of bits of the type
  }

  struct zbox {
    // We ensure that every bit except the ones specifically supposed to be on is off.
    std::array<Coordinate, num_dimensions> coords;
    std::array<Coordinate, num_dimensions> interleaved_bits;
    num_bits_type num_low_bits_ignored;

    zbox():num_low_bits_ignored(total_bits){ for (num_coordinates_type i = 0; i < num_dimensions; ++i) interleaved_bits[i] = 0; }

    bool subsumes(zbox const& other)const {
      if (other.num_low_bits_ignored > num_low_bits_ignored) return false;
      for (num_coordinates_type i = num_low_bits_ignored / coordinate_bits; i < num_dimensions; ++i) {
        Coordinate mask = ~Coordinate(0);
        if (i == num_low_bits_ignored / coordinate_bits) {
          mask &= ~(safe_left_shift_one(num_low_bits_ignored % coordinate_bits) - 1);
        }
        if ((interleaved_bits[i] & mask) != (other.interleaved_bits[i] & mask)) return false;
      }
      return true;
    }
    bool get_bit(num_bits_type bit)const {
      return interleaved_bits[bit / coordinate_bits] & safe_left_shift_one(bit % coordinate_bits);
    }
    num_bits_type num_bits_ignored_by_dimension(num_coordinates_type dim)const {
      return (num_low_bits_ignored + (num_dimensions - 1) - dim) / num_dimensions;
    }
    // note: gives "size=0" for max-sized things
    bounding_box get_bbox()const {
      bounding_box result;
      result.min = coords;
      for (num_coordinates_type i = 0; i < num_dimensions; ++i) {
        result.size[i] = safe_left_shift_one(num_bits_ignored_by_dimension(i));
      }
      return result;
    }
  };

  static int idx_of_highest_bit(Coordinate i) {
    int upper_bound = coordinate_bits;
    int lower_bound = -1;
    while(true) {
      int halfway_bit_idx = (upper_bound + lower_bound) >> 1;
      if (halfway_bit_idx == lower_bound) return lower_bound;

      if (i & ~(safe_left_shift_one(halfway_bit_idx) - 1)) lower_bound = halfway_bit_idx;
      else                                                 upper_bound = halfway_bit_idx;
    }
  }

  struct ztree_node {
    zbox here;
    ztree_node *child0;
    ztree_node *child1;
    unordered_set<ObjectIdentifier> objects_here;

    ztree_node(zbox box):here(box),child0(nullptr),child1(nullptr){}
  };

  static zbox smallest_joint_parent(zbox zb1, zbox zb2) {
    zbox new_box;
    for (int /* hack... TODO, should possibly be num_coordinates_type, but signed? */ i = num_dimensions - 1; i >= 0; --i) {
      const int highest_bit_idx = idx_of_highest_bit(zb1.interleaved_bits[i] ^ zb2.interleaved_bits[i]);
      assert((zb1.interleaved_bits[i] & ~((safe_left_shift_one(highest_bit_idx+1)) - 1)) == (zb2.interleaved_bits[i] & ~((safe_left_shift_one(highest_bit_idx+1)) - 1)));
      new_box.interleaved_bits[i] = (zb1.interleaved_bits[i]) & (~((safe_left_shift_one(highest_bit_idx + 1)) - 1));
      if (highest_bit_idx >= 0) {
        new_box.num_low_bits_ignored = highest_bit_idx+1 + i * coordinate_bits;
        for (num_coordinates_type j = 0; j < num_dimensions; ++j) {
          assert(             (zb1.coords[j] & ~(safe_left_shift_one(new_box.num_bits_ignored_by_dimension(j)) - 1))
                           == (zb2.coords[j] & ~(safe_left_shift_one(new_box.num_bits_ignored_by_dimension(j)) - 1)));
          new_box.coords[j] = zb1.coords[j] & ~(safe_left_shift_one(new_box.num_bits_ignored_by_dimension(j)) - 1);
        }
        return new_box;
      }
    }
    new_box.num_low_bits_ignored = 0;
    assert(zb1.coords == zb2.coords);
    new_box.coords = zb1.coords;
    return new_box;
  }

  static zbox box_from_coords(std::array<Coordinate, num_dimensions> const& coords, num_bits_type num_low_bits_ignored) {
    zbox result;
    result.num_low_bits_ignored = num_low_bits_ignored;
    for (num_coordinates_type i = 0; i < num_dimensions; ++i) {
      result.coords[i] = coords[i] & (~(safe_left_shift_one(result.num_bits_ignored_by_dimension(i)) - 1));
    }
    for (num_bits_type bit_within_interleaved_bits = num_low_bits_ignored;
                       bit_within_interleaved_bits < total_bits;
                     ++bit_within_interleaved_bits) {
      const num_bits_type bit_idx_within_coordinates = bit_within_interleaved_bits / num_dimensions;
      const num_coordinates_type which_coordinate    = bit_within_interleaved_bits % num_dimensions;
      const num_bits_type interleaved_bit_array_idx  = bit_within_interleaved_bits / coordinate_bits;
      const num_bits_type interleaved_bit_local_idx  = bit_within_interleaved_bits % coordinate_bits;
      assert(bit_idx_within_coordinates >= result.num_bits_ignored_by_dimension(which_coordinate));
      result.interleaved_bits[interleaved_bit_array_idx] |= ((coords[which_coordinate] >> bit_idx_within_coordinates) & 1) << interleaved_bit_local_idx;
    }
    return result;
  }

  static void insert_box(ztree_node*& tree, ObjectIdentifier obj, zbox box) {
    if (!tree) {
      tree = new ztree_node(box);
      tree->objects_here.insert(obj);
    }
    else {
      if (tree->here.subsumes(box)) {
        if (box.num_low_bits_ignored == tree->here.num_low_bits_ignored) {
          tree->objects_here.insert(obj);
        }
        else {
          if (box.get_bit(tree->here.num_low_bits_ignored - 1)) insert_box(tree->child1, obj, box);
          else                                                  insert_box(tree->child0, obj, box);
        }
      }
      else {
        ztree_node *new_tree = new ztree_node(smallest_joint_parent(tree->here, box));
        assert(new_tree->here.num_low_bits_ignored > tree->here.num_low_bits_ignored);
        assert(new_tree->here.subsumes(tree->here));
        assert(new_tree->here.subsumes(box));
        assert(tree->here.get_bit(new_tree->here.num_low_bits_ignored - 1) != box.get_bit(new_tree->here.num_low_bits_ignored - 1));
        if (tree->here.get_bit(new_tree->here.num_low_bits_ignored - 1)) new_tree->child1 = tree;
        else                                                             new_tree->child0 = tree;

        tree = new_tree;
        insert_box(tree, obj, box);
      }
    }
  }

  static void delete_object(ztree_node*& tree, ObjectIdentifier obj, bounding_box const& bbox) {
    if (!tree) return;
    if (tree->here.get_bbox().overlaps(bbox)) {
      tree->objects_here.erase(obj);
      delete_object(tree->child0, obj, bbox);
      delete_object(tree->child1, obj, bbox);

      if (tree->objects_here.empty()) {
        if (tree->child0) {
          if (!tree->child1) {
            tree = tree->child0;
          }
        }
        else tree = tree->child1; // which could be null
      }
    }
  }

  void zget_objects_overlapping(ztree_node const* tree, unordered_set<ObjectIdentifier>& results, bounding_box const& bbox)const {
    if (tree && tree->here.get_bbox().overlaps(bbox)) {
      for (const ObjectIdentifier obj : tree->objects_here) {
        auto bbox_iter = bboxes_by_object.find(obj);
        assert(bbox_iter != bboxes_by_object.end());
        if (bbox_iter->second.overlaps(bbox)) results.insert(obj);
      }
      zget_objects_overlapping(tree->child0, results, bbox);
      zget_objects_overlapping(tree->child1, results, bbox);
    }
  }

  unordered_map<ObjectIdentifier, bounding_box> bboxes_by_object;
  ztree_node* objects_tree;

public:

  void insert(ObjectIdentifier id, bounding_box const& bbox) {
    bboxes_by_object.insert(std::make_pair(id, bbox));
    Coordinate max_dim = bbox.size[0];
    for (num_coordinates_type i = 1; i < num_dimensions; ++i) {
      if (bbox.size[i] > max_dim) max_dim = bbox.size[i];
    }
    int exp = 0; while ((Coordinate(1) << exp) < max_dim) ++exp;
    int dimensions_we_can_single = 0;
    int dimensions_we_can_double = 0;
    const Coordinate base_box_size = safe_left_shift_one(exp);
    const Coordinate used_bits_mask = ~(base_box_size - 1);

    for (int i = num_dimensions - 1; i >= 0; --i) {
      if ((bbox.min[i] & used_bits_mask) + base_box_size >= bbox.min[i] + bbox.size[i]) ++dimensions_we_can_single;
      else break;
    }
    for (num_coordinates_type i = 0; i < num_dimensions - dimensions_we_can_single; ++i) {
      if (!(bbox.min[i] & base_box_size)) ++dimensions_we_can_double;
      else break;
    }
#ifdef ZTREE_TESTING
    std::cerr << dimensions_we_can_single << "... " << dimensions_we_can_double << "...\n";
#endif
    for (int i = 0; i < (1 << ((num_dimensions - dimensions_we_can_single) - dimensions_we_can_double)); ++i) {
      std::array<Coordinate, num_dimensions> coords = bbox.min;
      for (num_coordinates_type j = dimensions_we_can_double; j < num_dimensions - dimensions_we_can_single; ++j) {
        if ((i << dimensions_we_can_double) & (1<<j)) coords[j] += base_box_size;
      }
      zbox zb = box_from_coords(coords, exp * num_dimensions + dimensions_we_can_double);
      if (zb.get_bbox().overlaps(bbox))
        insert_box(objects_tree, id, zb);
    }
  }
  void erase(ObjectIdentifier id) {
    auto bbox_iter = bboxes_by_object.find(id);
    assert(bbox_iter != bboxes_by_object.end());
    delete_object(objects_tree, id, bbox_iter->second);
    bboxes_by_object.erase(bbox_iter);
  }

  void get_objects_overlapping(unordered_set<ObjectIdentifier>& results, bounding_box const& bbox)const {
    zget_objects_overlapping(objects_tree, results, bbox);
  }
};

/*

If there's one zbox in the tree [call it Z]

tree = ztree_node {
  Z
  nullptr
  nullptr
}

Two zboxes that differ at bit B:
child0 of a node with B ignored bits is the child whose Bth bit is 0.
tree = ztree_node {
  Z1/Z2, with B ignored bits
  ptr to ztree_node {
    Z1
    nullptr
    nullptr
  }
  ptr to ztree_node {
    Z2
    nullptr
    nullptr
  }
}

*/

#endif

<commit_msg>Fixed obvious memory leaks.<commit_after>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

    Lasercake is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Lasercake is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_BBOX_COLLISION_DETECTOR_HPP__
#define LASERCAKE_BBOX_COLLISION_DETECTOR_HPP__

#include <boost/integer.hpp>
#include <unordered_map>
#include <unordered_set>
#include <array>
#include <cassert>
#include <cstdlib>

using std::unordered_map;
using std::unordered_set;

typedef size_t num_bits_type;
typedef size_t num_coordinates_type;

// ObjectIdentifier needs hash and == and to be freely copiable. So, ints will do, pointers will do...
// coordinate_bits should usually be 32 or 64. I don't know if it works for other values.
template<typename ObjectIdentifier, num_bits_type coordinate_bits, num_coordinates_type num_dimensions>
class bbox_collision_detector {
  static_assert(num_dimensions >= 0, "You can't make a space with negative dimensions!");
  static_assert(coordinate_bits >= 0, "You can't have an int type with negative bits!");
  friend class zbox_tester;

public:
  typedef typename boost::uint_t<coordinate_bits>::fast Coordinate;
  struct bounding_box {
    std::array<Coordinate, num_dimensions> min, size;
    bool overlaps(bounding_box const& other)const {
      for (num_coordinates_type i = 0; i < num_dimensions; ++i) {
        // this should correctly handle zboxes' "size=0" when all bits are ignored
        if (other.min[i] + (other.size[i] - 1) <       min[i]) return false;
        if (      min[i] + (      size[i] - 1) < other.min[i]) return false;
      }
      return true;
    }
  };

  bbox_collision_detector():objects_tree(nullptr){}

private:
  static const num_bits_type total_bits = coordinate_bits * num_dimensions;

  static Coordinate safe_left_shift_one(num_bits_type shift) {
    if (shift >= 8*sizeof(Coordinate)) return 0;
    return Coordinate(1) << shift; // TODO address the fact that this could put bits higher than the appropriate amount if coordinate_bits isn't the number of bits of the type
  }

  struct zbox {
    // We ensure that every bit except the ones specifically supposed to be on is off.
    std::array<Coordinate, num_dimensions> coords;
    std::array<Coordinate, num_dimensions> interleaved_bits;
    num_bits_type num_low_bits_ignored;

    zbox():num_low_bits_ignored(total_bits){ for (num_coordinates_type i = 0; i < num_dimensions; ++i) interleaved_bits[i] = 0; }

    bool subsumes(zbox const& other)const {
      if (other.num_low_bits_ignored > num_low_bits_ignored) return false;
      for (num_coordinates_type i = num_low_bits_ignored / coordinate_bits; i < num_dimensions; ++i) {
        Coordinate mask = ~Coordinate(0);
        if (i == num_low_bits_ignored / coordinate_bits) {
          mask &= ~(safe_left_shift_one(num_low_bits_ignored % coordinate_bits) - 1);
        }
        if ((interleaved_bits[i] & mask) != (other.interleaved_bits[i] & mask)) return false;
      }
      return true;
    }
    bool get_bit(num_bits_type bit)const {
      return interleaved_bits[bit / coordinate_bits] & safe_left_shift_one(bit % coordinate_bits);
    }
    num_bits_type num_bits_ignored_by_dimension(num_coordinates_type dim)const {
      return (num_low_bits_ignored + (num_dimensions - 1) - dim) / num_dimensions;
    }
    // note: gives "size=0" for max-sized things
    bounding_box get_bbox()const {
      bounding_box result;
      result.min = coords;
      for (num_coordinates_type i = 0; i < num_dimensions; ++i) {
        result.size[i] = safe_left_shift_one(num_bits_ignored_by_dimension(i));
      }
      return result;
    }
  };

  static int idx_of_highest_bit(Coordinate i) {
    int upper_bound = coordinate_bits;
    int lower_bound = -1;
    while(true) {
      int halfway_bit_idx = (upper_bound + lower_bound) >> 1;
      if (halfway_bit_idx == lower_bound) return lower_bound;

      if (i & ~(safe_left_shift_one(halfway_bit_idx) - 1)) lower_bound = halfway_bit_idx;
      else                                                 upper_bound = halfway_bit_idx;
    }
  }

  struct ztree_node {
    zbox here;
    ztree_node *child0;
    ztree_node *child1;
    unordered_set<ObjectIdentifier> objects_here;

    ztree_node(zbox box):here(box),child0(nullptr),child1(nullptr){}
  };

  static zbox smallest_joint_parent(zbox zb1, zbox zb2) {
    zbox new_box;
    for (int /* hack... TODO, should possibly be num_coordinates_type, but signed? */ i = num_dimensions - 1; i >= 0; --i) {
      const int highest_bit_idx = idx_of_highest_bit(zb1.interleaved_bits[i] ^ zb2.interleaved_bits[i]);
      assert((zb1.interleaved_bits[i] & ~((safe_left_shift_one(highest_bit_idx+1)) - 1)) == (zb2.interleaved_bits[i] & ~((safe_left_shift_one(highest_bit_idx+1)) - 1)));
      new_box.interleaved_bits[i] = (zb1.interleaved_bits[i]) & (~((safe_left_shift_one(highest_bit_idx + 1)) - 1));
      if (highest_bit_idx >= 0) {
        new_box.num_low_bits_ignored = highest_bit_idx+1 + i * coordinate_bits;
        for (num_coordinates_type j = 0; j < num_dimensions; ++j) {
          assert(             (zb1.coords[j] & ~(safe_left_shift_one(new_box.num_bits_ignored_by_dimension(j)) - 1))
                           == (zb2.coords[j] & ~(safe_left_shift_one(new_box.num_bits_ignored_by_dimension(j)) - 1)));
          new_box.coords[j] = zb1.coords[j] & ~(safe_left_shift_one(new_box.num_bits_ignored_by_dimension(j)) - 1);
        }
        return new_box;
      }
    }
    new_box.num_low_bits_ignored = 0;
    assert(zb1.coords == zb2.coords);
    new_box.coords = zb1.coords;
    return new_box;
  }

  static zbox box_from_coords(std::array<Coordinate, num_dimensions> const& coords, num_bits_type num_low_bits_ignored) {
    zbox result;
    result.num_low_bits_ignored = num_low_bits_ignored;
    for (num_coordinates_type i = 0; i < num_dimensions; ++i) {
      result.coords[i] = coords[i] & (~(safe_left_shift_one(result.num_bits_ignored_by_dimension(i)) - 1));
    }
    for (num_bits_type bit_within_interleaved_bits = num_low_bits_ignored;
                       bit_within_interleaved_bits < total_bits;
                     ++bit_within_interleaved_bits) {
      const num_bits_type bit_idx_within_coordinates = bit_within_interleaved_bits / num_dimensions;
      const num_coordinates_type which_coordinate    = bit_within_interleaved_bits % num_dimensions;
      const num_bits_type interleaved_bit_array_idx  = bit_within_interleaved_bits / coordinate_bits;
      const num_bits_type interleaved_bit_local_idx  = bit_within_interleaved_bits % coordinate_bits;
      assert(bit_idx_within_coordinates >= result.num_bits_ignored_by_dimension(which_coordinate));
      result.interleaved_bits[interleaved_bit_array_idx] |= ((coords[which_coordinate] >> bit_idx_within_coordinates) & 1) << interleaved_bit_local_idx;
    }
    return result;
  }

  static void insert_box(ztree_node*& tree, ObjectIdentifier obj, zbox box) {
    if (!tree) {
      tree = new ztree_node(box);
      tree->objects_here.insert(obj);
    }
    else {
      if (tree->here.subsumes(box)) {
        if (box.num_low_bits_ignored == tree->here.num_low_bits_ignored) {
          tree->objects_here.insert(obj);
        }
        else {
          if (box.get_bit(tree->here.num_low_bits_ignored - 1)) insert_box(tree->child1, obj, box);
          else                                                  insert_box(tree->child0, obj, box);
        }
      }
      else {
        ztree_node *new_tree = new ztree_node(smallest_joint_parent(tree->here, box));
        assert(new_tree->here.num_low_bits_ignored > tree->here.num_low_bits_ignored);
        assert(new_tree->here.subsumes(tree->here));
        assert(new_tree->here.subsumes(box));
        assert(tree->here.get_bit(new_tree->here.num_low_bits_ignored - 1) != box.get_bit(new_tree->here.num_low_bits_ignored - 1));
        if (tree->here.get_bit(new_tree->here.num_low_bits_ignored - 1)) new_tree->child1 = tree;
        else                                                             new_tree->child0 = tree;

        tree = new_tree;
        insert_box(tree, obj, box);
      }
    }
  }

  static void delete_object(ztree_node*& tree, ObjectIdentifier obj, bounding_box const& bbox) {
    if (!tree) return;
    if (tree->here.get_bbox().overlaps(bbox)) {
      tree->objects_here.erase(obj);
      delete_object(tree->child0, obj, bbox);
      delete_object(tree->child1, obj, bbox);

      if (tree->objects_here.empty()) {
        if (tree->child0) {
          if (!tree->child1) {
            delete tree;
            tree = tree->child0;
          }
        }
        else {
          delete tree;
          tree = tree->child1; // which could be null
        }
      }
    }
  }

  static void delete_entire_tree(ztree_node*& tree) {
    if (!tree) return;
    delete_entire_tree(tree->child0);
    delete_entire_tree(tree->child1);
    delete tree;
    tree = nullptr;
  }

  void zget_objects_overlapping(ztree_node const* tree, unordered_set<ObjectIdentifier>& results, bounding_box const& bbox)const {
    if (tree && tree->here.get_bbox().overlaps(bbox)) {
      for (const ObjectIdentifier obj : tree->objects_here) {
        auto bbox_iter = bboxes_by_object.find(obj);
        assert(bbox_iter != bboxes_by_object.end());
        if (bbox_iter->second.overlaps(bbox)) results.insert(obj);
      }
      zget_objects_overlapping(tree->child0, results, bbox);
      zget_objects_overlapping(tree->child1, results, bbox);
    }
  }

  unordered_map<ObjectIdentifier, bounding_box> bboxes_by_object;
  ztree_node* objects_tree;

public:

  void insert(ObjectIdentifier id, bounding_box const& bbox) {
    bboxes_by_object.insert(std::make_pair(id, bbox));
    Coordinate max_dim = bbox.size[0];
    for (num_coordinates_type i = 1; i < num_dimensions; ++i) {
      if (bbox.size[i] > max_dim) max_dim = bbox.size[i];
    }
    int exp = 0; while ((Coordinate(1) << exp) < max_dim) ++exp;
    int dimensions_we_can_single = 0;
    int dimensions_we_can_double = 0;
    const Coordinate base_box_size = safe_left_shift_one(exp);
    const Coordinate used_bits_mask = ~(base_box_size - 1);

    for (int i = num_dimensions - 1; i >= 0; --i) {
      if ((bbox.min[i] & used_bits_mask) + base_box_size >= bbox.min[i] + bbox.size[i]) ++dimensions_we_can_single;
      else break;
    }
    for (num_coordinates_type i = 0; i < num_dimensions - dimensions_we_can_single; ++i) {
      if (!(bbox.min[i] & base_box_size)) ++dimensions_we_can_double;
      else break;
    }
#ifdef ZTREE_TESTING
    std::cerr << dimensions_we_can_single << "... " << dimensions_we_can_double << "...\n";
#endif
    for (int i = 0; i < (1 << ((num_dimensions - dimensions_we_can_single) - dimensions_we_can_double)); ++i) {
      std::array<Coordinate, num_dimensions> coords = bbox.min;
      for (num_coordinates_type j = dimensions_we_can_double; j < num_dimensions - dimensions_we_can_single; ++j) {
        if ((i << dimensions_we_can_double) & (1<<j)) coords[j] += base_box_size;
      }
      zbox zb = box_from_coords(coords, exp * num_dimensions + dimensions_we_can_double);
      if (zb.get_bbox().overlaps(bbox))
        insert_box(objects_tree, id, zb);
    }
  }
  void erase(ObjectIdentifier id) {
    auto bbox_iter = bboxes_by_object.find(id);
    assert(bbox_iter != bboxes_by_object.end());
    delete_object(objects_tree, id, bbox_iter->second);
    bboxes_by_object.erase(bbox_iter);
  }

  void get_objects_overlapping(unordered_set<ObjectIdentifier>& results, bounding_box const& bbox)const {
    zget_objects_overlapping(objects_tree, results, bbox);
  }

  ~bbox_collision_detector() { delete_entire_tree(objects_tree); }
};

/*

If there's one zbox in the tree [call it Z]

tree = ztree_node {
  Z
  nullptr
  nullptr
}

Two zboxes that differ at bit B:
child0 of a node with B ignored bits is the child whose Bth bit is 0.
tree = ztree_node {
  Z1/Z2, with B ignored bits
  ptr to ztree_node {
    Z1
    nullptr
    nullptr
  }
  ptr to ztree_node {
    Z2
    nullptr
    nullptr
  }
}

*/

#endif

<|endoftext|>


<commit_before>// Copyright (c) 2015, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

#include <hpp/core/path-optimization/partial-shortcut.hh>

// #include <limits>
// #include <deque>
// #include <cstdlib>
// #include <hpp/util/assertion.hh>
#include <hpp/util/debug.hh>
#include <hpp/model/joint.hh>
#include <hpp/model/joint-configuration.hh>
#include <hpp/model/device.hh>
#include <hpp/core/distance.hh>
#include <hpp/core/path-validation.hh>
#include <hpp/core/path-vector.hh>
#include <hpp/core/problem.hh>
#include <hpp/core/steering-method.hh>
#include <hpp/core/config-projector.hh>
#include <hpp/core/locked-joint.hh>

namespace hpp {
  namespace core {
    namespace pathOptimization {
      namespace {
        void unpack (PathPtr_t path, PathVectorPtr_t out) {
          PathVectorPtr_t pv = HPP_DYNAMIC_PTR_CAST(PathVector, path);
          if (!pv) {
            out->appendPath (path);
          } else {
            for (std::size_t i = 0; i < pv->numberPaths (); ++i)
              unpack (pv->pathAtRank (i), out);
          }
        }

        // Compute the length of a vector of paths assuming that each element
        // is optimal for the given distance.
        static value_type pathLength (const PathVectorPtr_t& path,
            const DistancePtr_t& distance)
        {
          value_type result = 0;
          for (std::size_t i=0; i<path->numberPaths (); ++i) {
            const PathPtr_t& element (path->pathAtRank (i));
            result += (*distance) (element->initial (), element->end ());
          }
          return result;
        }
      }

      PartialShortcut::Parameters::Parameters () :
        removeLockedJoints (true), onlyFullShortcut (true),
        numberOfConsecutiveFailurePerJoints (5), progressionMargin (1e-3)
      {}

      PartialShortcutPtr_t PartialShortcut::create (const Problem& problem)
      {
        return createWithTraits <PartialShortcutTraits> (problem);
      }

      PartialShortcut::PartialShortcut (const Problem& problem) :
        PathOptimizer (problem)
      {
      }

      PathVectorPtr_t PartialShortcut::optimize (const PathVectorPtr_t& path)
      {
        PathVectorPtr_t unpacked = PathVector::create (path->outputSize(),
            path->outputDerivativeSize ());
        unpack (path, unpacked);

        /// Step 1: Generate a suitable vector of joints
        JointVector_t straight_jv = generateJointVector (unpacked);
        JointVector_t jv;

        /// Step 2: First try to optimize each joint from beginning to end
        PathVectorPtr_t result = optimizeFullPath (unpacked, straight_jv, jv);
        if (parameters.onlyFullShortcut) return result;

        /// Step 3: Optimize randomly each joint
        return optimizeRandom (result, jv);
      }

      PathVectorPtr_t PartialShortcut::generatePath (
          PathVectorPtr_t path, const JointPtr_t joint,
          const value_type t1, ConfigurationIn_t q1,
          const value_type t2, ConfigurationIn_t q2) const
      {
        const SteeringMethodPtr_t& sm (problem ().steeringMethod ());
        value_type lt1, lt2;
        std::size_t rkAtP1 = path->rankAtParam (t1, lt1);
        std::size_t rkAtP2 = path->rankAtParam (t2, lt2);
        if (rkAtP2 == rkAtP1) return PathVectorPtr_t ();

        PathVectorPtr_t pv = PathVector::create (
            path->outputSize (), path->outputDerivativeSize ());
        PathPtr_t last;

        std::size_t rkCfg = joint->rankInConfiguration ();
        Configuration_t qi = q1;
        Configuration_t q_inter (path->outputSize ());
        value_type t = - lt1;
        for (std::size_t i = rkAtP1; i < rkAtP2; ++i) {
          t += path->pathAtRank (i)->timeRange().second;
          q_inter = path->pathAtRank (i)->end (),
          joint->configuration()->interpolate ( q1, q2,
              t / (t2-t1), rkCfg, q_inter);
          if (path->pathAtRank (i)->constraints ()) {
            if (!path->pathAtRank (i)->constraints ()->apply (q_inter)) {
              hppDout (warning, "PartialShortcut could not apply "
                  "the constraints");
              return PathVectorPtr_t ();
            }
          }
          last = (*sm) (qi, q_inter);
          if (!last) return PathVectorPtr_t ();
          pv->appendPath (last);
          qi = q_inter;
        }
        last = (*sm) (qi, q2);
        if (!last) return PathVectorPtr_t ();
        pv->appendPath (last);
        PathVectorPtr_t out = PathVector::create (
            path->outputSize (), path->outputDerivativeSize ());
        pv->flatten (out);
        return out;
      }

      JointVector_t PartialShortcut::generateJointVector
        (const PathVectorPtr_t& pv) const
      {
        const JointVector_t& rjv = problem().robot()->getJointVector ();
        JointVector_t jv;
        ConfigProjectorPtr_t proj =
          pv->pathAtRank (0)->constraints ()->configProjector ();
        LockedJoints_t lj;
        if (proj) lj = proj->lockedJoints ();

        for (JointVector_t::const_iterator it = rjv.begin ();
            it != rjv.end (); ++it) {
          if ((*it)->numberDof () > 0) {
            bool lock = false;
            if (parameters.removeLockedJoints && proj) {
              const std::size_t rkCfg = (*it)->rankInConfiguration ();
              for (LockedJoints_t::const_iterator itLJ = lj.begin ();
                  itLJ != lj.end (); ++itLJ) {
                if ((*itLJ)->rankInConfiguration () == rkCfg) {
                  lock = true;
                  break;
                }
              }
            }
            if (!lock) jv.push_back (*it);
          }
        }
        return jv;
      }

      PathVectorPtr_t PartialShortcut::optimizeFullPath (
          const PathVectorPtr_t& pv, const JointVector_t& jvIn,
          JointVector_t& jvOut) const
      {
        Configuration_t q0 = pv->initial ();
        Configuration_t q3 = pv->end ();
        const value_type t0 = 0;
        value_type t3;
        PathVectorPtr_t opted = pv;

        /// First try to optimize each joint from beginning to end
        for (std::size_t iJ = 0; iJ < jvIn.size(); ++iJ) {
          t3 = opted->timeRange ().second;
          JointPtr_t joint = jvIn[iJ];

          // Validate sub parts
          bool valid;
          PathVectorPtr_t straight;
          straight = generatePath (opted, joint, t0, q0, t3, q3);
          {
            PathPtr_t validPart;
            PathValidationReportPtr_t report;
            if (!straight) valid = false;
            else {
              valid = problem ().pathValidation ()->validate
                (straight, false, validPart, report);
            }
          }
          if (!valid) {
            jvOut.push_back (joint);
            continue;
          }
          opted = straight;

          hppDout (info, "length = " << pathLength (opted, problem ().distance ())
              << ", joint " << joint->name());
        }
        return opted;
      }

      PathVectorPtr_t PartialShortcut::optimizeRandom (
          const PathVectorPtr_t& pv, const JointVector_t& jv) const
      {
        PathVectorPtr_t current = pv,
                        result = pv;
        const value_type t0 = 0;
        value_type t3;
        Configuration_t q0 = pv->initial ();
        Configuration_t q3 = pv->end ();
        value_type length = pathLength (pv, problem ().distance ()),
                   newLength = std::numeric_limits <value_type>::infinity ();

        hppDout (info, "random partial shorcut on " << jv.size () << " joints.");

        // Maximal number of iterations without improvements
        const std::size_t maxFailure = jv.size ()
          * parameters.numberOfConsecutiveFailurePerJoints;
        std::size_t nbFail = 0;
        std::size_t iJ = 0;
        Configuration_t q1 (pv->outputSize ()), q2 (pv->outputSize ());
        while (nbFail < maxFailure) {
          iJ %= jv.size();
          JointPtr_t joint = jv[iJ];
          ++iJ;

          t3 = current->timeRange ().second;
          value_type u2 = t3 * rand ()/RAND_MAX;
          value_type u1 = t3 * rand ()/RAND_MAX;

          value_type t1, t2;
          if (u1 < u2) {t1 = u1; t2 = u2;} else {t1 = u2; t2 = u1;}
          bool success =
            (*current) (q1, t1) &&
            (*current) (q2, t2);
          if (success) {
            hppDout (warning, "The constraints could not be applied to the "
                "current path");
            nbFail++;
            continue;
          }
          // Validate sub parts
          bool valid [3];
          PathVectorPtr_t straight [3];
          straight [0] = generatePath (current, joint, t0, q0, t1, q1);
          straight [1] = generatePath (current, joint, t1, q1, t2, q2);
          straight [2] = generatePath (current, joint, t2, q2, t3, q3);
          for (unsigned i=0; i<3; ++i) {
            PathPtr_t validPart;
            PathValidationReportPtr_t report;
            if (!straight [i]) valid[i] = false;
            else {
              valid [i] = problem ().pathValidation ()->validate
                (straight [i], false, validPart, report);
            }
          }
          if (!valid[0] && !valid[1] && !valid[2]) {
            nbFail++;
            continue;
          }
          // Replace valid parts
          result = PathVector::create (pv->outputSize (),
              pv->outputDerivativeSize ());
          if (valid [0])
            result->concatenate (*straight [0]);
          else
            result->concatenate (*(current->extract
                  (std::make_pair (t0, t1))-> as <PathVector> ()));
          if (valid [1])
            result->concatenate (*straight [1]);
          else
            result->concatenate (*(current->extract
                  (std::make_pair (t1, t2))-> as <PathVector> ()));
          if (valid [2])
            result->concatenate (*straight [2]);
          else
            result->concatenate (*(current->extract
                  (std::make_pair (t2, t3))-> as <PathVector> ()));

          newLength = pathLength (result, problem ().distance ());
          if (newLength >= length) {
            nbFail++;
            continue;
          }
          if (newLength >= length - parameters.progressionMargin)
            nbFail++;
          else
            nbFail = 0;
          --iJ; // This joint could be optimized. Try another time on it.
          length = newLength;
          hppDout (info, "length = " << length << ", nbFail = " << nbFail
              << ", joint " << joint->name());
          current = result;
        }
        return result;
      }
    } // namespace pathOptimization
  } // namespace core
} // namespace hpp
<commit_msg>Use PathOptimizer::steer instead of directly using the steering method<commit_after>// Copyright (c) 2015, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

#include <hpp/core/path-optimization/partial-shortcut.hh>

// #include <limits>
// #include <deque>
// #include <cstdlib>
// #include <hpp/util/assertion.hh>
#include <hpp/util/debug.hh>
#include <hpp/model/joint.hh>
#include <hpp/model/joint-configuration.hh>
#include <hpp/model/device.hh>
#include <hpp/core/distance.hh>
#include <hpp/core/path-validation.hh>
#include <hpp/core/path-vector.hh>
#include <hpp/core/problem.hh>
#include <hpp/core/config-projector.hh>
#include <hpp/core/locked-joint.hh>

namespace hpp {
  namespace core {
    namespace pathOptimization {
      namespace {
        void unpack (PathPtr_t path, PathVectorPtr_t out) {
          PathVectorPtr_t pv = HPP_DYNAMIC_PTR_CAST(PathVector, path);
          if (!pv) {
            out->appendPath (path);
          } else {
            for (std::size_t i = 0; i < pv->numberPaths (); ++i)
              unpack (pv->pathAtRank (i), out);
          }
        }

        // Compute the length of a vector of paths assuming that each element
        // is optimal for the given distance.
        static value_type pathLength (const PathVectorPtr_t& path,
            const DistancePtr_t& distance)
        {
          value_type result = 0;
          for (std::size_t i=0; i<path->numberPaths (); ++i) {
            const PathPtr_t& element (path->pathAtRank (i));
            result += (*distance) (element->initial (), element->end ());
          }
          return result;
        }
      }

      PartialShortcut::Parameters::Parameters () :
        removeLockedJoints (true), onlyFullShortcut (true),
        numberOfConsecutiveFailurePerJoints (5), progressionMargin (1e-3)
      {}

      PartialShortcutPtr_t PartialShortcut::create (const Problem& problem)
      {
        return createWithTraits <PartialShortcutTraits> (problem);
      }

      PartialShortcut::PartialShortcut (const Problem& problem) :
        PathOptimizer (problem)
      {
      }

      PathVectorPtr_t PartialShortcut::optimize (const PathVectorPtr_t& path)
      {
        PathVectorPtr_t unpacked = PathVector::create (path->outputSize(),
            path->outputDerivativeSize ());
        unpack (path, unpacked);

        /// Step 1: Generate a suitable vector of joints
        JointVector_t straight_jv = generateJointVector (unpacked);
        JointVector_t jv;

        /// Step 2: First try to optimize each joint from beginning to end
        PathVectorPtr_t result = optimizeFullPath (unpacked, straight_jv, jv);
        if (parameters.onlyFullShortcut) return result;

        /// Step 3: Optimize randomly each joint
        return optimizeRandom (result, jv);
      }

      PathVectorPtr_t PartialShortcut::generatePath (
          PathVectorPtr_t path, const JointPtr_t joint,
          const value_type t1, ConfigurationIn_t q1,
          const value_type t2, ConfigurationIn_t q2) const
      {
        value_type lt1, lt2;
        std::size_t rkAtP1 = path->rankAtParam (t1, lt1);
        std::size_t rkAtP2 = path->rankAtParam (t2, lt2);
        if (rkAtP2 == rkAtP1) return PathVectorPtr_t ();

        PathVectorPtr_t pv = PathVector::create (
            path->outputSize (), path->outputDerivativeSize ());
        PathPtr_t last;

        std::size_t rkCfg = joint->rankInConfiguration ();
        Configuration_t qi = q1;
        Configuration_t q_inter (path->outputSize ());
        value_type t = - lt1;
        for (std::size_t i = rkAtP1; i < rkAtP2; ++i) {
          t += path->pathAtRank (i)->timeRange().second;
          q_inter = path->pathAtRank (i)->end (),
          joint->configuration()->interpolate ( q1, q2,
              t / (t2-t1), rkCfg, q_inter);
          if (path->pathAtRank (i)->constraints ()) {
            if (!path->pathAtRank (i)->constraints ()->apply (q_inter)) {
              hppDout (warning, "PartialShortcut could not apply "
                  "the constraints");
              return PathVectorPtr_t ();
            }
          }
          last = (steer) (qi, q_inter);
          if (!last) return PathVectorPtr_t ();
          pv->appendPath (last);
          qi = q_inter;
        }
        last = steer (qi, q2);
        if (!last) return PathVectorPtr_t ();
        pv->appendPath (last);
        PathVectorPtr_t out = PathVector::create (
            path->outputSize (), path->outputDerivativeSize ());
        pv->flatten (out);
        return out;
      }

      JointVector_t PartialShortcut::generateJointVector
        (const PathVectorPtr_t& pv) const
      {
        const JointVector_t& rjv = problem().robot()->getJointVector ();
        JointVector_t jv;
        ConfigProjectorPtr_t proj =
          pv->pathAtRank (0)->constraints ()->configProjector ();
        LockedJoints_t lj;
        if (proj) lj = proj->lockedJoints ();

        for (JointVector_t::const_iterator it = rjv.begin ();
            it != rjv.end (); ++it) {
          if ((*it)->numberDof () > 0) {
            bool lock = false;
            if (parameters.removeLockedJoints && proj) {
              const std::size_t rkCfg = (*it)->rankInConfiguration ();
              for (LockedJoints_t::const_iterator itLJ = lj.begin ();
                  itLJ != lj.end (); ++itLJ) {
                if ((*itLJ)->rankInConfiguration () == rkCfg) {
                  lock = true;
                  break;
                }
              }
            }
            if (!lock) jv.push_back (*it);
          }
        }
        return jv;
      }

      PathVectorPtr_t PartialShortcut::optimizeFullPath (
          const PathVectorPtr_t& pv, const JointVector_t& jvIn,
          JointVector_t& jvOut) const
      {
        Configuration_t q0 = pv->initial ();
        Configuration_t q3 = pv->end ();
        const value_type t0 = 0;
        value_type t3;
        PathVectorPtr_t opted = pv;

        /// First try to optimize each joint from beginning to end
        for (std::size_t iJ = 0; iJ < jvIn.size(); ++iJ) {
          t3 = opted->timeRange ().second;
          JointPtr_t joint = jvIn[iJ];

          // Validate sub parts
          bool valid;
          PathVectorPtr_t straight;
          straight = generatePath (opted, joint, t0, q0, t3, q3);
          {
            PathPtr_t validPart;
            PathValidationReportPtr_t report;
            if (!straight) valid = false;
            else {
              valid = problem ().pathValidation ()->validate
                (straight, false, validPart, report);
            }
          }
          if (!valid) {
            jvOut.push_back (joint);
            continue;
          }
          opted = straight;

          hppDout (info, "length = " << pathLength (opted, problem ().distance ())
              << ", joint " << joint->name());
        }
        return opted;
      }

      PathVectorPtr_t PartialShortcut::optimizeRandom (
          const PathVectorPtr_t& pv, const JointVector_t& jv) const
      {
        PathVectorPtr_t current = pv,
                        result = pv;
        const value_type t0 = 0;
        value_type t3;
        Configuration_t q0 = pv->initial ();
        Configuration_t q3 = pv->end ();
        value_type length = pathLength (pv, problem ().distance ()),
                   newLength = std::numeric_limits <value_type>::infinity ();

        hppDout (info, "random partial shorcut on " << jv.size () << " joints.");

        // Maximal number of iterations without improvements
        const std::size_t maxFailure = jv.size ()
          * parameters.numberOfConsecutiveFailurePerJoints;
        std::size_t nbFail = 0;
        std::size_t iJ = 0;
        Configuration_t q1 (pv->outputSize ()), q2 (pv->outputSize ());
        while (nbFail < maxFailure) {
          iJ %= jv.size();
          JointPtr_t joint = jv[iJ];
          ++iJ;

          t3 = current->timeRange ().second;
          value_type u2 = t3 * rand ()/RAND_MAX;
          value_type u1 = t3 * rand ()/RAND_MAX;

          value_type t1, t2;
          if (u1 < u2) {t1 = u1; t2 = u2;} else {t1 = u2; t2 = u1;}
          bool success =
            (*current) (q1, t1) &&
            (*current) (q2, t2);
          if (success) {
            hppDout (warning, "The constraints could not be applied to the "
                "current path");
            nbFail++;
            continue;
          }
          // Validate sub parts
          bool valid [3];
          PathVectorPtr_t straight [3];
          straight [0] = generatePath (current, joint, t0, q0, t1, q1);
          straight [1] = generatePath (current, joint, t1, q1, t2, q2);
          straight [2] = generatePath (current, joint, t2, q2, t3, q3);
          for (unsigned i=0; i<3; ++i) {
            PathPtr_t validPart;
            PathValidationReportPtr_t report;
            if (!straight [i]) valid[i] = false;
            else {
              valid [i] = problem ().pathValidation ()->validate
                (straight [i], false, validPart, report);
            }
          }
          if (!valid[0] && !valid[1] && !valid[2]) {
            nbFail++;
            continue;
          }
          // Replace valid parts
          result = PathVector::create (pv->outputSize (),
              pv->outputDerivativeSize ());
          if (valid [0])
            result->concatenate (*straight [0]);
          else
            result->concatenate (*(current->extract
                  (std::make_pair (t0, t1))-> as <PathVector> ()));
          if (valid [1])
            result->concatenate (*straight [1]);
          else
            result->concatenate (*(current->extract
                  (std::make_pair (t1, t2))-> as <PathVector> ()));
          if (valid [2])
            result->concatenate (*straight [2]);
          else
            result->concatenate (*(current->extract
                  (std::make_pair (t2, t3))-> as <PathVector> ()));

          newLength = pathLength (result, problem ().distance ());
          if (newLength >= length) {
            nbFail++;
            continue;
          }
          if (newLength >= length - parameters.progressionMargin)
            nbFail++;
          else
            nbFail = 0;
          --iJ; // This joint could be optimized. Try another time on it.
          length = newLength;
          hppDout (info, "length = " << length << ", nbFail = " << nbFail
              << ", joint " << joint->name());
          current = result;
        }
        return result;
      }
    } // namespace pathOptimization
  } // namespace core
} // namespace hpp
<|endoftext|>


<commit_before>/*
  Plant Functionality Type class

  -- copy constructor of array?
  -- Epetra_Vector copy constructor copy values?

*/

#include "utils.hh"

#include "PFT.hh"

namespace Amanzi {
namespace BGC {

PFT::PFT(std::string pft_type_, int ncells) :
    pft_type(pft_type_),
    BRootSoil(ncells) {}

PFT::PFT(std::string pft_type_, int ncells, double* brootcells_) :
    pft_type(pft_type_),
    BRootSoil(View, brootcells_, ncells) {}

void PFT::Init(double col_area)
{

  SLA = 20;
  leaf2rootratio = 1.0;
  leaf2stemratio = 5;
  Vcmax25 = 100;
  Jmax25 = 200;
  GDDleafon = 100;
  GDDbase = 0.0;
  GDD = 0.0;
  Bleaf = 1.0/SLA * col_area;//es note that all the following B vals are perm^2, so that elsewhere they should be *gridarea to account for varying grid areas.
  Bstore = 2* Bleaf;
  Bleafmemory = Bleaf;
  Bstem = Bleaf/leaf2stemratio;
  Broot = Bleaf/leaf2rootratio;
  leaflitterfrc[0] = 0.1;
  leaflitterfrc[1] = 0.5;
  leaflitterfrc[1] = 0.4;
  rootlitterfrc[0] = 0.1;
  rootlitterfrc[1] = 0.5;
  rootlitterfrc[1] = 0.4;
  stemlitterfrc[0] = 0.05;
  stemlitterfrc[1] = 0.15;
  stemlitterfrc[1] = 0.8;
  LUE = 0.05;
  LER = 0.8;
  mp = 6.0;
  GPP = 0.0;
  annNPP = 0.0;
  NPP = 0.0;
  root2leafrespratio = 0.8;
  stem2leafrespratio = 0.05;
  maxRootD = 0.5;
  minLeafWP = -2.0;
  storagecleaf2sw = 1.5;
  storagecroot2sw = 15;
  rootlongevity = 4.0;
  leaflongevity = 4.0;
  stemlongevity = 10.0;
  tar_leafstorageccon = 0.2;
  Emax25 = 0.1*Vcmax25;
  gRespF = 0.25;
  storagecRspFrc = 0.8;
  leafstatus = 1;
  leafondays = 5;
  leafoffdays = 5;
  leafoffdaysi = 365.25;
  leafondaysi = 0;
  CSinkLimit = 0.0;
  seedrainlai = 0.01;
  totalBiomass = Bleaf + Bstem + Broot;
  maxLAI = 1;

  for (int i = 0; i < 10; i++){
    annCBalance[i] = 0;
  }
}

void PFT::Init(Teuchos::ParameterList& plist,double col_area)
{
  Init(col_area);
  // ex
  // rootlongevity = plist.get<double>("root longevity", 4.0);
}

// Initialize the root distribution
void PFT::InitRoots(const Epetra_SerialDenseVector& SoilTArr,
                    const Epetra_SerialDenseVector& SoilDArr,
                    const Epetra_SerialDenseVector& SoilThicknessArr) {

  // locate the root depth
  int nSoilLayers = SoilTArr.Length();
  double initPermD = PermafrostDepth(SoilTArr,SoilThicknessArr,273.15);
  //rootD = std::min(maxRootD, initPermD);
  rootD = std::min(maxRootD, 0.3);//es following Xu's advice - 0.3m accounts for the previous year root depth that will contribute to this yr Broot. Note that if spinning data exists feed in last year's root depth instead of 0.3.

  double totalweights = 0.0;
  for (int c=0; c!=nSoilLayers; ++c) {
    if (SoilDArr[c] < rootD){
      BRootSoil[c] = SoilThicknessArr[c]*std::exp((rootD - SoilDArr[c]) / rootD);
      totalweights += BRootSoil[c];
    } else {
      BRootSoil[c] = 0.0;
    }
  }

  if (BRootSoil[0] <= 0.0) { //avoid the numerical errors
    BRootSoil[0] = 1.0;
    totalweights = 1.0;
  }

  for (int c=0; c!=nSoilLayers; ++c) {
    BRootSoil[c] = BRootSoil[c] / totalweights * Broot;
  }

  AssertRootBalance_or_die();
  return;
}

} // namespace
} // namespace
<commit_msg>C debug - now changing chongangs values<commit_after>/*
  Plant Functionality Type class

  -- copy constructor of array?
  -- Epetra_Vector copy constructor copy values?

*/

#include "utils.hh"

#include "PFT.hh"

namespace Amanzi {
namespace BGC {

PFT::PFT(std::string pft_type_, int ncells) :
    pft_type(pft_type_),
    BRootSoil(ncells) {}

PFT::PFT(std::string pft_type_, int ncells, double* brootcells_) :
    pft_type(pft_type_),
    BRootSoil(View, brootcells_, ncells) {}

void PFT::Init(double col_area)
{

  SLA = 20;
  leaf2rootratio = 1.0;
  leaf2stemratio = 5;
  Vcmax25 = 100;
  Jmax25 = 200;
  GDDleafon = 100;
  GDDbase = 0.0;
  GDD = 0.0;
  Bleaf = 1.0/SLA * col_area;//es note that all the following B vals are perm^2, so that elsewhere they should be *gridarea to account for varying grid areas.
  Bstore = 2* Bleaf;
  Bleafmemory = Bleaf;
  Bstem = Bleaf/leaf2stemratio;
  Broot = Bleaf/leaf2rootratio;
  leaflitterfrc[0] = 0.1;
  leaflitterfrc[1] = 0.5;
  leaflitterfrc[1] = 0.4;
  rootlitterfrc[0] = 0.1;
  rootlitterfrc[1] = 0.5;
  rootlitterfrc[1] = 0.4;
  stemlitterfrc[0] = 0.05;
  stemlitterfrc[1] = 0.15;
  stemlitterfrc[1] = 0.8;
  LUE = 0.05;
  LER = 0.8;
  mp = 6.0;
  GPP = 0.0;
  annNPP = 0.0;
  NPP = 0.0;
  root2leafrespratio = 0.8;
  stem2leafrespratio = 0.05;
  maxRootD = 0.5;
  minLeafWP = -2.0;
  storagecleaf2sw = 1.5;
  storagecroot2sw = 15;
  rootlongevity = 4.0;
  leaflongevity = 4.0;
  stemlongevity = 10.0;
  tar_leafstorageccon = 0.2;
  Emax25 = 0.1*Vcmax25;
  gRespF = 0.25;
  storagecRspFrc = 0.8;
  leafstatus = 1;
  leafondays = 5;
  leafoffdays = 5;
  leafoffdaysi = 365.25;
  leafondaysi = 0;
  CSinkLimit = 0.0;
  seedrainlai = 0.01;
  totalBiomass = Bleaf + Bstem + Broot;
  maxLAI = 1;

  for (int i = 0; i < 10; i++){
    annCBalance[i] = 0;
  }
}

void PFT::Init(Teuchos::ParameterList& plist,double col_area)
{
  Init(col_area);
  // ex
  // rootlongevity = plist.get<double>("root longevity", 4.0);
  //note default vals below are those of sedge
       maxRootD = plist.get<double>("max root depth", 0.5);
       Vcmax25 = plist.get<double>("Vcmax25", 100.);
       Emax25 = plist.get<double>("Emax25", 10.);
       SLA = plist.get<double>("SLA", 16);

}

// Initialize the root distribution
void PFT::InitRoots(const Epetra_SerialDenseVector& SoilTArr,
                    const Epetra_SerialDenseVector& SoilDArr,
                    const Epetra_SerialDenseVector& SoilThicknessArr) {

  // locate the root depth
  int nSoilLayers = SoilTArr.Length();
  double initPermD = PermafrostDepth(SoilTArr,SoilThicknessArr,273.15);
  //rootD = std::min(maxRootD, initPermD);
  rootD = std::min(maxRootD, 0.3);//es following Xu's advice - 0.3m accounts for the previous year root depth that will contribute to this yr Broot. Note that if spinning data exists feed in last year's root depth instead of 0.3.

  double totalweights = 0.0;
  for (int c=0; c!=nSoilLayers; ++c) {
    if (SoilDArr[c] < rootD){
      BRootSoil[c] = SoilThicknessArr[c]*std::exp((rootD - SoilDArr[c]) / rootD);
      totalweights += BRootSoil[c];
    } else {
      BRootSoil[c] = 0.0;
    }
  }

  if (BRootSoil[0] <= 0.0) { //avoid the numerical errors
    BRootSoil[0] = 1.0;
    totalweights = 1.0;
  }

  for (int c=0; c!=nSoilLayers; ++c) {
    BRootSoil[c] = BRootSoil[c] / totalweights * Broot;
  }

  AssertRootBalance_or_die();
  return;
}

} // namespace
} // namespace
<|endoftext|>


<commit_before>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2010 Laurent Peuch  <cortex@worlddomination.be>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "se_parser_yauba.h"
#include "miscutil.h"

#include <strings.h>
#include <iostream>

using sp::miscutil;

namespace seeks_plugins
{
        se_parser_yauba::se_parser_yauba()
                :se_parser(),_in_item(false),_in_title(false),_in_result(false),_in_summary(false),_in_cite(false)
        {
        }

        se_parser_yauba::~se_parser_yauba()
        {
        }

        void se_parser_yauba::start_element(parser_context *pc,
                        const xmlChar *name,
                        const xmlChar **attributes)
        {
                const char *tag = (const char*)name;

                if (strcasecmp(tag, "div") == 0)
                {
                        const char *div_attr = se_parser::get_attribute((const char**)attributes, "class");
                        if (div_attr && strcasecmp(div_attr, "imageblock") == 0)
                        {
                                std::cout << "<div> " << std::endl;
                                _in_result = true;
                                // create new snippet.
                                search_snippet *sp = new search_snippet(_count + 1);
                                _count++;
                                sp->_engine |= std::bitset<NSEs>(SE_YAUBA);
                                pc->_current_snippet = sp;
                        }
                }
                if (_in_result && strcasecmp(tag, "h1") == 0)
                {
                        std::cout << "  <h1>" << std::endl;
                        _in_title = true;
                }
                if (_in_result && strcasecmp(tag, "a") == 0 && pc->_current_snippet->_url.empty())
                {
                        std::cout << "  <a href=>" << std::endl;
                        const char *url = se_parser::get_attribute((const char**)attributes, "href");
                        if (url)
                                pc->_current_snippet->set_url(std::string(url));
                }
                if (_in_result && strcasecmp(tag, "p") == 0)
                {
                        std::cout << "  <p>" << std::endl;
                        _in_summary = true;
                }
                if (_in_result && strcasecmp(tag, "li") == 0)
                {
                        const char *li_class = se_parser::get_attribute((const char**)attributes, "class");
                        if (li_class && strcasecmp(li_class, "bluecolor") == 0)
                        {
                                std::cout << "  <li>" << std::endl;
                                _in_cite = true;
                        }
                }
                //if (strcasecmp(tag, "item") == 0)
                //{
                        //std::cout << "<item>" << std::endl;
                        //_in_item = true;
                //}
                //if (_in_item && strcasecmp(tag, "title") == 0)
                //{
                        //std::cout << "  <title>" << std::endl;
                        //_in_title = true;
                //}
                ////if (_in_entry && strcasecmp(tag, "link") == 0)
                ////{
                        ////std::cout << "  <link />" << std::endl;
                ////}
        }

        void se_parser_yauba::characters(parser_context *pc,
                        const xmlChar *chars,
                        int length)
        {
                handle_characters(pc, chars, length);
        }

        void se_parser_yauba::cdata(parser_context *pc,
                        const xmlChar *chars,
                        int length)
        {
                handle_characters(pc, chars, length);
        }

        void se_parser_yauba::handle_characters(parser_context *pc,
                        const xmlChar *chars,
                        int length)
        {
                if (_in_cite)
                {
                        std::string a_chars = std::string((char*)chars);
                        miscutil::replace_in_string(a_chars,"\n"," ");
                        miscutil::replace_in_string(a_chars,"\r"," ");
                        miscutil::replace_in_string(a_chars,"-"," ");
                        _cite += a_chars;
                        std::cout << "    " << _cite << std::endl;
                }
                if (_in_summary)
                {
                        std::string a_chars = std::string((char*)chars);
                        miscutil::replace_in_string(a_chars,"\n"," ");
                        miscutil::replace_in_string(a_chars,"\r"," ");
                        miscutil::replace_in_string(a_chars,"-"," ");
                        _summary += a_chars;
                        std::cout << "    " << _summary << std::endl;
                }
                if (_in_title)
                {
                        std::string a_chars = std::string((char*)chars);
                        miscutil::replace_in_string(a_chars,"\n"," ");
                        miscutil::replace_in_string(a_chars,"\r"," ");
                        miscutil::replace_in_string(a_chars,"-"," ");
                        _title += a_chars;
                        std::cout << "    " << _title << std::endl;
                }
        }

        void se_parser_yauba::end_element(parser_context *pc,
                        const xmlChar *name)
        {
                const char *tag = (const char*) name;

                if (strcasecmp(tag, "ul") == 0)
                {
                        std::cout << "</false div>" << std::endl;
                        _in_result = false;

                        // assert previous snippet if any.
                        if (pc->_current_snippet)
                        {
                                if (pc->_current_snippet->_title.empty()  // consider the parsing did fail on the snippet.
                                        || pc->_current_snippet->_cite.empty()
                                        || pc->_current_snippet->_url.empty())
                                {
                                        std::cout << "[snippet fail]" << " title: " << pc->_current_snippet->_title.empty() << " url: " << pc->_current_snippet->_url.empty() << std::endl;
                                        delete pc->_current_snippet;
                                        pc->_current_snippet = NULL;
                                        _count--;
                                }
                                else pc->_snippets->push_back(pc->_current_snippet);
                                pc->_current_snippet = NULL;
                        }
                }
                if (_in_result && _in_title && strcasecmp(tag, "h1") == 0)
                {
                        std::cout << "  </h1>" << std::endl;
                        _in_title = false;
                        pc->_current_snippet->_title = _title;
                        _title = "";
                }
                if (_in_result && _in_summary && strcasecmp(tag, "p") == 0)
                {
                        std::cout << "  </p>" << std::endl;
                        _in_summary = false;
                        pc->_current_snippet->_summary = _summary;
                        _summary = "";
                }
                if (_in_cite && strcasecmp(tag, "li") == 0)
                {
                        std::cout << "  </li>" << std::endl;
                        _in_cite = false;
                        pc->_current_snippet->_cite = _cite;
                        _cite = "";
                }
        }

} /* end of namespace. */
<commit_msg>remove cout and some useless comment from yauba parser<commit_after>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2010 Laurent Peuch  <cortex@worlddomination.be>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "se_parser_yauba.h"
#include "miscutil.h"

#include <strings.h>
#include <iostream>

using sp::miscutil;

namespace seeks_plugins
{
        se_parser_yauba::se_parser_yauba()
                :se_parser(),_in_item(false),_in_title(false),_in_result(false),_in_summary(false),_in_cite(false)
        {
        }

        se_parser_yauba::~se_parser_yauba()
        {
        }

        void se_parser_yauba::start_element(parser_context *pc,
                        const xmlChar *name,
                        const xmlChar **attributes)
        {
                const char *tag = (const char*)name;

                if (strcasecmp(tag, "div") == 0)
                {
                        const char *div_attr = se_parser::get_attribute((const char**)attributes, "class");
                        if (div_attr && strcasecmp(div_attr, "imageblock") == 0)
                        {
                                _in_result = true;
                                // create new snippet.
                                search_snippet *sp = new search_snippet(_count + 1);
                                _count++;
                                sp->_engine |= std::bitset<NSEs>(SE_YAUBA);
                                pc->_current_snippet = sp;
                        }
                }
                if (_in_result && strcasecmp(tag, "h1") == 0)
                {
                        _in_title = true;
                }
                if (_in_result && strcasecmp(tag, "a") == 0 && pc->_current_snippet->_url.empty())
                {
                        const char *url = se_parser::get_attribute((const char**)attributes, "href");
                        if (url)
                                pc->_current_snippet->set_url(std::string(url));
                }
                if (_in_result && strcasecmp(tag, "p") == 0)
                {
                        _in_summary = true;
                }
                if (_in_result && strcasecmp(tag, "li") == 0)
                {
                        const char *li_class = se_parser::get_attribute((const char**)attributes, "class");
                        if (li_class && strcasecmp(li_class, "bluecolor") == 0)
                        {
                                _in_cite = true;
                        }
                }
        }

        void se_parser_yauba::characters(parser_context *pc,
                        const xmlChar *chars,
                        int length)
        {
                handle_characters(pc, chars, length);
        }

        void se_parser_yauba::cdata(parser_context *pc,
                        const xmlChar *chars,
                        int length)
        {
                handle_characters(pc, chars, length);
        }

        void se_parser_yauba::handle_characters(parser_context *pc,
                        const xmlChar *chars,
                        int length)
        {
                if (_in_cite)
                {
                        std::string a_chars = std::string((char*)chars);
                        miscutil::replace_in_string(a_chars,"\n"," ");
                        miscutil::replace_in_string(a_chars,"\r"," ");
                        miscutil::replace_in_string(a_chars,"-"," ");
                        _cite += a_chars;
                }
                if (_in_summary)
                {
                        std::string a_chars = std::string((char*)chars);
                        miscutil::replace_in_string(a_chars,"\n"," ");
                        miscutil::replace_in_string(a_chars,"\r"," ");
                        miscutil::replace_in_string(a_chars,"-"," ");
                        _summary += a_chars;
                }
                if (_in_title)
                {
                        std::string a_chars = std::string((char*)chars);
                        miscutil::replace_in_string(a_chars,"\n"," ");
                        miscutil::replace_in_string(a_chars,"\r"," ");
                        miscutil::replace_in_string(a_chars,"-"," ");
                        _title += a_chars;
                }
        }

        void se_parser_yauba::end_element(parser_context *pc,
                        const xmlChar *name)
        {
                const char *tag = (const char*) name;

                if (strcasecmp(tag, "ul") == 0)
                {
                        _in_result = false;

                        // assert previous snippet if any.
                        if (pc->_current_snippet)
                        {
                                if (pc->_current_snippet->_title.empty()  // consider the parsing did fail on the snippet.
                                        || pc->_current_snippet->_cite.empty()
                                        || pc->_current_snippet->_url.empty())
                                {
                                        delete pc->_current_snippet;
                                        pc->_current_snippet = NULL;
                                        _count--;
                                }
                                else pc->_snippets->push_back(pc->_current_snippet);
                                pc->_current_snippet = NULL;
                        }
                }
                if (_in_result && _in_title && strcasecmp(tag, "h1") == 0)
                {
                        _in_title = false;
                        pc->_current_snippet->_title = _title;
                        _title = "";
                }
                if (_in_result && _in_summary && strcasecmp(tag, "p") == 0)
                {
                        _in_summary = false;
                        pc->_current_snippet->_summary = _summary;
                        _summary = "";
                }
                if (_in_cite && strcasecmp(tag, "li") == 0)
                {
                        _in_cite = false;
                        pc->_current_snippet->_cite = _cite;
                        _cite = "";
                }
        }

} /* end of namespace. */
<|endoftext|>


<commit_before>/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

/*************************************************************************************************/

#include <GG/adobe/future/widgets/headers/platform_edit_text.hpp>

#include <GG/adobe/controller_concept.hpp>
#include <GG/adobe/placeable_concept.hpp>
#include <GG/adobe/future/widgets/headers/display.hpp>
#include <GG/adobe/future/widgets/headers/platform_label.hpp>
#include <GG/adobe/future/widgets/headers/platform_metrics.hpp>
#include <GG/adobe/future/widgets/headers/platform_widget_utils.hpp>

#include <GG/GUI.h>
#include <GG/MultiEdit.h>
#include <GG/StyleFactory.h>

/*************************************************************************************************/

namespace {

/*************************************************************************************************/

struct EditHandler
{
    EditHandler(adobe::edit_text_t& edit_text) :
        m_edit_text(&edit_text)
        {}

    void operator()(const std::string& text)
        {
            m_edit_text->value_m = text;
            m_edit_text->post_edit_proc_m(text);
        }

    adobe::edit_text_t* m_edit_text;
};

/*************************************************************************************************/

const int gap = 4;

} // namespace

/*************************************************************************************************/

namespace adobe {

namespace implementation {

/*************************************************************************************************/

class EditTextFilter :
    public GG::Wnd
{
public:
    EditTextFilter(edit_text_t& edit_text) :
        Wnd(GG::X0, GG::Y0, GG::X1, GG::Y1),
        m_edit_text(edit_text)
        {}

    virtual bool EventFilter(GG::Wnd*, const GG::WndEvent& event)
        {
            bool retval = false;
            if (event.Type() == GG::WndEvent::MouseWheel) {
                bool squelch;
                if (event.WheelMove() < 0)
                    m_edit_text.pre_edit_proc_m(std::string(30, 1), squelch);
                else if (0 < event.WheelMove())
                    m_edit_text.pre_edit_proc_m(std::string(31, 1), squelch);
                retval = true;
            } else if (event.Type() == GG::WndEvent::KeyPress) {
                bool nontext =
                    event.GetKey() == GG::GGK_HOME ||
                    event.GetKey() == GG::GGK_LEFT ||
                    event.GetKey() == GG::GGK_RIGHT ||
                    event.GetKey() == GG::GGK_END ||
                    event.GetKey() == GG::GGK_PAGEUP ||
                    event.GetKey() == GG::GGK_PAGEDOWN ||
                    event.GetKey() == GG::GGK_BACKSPACE ||
                    event.GetKey() == GG::GGK_DELETE ||
                    event.GetKey() == GG::GGK_RETURN ||
                    event.GetKey() == GG::GGK_KP_ENTER;

                if (nontext)
                    return false;

                bool squelch =
                    m_edit_text.rows_m == 1 &&
                    0 < m_edit_text.max_cols_m &&
                    static_cast<std::size_t>(m_edit_text.max_cols_m) <
                    m_edit_text.control_m->Text().size() + 1;

                if (squelch)
                    return true;

                std::string translated_code_point;
                GG::GetTranslatedCodePoint(event.GetKey(), event.KeyCodePoint(),
                                           event.ModKeys(), translated_code_point);

                std::string new_value = m_edit_text.control_m->Text() + translated_code_point;

                if (m_edit_text.pre_edit_proc_m)
                    m_edit_text.pre_edit_proc_m(new_value, squelch);

                if (squelch)
                    retval = true;
            }
            return retval;
        }

    edit_text_t& m_edit_text;
};

}

/*************************************************************************************************/

void edit_text_t::display(const model_type& value) // values that come in from Adam
{
    if (value != value_m)
        set_field_text(value_m = value);
}

/****************************************************************************************************/

edit_text_t::edit_text_t(const edit_text_ctor_block_t& block) :
    name_m(block.name_m, block.alt_text_m, 0, GG::FORMAT_NONE, block.theme_m),
    alt_text_m(block.alt_text_m),
    field_text_m(),
    using_label_m(!block.name_m.empty()),
    rows_m(block.num_lines_m),
    cols_m(block.min_characters_m),
    max_cols_m(block.max_characters_m),
    scrollable_m(block.scrollable_m),
    password_m(block.password_m)
{}

/****************************************************************************************************/

extents_t calculate_edit_bounds(GG::Edit* edit, int cols, int rows);

void edit_text_t::measure(extents_t& result)
{
    assert(control_m);
    //
    // The calculate_edit_bounds function can figure out the size this edit box
    // should be, based on the number of rows and columns.
    //
    result = calculate_edit_bounds(control_m, cols_m, original_height_m);
    //
    // If we have a label then we need to make extra space
    // for it.
    //
    if (!using_label_m)
        return;
    const boost::shared_ptr<GG::Font>& font = implementation::DefaultFont();
    extents_t label_bounds(measure_text(name_m.name_m, font));
    label_bounds.vertical().guide_set_m.push_back(Value(font->Ascent()));
    //
    // Make sure that the height can accomodate both the label
    // and the edit widget.
    //
    align_slices(result.vertical(), label_bounds.vertical());
    //
    // We put the label on the left side of the edit box, and
    // place a point of interest at the end of the label, so
    // that colon alignment can be performed.
    //

    result.width() += gap + label_bounds.width();
    result.horizontal().guide_set_m.push_back(label_bounds.width());
}

/****************************************************************************************************/

void edit_text_t::place(const place_data_t& place_data)
{
    using adobe::place;

    assert(control_m);

    place_data_t local_place_data(place_data);

    if (using_label_m)
    {
        //
        // The vertical offset of the label is the geometry's
        // baseline - the label's baseline.
        //
        assert(place_data.vertical().guide_set_m.empty() == false);

        place_data_t label_place_data;
        label_place_data.horizontal().position_m = left(local_place_data);
        label_place_data.vertical().position_m = top(local_place_data);

        //
        // The width of the label is the first horizontal
        // point of interest.
        //
        assert(place_data.horizontal().guide_set_m.empty() == false);
        width(label_place_data) = place_data.horizontal().guide_set_m[0];
        height(label_place_data) = height(place_data);;

        //
        // Set the label dimensions.
        //
        place(get_label(), label_place_data);

        //
        // Now we need to adjust the position of the popup
        // widget.
        //
        long width = gap + adobe::width(label_place_data);
        local_place_data.horizontal().position_m += width;
        adobe::width(local_place_data) -= width;
    }

    implementation::set_control_bounds(control_m, local_place_data);
}

/****************************************************************************************************/

label_t& edit_text_t::get_label()
{ return name_m; }

/****************************************************************************************************/

void edit_text_t::enable(bool active)
{
    assert(control_m);

    control_m->Disable(!active);

    if (using_label_m) {
        using adobe::enable;
        enable(get_label(), active);
    }
}

/****************************************************************************************************/

void edit_text_t::set_theme(theme_t theme)
{ theme_m = theme; }

/****************************************************************************************************/

void edit_text_t::set_field_text(const std::string& text)
{
    assert(control_m);
    control_m->SetText(text);
}

/****************************************************************************************************/

void edit_text_t::signal_pre_edit(edit_text_pre_edit_proc_t proc)
{
    assert(control_m);

    if (!pre_edit_proc_m)
        pre_edit_proc_m = proc;
}

/****************************************************************************************************/

void edit_text_t::monitor(setter_type proc)
{
    if (!post_edit_proc_m)
        post_edit_proc_m = proc;
}

/****************************************************************************************************/
/// This function is used by the edit widget, as well as the popup widget
/// (which contains an edit widget).
///
/// \param  control the edit control to obtain the best bounds for.
/// \param  cols    the number of columns (or characters across) the edit control should contain
/// \param  rows    the number of rows of text to contain.
///
/// \return the best bounds for the edit control, including baseline.
//
extents_t calculate_edit_bounds(GG::Edit* edit, int cols, int original_height)
{
    extents_t result;

    assert(edit);
    assert(0 < cols);
    assert(0 < original_height);

    GG::Pt non_client_size = implementation::NonClientSize(*edit);

    result.width() = Value(cols * implementation::CharWidth() + non_client_size.x);
    result.height() = original_height;
    GG::Y baseline =
        (static_cast<int>(result.height()) - implementation::CharHeight()) / 2 +
        implementation::DefaultFont()->Ascent();
    result.vertical().guide_set_m.push_back(Value(baseline));

    return result;
}

/****************************************************************************************************/

template <>
platform_display_type insert<edit_text_t>(display_t&             display,
                                          platform_display_type& parent,
                                          edit_text_t&           element)
{
    if (element.using_label_m)
        insert(display, parent, element.get_label());

    assert(0 < element.rows_m);
    if (element.rows_m <= 1) {
        element.control_m =
            implementation::Factory().NewEdit(GG::X0, GG::Y0, GG::X1, "",
                                              implementation::DefaultFont(), GG::CLR_GRAY);
        GG::Connect(element.control_m->EditedSignal, EditHandler(element));
    } else {
        GG::Y height =
            implementation::CharHeight() * static_cast<int>(element.rows_m) +
            static_cast<int>(2 * GG::MultiEdit::BORDER_THICK);
        GG::Flags<GG::MultiEditStyle> style = GG::MULTI_LINEWRAP;
        if (!element.scrollable_m)
            style |= GG::MULTI_NO_SCROLL;
        element.control_m =
            implementation::Factory().NewMultiEdit(GG::X0, GG::Y0, GG::X1, height, "",
                                                   implementation::DefaultFont(), GG::CLR_GRAY, style);
        GG::Connect(element.control_m->EditedSignal, EditHandler(element));
    }

    if (element.password_m)
        element.control_m->PasswordMode(true);

    element.original_height_m = Value(element.control_m->Height());

    element.filter_m.reset(new implementation::EditTextFilter(element));
    element.control_m->InstallEventFilter(element.filter_m.get());

    if (!element.alt_text_m.empty())
        implementation::set_control_alt_text(element.control_m, element.alt_text_m);

   return display.insert(parent, get_display(element));
}

/****************************************************************************************************/

} // namespace adobe

/*************************************************************************************************/
<commit_msg>Fixed character/code point confusion in edit_text.<commit_after>/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

/*************************************************************************************************/

#include <GG/adobe/future/widgets/headers/platform_edit_text.hpp>

#include <GG/adobe/controller_concept.hpp>
#include <GG/adobe/placeable_concept.hpp>
#include <GG/adobe/future/widgets/headers/display.hpp>
#include <GG/adobe/future/widgets/headers/platform_label.hpp>
#include <GG/adobe/future/widgets/headers/platform_metrics.hpp>
#include <GG/adobe/future/widgets/headers/platform_widget_utils.hpp>

#include <GG/GUI.h>
#include <GG/MultiEdit.h>
#include <GG/StyleFactory.h>
#include <GG/utf8/checked.h>

/*************************************************************************************************/

namespace {

/*************************************************************************************************/

struct EditHandler
{
    EditHandler(adobe::edit_text_t& edit_text) :
        m_edit_text(&edit_text)
        {}

    void operator()(const std::string& text)
        {
            m_edit_text->value_m = text;
            m_edit_text->post_edit_proc_m(text);
        }

    adobe::edit_text_t* m_edit_text;
};

/*************************************************************************************************/

const int gap = 4;

} // namespace

/*************************************************************************************************/

namespace adobe {

namespace implementation {

/*************************************************************************************************/

class EditTextFilter :
    public GG::Wnd
{
public:
    EditTextFilter(edit_text_t& edit_text) :
        Wnd(GG::X0, GG::Y0, GG::X1, GG::Y1),
        m_edit_text(edit_text)
        {}

    virtual bool EventFilter(GG::Wnd*, const GG::WndEvent& event)
        {
            bool retval = false;
            if (event.Type() == GG::WndEvent::MouseWheel) {
                bool squelch;
                if (event.WheelMove() < 0)
                    m_edit_text.pre_edit_proc_m(std::string(30, 1), squelch);
                else if (0 < event.WheelMove())
                    m_edit_text.pre_edit_proc_m(std::string(31, 1), squelch);
                retval = true;
            } else if (event.Type() == GG::WndEvent::KeyPress) {
                bool nontext =
                    event.GetKey() == GG::GGK_HOME ||
                    event.GetKey() == GG::GGK_LEFT ||
                    event.GetKey() == GG::GGK_RIGHT ||
                    event.GetKey() == GG::GGK_END ||
                    event.GetKey() == GG::GGK_PAGEUP ||
                    event.GetKey() == GG::GGK_PAGEDOWN ||
                    event.GetKey() == GG::GGK_BACKSPACE ||
                    event.GetKey() == GG::GGK_DELETE ||
                    event.GetKey() == GG::GGK_RETURN ||
                    event.GetKey() == GG::GGK_KP_ENTER;

                if (nontext)
                    return false;

                const std::string& text = m_edit_text.control_m->Text();

                bool squelch =
                    m_edit_text.rows_m == 1 &&
                    0 < m_edit_text.max_cols_m &&
                    static_cast<std::size_t>(m_edit_text.max_cols_m) <
                    utf8::distance(text.begin(), text.end()) + 1;

                if (squelch)
                    return true;

                std::string translated_code_point;
                GG::GetTranslatedCodePoint(event.GetKey(), event.KeyCodePoint(),
                                           event.ModKeys(), translated_code_point);

                std::string new_value = m_edit_text.control_m->Text() + translated_code_point;

                if (m_edit_text.pre_edit_proc_m)
                    m_edit_text.pre_edit_proc_m(new_value, squelch);

                if (squelch)
                    retval = true;
            }
            return retval;
        }

    edit_text_t& m_edit_text;
};

}

/*************************************************************************************************/

void edit_text_t::display(const model_type& value) // values that come in from Adam
{
    if (value != value_m)
        set_field_text(value_m = value);
}

/****************************************************************************************************/

edit_text_t::edit_text_t(const edit_text_ctor_block_t& block) :
    name_m(block.name_m, block.alt_text_m, 0, GG::FORMAT_NONE, block.theme_m),
    alt_text_m(block.alt_text_m),
    field_text_m(),
    using_label_m(!block.name_m.empty()),
    rows_m(block.num_lines_m),
    cols_m(block.min_characters_m),
    max_cols_m(block.max_characters_m),
    scrollable_m(block.scrollable_m),
    password_m(block.password_m)
{}

/****************************************************************************************************/

extents_t calculate_edit_bounds(GG::Edit* edit, int cols, int rows);

void edit_text_t::measure(extents_t& result)
{
    assert(control_m);
    //
    // The calculate_edit_bounds function can figure out the size this edit box
    // should be, based on the number of rows and columns.
    //
    result = calculate_edit_bounds(control_m, cols_m, original_height_m);
    //
    // If we have a label then we need to make extra space
    // for it.
    //
    if (!using_label_m)
        return;
    const boost::shared_ptr<GG::Font>& font = implementation::DefaultFont();
    extents_t label_bounds(measure_text(name_m.name_m, font));
    label_bounds.vertical().guide_set_m.push_back(Value(font->Ascent()));
    //
    // Make sure that the height can accomodate both the label
    // and the edit widget.
    //
    align_slices(result.vertical(), label_bounds.vertical());
    //
    // We put the label on the left side of the edit box, and
    // place a point of interest at the end of the label, so
    // that colon alignment can be performed.
    //

    result.width() += gap + label_bounds.width();
    result.horizontal().guide_set_m.push_back(label_bounds.width());
}

/****************************************************************************************************/

void edit_text_t::place(const place_data_t& place_data)
{
    using adobe::place;

    assert(control_m);

    place_data_t local_place_data(place_data);

    if (using_label_m)
    {
        //
        // The vertical offset of the label is the geometry's
        // baseline - the label's baseline.
        //
        assert(place_data.vertical().guide_set_m.empty() == false);

        place_data_t label_place_data;
        label_place_data.horizontal().position_m = left(local_place_data);
        label_place_data.vertical().position_m = top(local_place_data);

        //
        // The width of the label is the first horizontal
        // point of interest.
        //
        assert(place_data.horizontal().guide_set_m.empty() == false);
        width(label_place_data) = place_data.horizontal().guide_set_m[0];
        height(label_place_data) = height(place_data);;

        //
        // Set the label dimensions.
        //
        place(get_label(), label_place_data);

        //
        // Now we need to adjust the position of the popup
        // widget.
        //
        long width = gap + adobe::width(label_place_data);
        local_place_data.horizontal().position_m += width;
        adobe::width(local_place_data) -= width;
    }

    implementation::set_control_bounds(control_m, local_place_data);
}

/****************************************************************************************************/

label_t& edit_text_t::get_label()
{ return name_m; }

/****************************************************************************************************/

void edit_text_t::enable(bool active)
{
    assert(control_m);

    control_m->Disable(!active);

    if (using_label_m) {
        using adobe::enable;
        enable(get_label(), active);
    }
}

/****************************************************************************************************/

void edit_text_t::set_theme(theme_t theme)
{ theme_m = theme; }

/****************************************************************************************************/

void edit_text_t::set_field_text(const std::string& text)
{
    assert(control_m);
    control_m->SetText(text);
}

/****************************************************************************************************/

void edit_text_t::signal_pre_edit(edit_text_pre_edit_proc_t proc)
{
    assert(control_m);

    if (!pre_edit_proc_m)
        pre_edit_proc_m = proc;
}

/****************************************************************************************************/

void edit_text_t::monitor(setter_type proc)
{
    if (!post_edit_proc_m)
        post_edit_proc_m = proc;
}

/****************************************************************************************************/
/// This function is used by the edit widget, as well as the popup widget
/// (which contains an edit widget).
///
/// \param  control the edit control to obtain the best bounds for.
/// \param  cols    the number of columns (or characters across) the edit control should contain
/// \param  rows    the number of rows of text to contain.
///
/// \return the best bounds for the edit control, including baseline.
//
extents_t calculate_edit_bounds(GG::Edit* edit, int cols, int original_height)
{
    extents_t result;

    assert(edit);
    assert(0 < cols);
    assert(0 < original_height);

    GG::Pt non_client_size = implementation::NonClientSize(*edit);

    result.width() = Value(cols * implementation::CharWidth() + non_client_size.x);
    result.height() = original_height;
    GG::Y baseline =
        (static_cast<int>(result.height()) - implementation::CharHeight()) / 2 +
        implementation::DefaultFont()->Ascent();
    result.vertical().guide_set_m.push_back(Value(baseline));

    return result;
}

/****************************************************************************************************/

template <>
platform_display_type insert<edit_text_t>(display_t&             display,
                                          platform_display_type& parent,
                                          edit_text_t&           element)
{
    if (element.using_label_m)
        insert(display, parent, element.get_label());

    assert(0 < element.rows_m);
    if (element.rows_m <= 1) {
        element.control_m =
            implementation::Factory().NewEdit(GG::X0, GG::Y0, GG::X1, "",
                                              implementation::DefaultFont(), GG::CLR_GRAY);
        GG::Connect(element.control_m->EditedSignal, EditHandler(element));
    } else {
        GG::Y height =
            implementation::CharHeight() * static_cast<int>(element.rows_m) +
            static_cast<int>(2 * GG::MultiEdit::BORDER_THICK);
        GG::Flags<GG::MultiEditStyle> style = GG::MULTI_LINEWRAP;
        if (!element.scrollable_m)
            style |= GG::MULTI_NO_SCROLL;
        element.control_m =
            implementation::Factory().NewMultiEdit(GG::X0, GG::Y0, GG::X1, height, "",
                                                   implementation::DefaultFont(), GG::CLR_GRAY, style);
        GG::Connect(element.control_m->EditedSignal, EditHandler(element));
    }

    if (element.password_m)
        element.control_m->PasswordMode(true);

    element.original_height_m = Value(element.control_m->Height());

    element.filter_m.reset(new implementation::EditTextFilter(element));
    element.control_m->InstallEventFilter(element.filter_m.get());

    if (!element.alt_text_m.empty())
        implementation::set_control_alt_text(element.control_m, element.alt_text_m);

   return display.insert(parent, get_display(element));
}

/****************************************************************************************************/

} // namespace adobe

/*************************************************************************************************/
<|endoftext|>