mirror of https://github.com/CGAL/cgal
738 lines
23 KiB
C++
738 lines
23 KiB
C++
// Copyright (c) 2005 Stanford University (USA).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); 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; version 2.1 of the License.
|
|
// See the file LICENSE.LGPL distributed with CGAL.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
//
|
|
//
|
|
// Author(s) : Daniel Russel <drussel@alumni.princeton.edu>
|
|
|
|
#ifndef CGAL_KINETIC_SIMULATOR_BASE_H_
|
|
#define CGAL_KINETIC_SIMULATOR_BASE_H_
|
|
#include <CGAL/Kinetic/basic.h>
|
|
#include <CGAL/Kinetic/Heap_pointer_event_queue.h>
|
|
#include <vector>
|
|
#include <CGAL/Interval_arithmetic.h>
|
|
#include <CGAL/Kinetic/Ref_counted.h>
|
|
#include <CGAL/Kinetic/Multi_listener.h>
|
|
|
|
namespace CGAL { namespace Kinetic {
|
|
|
|
#ifdef CGAL_KINETIC_CHECK_EXPENSIVE
|
|
#ifndef CGAL_KINETIC_DISABLE_AUDITING
|
|
#define CGAL_KINETIC_ENABLE_AUDITING
|
|
#endif
|
|
//#warning Kinetic data structures will be audited at run time.
|
|
#endif
|
|
|
|
|
|
//! The simulator
|
|
/*! The simulator is responsible for maintaining the event queue and
|
|
processing events in the proper order. It takes a PolynomialKernel
|
|
and an EventQueue as arguments as well as a flag saying whether the
|
|
computations are performed exactly or not. This flag affects how it
|
|
treats the output of the solvers. The PolynomialKernel is used to
|
|
generate solvers as well as evaluate some predicates on the
|
|
functions being solved.
|
|
|
|
The Simulator creates two types of notifications, one when time is
|
|
reversed (DIRECTION_OF_TIME) and one when there is a time at which
|
|
the kinetic data structures can efficient audit themselves
|
|
(HAS_AUDIT_TIME). The notification is done through a standard
|
|
interface describe in CGAL::Listener.
|
|
|
|
The solvers defined by the PolynomialKernel should not be the
|
|
CGAL::Polynomial::GSL_solver or CGAL::Polynomial::Linear_solver. Use
|
|
CGAL::Kinetic::GSL_solver or CGAL::KDS::Linear_solver instead as they
|
|
are more robust in the case of kinetic data structures.
|
|
|
|
Even though time can be "reversed" the future is always with
|
|
increasing time. When time is reversed the current_time() becomes
|
|
the negative of the old current_time(). In some cases, this means
|
|
processing some events (since there needs to be a value of time
|
|
after the last event and before the next one in order to reverse).
|
|
|
|
Auditing occurs once between each pair of disjoint events. It occurs
|
|
at a time close to the midpoint between the two event times. It is
|
|
triggered by the time being advanced beyond the midpoint between the
|
|
two event times.
|
|
|
|
The Root_enumerator type is not that defined by the
|
|
Polynomial_kernel since the polynomial kernel needs to have a real
|
|
solver which returns all roots, where as the Simulator solver can
|
|
check various invariants and skip even roots and things. This is
|
|
especially important when performing numeric computations.
|
|
|
|
I cannot put the Instantaneous_kernel in here since that might
|
|
depend on the static data structure being used.
|
|
*/
|
|
template <class Polynomial_kernel_t,
|
|
class Queue= CGAL::Kinetic::Heap_pointer_event_queue<Polynomial_kernel_t> >
|
|
class Default_simulator: public Ref_counted<Default_simulator<Polynomial_kernel_t, Queue> >
|
|
{
|
|
protected:
|
|
typedef Default_simulator<Polynomial_kernel_t, Queue> This;
|
|
//typedef typename Polynomial_kernel_t::Function Poly;
|
|
|
|
|
|
|
|
typedef typename Queue::Priority Queue_time;
|
|
|
|
public:
|
|
//typedef Kinetic_kernel_t Kinetic_kernel;
|
|
//! The polynomial kernel.
|
|
/*!
|
|
I don't know that there is any actual use for this, so
|
|
maybe it should not be exposed.
|
|
*/
|
|
typedef Polynomial_kernel_t Function_kernel;
|
|
|
|
//! The solver.
|
|
//typedef typename Function_kernel::Root_stack Root_stack;
|
|
|
|
//! The current time.
|
|
/*! This is a Root from the Polynomial package and supports
|
|
whatever operations they support. See
|
|
CGAL::Polynomial::Simple_interval_root for an example.
|
|
*/
|
|
typedef typename Function_kernel::Root Time;
|
|
|
|
//! A key which uniquely identifies a scheduled event
|
|
/*! If an event is not actually schedule (for example if it occurs
|
|
past the last time of interest), it is assigned a special
|
|
Event_key called null_event().
|
|
*/
|
|
//#ifdef NDEBUG
|
|
typedef typename Queue::Key Event_key;
|
|
/*#else
|
|
typedef typename Queue::Key Queue_key;
|
|
struct Event_key: public Queue_key {
|
|
Event_key(){}
|
|
Event_key(Queue_key k): Queue_key(k){}
|
|
};
|
|
#endif*/
|
|
|
|
//! The basic number type
|
|
typedef typename Function_kernel::FT NT;
|
|
|
|
//! Create a simulator passing the start time and the end time.
|
|
Default_simulator(const Time &start_time,
|
|
const Time &end_time,
|
|
Function_kernel fk=Function_kernel()):queue_(start_time, end_time, fk, 100),
|
|
cur_time_(start_time),
|
|
//last_event_time_(start_time),
|
|
mp_(fk.rational_between_roots_object()),
|
|
//ir_(fk.is_rational_object()),
|
|
//tr_(fk.to_rational_object()),
|
|
is_forward_(true) {
|
|
number_of_events_=0;
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
// make it less than the current time.
|
|
//std::pair<double, double> ival= to_interval(cur_time_);
|
|
//audit_time_=NT(ival.first-10.0);
|
|
audit_time_= CGAL::to_interval(start_time).second;
|
|
#endif
|
|
};
|
|
|
|
Default_simulator(const Time &start_time,
|
|
Function_kernel fk=Function_kernel()):queue_(start_time, fk, 100),
|
|
cur_time_(start_time),
|
|
//last_event_time_(start_time),
|
|
mp_(fk.rational_between_roots_object()),
|
|
//ir_(fk.is_rational_object()),
|
|
//tr_(fk.to_rational_object()),
|
|
is_forward_(true) {
|
|
number_of_events_=0;
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
// make it less than the current time.
|
|
//std::pair<double, double> ival= to_interval(cur_time_);
|
|
//audit_time_=NT(ival.first-10.0);
|
|
audit_time_= CGAL::to_interval(start_time).second;
|
|
#endif
|
|
};
|
|
|
|
//! Return the current time
|
|
/*! If an event is currently being processed, then this is the
|
|
failure time of that event. Otherwise it is between the last event
|
|
which was processed and the next event to be processed.
|
|
*/
|
|
CGAL_GET(Time, current_time, return cur_time_);
|
|
|
|
//! Set the current time to t
|
|
/*!
|
|
t must be after (or equal to) current_time(). Any events
|
|
between current_time() and t are processed in the proper
|
|
order.
|
|
*/
|
|
void set_current_time(const Time &t) {
|
|
CGAL_precondition_code(CGAL::Comparison_result debug_cr
|
|
=CGAL::compare(t, cur_time_));
|
|
CGAL_precondition(debug_cr != CGAL::SMALLER);
|
|
/*#ifdef CGAL_KINETIC_CHECK_EXPENSIVE
|
|
if (current_time() < audit_time_ && t >= audit_time_) {
|
|
audit_all_kdss();
|
|
}
|
|
#endif*/
|
|
while (CGAL::compare(next_event_time(), t) == CGAL::SMALLER
|
|
&& !queue_.empty()) {
|
|
//Time net= next_event_time();
|
|
//CGAL::Comparison_result cr= CGAL::compare(next_event_time(), t);
|
|
process_next_event();
|
|
/*#ifdef CGAL_KINETIC_CHECK_EXPENSIVE
|
|
if (current_time() < audit_time_ && t >= audit_time_) {
|
|
audit_all_kdss();
|
|
}
|
|
cur_time_=audit_time_;
|
|
#endif*/
|
|
}
|
|
if (queue_.is_after_end(t)) {
|
|
cur_time_= queue_.end_priority();
|
|
} else {
|
|
cur_time_=t;
|
|
}
|
|
|
|
}
|
|
|
|
//! Not clear if I want two methods
|
|
void set_interval(const Time &ts, const Time &te) {
|
|
//CGAL_precondition(t <=cur_time_);
|
|
if (!queue_.empty()) {
|
|
std::cerr << queue_ << std::endl;
|
|
}
|
|
CGAL_precondition(queue_.empty());
|
|
cur_time_=ts;
|
|
//last_event_time_=ts;
|
|
queue_.set_interval(ts, te);
|
|
}
|
|
|
|
//! Return a rational number for current time.
|
|
/*! This returns a ration number representing the current
|
|
time. This only returns a valid time if
|
|
has_rational_current_time() is true.
|
|
*/
|
|
NT next_time_representable_as_nt() const
|
|
{
|
|
// why did I have this? "&& cur_time_ != end_time()"
|
|
double ub= to_interval(current_time()).second;
|
|
if (CGAL::compare(current_time(), next_event_time()) == CGAL::EQUAL
|
|
|| CGAL::compare(Time(ub), next_event_time()) == CGAL::SMALLER) {
|
|
return NT(ub);
|
|
} else {
|
|
//typename Function_kernel::Rational_between_roots bet= kernel_.rational_between_roots_object();
|
|
if (current_time() == end_time()) {
|
|
// really, I do want last_event, but I removed it :-(
|
|
std::pair<double,double> ti= CGAL::to_interval(end_time());
|
|
if (ti.first == ti.second) {
|
|
return NT(ti.first);
|
|
} else {
|
|
std::cerr << "You cannot currently call this function at the end of time if the end time is not"
|
|
"exactly representable as a double. Sorry. This is fixable, so complain to me--Daniel" << std::endl;
|
|
CGAL_error();
|
|
return NT(ti.first);
|
|
}
|
|
} else {
|
|
return mp_(current_time(), next_event_time());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//! Returns true if the current time is a rational number and there are no events at the current time
|
|
/*!
|
|
precondition that has_rational_current_time().
|
|
*/
|
|
bool has_audit_time() const
|
|
{
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
return CGAL::compare(Time(audit_time_), current_time()) != CGAL::SMALLER;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
const NT& audit_time() const
|
|
{
|
|
CGAL_precondition(has_audit_time());
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
CGAL_precondition(queue_.empty() || Time(audit_time_) < next_event_time());
|
|
return audit_time_;
|
|
#else
|
|
CGAL_precondition(0);
|
|
static NT z(0);
|
|
return z;
|
|
#endif
|
|
}
|
|
|
|
//! The time of the next event
|
|
/*!
|
|
Or end_time() if the queue is empty.
|
|
*/
|
|
CGAL_GETNR(Time, next_event_time, return queue_.empty()?
|
|
end_time(): Time(queue_.front_priority()));
|
|
|
|
CGAL_GETNR(Event_key, next_event, return queue_.empty()?
|
|
Event_key(): queue_.front());
|
|
|
|
//! The last time of interest
|
|
/*!
|
|
If time is running backwards, then this returns Time::infinity()
|
|
*/
|
|
CGAL_GETNR(Time, end_time, return is_forward_?
|
|
queue_.end_priority():
|
|
std::numeric_limits<Time>::infinity()
|
|
);
|
|
|
|
//! Set the last time to track events for
|
|
/*!
|
|
The current_time() must equal the end_time() in order
|
|
to ensure that no events were missed.
|
|
*/
|
|
/*void set_end_time(const Time &t) {
|
|
CGAL_precondition(cur_time_==end_time());
|
|
//end_time_= t;
|
|
queue_.set_end_priority(t);
|
|
}*/
|
|
|
|
//! Create a new event and return its key
|
|
/*! The only interaction with the actual event is through the
|
|
EventQueue template paramenter. See CGAL::Kinetic::Pointer_event_queue
|
|
for the requirements of the default event queue. If the event's
|
|
failure time is past end_time() then a key equal to null_event()
|
|
is returned.
|
|
*/
|
|
template <class E>
|
|
Event_key new_event(const Time &t, const E& cert) {
|
|
//CGAL_precondition(t != Time());
|
|
//CGAL_exactness_precondition(!(t < current_time()));
|
|
//if (cert.time() == Time::infinity()) return final_event();
|
|
//CGAL_assertion(cert.time() < end_time());
|
|
//if (0) cert.process();
|
|
//std::cout << "Requested to schedule "; cert->write(std::cout);
|
|
//std::cout<< " at time " << t << std::endl;
|
|
CGAL_exactness_precondition(CGAL::compare(t, current_time()) != CGAL::SMALLER);
|
|
CGAL_precondition(!std::numeric_limits<Time>::has_infinity
|
|
|| CGAL::compare(t, std::numeric_limits<Time>::infinity())
|
|
== CGAL::SMALLER);
|
|
Event_key key= queue_.insert(t, cert);
|
|
//write_eventqueue(log().stream(Log::DEBUG));
|
|
//log()->stream(Log::SOME) << key;
|
|
//log()->stream(Log::SOME)
|
|
|
|
CGAL_LOG(Log::SOME, "Created event " << key << std::endl);
|
|
//CGAL_LOG(Log::SOME, *this << std::endl);
|
|
//if (log()->is_output(Log::LOTS)) write(log()->stream(Log::LOTS));
|
|
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
if (CGAL::compare(Time(audit_time_), t) != CGAL::SMALLER && has_audit_time() ) {
|
|
compute_audit_time(current_time());
|
|
}
|
|
//if (key != null_event()) audit_event(key);
|
|
#endif
|
|
|
|
return key;
|
|
//}
|
|
}
|
|
|
|
|
|
//! The key corresponding to events which never occur.
|
|
/*! Events can never occur if their time is past the end time or
|
|
their certificate function has no roots.
|
|
*/
|
|
CGAL_GETNR(Event_key, null_event, return queue_.end_key());
|
|
|
|
/*const Event_key& final_event() const {
|
|
return queue_.final_event();
|
|
}*/
|
|
|
|
//! Register an event to be processed after all events.
|
|
/*! I am not sure if I use this capability, so it may be droppable
|
|
*/
|
|
template <class E>
|
|
Event_key new_final_event(const E &cert) {
|
|
// this should be in the simulator anyway,
|
|
return queue_.insert(end_time(), cert);
|
|
}
|
|
|
|
//! Delete the event with key k
|
|
/*!
|
|
This is just passed to the event queue.
|
|
*/
|
|
void delete_event(const Event_key &k) {
|
|
audit_event(k);
|
|
//if (k== final_event()) return;
|
|
//#ifdef NDEBUG
|
|
if (k== null_event() || k== Event_key()) {
|
|
return;
|
|
}
|
|
//#endif
|
|
CGAL_LOG(Log::SOME, "Deleting event " << k << std::endl);
|
|
queue_.erase(k);
|
|
//CGAL_LOG(Log::LOTS , *this);
|
|
}
|
|
|
|
//! The type for a handle to an event.
|
|
/*template <class E>
|
|
struct Event_handle: public Queue::template Event_info<E>::Handle {
|
|
Event_handle(typename Queue::template Event_info<E>::Pointer p): Queue::template Event_info<E>::Handle(p) {
|
|
}
|
|
Event_handle(){}
|
|
};*/
|
|
|
|
//! Access an event
|
|
/*! The type of the returned pointer is an Event_pointer<E> where E
|
|
is the template argument. I recommend just fetching the event each
|
|
time you need it, rather than trying to store the pointer
|
|
type. This method is effectively free (it is just a cast in the
|
|
default implementation).
|
|
|
|
You cannot change the event using this pointer, it is simply for
|
|
recovering cached data (like Solvers).
|
|
|
|
If you need to store it, wrap the return value in an Event_handle
|
|
to get reference counting, otherwise the event might be processed
|
|
and the object for it go away.
|
|
|
|
The second argument really shouldn't be there, but gcc seems to
|
|
have issues sometimes if you try to specify the template value
|
|
directly.
|
|
*/
|
|
/*template <class Ev>
|
|
typename Queue::template Event_pointer<Ev>::Pointer event(const Event_key &k, const Ev& e) const {
|
|
CGAL_LOG(Log::LOTS, "Accessing event for key " << k << std::endl);
|
|
return queue_.event(k,e);
|
|
}*/
|
|
|
|
template <class Event_type>
|
|
const Event_type& event(const Event_key &k) const
|
|
{
|
|
CGAL_precondition(k != Event_key());
|
|
CGAL_precondition(k != null_event());
|
|
//CGAL_LOG(Log::LOTS, "Accessing event for key " << k << std::endl);
|
|
return queue_.template get<Event_type>(k);
|
|
}
|
|
|
|
|
|
template <class Event_type>
|
|
Event_type& event(const Event_key &k){
|
|
CGAL_precondition(k != Event_key());
|
|
CGAL_precondition(k != null_event());
|
|
//CGAL_LOG(Log::LOTS, "Accessing event for key " << k << std::endl);
|
|
return queue_.template get<Event_type>(k);
|
|
}
|
|
|
|
/*template <class Event_type>
|
|
const Event_type& event(const Event_key &k, const Event_type&) const {
|
|
CGAL_LOG(Log::LOTS, "Accessing event for key " << k << std::endl);
|
|
return queue_.template get<Event_type>(k);
|
|
}*/
|
|
|
|
//! Access the time of an event
|
|
const Time &event_time(const Event_key &k) const
|
|
{
|
|
CGAL_precondition(k != Event_key());
|
|
return queue_.priority(k);
|
|
}
|
|
|
|
//! Change an event to have a new object
|
|
/*!
|
|
*/
|
|
template <class Ev>
|
|
Event_key set_event(const Event_key &k, const Ev& ev) {
|
|
CGAL_LOG(Log::SOME, "Changed event " << k << std::flush);
|
|
Event_key rk= queue_.set(k, ev);
|
|
CGAL_LOG(Log::SOME, " to event " << rk << std::endl);
|
|
CGAL_LOG(Log::LOTS, *this);
|
|
return rk;
|
|
}
|
|
|
|
//! Set which direction time is running
|
|
/*! Set it to CGAL::NEGATIVE to make time run backwards,
|
|
CGAL::POSITIVE to make it run forwards. CGAL::ZERO is an error.
|
|
*/
|
|
void set_direction_of_time(Sign sn);
|
|
|
|
//! Return the direction of time.
|
|
CGAL_GETNR(CGAL::Sign, direction_of_time, return is_forward_?
|
|
CGAL::POSITIVE: CGAL::NEGATIVE);
|
|
|
|
//! Return the number of events which has been processed.
|
|
CGAL_GETNR(unsigned int, current_event_number, return number_of_events_);
|
|
|
|
|
|
bool empty() const {
|
|
return queue_.empty();
|
|
}
|
|
|
|
//! Process all events up to event i
|
|
/*!
|
|
i must be greater than current_event_number().
|
|
*/
|
|
CGAL_SET(unsigned int, current_event_number,
|
|
while (!queue_.empty() && number_of_events_ < k) {
|
|
/*#ifdef CGAL_KINETIC_CHECK_EXPENSIVE
|
|
if (current_time() < audit_time_ && next_event_time() >= audit_time_) {
|
|
audit_all_kdss();
|
|
}
|
|
#endif*/
|
|
process_next_event();
|
|
}
|
|
);
|
|
|
|
std::ostream& write(std::ostream &out) const
|
|
{
|
|
out << "Simulator: (" << to_double(current_time())
|
|
<< "..." << to_double(end_time()) << ")\n";
|
|
out << queue_ << std::endl;
|
|
return out;
|
|
}
|
|
|
|
void print() const
|
|
{
|
|
write(std::cout);
|
|
}
|
|
|
|
void clear() {
|
|
queue_.clear();
|
|
}
|
|
|
|
void audit_events() const {
|
|
queue_.audit_events();
|
|
}
|
|
|
|
void audit_event(Event_key k) const {
|
|
if (k!= null_event()) {
|
|
CGAL_assertion(k != Event_key());
|
|
#ifndef NDEBUG
|
|
if (!queue_.contains(k)) {
|
|
CGAL_ERROR("Event " << k << " is not in queue.");
|
|
}
|
|
#endif
|
|
CGAL_assertion(queue_.contains(k));
|
|
queue_.audit_event(k);
|
|
}
|
|
}
|
|
|
|
Event_key current_event() const {
|
|
return cur_event_;
|
|
}
|
|
|
|
protected:
|
|
|
|
template <class Root>
|
|
bool compute_audit_time(const Root &) {
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
|
|
if (current_time() == end_time()
|
|
&& end_time() == std::numeric_limits<Time>::infinity()) {
|
|
return false;
|
|
}
|
|
if (queue_.empty()) {
|
|
if (cur_time_ != end_time()) {
|
|
std::pair<double,double> ei= CGAL::to_interval(end_time());
|
|
if (cur_time_ > Time(ei.first)) {
|
|
return false;
|
|
}
|
|
else {
|
|
audit_time_=ei.first;
|
|
return true;
|
|
}
|
|
|
|
} else {
|
|
// bad form to just return like that
|
|
audit_time_= NT(CGAL::to_interval(current_time()).first-10.0);
|
|
return false;
|
|
}
|
|
} else {
|
|
audit_time_= CGAL::to_interval(current_time()).second;
|
|
if (CGAL::compare(Time(audit_time_), next_event_time()) != CGAL::SMALLER) {
|
|
if(CGAL::compare(next_event_time(), current_time()) != CGAL::EQUAL) {
|
|
audit_time_= mp_(current_time(), next_event_time());
|
|
return true;
|
|
} else {
|
|
audit_time_= CGAL::to_interval(current_time()).first -10;
|
|
return false;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
bool compute_audit_time(double) {
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
//bool audit_on_doubles;
|
|
if (next_event_time()-current_time() < .1) return false;
|
|
else {
|
|
audit_time_= (current_time()+ next_event_time())/2.0;
|
|
return audit_time_ > current_time() && audit_time_ < next_event_time();
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
//! Return a time between the current and the next event to use for validating
|
|
/*! This is a time between the last certificate failure time and
|
|
the next. Return true if there is such a time.
|
|
*/
|
|
//NT compute_free_time() const;
|
|
|
|
//! Process the next event
|
|
void process_next_event() {
|
|
CGAL_LOG(Log::LOTS, *this);
|
|
/*#ifndef NDEBUG
|
|
if (cur_time_ < audit_time_){
|
|
audit_all_kdss();
|
|
}
|
|
#endif*/
|
|
/*#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
if (CGAL::compare(next_event_time(), current_time()) != CGAL::EQUAL) {
|
|
//typename Function_kernel::Rational_between_roots bet= kernel_.rational_between_roots_object();
|
|
CGAL_LOG(Log::SOME, "Audit is at time " << audit_time_ << std::endl);
|
|
//if (current_time() < audit_time_ && t >= audit_time_) {
|
|
audit_all_kdss();
|
|
//}
|
|
} else {
|
|
CGAL_LOG(Log::SOME, "Can't audit between events.\n");
|
|
}
|
|
#endif*/
|
|
|
|
CGAL_precondition(!queue_.empty());
|
|
CGAL_exactness_precondition(CGAL::compare(next_event_time(),current_time())
|
|
!= CGAL::SMALLER);
|
|
//if (CGAL::compare(next_event_time(),cur_time_) == CGAL::LARGER) {
|
|
cur_time_= next_event_time();
|
|
cur_event_= queue_.front();
|
|
CGAL_LOG(Log::LOTS, "Processing event at time " << cur_time_ << std::endl);
|
|
queue_.process_front();
|
|
++number_of_events_;
|
|
cur_event_= Event_key();
|
|
|
|
CGAL_LOG(Log::LOTS, *this);
|
|
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
if (compute_audit_time(Time())) {
|
|
CGAL_LOG(Log::SOME, "Audit is at time " << audit_time_ << std::endl);
|
|
//if (current_time() < audit_time_ && t >= audit_time_) {
|
|
audit_all_kdss();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void audit_all_kdss() ;
|
|
|
|
|
|
|
|
/*struct Listener_core
|
|
{
|
|
typedef typename This::Handle Notifier_handle;
|
|
typedef enum {}
|
|
Notification_type;
|
|
};*/
|
|
CGAL_KINETIC_MULTILISTENER2(HAS_AUDIT_TIME, DIRECTION_OF_TIME)
|
|
|
|
protected:
|
|
Queue queue_;
|
|
Time cur_time_; //, last_event_time_;
|
|
unsigned int number_of_events_;
|
|
typename Function_kernel::Rational_between_roots mp_;
|
|
// typename Function_kernel::Is_rational ir_;
|
|
// typename Function_kernel::To_rational tr_;
|
|
bool is_forward_;
|
|
Event_key cur_event_;
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
NT audit_time_;
|
|
#endif
|
|
};
|
|
|
|
/*template <class S, bool E, class PQ>
|
|
typename Default_simulator<S, E, PQ>::NT Default_simulator<S, E, PQ>::compute_free_time() const {
|
|
if (!(last_time_ < next_event_time())) {
|
|
std::cerr << "No time between " << current_time() << " and " << next_event_time() << std::endl;
|
|
return current_time_nt()- CGAL::abs(current_time_nt());
|
|
} else {
|
|
if (current_time() != last_time_){
|
|
double dt= CGAL::to_double(current_time());
|
|
NT ntdt(dt);
|
|
Time tdt(ntdt);
|
|
if (tdt > last_time_ && tdt < next_event_time()) return NT(dt);
|
|
}
|
|
|
|
return mp_(current_time(), next_event_time());
|
|
}
|
|
}*/
|
|
|
|
template <class S, class PQ>
|
|
void Default_simulator<S, PQ>::set_direction_of_time(CGAL::Sign dir)
|
|
{
|
|
if (dir != direction_of_time()) {
|
|
while (next_event_time() == current_time()) {
|
|
std::cerr << "Processing event in order to reverse time.\n";
|
|
process_next_event();
|
|
}
|
|
|
|
Time oct= cur_time_;
|
|
NT tnt= NT(to_interval(cur_time_).second);// was CGAL::
|
|
|
|
Time tdt(tnt);
|
|
if (tdt == cur_time_) {
|
|
tnt= tnt+ NT(.000001);
|
|
tdt= Time(tnt);
|
|
}
|
|
|
|
if (CGAL::compare(tdt, next_event_time()) != CGAL::SMALLER) {
|
|
//typename Function_kernel::Rational_between_roots rbr= kernel_.rational_between_roots_object();
|
|
tnt= mp_(cur_time_, next_event_time());
|
|
tdt= Time(tnt);
|
|
}
|
|
|
|
cur_time_= Time(-tnt);
|
|
|
|
is_forward_= !is_forward_;
|
|
//end_time_=-end_time_;
|
|
//last_event_time_= -std::numeric_limits<Time>::infinity();
|
|
CGAL_LOG(Log::SOME, "Current time is " << cur_time_ << " and was " << oct
|
|
<< ", end_time() is " << end_time() << std::endl);
|
|
CGAL_KINETIC_MULTINOTIFY(DIRECTION_OF_TIME);
|
|
}
|
|
else {
|
|
CGAL_LOG(Log::SOME, dir << " " << end_time() << " " << cur_time_ << std::endl);
|
|
}
|
|
}
|
|
|
|
|
|
template <class S, class PQ>
|
|
void Default_simulator<S, PQ>::audit_all_kdss()
|
|
{
|
|
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
|
cur_time_= Time(audit_time_);
|
|
CGAL_LOG(Log::SOME, "Auditing KDSs at time " << audit_time() << std::endl);
|
|
CGAL_KINETIC_MULTINOTIFY(HAS_AUDIT_TIME);
|
|
queue_.audit_events();
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
CGAL_OUTPUT2(Default_simulator)
|
|
|
|
|
|
} } //namespace CGAL::Kinetic
|
|
#endif
|