49#define EST_REAC_THRESHOLD 3.
50#define ClutchEngageSpeed 0.5
51#define EIDM_POS_ACC_EPS 0.05
78 WRITE_WARNINGF(
"CarFollowModel EIDM is not compatible with actionStepLength % in vType '%'", STEPS2TIME(vtype->getActionStepLength()), vtype->getID());
88 std::ostringstream internals;
96 internals <<
v0_int <<
" ";
97 internals <<
v0_old <<
" ";
98 internals <<
t_off <<
" ";
115 const std::string cfmID = attrs.
get<std::string>(
SUMO_ATTR_ID,
nullptr, ok);
116 if (cfmID !=
"EIDM") {
117 throw ProcessError(
TLF(
"incompatible carFollowModel '%' when loading state for EIDM", cfmID));
181 x = (-b + sqrt(b * b - 4.*a * c)) / (2.*a);
191 if (origSafeDecel >
myDecel + NUMERICAL_EPS) {
198#ifdef DEBUG_EMERGENCYDECEL
200 std::cout <<
SIMTIME <<
" initial vsafe=" << x
201 <<
" egoSpeed=" << egoSpeed <<
" (origSafeDecel=" << origSafeDecel <<
")"
202 <<
" predSpeed=" << predSpeed <<
" (predDecel=" << predMaxDecel <<
")"
203 <<
" safeDecel=" << safeDecel
210 safeDecel =
MIN2(safeDecel, origSafeDecel);
216#ifdef DEBUG_EMERGENCYDECEL
218 std::cout <<
" -> corrected emergency deceleration: " << safeDecel << std::endl;
225 assert(!std::isnan(x));
233 const double g = gap - NUMERICAL_EPS;
248 vsafe = (-b + sqrt(b * b - 4.*a * c)) / (2.*a);
276 const double intensity =
MIN3(Accel_vMax, 1.5,
MAX2(vMax - 0.5 * Accel_vMax, 0.0));
277 const double criticality =
MIN2(
MAX2(s / vars->
mys_est - 0.5, -0.4), 0.0);
279 const double drivingerror =
mySigmaerror * vars->
myw_error * intensity * (2.75 * 2.75 * criticality * criticality + 1.0);
294 if (newSpeed == 0 || newSpeed <= currentSpeed) {
298 double remainingDelay = 0.0;
299 if (newSpeed != vMax) {
303 double v_corr = currentSpeed;
318 v_corr = v_corr + (newSpeed - currentSpeed) /
myIterations;
330 const double oldV = veh->
getSpeed();
337 for (
auto it = vars->
stop.cbegin(); it != vars->
stop.cend(); ++it) {
338 if (vPos > oldV +
ACCEL2SPEED(it->first) - NUMERICAL_EPS && vPos < oldV +
ACCEL2SPEED(it->first) + NUMERICAL_EPS) {
352 vMax =
MAX2(vMin, vMax);
357 <<
" EIDM::finalizeSpeed "
358 <<
" veh=" << veh->
getID()
361 <<
" _vPos=" << _vPos
362 <<
" vStop=" << vStop
363 <<
" vMinEmergency=" << vMinEmergency
388 }
else if (vNext <= oldV && vNext < vMax - NUMERICAL_EPS && oldV >
ClutchEngageSpeed * 2) {
413 vNext =
MAX2(vNext, vMin);
428 <<
" EIDM::finalizeSpeed (2) "
429 <<
" veh=" << veh->
getID()
432 <<
" addTime=" << addTime
433 <<
" vDelay=" << vDelay
435 <<
" vNext=" << vNext
460 <<
" EIDM::finalizeSpeed (3) "
461 <<
" veh=" << veh->
getID()
462 <<
" vars->myw_gap=" << vars->
myw_gap
463 <<
" vars->myw_speed=" << vars->
myw_speed
464 <<
" vars->myw_error=" << vars->
myw_error
465 <<
" vars->lastacc=" << vars->
lastacc
524 <<
" EIDM::followSpeed "
525 <<
" veh=" << veh->
getID()
526 <<
" speed=" << speed
527 <<
" gap2pred=" << gap2pred
528 <<
" predSpeed=" << predSpeed
529 <<
" vars->v0_int=" << vars->
v0_int
535 double result =
_v(veh, gap2pred, speed, predSpeed, vars->
v0_int,
true,
update, _vUsage);
563 <<
" EIDM::stopSpeed "
564 <<
" veh=" << veh->
getID()
565 <<
" speed=" << speed
567 <<
" vars->v0_int=" << vars->
v0_int
573 double result =
_v(veh, gap, speed, 0, vars->
v0_int,
false,
update, _vUsage);
583MSCFModel_EIDM::freeSpeed(
const double currentSpeed,
const double decel,
const double dist,
const double targetSpeed,
const bool onInsertion) {
599 const double y =
MAX2(0.0, ((sqrt((b + 2.0 * v) * (b + 2.0 * v) + 8.0 * b * dist) - b) * 0.5 - v) / b);
600 const double yFull = floor(y);
601 const double exactGap = (yFull * yFull + yFull) * 0.5 * b + yFull * v + (y > yFull ? v : 0.0);
602 const double fullSpeedGain = (yFull + (onInsertion ? 1. : 0.)) *
ACCEL2SPEED(decel);
603 return DIST2SPEED(
MAX2(0.0, dist - exactGap) / (yFull + 1)) + fullSpeedGain + targetSpeed;
618 assert(currentSpeed >= 0);
619 assert(targetSpeed >= 0);
621 const double dt = onInsertion ? 0 :
TS;
622 const double v0 = currentSpeed;
623 const double vT = targetSpeed;
624 const double b = decel;
625 const double d = dist - NUMERICAL_EPS;
634 if (0.5 * (v0 + vT)*dt >= d) {
638 const double q = ((dt * v0 - 2 * d) * b - vT * vT);
639 const double p = 0.5 * b * dt;
640 return -p + sqrt(p * p - q);
669 <<
" EIDM::freeSpeed "
670 <<
" veh=" << veh->
getID()
671 <<
" speed=" << speed
673 <<
" maxSpeed=" << maxSpeed
675 <<
" onInsertion=" << onInsertion
688 double vSafe, remaining_time, targetDecel;
702 targetDecel = (speed - maxSpeed) / remaining_time;
735 vSafe =
_v(veh, 500., speed, maxSpeed, vars->
v0_int,
true,
update, _vUsage);
749 const double vNext = veh->
getSpeed() + acc;
750 const double gap = (vNext - vL) * (veh->
getSpeed() + vL) / (2 *
myDecel) + vL;
762 const double delta_v = speed - leaderSpeed;
779 const double delta_v = speed - leaderSpeed;
785 if (speed <= vars->v0_int) {
786 erg = sqrt((s * s) / (
MAX2(targetDecel / Accel_speed + 1.0, 1.0)));
789 erg = sqrt((s * s) / (
MAX2(targetDecel / Accel_speed + 1.0 + a_free / Accel_speed, 1.0)));
800 double v_limcurr, v_limprev;
807 std::vector<MSLink*>::const_iterator link =
MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
810 bool activeGLOSA =
false;
823 double speedlim = 200;
863 if ((*link)->getViaLane() ==
nullptr) {
866 lane = (*link)->getViaLaneOrLane();
881 if (!(v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) ||
882 (v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS && !(v_limprev < v_limcurr + NUMERICAL_EPS && v_limprev > v_limcurr - NUMERICAL_EPS))) {
884 if ((v_limcurr < v_limprev + NUMERICAL_EPS && v_limcurr < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) ||
885 (v_limcurr > v_limprev - NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS && v_limprev < v0 + NUMERICAL_EPS)) {
888 if (v_limcurr >= v0 - NUMERICAL_EPS) {
896 if (v_limcurr < v0 + NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS) {
904 }
else if (!(v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) ||
905 (v_limprev < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS && !(v_limprev < v_limcurr + NUMERICAL_EPS && v_limprev > v_limcurr - NUMERICAL_EPS))) {
907 if ((v_limcurr < v_limprev + NUMERICAL_EPS && v_limcurr < v0 + NUMERICAL_EPS && v_limprev > v0 - NUMERICAL_EPS) ||
908 (v_limcurr > v_limprev - NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS && v_limprev < v0 + NUMERICAL_EPS)) {
911 if (v_limcurr >= v0 - NUMERICAL_EPS) {
919 if (v_limcurr < v0 + NUMERICAL_EPS && v_limcurr > v0 - NUMERICAL_EPS) {
930 const double predSpeed,
const double desSpeed,
const bool respectMinGap,
const int update,
const CalcReason usage)
const {
932 double v0 =
MAX2(NUMERICAL_EPS, desSpeed);
944 double wantedacc = 0., a_free;
945 double wouldacc = 0., woulds, woulda_free;
947 double estSpeed, estleaderSpeed, estGap;
948 double current_estSpeed, current_estGap, current_estleaderSpeed;
951 double a_leader = NUMERICAL_EPS;
952 double newSpeed = egoSpeed;
953 bool lastrespectMinGap = respectMinGap;
959 current_gap =
MAX2(NUMERICAL_EPS, gap2pred +
MAX2(NUMERICAL_EPS,
myType->getMinGap() - 0.25));
962 current_gap =
MAX2(NUMERICAL_EPS, gap2pred + minGapStop_EPS);
965 double newGap = current_gap;
970 current_estSpeed = newSpeed;
976 current_estleaderSpeed = predSpeed;
979 current_estGap = newGap;
989 estSpeed = current_estSpeed;
990 estleaderSpeed = current_estleaderSpeed;
991 estGap = current_estGap;
1001 if (lastrespectMinGap) {
1013 estSpeed = current_estSpeed;
1014 estleaderSpeed = current_estleaderSpeed;
1015 estGap = current_estGap;
1025 double s =
MAX2(0., estSpeed * headwayTime + estSpeed * (estSpeed - estleaderSpeed) / (2 * sqrt(Accel_estSpeed *
myDecel)));
1026 if (lastrespectMinGap) {
1034 if (lastrespectMinGap) {
1062 if (estSpeed <= v0) {
1063 a_free = Accel_estSpeed * (1. - pow(estSpeed / v0,
myDelta));
1065 wantedacc = Accel_estSpeed * (1. - (s * s) / (estGap * estGap));
1067 wantedacc = a_free * (1. - pow(s / estGap, 2 * Accel_estSpeed / a_free));
1072 wantedacc = a_free + Accel_estSpeed * (1. - (s * s) / (estGap * estGap));
1082 woulds =
MAX2(0., current_estSpeed * headwayTime + current_estSpeed * (current_estSpeed - current_estleaderSpeed) / (2 * sqrt(Accel_current_estSpeed *
myDecel)));
1083 if (respectMinGap) {
1089 if (current_estSpeed <= v0) {
1090 woulda_free = Accel_current_estSpeed * (1. - pow(current_estSpeed / v0,
myDelta));
1091 if (woulds >= current_estGap) {
1092 wouldacc = Accel_current_estSpeed * (1. - (woulds * woulds) / (current_estGap * current_estGap));
1094 wouldacc = woulda_free * (1. - pow(woulds / current_estGap, 2 * Accel_current_estSpeed / woulda_free));
1097 woulda_free = -
myDecel * (1. - pow(v0 / current_estSpeed, Accel_current_estSpeed *
myDelta /
myDecel));
1098 if (woulds >= current_estGap) {
1099 wouldacc = woulda_free + Accel_current_estSpeed * (1. - (woulds * woulds) / (current_estGap * current_estGap));
1101 wouldacc = woulda_free;
1113 double calc_gap = estGap;
1126 if (estSpeed <= v0) {
1127 a_free = Accel_estSpeed * (1. - pow(estSpeed / v0,
myDelta));
1128 if (s >= calc_gap) {
1129 acc = Accel_estSpeed * (1. - (s * s) / (calc_gap * calc_gap));
1131 acc = a_free * (1. - pow(s / calc_gap, 2 * Accel_estSpeed / a_free));
1135 if (s >= calc_gap) {
1136 acc = a_free + Accel_estSpeed * (1. - (s * s) / (calc_gap * calc_gap));
1148 if (leader !=
nullptr && lastrespectMinGap && estleaderSpeed >= SPEED_EPS) {
1151 if (estGap > s * 3 / 2) {
1152 a_leader = a_leader * (s * 3 / 2) / estGap;
1157 if (estleaderSpeed < SPEED_EPS) {
1158 estleaderSpeed = SPEED_EPS;
1164 if (estleaderSpeed * (estSpeed - estleaderSpeed) <= -2 * estGap * a_leader) {
1165 a_cah = (estSpeed * estSpeed * a_leader) / (estleaderSpeed * estleaderSpeed - 2 * estGap * a_leader);
1167 if (estSpeed - estleaderSpeed >= 0) {
1168 a_cah = a_leader - ((estSpeed - estleaderSpeed) * (estSpeed - estleaderSpeed)) / (2 * estGap);
1214 <<
" veh=" << veh->
getID()
1215 <<
" vars->minaccel=" << vars->
minaccel
1217 <<
" vars->myv_est_l=" << vars->
myv_est_l
1218 <<
" vars->myv_est=" << vars->
myv_est
1219 <<
" vars->mys_est=" << vars->
mys_est
1220 <<
" vars->wouldacc=" << vars->
wouldacc
1221 <<
" vars->realacc=" << vars->
realacc
1225 <<
" veh=" << veh->
getID()
1226 <<
" newSpeed=" << newSpeed
1227 <<
" newGap=" << newGap
1228 <<
" predSpeed=" << predSpeed
1229 <<
" estSpeed=" << estSpeed
1230 <<
" estleaderSpeed=" << estleaderSpeed
1231 <<
" estGap=" << estGap
1232 <<
" wantedacc=" << wantedacc
1233 <<
" wouldacc=" << wouldacc
1275 vars->
stop.push_back(std::make_pair(acc, gap2pred));
1278 return MAX2(0., newSpeed);
#define EMERGENCY_DECEL_AMPLIFIER
#define ClutchEngageSpeed
#define EST_REAC_THRESHOLD
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ TURN_LEFTHAND
The link is a 180 degree turn (left-hand network).
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link).
@ SUMO_ATTR_CF_EIDM_T_ACC_MAX
@ SUMO_ATTR_CF_EIDM_EPSILON_ACC
@ SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD
@ SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS
@ SUMO_ATTR_CF_EIDM_C_COOLNESS
@ SUMO_ATTR_CF_EIDM_SIG_ERROR
@ SUMO_ATTR_CF_EIDM_T_REACTION
@ SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE
@ SUMO_ATTR_CF_EIDM_SIG_GAP
@ SUMO_ATTR_CF_EIDM_JERK_MAX
@ SUMO_ATTR_CF_IDM_STEPPING
@ SUMO_ATTR_COLLISION_MINGAP_FACTOR
@ SUMO_ATTR_CF_EIDM_M_FLATNESS
@ SUMO_ATTR_CF_EIDM_M_BEGIN
@ SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE
@ SUMO_ATTR_CF_EIDM_SIG_LEADER
@ SUMO_ATTR_STATE
The state of a link.
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
virtual double patchSpeed(const double min, const double wanted, const double max, const MSCFModel &cfModel)=0
Called to adapt the speed in order to allow a lane change. It uses information on LC-related desired ...
virtual bool isSelected() const
whether this vehicle is selected in the GUI
double getChosenSpeedFactor() const
Returns the precomputed factor by which the driver wants to be faster than the speed limit.
MSDevice * getDevice(const std::type_info &type) const
Returns a device of the given type if it exists, nullptr otherwise.
void loadState(const SUMOSAXAttributes &attrs)
Loads the state of the vehicle variables from the given description.
std::vector< std::pair< double, double > > stop
void saveState(OutputDevice &out, const MSCFModel &cfm) const
Saves the vehicle variables.
const double myTPersEstimate
double patchSpeedBeforeLCEIDM(const MSVehicle *veh, double vMin, double vMax, const VehicleVariables *vars) const
Applies dawdling / driving error.
const double myTPersDrive
const bool myUseVehDynamics
~MSCFModel_EIDM()
Destructor.
const double mySigmaleader
const double myEpsilonacc
double slowToStartTerm(MSVehicle *const veh, const double newSpeed, const double currentSpeed, const double vMax, VehicleVariables *vars) const
double maximumSafeFollowSpeed(double gap, double egoSpeed, double predSpeed, double predMaxDecel, bool onInsertion=false, const CalcReason usage=CalcReason::CURRENT) const
Returns the maximum safe velocity for following the given leader.
double maximumSafeStopSpeed(double gap, double decel, double currentSpeed, bool onInsertion=false, double headway=-1) const
Returns the maximum next velocity for stopping within gap.
double insertionFollowSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0) const
Computes the vehicle's safe speed (no dawdling) This method is used during the insertion stage....
double finalizeSpeed(MSVehicle *const veh, double vPos) const
Applies interaction with stops and lane changing model influences.
double stopSpeed(const MSVehicle *const veh, const double speed, double gap, double decel, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed for approaching a non-moving obstacle.
MSCFModel_EIDM(const MSVehicleType *vtype)
Constructor.
double insertionStopSpeed(const MSVehicle *const veh, double speed, double gap) const
Computes the vehicle's safe speed for approaching an obstacle at insertion without constraints due to...
double freeSpeed(const MSVehicle *const veh, double speed, double seen, double maxSpeed, const bool onInsertion=false, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed without a leader.
double internalsecuregap(const MSVehicle *const veh, const double speed, const double leaderSpeed, const double targetDecel) const
double followSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed.
void internalspeedlimit(MSVehicle *const veh, const double oldV) const
double getSecureGap(const MSVehicle *const veh, const MSVehicle *const, const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0).
MSCFModel * duplicate(const MSVehicleType *vtype) const
Duplicates the car-following model.
double interactionGap(const MSVehicle *const, double vL) const
Returns the maximum gap at which an interaction between both vehicles occurs.
const double mySigmaerror
double _v(const MSVehicle *const veh, const double gap2pred, const double mySpeed, const double predSpeed, const double desSpeed, const bool respectMinGap, const int update, const CalcReason usage) const
The car-following model abstraction.
virtual double maxNextSpeed(double speed, const MSVehicle *const veh) const
Returns the maximum speed given the current speed.
virtual double getCurrentAccel(const double speed) const
Get the vehicle type's maximum acceleration [m/s^2].
virtual double minNextSpeedEmergency(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed after emergency braking, given the current speed (depends on the numerical ...
virtual std::string getParameter(const MSVehicle *veh, const std::string &key) const
try to get the given parameter for this carFollowingModel
virtual double applyStartupDelay(const MSVehicle *veh, const double vMin, const double vMax, const SUMOTime addTime=0) const
apply speed adaptation on startup
double getEmergencyDecel() const
Get the vehicle type's maximal physically possible deceleration [m/s^2].
virtual double minNextSpeed(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed given the current speed (depends on the numerical update scheme and its ste...
SUMOTime myStartupDelay
The startup delay after halting [s].
double myEmergencyDecel
The vehicle's maximum emergency deceleration [m/s^2].
CalcReason
What the return value of stop/follow/free-Speed is used for.
@ FUTURE
the return value is used for calculating future speeds
@ LANE_CHANGE
the return value is used for lane change calculations
@ CURRENT
the return value is used for calculating the next speed
@ CURRENT_WAIT
the return value is used for calculating junction stop speeds
double myCollisionMinGapFactor
The factor of minGap that must be maintained to avoid a collision event.
double calculateEmergencyDeceleration(double gap, double egoSpeed, double predSpeed, double predMaxDecel) const
Returns the minimal deceleration for following the given leader safely.
MSCFModel(const MSVehicleType *vtype)
Constructor.
double myDecel
The vehicle's maximum deceleration [m/s^2].
const MSVehicleType * myType
The type to which this model definition belongs to.
double maximumSafeStopSpeedBallistic(double gap, double decel, double currentSpeed, bool onInsertion=false, double headway=-1) const
Returns the maximum next velocity for stopping within gap when using the ballistic positional update.
double myHeadwayTime
The driver's desired time headway (aka reaction time tau) [s].
A device which collects info on the vehicle trip (mainly on departure and arrival).
bool isSpeedAdviceActive() const
Returns if the GLOSA device is currently changing the speedFactor.
double getOriginalSpeedFactor() const
Returns the precomputed, original factor by which the driver wants to be faster than the speed limit.
static bool gSemiImplicitEulerUpdate
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Representation of a lane in the micro simulation.
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
double getLength() const
Returns the lane's length.
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Representation of a vehicle in the micro simulation.
SUMOTime getTimeSinceStartup() const
Returns the SUMOTime spent driving since startup (speed was larger than 0.1m/s).
MSAbstractLaneChangeModel & getLaneChangeModel()
double getAcceleration() const
Returns the vehicle's acceleration in m/s (this is computed as the last step's mean acceleration in c...
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
const MSLane * getLane() const
Returns the lane the vehicle is on.
double getSpeed() const
Returns the vehicle's current speed.
double processNextStop(double currentVelocity)
Processes stops, returns the velocity needed to reach the stop.
double getPositionOnLane() const
Get the vehicle's position along the lane.
MSCFModel::VehicleVariables * getCarFollowVariables() const
Returns the vehicle's car following model variables.
std::pair< const MSVehicle *const, double > getLeader(double dist=0, bool considerFoes=true) const
Returns the leader of the vehicle looking for a fixed distance.
The car-following model and parameter.
const SUMOVTypeParameter & getParameter() const
SUMOTime getActionStepLength() const
Returns this type's default action step length.
const std::string & getID() const
Returns the id.
Static storage of an output device and its base (abstract) implementation.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false)
writes a named attribute
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
static double randNorm(double mean, double variance, SumoRNG *rng=nullptr)
Access to a random number from a normal distribution.
Encapsulated SAX-Attributes.
virtual std::string getString(int id, bool *isPresent=nullptr) const =0
Returns the string-value of the named (by its enum-value) attribute.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.