00001 #ifndef GRAL_GB_SHRUNK_GRID_VIEW_H
00002 #define GRAL_GB_SHRUNK_GRID_VIEW_H
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "Gral/Base/common-grid-basics.h"
00019 #include "Gral/Base/grid-function-hash.h"
00020
00021 #include "Geometry/point-traits.h"
00022
00023 #include <iostream>
00024
00025 namespace GrAL {
00026
00061 namespace shrink_grid_view {
00062
00063
00064
00065 template<class GRID>
00066 class grid_view;
00067
00068 template<class GRID>
00069 class cell_iterator;
00070
00071 template<class GRID>
00072 class vertex_iterator;
00073
00074 template<class GRID>
00075 class vertex_on_cell_iterator;
00076
00077 template<class GRID>
00078 class vertex_handle_t;
00079
00080 template<class GRID>
00081 class local_grid_types : public grid_types_detail::grid_types_root {
00082 public:
00083 typedef grid_view<GRID> grid_type;
00084 typedef cell_iterator<GRID> Cell;
00085 typedef cell_iterator<GRID> CellIterator;
00086 typedef vertex_iterator<GRID> Vertex;
00087 typedef vertex_iterator<GRID> VertexIterator;
00088 typedef vertex_on_cell_iterator<GRID> VertexOnCellIterator;
00089
00090 typedef grid_types<GRID> bgt;
00091 typedef GRID base_grid_type;
00092 typedef typename bgt::size_type size_type;
00093 typedef typename bgt::dimension_tag dimension_tag;
00094
00095 typedef typename bgt::cell_handle cell_handle;
00096 typedef vertex_handle_t<GRID> vertex_handle;
00097
00098 typedef typename bgt::archetype_type archetype_type;
00099 typedef typename bgt::archetype_handle archetype_handle;
00100 typedef typename bgt::archetype_iterator archetype_iterator;
00101 typedef typename bgt::archgt archgt;
00102 };
00103
00104
00105
00106
00107
00108
00109
00110 namespace detail {
00111 template<class GRID, class element_tag>
00112 struct map_types_for_grid_view { };
00113
00114 template<class GRID>
00115 struct map_types_for_grid_view<GRID, vertex_type_tag> {
00116 typedef shrink_grid_view::vertex_iterator<GRID> element_type;
00117 typedef shrink_grid_view::vertex_iterator<GRID> element_iterator;
00118 };
00119
00120 template<class GRID>
00121 struct map_types_for_grid_view<GRID, cell_type_tag> {
00122 typedef shrink_grid_view::cell_iterator<GRID> element_type;
00123 typedef shrink_grid_view::cell_iterator<GRID> element_iterator;
00124 };
00125 }
00126
00132 template<class GRID>
00133 class grid_view : public local_grid_types<GRID> {
00134 typedef grid_view<GRID> self;
00135 typedef local_grid_types<GRID> gt;
00136 public:
00137 typedef self grid_type;
00138 enum { dim = gt::dimension_tag::dim };
00139 typedef grid_view_category_d<dim> category;
00140
00141 typedef typename gt::archetype_iterator archetype_iterator;
00142 typedef typename gt::archetype_type archetype_type;
00143 typedef typename gt::archetype_handle archetype_handle;
00144 typedef typename gt::base_grid_type base_grid_type;
00145 typedef typename gt::Cell Cell;
00146 typedef typename gt::cell_handle cell_handle;
00147 typedef typename gt::bgt bgt;
00148 private:
00149 base_grid_type const* g;
00150
00151 mutable int num_of_vertices;
00152 mutable bool num_of_vertices_valid;
00153 public:
00154 grid_view(base_grid_type const& gg)
00155 : g(&gg), num_of_vertices(0), num_of_vertices_valid(false) {}
00156
00157 unsigned NumOfCells() const { return BaseGrid().NumOfCells();}
00158 unsigned NumOfVertices() const {
00159 if(! num_of_vertices_valid)
00160 calculate_num_of_vertices();
00161 return num_of_vertices;
00162 }
00163 cell_iterator<GRID> FirstCell() const;
00164 vertex_iterator<GRID> FirstVertex() const;
00165 cell_iterator<GRID> EndCell() const;
00166 vertex_iterator<GRID> EndVertex() const;
00167 base_grid_type const& BaseGrid() const { return *g;}
00168
00169
00170 template<class element_tag>
00171 struct map_types : public detail::map_types_for_grid_view<GRID,element_tag> {};
00172
00173 archetype_iterator BeginArchetype() const
00174 { return BaseGrid().BeginArchetype();}
00175 archetype_iterator EndArchetype() const
00176 { return BaseGrid().EndArchetype();}
00177 archetype_handle handle(archetype_iterator it) const { return BaseGrid().handle(it);}
00178
00179 archetype_type const& Archetype(archetype_handle a) const { return BaseGrid().Archetype(a);}
00180 archetype_type const& ArchetypeOf(Cell const& c) const
00181 { return BaseGrid().ArchetypeOf(c.BaseCell()); }
00182 archetype_handle archetype_of(Cell const& c) const
00183 { return BaseGrid().archetype_of(c.BaseCell());}
00184 archetype_handle archetype_of(cell_handle c) const
00185 { return BaseGrid().archetype_of(c);}
00186
00187 private:
00188 void calculate_num_of_vertices() const {
00189 num_of_vertices = 0;
00190 for(typename bgt::CellIterator c(BaseGrid()); ! c.IsDone(); ++c)
00191 num_of_vertices += (*c).NumOfVertices();
00192 num_of_vertices_valid = true;
00193 }
00194
00195
00196 };
00197
00198 template<class GRID>
00199 struct vertex_handle_t : public local_grid_types<GRID> {
00200 typedef local_grid_types<GRID> base;
00201 typedef typename base::bgt bgt;
00202 typedef typename bgt::vertex_handle base_vertex_handle;
00203 typedef typename base::cell_handle cell_handle;
00204 typedef grid_vertex_handle_category category;
00205
00206 cell_handle c;
00207 base_vertex_handle v;
00208 public:
00209 vertex_handle_t() {}
00210 vertex_handle_t(cell_handle cc, base_vertex_handle vv) : c(cc), v(vv) {}
00211 };
00212
00213 template<class GRID>
00214 inline
00215 ::std::ostream& operator<<( ::std::ostream& out, vertex_handle_t<GRID> const& h)
00216 { return (out << h.c << ' ' << h.v);}
00217
00218
00219
00220 template<class GRID>
00221 class cell_iterator : public local_grid_types<GRID> {
00222 private:
00223 typedef cell_iterator<GRID> self;
00224 typedef local_grid_types<GRID> gt;
00225 friend class vertex_on_cell_iterator<GRID>;
00226 public:
00227 typedef typename gt::bgt bgt;
00228 typedef typename gt::archgt archgt;
00229 typedef typename gt::grid_type grid_type;
00230 typedef typename gt::cell_handle cell_handle;
00231 typedef typename gt::vertex_handle vertex_handle;
00232 typedef typename gt::Vertex Vertex;
00233
00234 typedef cell_type_tag element_type_tag;
00235 struct category :
00236 virtual grid_cell_category,
00237 virtual grid_cell_iterator_category {};
00238
00239 typedef grid_type anchor_type;
00240 typedef self value_type;
00241 private:
00242 grid_type const* g;
00243 typename bgt::CellIterator c;
00244 public:
00245 cell_iterator() : g(0) {}
00246 explicit
00247 cell_iterator(grid_type const& gg) : g(&gg), c(g->BaseGrid()) {}
00248 cell_iterator(grid_type const& gg,
00249 cell_handle cc) : g(&gg), c(g->BaseGrid(), cc) {}
00250 cell_iterator(grid_type const& gg,
00251 typename bgt::CellIterator bc) : g(&gg), c(bc) {}
00252 self & operator++() { ++c; return *this;}
00253 self const& operator*() const { return *this;}
00254 bool IsDone() const { return c.IsDone();}
00255 cell_handle handle() const { return c.handle();}
00256
00257 grid_type const& TheGrid() const { return *g;}
00258 grid_type const& TheAnchor() const { return *g;}
00259
00260
00261 vertex_on_cell_iterator<GRID> FirstVertex() const;
00262 vertex_on_cell_iterator<GRID> EndVertex() const;
00263 unsigned NumOfVertices() const { return c.NumOfVertices();}
00264 vertex_iterator<GRID> V(typename archgt::Vertex av) const
00265 { return Vertex(*g, vertex_handle(handle(), BaseCell().v(av.handle()) )); }
00266
00267
00268
00269 bool operator==(self const& rhs) const { return c == rhs.c;}
00270 bool operator!=(self const& rhs) const { return !(*this == rhs);}
00271 bool operator< (self const& rhs) const { return c < rhs.c;}
00272
00273 bool bound() const { return (g!= 0);}
00274 bool valid() const { return bound() && c.valid();}
00275
00276 typename bgt::Cell const& BaseCell() const { return *c;}
00277 typename bgt::Cell const& Base () const { return *c;}
00278 };
00279
00280
00281 template<class GRID>
00282 class vertex_iterator : public local_grid_types<GRID> {
00283 private:
00284 typedef vertex_iterator<GRID> self;
00285 typedef local_grid_types<GRID> gt;
00286 public:
00287 typedef typename gt::bgt bgt;
00288 typedef typename gt::archgt archgt;
00289 typedef typename gt::grid_type grid_type;
00290 typedef typename gt::cell_handle cell_handle;
00291 typedef typename gt::vertex_handle vertex_handle;
00292 typedef typename gt::Cell Cell;
00293
00294 typedef vertex_type_tag element_type_tag;
00295 struct category :
00296 virtual grid_vertex_category,
00297 virtual grid_vertex_iterator_category {};
00298 typedef grid_type anchor_type;
00299 typedef self value_type;
00300 private:
00301
00302 grid_type const* g;
00303 typename bgt::CellIterator c;
00304 typename bgt::VertexOnCellIterator vc;
00305 public:
00306 vertex_iterator() {}
00307
00308 explicit
00309 vertex_iterator(grid_type const& gg)
00310 : g(&gg), c(g->BaseGrid().FirstCell())
00311 { if (!c.IsDone()) vc = c.FirstVertex(); }
00312
00313 vertex_iterator(grid_type const& gg,
00314 typename bgt::CellIterator bc)
00315 : g(&gg), c(bc)
00316 { if (!c.IsDone()) vc = c.FirstVertex(); }
00317
00318 vertex_iterator(grid_type const& gg,
00319 vertex_handle h)
00320 : g(&gg), c(gg.BaseGrid(),h.c)
00321 {
00322 vc = c.FirstVertex();
00323 while(vc.handle() != h.v) ++vc;
00324 REQUIRE(vc.handle() == h.v,
00325 "invalid handle h = " << h << '\n' ,1);
00326 }
00327
00328 explicit
00329 vertex_iterator(vertex_on_cell_iterator<GRID> const& vvc);
00330
00331 self& operator++() {
00332 ++vc;
00333 if(vc.IsDone()) {
00334 ++c;
00335 if(! c.IsDone())
00336 vc = c.FirstVertex();
00337 }
00338 return *this;
00339 }
00340 self const& operator*() const { return *this;}
00341 bool IsDone() const { return c.IsDone();}
00342 vertex_handle handle() const
00343 { return vertex_handle(c.handle(),vc.handle());}
00344 grid_type const& TheGrid() const { return *g;}
00345 grid_type const& TheAnchor() const { return *g;}
00346
00347 bool operator==(self const& rhs) const { return (c == rhs.c && IsDone()) || (c == rhs.c && vc == rhs.vc);}
00348 bool operator!=(self const& rhs) const { return !(*this == rhs);}
00349 bool operator< (self const& rhs) const { return c < rhs.c || (c == rhs.c && !IsDone() && vc < rhs.vc);}
00350
00351 Cell Cell_() const { return Cell(*g,c.handle());}
00352 typename bgt::Vertex BaseVertex() const { return *vc;}
00353 typename bgt::Vertex Base() const { return *vc;}
00354 };
00355
00356
00357
00358 template<class GRID>
00359 class vertex_on_cell_iterator : public local_grid_types<GRID> {
00360 typedef vertex_on_cell_iterator<GRID> self;
00361 typedef local_grid_types<GRID> gt;
00362 public:
00363 typedef typename gt::bgt bgt;
00364 typedef typename gt::grid_type grid_type;
00365 typedef typename gt::vertex_handle vertex_handle;
00366 typedef typename gt::Vertex Vertex;
00367 typedef typename gt::Cell Cell;
00368
00369 typedef grid_incidence_iterator_category_d<0,grid_type::dim> category;
00370 typedef Vertex value_type;
00371 typedef Cell anchor_type;
00372 private:
00373 grid_type const* g;
00374 typename bgt::VertexOnCellIterator vc;
00375 public:
00376 vertex_on_cell_iterator() : g(0) {}
00377 explicit
00378 vertex_on_cell_iterator(Cell const& c)
00379 : g(&(c.TheGrid())), vc(c.c.FirstVertex()) {}
00380 vertex_on_cell_iterator(Cell const& c, typename bgt::VertexOnCellIterator vvc)
00381 : g(&c.TheGrid()), vc(vvc) {}
00382
00383 self& operator++() { ++vc; return *this;}
00384 Vertex operator*() const { return Vertex(*g,handle());}
00385 vertex_handle handle() const
00386 { return vertex_handle(vc.TheCell().handle(),
00387 vc.handle());}
00388 bool IsDone() const { return vc.IsDone();}
00389
00390 grid_type const& TheGrid() const { return *g;}
00391 Cell TheAnchor() const { return Cell(TheGrid(), vc.TheCell());}
00392
00393 bool operator==(self const& rhs) const { return vc == rhs.vc;}
00394 bool operator!=(self const& rhs) const { return !(*this == rhs);}
00395 bool operator< (self const& rhs) const { return vc < rhs.vc;}
00396
00397 };
00398
00399
00400
00401
00402 template<class GRID>
00403 inline vertex_on_cell_iterator<GRID>
00404 cell_iterator<GRID>::FirstVertex() const
00405 { return typename gt::VertexOnCellIterator(*this);}
00406
00407 template<class GRID>
00408 inline vertex_on_cell_iterator<GRID>
00409 cell_iterator<GRID>::EndVertex() const
00410 { return typename gt::VertexOnCellIterator(*this, GrAL::end<typename bgt::Vertex>(Base()));}
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 template<class GRID>
00423 inline
00424 vertex_iterator<GRID>
00425 grid_view<GRID>::FirstVertex() const { return typename gt::VertexIterator(*this);}
00426
00427 template<class GRID>
00428 inline
00429 cell_iterator<GRID>
00430 grid_view<GRID>::FirstCell() const { return typename gt::CellIterator(*this);}
00431
00432 template<class GRID>
00433 inline
00434 vertex_iterator<GRID>
00435 grid_view<GRID>::EndVertex() const { return typename gt::VertexIterator(*this, BaseGrid().EndCell());}
00436
00437 template<class GRID>
00438 inline
00439 cell_iterator<GRID>
00440 grid_view<GRID>::EndCell() const { return typename gt::CellIterator(*this, BaseGrid().EndCell());}
00441
00442
00443
00444
00445
00449 template<class GRID, class GEOM>
00450 class geom_view : public local_grid_types<GRID> {
00451 typedef GEOM base_geom_type;
00452 typedef local_grid_types<GRID> gt;
00453 public:
00454 typedef grid_geometry_category category;
00455 typedef typename base_geom_type::coord_type coord_type;
00456 typedef point_traits<coord_type> pt;
00457 typedef typename gt::bgt bgt;
00458 typedef typename gt::grid_type grid_type;
00459 typedef typename gt::vertex_handle vertex_handle;
00460 typedef typename gt::Vertex Vertex;
00461 typedef typename gt::Cell Cell;
00462 typedef typename gt::VertexOnCellIterator VertexOnCellIterator;
00463
00464 private:
00465 grid_type const* g;
00466 base_geom_type const* geom;
00467 double t;
00468 public:
00469 geom_view(grid_type const& gg,
00470 base_geom_type const& ggeom,
00471 double tt = 1.0)
00472 : g(&gg), geom(&ggeom), t(tt) {}
00473 void set_shrink_factor(double tt) { t = tt;}
00474
00475 coord_type coord(Vertex const& v) const
00476 {
00477 coord_type ctr = barycenter(v.Cell_());
00478 return ctr + t*(geom->coord(v.BaseVertex()) - ctr);
00479 }
00480
00481 coord_type barycenter(Cell const& c) const {
00482 int nv = c.NumOfVertices();
00483 coord_type sum(pt::Origin());
00484 for(VertexOnCellIterator vc(c); ! vc.IsDone(); ++vc)
00485 sum += geom->coord((*vc).BaseVertex());
00486 return sum * (1.0/(double)nv);
00487 }
00488 };
00489
00490 }
00491
00492
00493
00494
00495
00496
00497 template<class GRID>
00498 class grid_types<shrink_grid_view::grid_view<GRID> > :
00499 public grid_types_base<shrink_grid_view::local_grid_types<GRID> > {};
00500
00501
00502 template<class GRID>
00503 struct element_traits<shrink_grid_view::vertex_iterator<GRID> >
00504 : public element_traits_vertex_base<shrink_grid_view::grid_view<GRID> >
00505 {
00506 typedef element_traits_vertex_base<shrink_grid_view::grid_view<GRID> > base;
00507 typedef typename base::element_type element_type;
00508 typedef typename base::handle_type handle_type;
00509
00510 struct hasher_type : public base::hasher_type_elem_base {
00511 unsigned operator()(handle_type const& v) const
00512 { return (8*v.c + v.v);}
00513 unsigned operator()(element_type const& v) const
00514 { return (*this)(v.handle());}
00515 };
00516 };
00517
00518
00519 template<class GRID>
00520 struct element_traits<shrink_grid_view::cell_iterator<GRID> >
00521 : public element_traits_cell_base<shrink_grid_view::grid_view<GRID> >
00522 {
00523 typedef element_traits_cell_base<shrink_grid_view::grid_view<GRID> > base;
00524 typedef typename base::element_type element_type;
00525 typedef typename base::handle_type handle_type;
00526
00527 typedef shrink_grid_view::local_grid_types<GRID> lgt;
00528 typedef typename lgt::bgt bgt;
00529 typedef element_traits<typename bgt::Cell> bet;
00530 typedef typename bet::hasher_type base_hasher_type;
00531
00532 struct hasher_type : public base::hasher_type_elem_base {
00533
00534 unsigned operator()(handle_type const& v) const
00535 { base_hasher_type h; return h(v);}
00536 unsigned operator()(element_type const& v) const
00537 { return (*this)(v.handle());}
00538 };
00539 };
00540
00541
00542 namespace shrink_grid_view {
00543 #define gt grid_types<grid_view<GRID> >
00544
00545 template<class GRID>
00546 typename gt::VertexIterator gral_begin(grid_view<GRID> const& g, typename gt::VertexIterator)
00547 { return g.FirstVertex();}
00548
00549 template<class GRID>
00550 typename gt::VertexIterator gral_end (grid_view<GRID> const& g, typename gt::VertexIterator)
00551 { return g.EndVertex();}
00552
00553 template<class GRID>
00554 typename gt::size_type gral_size (grid_view<GRID> const& g, typename gt::VertexIterator)
00555 { return g.NumOfVertices();}
00556
00557 template<class GRID>
00558 typename gt::CellIterator gral_begin(grid_view<GRID> const& g, typename gt::CellIterator)
00559 { return g.FirstCell();}
00560
00561 template<class GRID>
00562 typename gt::CellIterator gral_end (grid_view<GRID> const& g, typename gt::CellIterator)
00563 { return g.EndCell();}
00564
00565 template<class GRID>
00566 typename gt::size_type gral_size (grid_view<GRID> const& g, typename gt::CellIterator)
00567 { return g.NumOfCells();}
00568
00569
00570 template<class GRID>
00571 typename gt::VertexOnCellIterator
00572 gral_begin(cell_iterator<GRID> const& c, typename gt::VertexOnCellIterator)
00573 { return c.FirstVertex();}
00574
00575 template<class GRID>
00576 typename gt::VertexOnCellIterator
00577 gral_end (cell_iterator<GRID> const& c, typename gt::VertexOnCellIterator)
00578 { return c.EndVertex();}
00579
00580 template<class GRID>
00581 typename gt::size_type
00582 gral_size (cell_iterator<GRID> const& c, typename gt::VertexOnCellIterator)
00583 { return c.NumOfVertices();}
00584
00585
00586 #undef gt
00587
00588 }
00589
00590
00591 template<class GRID, class T>
00592 class grid_function<shrink_grid_view::vertex_iterator<GRID>, T>
00593 : public grid_function_hash<shrink_grid_view::vertex_iterator<GRID>, T>
00594 {
00595 typedef grid_function_hash<shrink_grid_view::vertex_iterator<GRID>, T> base;
00596 public:
00597 typedef typename base::grid_type grid_type;
00598
00599 grid_function() {}
00600 grid_function(grid_type const& g) : base(g) {}
00601 grid_function(grid_type const& g,
00602 T const& t0) : base(g,t0) {}
00603 };
00604
00608 template<class GRID, class T>
00609 class grid_function<shrink_grid_view::cell_iterator<GRID>, T>
00610 : public grid_function_hash<shrink_grid_view::cell_iterator<GRID>, T>
00611 {
00612 typedef grid_function_hash<shrink_grid_view::cell_iterator<GRID>, T> base;
00613 public:
00614 typedef typename base::grid_type grid_type;
00615
00616 grid_function() {}
00617 grid_function(grid_type const& g) : base(g) {}
00618 grid_function(grid_type const& g,
00619 T const& t0) : base(g,t0) {}
00620 };
00621
00622
00623
00624 namespace shrink_grid_view {
00634 template<class GF>
00635 class grid_function_view {
00636 private:
00637 typedef grid_function_view<GF> self;
00638 typedef typename GF::grid_type base_grid_type;
00639 typedef typename GF::element_type base_element_type;
00640 typedef element_traits<base_element_type> bet;
00641 typedef typename bet::element_type_tag btag;
00642 typedef typename GF::const_iterator base_const_iterator;
00643 public:
00644 typedef grid_function_view_category<typename category<GF>::type> category;
00645 typedef typename GF::value_type value_type;
00646 typedef typename GF::reference reference;
00647 typedef typename GF::const_reference const_reference;
00648 typedef typename GF::size_type size_type;
00649
00650 typedef grid_view<base_grid_type> grid_type;
00651 typedef typename grid_type::template map_types<btag> map_types;
00652 typedef typename map_types::element_type element_type;
00653 typedef typename map_types::element_iterator element_iterator;
00654 typedef element_traits<element_type> et;
00655 private:
00656 grid_view<base_grid_type> const* g;
00657 GF const* gf;
00658 public:
00659 grid_function_view(grid_type const& g_,
00660 GF const& gf_) : g(&g_), gf(&gf_) {}
00661
00662 const_reference operator()(element_type const& e) const { return (*gf)(e.Base());}
00663 grid_type const& TheGrid() const { return *g;}
00664
00665 element_iterator FirstElement() const { return et::FirstElement(TheGrid());}
00666 element_iterator EndElement() const { return et::EndElement (TheGrid());}
00667
00668
00669 template<class GFV, class BASEIT>
00670 class const_iterator_t {
00671 typedef const_iterator_t<GFV,BASEIT> self;
00672 typedef GFV gf_type;
00673 typedef typename gf_type::element_iterator element_iterator;
00674 typedef std::iterator_traits<BASEIT> bt;
00675 public:
00676 typedef typename gf_type::const_reference const_reference;
00677
00678 typedef typename bt::reference reference;
00679 typedef typename bt::value_type value_type;
00680 typedef typename bt::pointer pointer;
00681 typedef typename bt::difference_type difference_type;
00682 typedef std::forward_iterator_tag iterator_category;
00683 private:
00684 gf_type const* gfv;
00685 element_iterator e;
00686 public:
00687 const_iterator_t() : gfv(0) {}
00688 const_iterator_t(gf_type const& gf, element_iterator const& ee)
00689 : gfv(&gf), e(ee) {}
00690
00691 const_reference operator*() const { return (*gfv)(*e);}
00692 self & operator++() { ++e; return *this;}
00693 bool operator==(self const& rhs) const { return e == rhs.e;}
00694 bool operator!=(self const& rhs) const { return e != rhs.e;}
00695 };
00696
00697 typedef const_iterator_t<self,base_const_iterator> const_iterator;
00698
00699 size_type size() const { return et::size(*g);}
00700 const_iterator begin() const { return const_iterator(*this, FirstElement());}
00701 const_iterator end() const { return const_iterator(*this, EndElement());}
00702
00703 };
00704
00705 }
00706
00707 }
00708
00709 #endif
00710