/*
* Copyright (c) 1991,1993 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory.
* 4. Neither the name of the University nor of the Laboratory may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#) $Header: /cvsroot/nsnam/nam-1/node.cc,v 1.62 2001/08/31 03:18:15 mehringe Exp $ (LBL)
*/
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <tcl.h>
#include "view.h"
#include "netview.h"
#include "psview.h"
#include "editview.h"
#include "node.h"
#include "queue.h"
#include "feature.h"
#include "agent.h"
#include "edge.h"
#include "route.h"
#include "monitor.h"
#include "lan.h"
#include "paint.h"
#include "trace.h"
//----------------------------------------------------------------------
//----------------------------------------------------------------------
MovementElement::MovementElement(double time, double x, double y) {
next_ = NULL;
time_ = time;
x_ = x;
y_ = y;
x_velocity_ = 0.0;
y_velocity_ = 0.0;
duration_ = 0.0;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
MovementElement::MovementElement(double time, double x,
double y, double x_velocity,
double y_velocity, double duration) {
next_ = NULL;
time_ = time;
x_ = x;
y_ = y;
x_velocity_ = x_velocity;
y_velocity_ = y_velocity;
duration_ = duration;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
MovementElement::~MovementElement() {
next_ = NULL;
}
//----------------------------------------------------------------------
// bool
// MovementElement::contains(double time, double duration);
// - returns true if time >= time_
// and < time_ + duration_
//----------------------------------------------------------------------
bool
MovementElement::contains(double time, double duration) {
return (time >= time_ && time < (time_ + duration_));
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
MovementList::MovementList() {
head_ = NULL;
}
//----------------------------------------------------------------------
// MovementList::~MovementList()
// - deletes the remaining part of the list
//----------------------------------------------------------------------
MovementList::~MovementList() {
clear();
}
//----------------------------------------------------------------------
// void
// MovementList::clear() {
// - deletes all items on the list
//----------------------------------------------------------------------
void
MovementList::clear() {
MovementElement * run;
if (head_) {
for (run = head_->next_; run; run = run->next_) {
delete head_;
head_ = run;
}
if (head_) {
delete head_;
}
head_ = NULL;
}
}
//----------------------------------------------------------------------
// MovementList *
// MovementList::add(double x, double y, double time)
// - adds a new time value to the list which is
// sorted in ascending order
//----------------------------------------------------------------------
MovementElement *
MovementList::add(double x, double y, double time) {
MovementElement * new_movement, * run, * previous;
if (!head_) {
// First element on list
head_ = new MovementElement(time, x, y);
} else {
// Have to place down on list
previous = NULL;
run = head_;
for (run = head_; run; run = run->next_) {
// slight rounding errors occur with strtod so we need to
// have an acceptable error range
if ((run->time_ - time <= 0.000001) &&
(run->time_ - time >= -0.000001)) {
// Update time with new x,y
run->x_ = x;
run->y_ = y;
break;
} else if (time < run->time_) {
if (previous) {
// Place in middle of list
new_movement = new MovementElement(time, x, y);
new_movement->next_ = run;
previous->next_ = new_movement;
} else {
// Add to front of list
new_movement = new MovementElement(time, x, y);
new_movement->next_ = head_;
head_ = new_movement;
}
break;
}
previous = run;
}
if (!run) {
// We ran to the end of the list and couldn't place
// the new time so we have to place it at the end
previous->next_ = new MovementElement(time, x, y);
run = previous->next_;
}
}
return run;
}
//----------------------------------------------------------------------
// MovementList *
// MovementList::remove(double time)
// - removes time from the list
//----------------------------------------------------------------------
void
MovementList::remove(double time) {
MovementElement * run, * previous;
previous = NULL;
for (run = head_; run; run = run->next_) {
// slight rounding errors occur with strtod so we need to
// have an acceptable error range
if ((run->time_ - time <= 0.000001) &&
(run->time_ - time >= -0.000001)) {
if (previous) {
previous->next_ = run->next_;
delete run;
} else {
// Element is at the front of the list
head_ = run->next_;
}
size_--;
break;
}
previous = run;
}
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void
MovementList::setList(char * list_string) {
char * run, * next;
double time;
// Erase all items on the list
clear();
// Run down the list string and add values to the list
run = list_string;
while (run) {
time = strtod(run, &next);
if (run != next) {
//add(time);
} else {
break;
}
run = next;
}
}
//----------------------------------------------------------------------
// void
// MovementList::getListString(char * buffer, int buffer_size)
// - fills buffer with a space delimited list of all values on the
// time list sorted in ascending order
//
// - the returned list should be freed when it is not needed anymore
//----------------------------------------------------------------------
int
MovementList::getListString(char * buffer, int buffer_size) {
int total_written, just_written;
MovementElement * run;
total_written = 1; // Need space for the /0 character
for (run = head_; run; run = run->next_) {
just_written = sprintf(buffer, "%f ", run->time_);
if (just_written == -1) {
fprintf(stderr, "Ran out of buffer space when creating time list string\n");
total_written = -1;
break;
}
//Advance buffer pointer past written characters
buffer += just_written;
total_written += just_written;
}
return total_written;
}
//----------------------------------------------------------------------
//
//----------------------------------------------------------------------
double
MovementList::lastStopMovement() {
MovementElement * element;
double stop_time = 0.0;
bool start = true;
for (element = head(); element; element = element->next_) {
if (start) {
start = false;
} else {
stop_time = element->time_;
start = true;
}
}
return stop_time;
}
//----------------------------------------------------------------------
// double
// MovementList::getXPositionAt(double time)
// - Calculates the x position of a node based on where it should be
// on it's movement list
// - If the list is empty then it doesn't modify x and y
//
//----------------------------------------------------------------------
void
MovementList::getPositionAt(double time, double & x, double & y) {
MovementElement * before, * after;
if (!head()) {
return;
}
before = NULL;
for (after = head(); after; after = after->next_) {
if (time < after->time_) {
break;
}
before = after;
}
if (before) {
if (after) {
// We need to calculate the movement between 2 positions
x = before->x_ + (after->x_ - before->x_) *
(before->time_ - time) /
(before->time_ - after->time_);
y = before->y_ + (after->y_ - before->y_) *
(before->time_ - time) /
(before->time_ - after->time_);
} else {
// We are at the end of the list so set the position to the
// before movement x,y
x = before->x_;
y = before->y_;
}
} else {
// If there is no before then give the first item in the list
before = head();
if (before) {
x = before->x_;
y = before->y_;
}
}
}
//----------------------------------------------------------------------
// Wrapper for tcl creation of Nodes
//----------------------------------------------------------------------
static class NodeClass : public TclClass {
public:
NodeClass() : TclClass("Node") {}
TclObject * create(int argc, const char*const* argv) {
Node * node;
double size = strtod(argv[6], NULL);
// set <node> [new Node node_id type size]
if (!strcmp(argv[5], "circle")) {
node = new CircleNode(argv[4], size);
} else if (!strcmp(argv[5], "box")) {
node = new BoxNode(argv[4], size);
} else {
node = new HexagonNode(argv[4], size);
}
return node;
}
} class_node;
//----------------------------------------------------------------------
//----------------------------------------------------------------------
Node::Node(const char* name, double size) :
Animation(0, 0),
queue_(0),
size_(size),
nsize_((float) size),
x_(0.),
y_(0.),
x_vel_(0.),
y_vel_(0.),
starttime_(0.),
endtime_(0.),
links_(0),
routes_(0),
agents_(0),
anchor_(0),
mark_(0),
state_(UP),
nm_(NULL),
nMark_(0),
dlabel_(0),
// lcolor_(0),
// dcolor_(0), // This is some type of hack to not use dcolor
// ncolor_(0),
direction_(0) {
next_ = NULL;
label_ = new char[strlen(name) + 1];
strcpy(label_, name);
addr_ = nn_ = atoi(name); /*XXX*/
lcolor_ = NULL;
dcolor_ = NULL;
ncolor_ = NULL;
init_color("black");
dx_ = 0.0;
dy_ = 0.0;
tcl_script_label_ = NULL;
tcl_script_ = NULL;
wireless_ = false;
paint_ = Paint::instance()->thick();
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
Node::~Node() {
if (nm_ != NULL) {
NodeMark *p = nm_;
nm_ = nm_->next;
delete p;
}
delete label_;
if (queue_ != NULL)
delete queue_;
if (tcl_script_) {
delete [] tcl_script_;
}
if (tcl_script_label_) {
delete [] tcl_script_label_;
}
}
//----------------------------------------------------------------------
// void
// Node::init_color(const char *clr) {
//----------------------------------------------------------------------
void
Node::init_color(const char *clr) {
color(clr);
lcolor(clr);
ncolor(clr);
dcolor(clr);
oldPaint_ = paint_;
}
void Node::set_down(char *color)
{
// If current color is down, don't change it again.
// Assuming only one down color. User can change this behavior
// by adding tcl code for link-up and link-down events.
if (state_ == UP) {
int pno = Paint::instance()->lookup(color, 3);
oldPaint_ = paint_;
paint_ = pno;
state_ = DOWN;
}
}
void Node::set_up()
{
if (state_ == DOWN) {
state_ = UP;
toggle_color();
}
}
float Node::distance(float x, float y) const
{
return ((x_-x) * (x_-x) + (y_-y) * (y_-y));
}
void Node::size(double s)
{
size_ = s;
update_bb();
}
// We don't need one update_bb() for every derived class because their
// sizes are all based on 0.5*size_. Otherwise we'll have to do update_bb
// individually
void Node::update_bb()
{
double off = 0.5 * size_ + NodeMarkScale * size_; // thick circles
if (nMark_ > 0)
off += nMark_ * NodeMarkScale * size_;
/*XXX*/
bb_.xmin = x_ - off;
bb_.ymin = y_ - off;
bb_.xmax = x_ + off;
bb_.ymax = y_ + off;
}
const char* Node::info() const
{
static char text[128];
sprintf(text, "Node: %s (%g, %g)", label_, x(), y());
return (text);
}
//----------------------------------------------------------------------
// const char *
// Node::property()
// - returns a string of property types and values for the node
// object
//----------------------------------------------------------------------
const char *
Node::property() {
static char text[256];
char *p;
rgb * color;
color = Paint::instance()->paint_to_rgb(paint_);
// object type and id
p = text;
sprintf(text, "{\"Node: %d\" nn_ title \"Node %d\"} ", nn_, nn_);
// node size
p = &text[strlen(text)];
sprintf(p, "{Size size_ text %.1f} ", size_);
// node color
p = &text[strlen(text)];
sprintf(p, "{Color color color %s} ", color->colorname);
// label if it exists
p = &text[strlen(text)];
if (dlabel_) {
sprintf(p, "{Label dlabel_ text %s} ", dlabel_);
} else {
sprintf(p, "{Label dlabel_ text } ");
}
if (movement_list.head()) {
}
return(text);
}
const char* Node::getname() const
{
static char text[128];
sprintf(text, "n %s", label_);
return (text);
}
void Node::monitor(Monitor *m, double /*now*/, char *result, int /*len*/)
{
monitor_=m;
sprintf(result, "Node: %s", label_);
return;
}
void Node::add_link(Edge* e)
{
movement_list.clear();
e->next_ = links_;
links_ = e;
}
void Node::delete_link(Edge* e) {
Edge *h, *k;
h = links_;
for (k = links_; k != 0; k = k->next_) {
if (k->src() == e->src() && k->dst() == e->dst()) {
if (k == links_) {
links_ = k->next_;
break;
} else {
h->next_ = k->next_;
break;
}
}
h = k;
}
}
void Node::add_agent(Agent* a)
{
a->next_ = agents_;
agents_ = a;
}
void Node::delete_agent(Agent* r)
{
/*given a agent, remove it from a node's agent list*/
Agent *ta1, *ta2;
ta1=agents_;
ta2=agents_;
while ((ta1!=r)&&(ta1!=NULL))
{
ta2=ta1;
ta1=ta1->next();
}
if (ta1==r)
{
ta2->next(ta1->next());
if (ta1==agents_)
agents_=ta1->next();
}
}
Agent *Node::find_agent(char *name) const
{
Agent *ta=NULL;
ta=agents_;
while (ta!=NULL)
{
if (strcmp(ta->name(), name)==0)
return ta;
ta=ta->next();
}
return NULL;
}
void Node::add_route(Route* r)
{
r->next_ = routes_;
routes_ = r;
}
void Node::delete_route(Route* r)
{
/*given a route, remove it from a node's route list*/
Route *tr1, *tr2;
tr1=routes_;
tr2=routes_;
while ((tr1!=r)&&(tr1!=NULL))
{
tr2=tr1;
tr1=tr1->next();
}
if (tr1==r)
{
tr2->next(tr1->next());
if (tr1==routes_)
routes_=tr1->next();
}
if (routes_!=NULL)
{
/*need to reposition routes on this edge*/
Edge *e=tr1->edge();
int ctr=0;
for (tr2=routes_;tr2!=NULL;tr2=tr2->next())
if (tr2->edge()==e)
tr2->place(e->x0(), e->y0(), ctr++);
}
}
Route *Node::find_route(Edge *e, int group, int pktsrc, int oif) const
{
Route *tr=NULL;
tr=routes_;
while (tr!=NULL)
{
if (tr->matching_route(e, group, pktsrc, oif)==1)
return tr;
tr=tr->next();
}
return NULL;
}
void Node::place_route(Route *r)
{
if (r->node() != this)
return;
if (r->marked() == 0) {
r->place(r->edge()->x0(), r->edge()->y0());
r->mark(1);
}
}
// Used when topology is relayout
void Node::place_all_routes()
{
Route *tr = routes_;
while (tr != NULL) {
place_route(tr);
tr = tr->next();
}
}
// Clear mark on routes so we can replace them
void Node::clear_routes()
{
Route *tr = routes_;
while (tr != NULL) {
tr->mark(0);
tr = tr->next();
}
}
int Node::no_of_routes(Edge *e) const
{
Route *tr=routes_;
int no_of_routes=0;
while (tr!=NULL)
{
if (tr->edge()==e)
no_of_routes++;
tr=tr->next();
}
return no_of_routes;
}
void
Node::label(const char* name, int anchor) {
delete []label_;
label_ = new char[strlen(name) + 1];
strcpy(label_, name);
anchor_ = anchor;
}
void Node::lcolor(const char* name)
{
if (name[0] == 0) {
if (lcolor_) {
delete []lcolor_;
lcolor_ = 0;
}
return;
}
if (lcolor_)
delete []lcolor_;
lcolor_ = new char[strlen(name) + 1];
strcpy(lcolor_, name);
}
void Node::dlabel(const char* name)
{
if (name[0] == 0) {
if (dlabel_) {
delete []dlabel_;
dlabel_ = 0;
}
return;
}
if (dlabel_)
delete []dlabel_;
dlabel_ = new char[strlen(name) + 1];
strcpy(dlabel_, name);
}
//----------------------------------------------------------------------
// void
// Node::dcolor(const char* name)
//----------------------------------------------------------------------
void Node::dcolor(const char* name) {
if (name[0] == 0) {
if (dcolor_) {
delete []dcolor_;
dcolor_ = 0;
}
return;
}
if (dcolor_)
delete []dcolor_;
dcolor_ = new char[strlen(name) + 1];
strcpy(dcolor_, name);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void
Node::ncolor(const char* name) {
if (name[0] == 0) {
if (ncolor_) {
delete []ncolor_;
ncolor_ = 0;
}
return;
}
if (ncolor_)
delete []ncolor_;
ncolor_ = new char[strlen(name) + 1];
strcpy(ncolor_, name);
}
void Node::direction(const char* name)
{
if (name[0] == 0) {
if (direction_) {
direction_ = 0;
}
return;
}
if (!strcmp(name, "EAST"))
direction_ = 1;
else if (!strcmp(name, "SOUTH"))
direction_ = 2;
else if (!strcmp(name, "WEST"))
direction_ = 3;
else if (!strcmp(name, "NORTH"))
direction_ = 4;
else
direction_ = 0;
}
void Node::add_sess_queue(unsigned int, Queue *q)
{
if (queue_ != NULL)
// Currently we only allow one queue per node
return;
queue_ = q;
queue_->place(size_*0.5, x_+size_*.05, y_+size_*0.5);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
char * Node::getTclScript() {
return tcl_script_;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
char * Node::getTclScriptLabel() {
return tcl_script_label_;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void Node::setTclScript(const char * label, const char * script) {
if (tcl_script_label_) {
delete [] tcl_script_label_;
}
tcl_script_label_ = new char[strlen(label)];
strcpy(tcl_script_label_, label);
if (tcl_script_) {
delete [] tcl_script_;
}
tcl_script_ = new char[strlen(script)];
strcpy(tcl_script_, script);
}
//----------------------------------------------------------------------
// int
// Node::command(int argc, const char * const * argv)
// - Interface between tcl and c
//----------------------------------------------------------------------
int
Node::command(int argc, const char * const * argv) {
double start_x, start_y, destination_x, destination_y;
double speed, start_time, destination_time;
if (!strcmp(argv[1], "addMovement")) {
// $node addMovement time x y speed
// - time is time of start of movement
// - x,y is destination location
// - speed is how fast the node is travelling
start_time = strtod(argv[2],NULL);
destination_x = strtod(argv[3],NULL);
destination_y = strtod(argv[4],NULL);
speed = strtod(argv[5],NULL);
// We need to calculate at what time we reach
// destination x,y
start_x = x(); // intial x,y values should have been set for
start_y = y(); // node before add the Movement positions
if (movement_list.head()) {
movement_list.getPositionAt(start_time, start_x, start_y);
} else {
addMovementDestination(start_x, start_y, start_time);
}
// Now we need to find the arrival time at the
// destination coordinates
if (speed != 0.0) {
destination_time = sqrt((start_x - destination_x) *
(start_x - destination_x) +
(start_y - destination_y) *
(start_y - destination_y)) / speed +
start_time;
addMovementDestination(destination_x,
destination_y,
destination_time);
}
return TCL_OK;
}
return TCL_ERROR;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
NodeMark* Node::find_mark(char *name) {
NodeMark *p = nm_;
while (p != NULL) {
if (strcmp(p->name, name) == 0)
break;
p = p->next;
}
return p;
}
int Node::add_mark(char *name, char *color, char *shape)
{
if (find_mark(name) != NULL)
return 1;
NodeMark *cm = new NodeMark(name);
cm->color = Paint::instance()->lookup(color, 2);
if (strcmp(shape, "circle") == 0)
cm->shape = NodeMarkCircle;
else if (strcmp(shape, "square") == 0)
cm->shape = NodeMarkSquare;
else if (strcmp(shape, "hexagon") == 0)
cm->shape = NodeMarkHexagon;
if (nm_ != NULL)
cm->next = nm_;
nm_ = cm;
nMark_++;
update_bb();
return 0;
}
void Node::delete_mark(char *name)
{
NodeMark **p;
p = &nm_;
while (*p != NULL) {
if (strcmp((*p)->name, name) == 0) {
NodeMark *q = *p;
*p = (*p)->next;
delete q;
nMark_--;
update_bb();
return;
}
p = &((*p)->next);
}
}
void Node::update(double now) {
if (now >= endtime_ || now <= starttime_ ) {
return;
}
double xpos = xorig_ + (now - starttime_)* x_vel_;
double ypos = yorig_ + (now - starttime_)* y_vel_;
place(xpos,ypos);
}
void Node::draw_mark(View* nv) const
{
NodeMark *cm;
double s = size_ * 0.7;
for (cm = nm_; cm != NULL; cm = cm->next, s += size_ * NodeMarkScale) {
switch (cm->shape) {
case NodeMarkCircle:
nv->circle(x_, y_, s, cm->color);
break;
case NodeMarkSquare: {
double x[2], y[2];
x[0] = x_ - s, x[1] = x_ + s;
y[0] = y_ - s, y[1] = y_ + s;
nv->rect(x[0], y[0], x[1], y[1], cm->color);
break;
}
case NodeMarkHexagon: {
float x[6], y[6];
double qd = 0.5 * s;
x[0] = x_ - s;
y[0] = y_;
x[1] = x_ - qd;
y[1] = y_ + s;
x[2] = x_ + qd;
y[2] = y_ + s;
x[3] = x_ + s;
y[3] = y_;
x[4] = x_ + qd;
y[4] = y_ - s;
x[5] = x_ - qd;
y[5] = y_ - s;
nv->polygon((float *)x, (float *)y, 6, cm->color);
break;
}
}
}
}
void Node::drawlabel(View* nv) const
{
/*XXX node number */
if (label_ != 0)
nv->string(x_, y_, size_, label_, anchor_, lcolor_);
if (monitor_!=NULL)
monitor_->draw(nv, x_, y_-size_/2);
if (dlabel_ != 0) {
switch (direction_) {
case 0:
nv->string(x_, y_+size_, size_*0.7, dlabel_, 0, dcolor_);
break;
case 1:
nv->string(x_-size_*1.5, y_, size_*0.7, dlabel_, 0,
dcolor_);
break;
case 2:
nv->string(x_, y_-size_, size_*0.7, dlabel_, 0, dcolor_);
break;
case 3:
nv->string(x_+size_*1.5, y_, size_*0.7, dlabel_, 0,
dcolor_);
break;
case 4:
nv->string(x_, y_+size_, size_*0.7, dlabel_, 0,
dcolor_);
break;
default:
nv->string(x_, y_+size_, size_*0.7, dlabel_, 0,
dcolor_);
break;
}
}
}
void Node::reset(double)
{
//XXX why should reset to black???
// paint_ = Paint::instance()->thick();
}
//----------------------------------------------------------------------
// MovementElement *
// Node::addMovementDestination(double x, double y, double time)
// - add a movement destination to node if it doesn't have any links
// - only node without links can be moved
//----------------------------------------------------------------------
MovementElement *
Node::addMovementDestination(double world_x, double world_y, double time) {
if (!links()) {
if (!movement_list.head() && time != 0.0) {
addMovementDestination(x(), y(), 0.0);
}
return movement_list.add(world_x,world_y,time);
} else {
place(world_x,world_y);
return NULL;
}
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void
Node::removeMovementDestination(double time) {
movement_list.remove(time);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
int
Node::getMovementTimeList(char * buffer, int buffer_size) {
return movement_list.getListString(buffer, buffer_size);
}
//----------------------------------------------------------------------
// double
// Node::getMaximumX()
// - Get the maximum x value that a node can be at during it's
// movement sequence
//----------------------------------------------------------------------
double
Node::getMaximumX() {
MovementElement * movement;
double X;
movement = movement_list.head();
if (movement) {
X = movement->x_;
while(movement) {
if (movement->x_ > X) {
X = movement->x_;
}
movement = movement->next_;
}
} else {
X = x();
}
return X;
}
//----------------------------------------------------------------------
// double
// Node::getMaximumY()
// - Get the maximum y value that a node can be at during it's
// movement sequence
//----------------------------------------------------------------------
double
Node::getMaximumY() {
MovementElement * movement;
double Y;
movement = movement_list.head();
if (movement) {
Y = movement->y_;
while(movement) {
if (movement->y_ > Y) {
Y = movement->y_;
}
movement = movement->next_;
}
} else {
Y = y();
}
return Y;
}
void Node::place(double _x, double _y) {
x_ = _x;
y_ = _y;
mark_ = 1;
update_bb();
if (!links() && !movement_list.head()) {
addMovementDestination(x(), y(), 0.0);
}
// Should we place queues here too?
if (queue_ != NULL) {
queue_->place(0.5 * size_, x_+0.5*size_, y_+0.5*size_);
}
}
//----------------------------------------------------------------------
// void
// Node::move(EditView *v, float wdx, float wdy)
// - Move by a displacement in *window* coordinates
//----------------------------------------------------------------------
void Node::move(EditView * edit_view, float wdx, float wdy) {
float cx, cy;
// First get our position in window coordinates
cx = x_, cy = y_;
edit_view->map(cx, cy);
cx += wdx;
cy += wdy;
// Now switch back to world coordinates
edit_view->imap(cx, cy);
// Place the new location
place(cx, cy);
// Because all placements are centrally organized by AutoNetModel,
// we'll have to call back. :(
edit_view->moveNode(this);
}
//----------------------------------------------------------------------
//
//
//----------------------------------------------------------------------
void
Node::updatePositionAt(double current_time) {
double world_x, world_y;
world_x = x();
world_y = y();
movement_list.getPositionAt(current_time, world_x, world_y);
place(world_x, world_y);
}
Edge *Node::find_edge(int dst) const
{
for (Edge *e = links_; e != 0; e = e->next_)
if (e->dst() == dst)
return e;
return NULL;
}
int Node::save(FILE *file)
{
char buffer[TRACE_LINE_MAXLEN], *p;
rgb *color;
color=Paint::instance()->paint_to_rgb(paint_);
buffer[0] = 0;
if (state_ == UP)
strcpy(buffer, "-S UP");
else if (state_==DOWN)
strcpy(buffer, "-S DOWN");
p = buffer + strlen(buffer);
if (dlabel_)
sprintf(p, " -b \"%s\"", dlabel_);
fprintf(file, "n -t * -s %d -v %s -c %s -z %f %s\n",
nn_, style(), color->colorname, size_, buffer);
return(0);
}
//----------------------------------------------------------------------
// int
// Node::writeNsScript(FILE *file)
//----------------------------------------------------------------------
int
Node::writeNsScript(FILE *file) {
int chars_written = 0;
rgb * color;
color = Paint::instance()->paint_to_rgb(paint_);
double start_x, start_y;
// If there are no values on movement_list then start_ and start_y
// will be unchanged. So we need to intialize start_x and start_y
// to the current values
start_x = x();
start_y = y();
movement_list.getPositionAt(0.0, start_x, start_y);
chars_written += fprintf(file, "set node(%d) [$ns node]\n", number());
chars_written += fprintf(file, "## node(%d) at %f,%f\n", number(), start_x, start_y);
chars_written += fprintf(file, "$node(%d) set X_ %f\n", number(), start_x);
chars_written += fprintf(file, "$node(%d) set Y_ %f\n", number(), start_y);
chars_written += fprintf(file, "$node(%d) set Z_ 0.0\n", number());
// chars_written += fprintf(file, "$node(%d) size \"%f\"\n", number(), size_);
chars_written += fprintf(file, "$node(%d) color \"%s\"\n", number(), color->colorname);
if (dlabel_) {
chars_written += fprintf(file, "$ns at 0.0 \"$node(%d) label %s\"\n", number(), dlabel_);
}
return chars_written;
}
//----------------------------------------------------------------------
// int
// Node::writeNsMovement(FILE *file)
//----------------------------------------------------------------------
int
Node::writeNsMovement(FILE *file) {
int chars_written = 0;
MovementElement * start, * destination;
double speed;
start = movement_list.head();
if (start) {
fprintf(file, "$ns initial_node_pos $node(%d) %f\n", number(), size());
// Skip first command since it is our starting place
destination = start->next_;
while (destination) {
if (start->x_ != destination->x_ ||
start->y_ != destination->y_) {
// find speed from start to destination
speed = sqrt((start->x_ - destination->x_) *
(start->x_ - destination->x_) +
(start->y_ - destination->y_) *
(start->y_ - destination->y_))/
(destination->time_ - start->time_);
chars_written += fprintf(file, "$ns at %f \"$node(%d) setdest %f %f %f\"\n",
start->time_, number(),
destination->x_, destination->y_, speed);
}
start = destination;
destination = destination->next_;
}
}
return chars_written;
}
BoxNode::BoxNode(const char* name, double size) : Node(name, size)
{
BoxNode::size(size);
}
void BoxNode::size(double s)
{
Node::size(s);
double delta = 0.5 * s;
x0_ = x_ - delta;
y0_ = y_ - delta;
x1_ = x_ + delta;
y1_ = y_ + delta;
}
void BoxNode::draw(View* nv, double now) {
nv->rect(x0_, y0_, x1_, y1_, paint_);
drawlabel(nv);
draw_mark(nv);
}
void BoxNode::place(double x, double y)
{
Node::place(x, y);
double delta = 0.5 * size_;
x0_ = x_ - delta;
y0_ = y_ - delta;
x1_ = x_ + delta;
y1_ = y_ + delta;
}
CircleNode::CircleNode(const char* name, double size) : Node(name, size)
{
CircleNode::size(size);
}
void CircleNode::size(double s)
{
Node::size(s);
radius_ = 0.5 * s;
}
void
CircleNode::draw(View* nv, double now) {
nv->circle(x_, y_, radius_, paint_);
drawlabel(nv);
draw_mark(nv);
}
HexagonNode::HexagonNode(const char* name, double size) : Node(name, size)
{
HexagonNode::size(size);
}
void HexagonNode::size(double s)
{
Node::size(s);
double hd = 0.5 * s;
double qd = 0.5 * hd;
xpoly_[0] = x_ - hd; ypoly_[0] = y_;
xpoly_[1] = x_ - qd; ypoly_[1] = y_ + hd;
xpoly_[2] = x_ + qd; ypoly_[2] = y_ + hd;
xpoly_[3] = x_ + hd; ypoly_[3] = y_;
xpoly_[4] = x_ + qd; ypoly_[4] = y_ - hd;
xpoly_[5] = x_ - qd; ypoly_[5] = y_ - hd;
}
void HexagonNode::draw(View* nv, double now) {
nv->polygon(xpoly_, ypoly_, 6, paint_);
drawlabel(nv);
draw_mark(nv);
}
void HexagonNode::place(double x, double y)
{
Node::place(x, y);
double hd = 0.5 * size_;
double qd = 0.5 * hd;
xpoly_[0] = x_ - hd; ypoly_[0] = y_;
xpoly_[1] = x_ - qd; ypoly_[1] = y_ + hd;
xpoly_[2] = x_ + qd; ypoly_[2] = y_ + hd;
xpoly_[3] = x_ + hd; ypoly_[3] = y_;
xpoly_[4] = x_ + qd; ypoly_[4] = y_ - hd;
xpoly_[5] = x_ - qd; ypoly_[5] = y_ - hd;
}
VirtualNode::VirtualNode(const char* name, Lan *lan) :
Node(name, 0), lan_(lan)
{
}
void VirtualNode::size(double s)
{
Node::size(0);
lan_->size(s);
}
void VirtualNode::draw(View* nv, double now) {
printf("drawing vn at %f %f\n", x_, y_);
}
void VirtualNode::place(double x, double y)
{
Node::place(x, y);
lan_->place(x, y);
}
void VirtualNode::arrive_packet(Packet *p, Edge *e, double atime)
{
lan_->arrive_packet(p,e,atime);
}
void VirtualNode::delete_packet(Packet *p)
{
lan_->delete_packet(p);
}
double VirtualNode::x(Edge *e) const
{
return lan_->x(e);
}
double VirtualNode::y(Edge *e) const
{
return lan_->y(e);
}
syntax highlighted by Code2HTML, v. 0.9.1