--- a/src/tools/visualizer/doc/readme.txt Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-NS-3 PyViz is a live simulation visualizer, meaning that it uses no
-trace files. It can be most useful for debugging purposes, i.e. to
-figure out if mobility models are what you expect, where packets are
-being dropped, etc. There's also a builtin interactive python console
-that can be used to debug the state of the running objects. Although
-it is mostly written in Python, it works both with Python and pure C++
-simulations.
-
-For more information, see http://www.nsnam.org/wiki/index.php/PyViz
--- a/src/tools/visualizer/examples/readme.txt Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-For activating the visualizer, with any example, just pass the option
---SimulatorImplementationType=ns3::VisualSimulatorImpl to it, assuming
-the script uses ns-3's command line parser (class CommandLine).
--- a/src/tools/visualizer/model/pyviz.cc Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1406 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2008 INESC Porto
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Gustavo Carneiro <gjc@inescporto.pt>
- */
-
-#include <stdlib.h>
-#include "pyviz.h"
-#include "ns3/simulator.h"
-#include "ns3/config.h"
-#include "ns3/node-list.h"
-#include "ns3/wifi-net-device.h"
-#include "ns3/ppp-header.h"
-#include "ns3/wifi-mac-header.h"
-#include "ns3/ethernet-header.h"
-#include "ns3/log.h"
-#include "ns3/abort.h"
-
-#include "visual-simulator-impl.h"
-
-#include <sstream>
-
-NS_LOG_COMPONENT_DEFINE ("PyViz");
-#define NUM_LAST_PACKETS 10
-
-static
-std::vector<std::string>
-PathSplit (std::string str)
-{
- std::vector<std::string> results;
- size_t cutAt;
- while ((cutAt = str.find_first_of('/')) != str.npos)
- {
- if(cutAt > 0)
- {
- results.push_back(str.substr(0,cutAt));
- }
- str = str.substr(cutAt+1);
- }
- if (str.length() > 0)
- {
- results.push_back(str);
- }
- return results;
-}
-
-
-namespace ns3 {
-
-static PyViz* g_visualizer = NULL;
-
-
-
-struct PyVizPacketTag : public Tag
-{
- static TypeId GetTypeId (void);
- virtual TypeId GetInstanceTypeId (void) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void Serialize (TagBuffer buf) const;
- virtual void Deserialize (TagBuffer buf);
- virtual void Print (std::ostream &os) const;
- PyVizPacketTag ();
-
- uint32_t m_packetId;
-};
-
-
-TypeId
-PyVizPacketTag::GetTypeId (void)
-{
- static TypeId tid = TypeId ("ns3::PyVizPacketTag")
- .SetParent<Tag> ()
- .AddConstructor<PyVizPacketTag> ()
- ;
- return tid;
-}
-TypeId
-PyVizPacketTag::GetInstanceTypeId (void) const
-{
- return GetTypeId ();
-}
-uint32_t
-PyVizPacketTag::GetSerializedSize (void) const
-{
- return 4;
-}
-void
-PyVizPacketTag::Serialize (TagBuffer buf) const
-{
- buf.WriteU32 (m_packetId);
-}
-void
-PyVizPacketTag::Deserialize (TagBuffer buf)
-{
- m_packetId = buf.ReadU32 ();
-}
-void
-PyVizPacketTag::Print (std::ostream &os) const
-{
- os << "PacketId=" << m_packetId;
-}
-PyVizPacketTag::PyVizPacketTag ()
- : Tag ()
-{}
-
-
-
-PyViz::PyViz ()
-{
- NS_LOG_FUNCTION_NOARGS ();
- NS_ASSERT (g_visualizer == NULL);
- g_visualizer = this;
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/MacTx",
- MakeCallback (&PyViz::TraceNetDevTxWifi, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx",
- MakeCallback (&PyViz::TraceNetDevRxWifi, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacTx",
- MakeCallback (&PyViz::TraceNetDevTxCsma, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacRx",
- MakeCallback (&PyViz::TraceNetDevRxCsma, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacPromiscRx",
- MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop",
- MakeCallback (&PyViz::TraceDevQueueDrop, this));
-
- Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Drop",
- MakeCallback (&PyViz::TraceIpv4Drop, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/MacTx",
- MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/MacRx",
- MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Tx",
- MakeCallback (&PyViz::TraceNetDevTxWimax, this));
-
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Rx",
- MakeCallback (&PyViz::TraceNetDevRxWimax, this));
-
-}
-
-void
-PyViz::RegisterCsmaLikeDevice (std::string const &deviceTypeName)
-{
- TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
-
- std::ostringstream sstream;
- sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/MacTx";
- Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxCsma, this));
-
- sstream.str ("");
- sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
- Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxCsma, this));
-
- sstream.str ("");
- sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/PromiscRx";
- Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
-}
-
-void
-PyViz::RegisterWifiLikeDevice (std::string const &deviceTypeName)
-{
- TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
-
- std::ostringstream sstream;
- sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Tx";
- Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxWifi, this));
-
- sstream.str ("");
- sstream <<"/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
- Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxWifi, this));
-}
-
-void
-PyViz::RegisterPointToPointLikeDevice (std::string const &deviceTypeName)
-{
- TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
-
- std::ostringstream sstream;
- sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
- Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
-
- sstream.str ("");
- sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
- Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
-}
-
-void
-PyViz::SetPacketCaptureOptions (uint32_t nodeId, PacketCaptureOptions options)
-{
- NS_LOG_DEBUG (" SetPacketCaptureOptions " << nodeId
- << " PacketCaptureOptions (headers size = " << options.headers.size ()
- << " mode = " << options.mode << " numLastPackets = " << options.numLastPackets
- << ")");
- m_packetCaptureOptions[nodeId] = options;
-}
-
-void
-PyViz::RegisterDropTracePath (std::string const &tracePath)
-{
- Config::Connect (tracePath, MakeCallback (&PyViz::TraceDevQueueDrop, this));
-}
-
-PyViz::~PyViz ()
-{
- NS_LOG_FUNCTION_NOARGS ();
-
- NS_ASSERT (g_visualizer == this);
- g_visualizer = NULL;
-}
-
-void PyViz::DoPause (std::string const &message)
-{
- m_pauseMessages.push_back (message);
- m_stop = true;
- NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": Have "
- << g_visualizer->m_pauseMessages.size () << " pause messages");
-}
-
-void PyViz::Pause (std::string const &message)
-{
- NS_ASSERT (g_visualizer);
- g_visualizer->DoPause (message);
-}
-
-std::vector<std::string>
-PyViz::GetPauseMessages () const
-{
- NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": GetPauseMessages: have "
- << g_visualizer->m_pauseMessages.size () << " pause messages");
- return m_pauseMessages;
-}
-
-
-void
-PyViz::CallbackStopSimulation ()
-{
- NS_LOG_FUNCTION_NOARGS ();
- Simulator::Stop (Seconds (0)); // Stop right now
- m_stop = true;
-}
-
-void
-PyViz::SimulatorRunUntil (Time time)
-{
- NS_LOG_LOGIC ("SimulatorRunUntil " << time << " (now is " << Simulator::Now () << ")");
-
- m_pauseMessages.clear ();
- m_transmissionSamples.clear ();
- m_packetDrops.clear ();
-
- Time expirationTime = Simulator::Now () - Seconds (10);
-
- // Clear very old transmission records
- for (std::map<TxRecordKey, TxRecordValue>::iterator iter = m_txRecords.begin ();
- iter != m_txRecords.end ();)
- {
- if (iter->second.time < expirationTime)
- {
- m_txRecords.erase (iter++);
- }
- else
- {
- iter++;
- }
- }
-
- // Clear very old packets of interest
- for (std::map<uint32_t, Time>::iterator iter = m_packetsOfInterest.begin ();
- iter != m_packetsOfInterest.end ();)
- {
- if (iter->second < expirationTime)
- {
- m_packetsOfInterest.erase (iter++);
- }
- else
- {
- iter++;
- }
- }
-
- if (Simulator::Now () >= time)
- {
- return;
- }
- // Schedule a dummy callback function for the target time, to make
- // sure we stop at the right time. Otherwise, simulations with few
- // events just appear to "jump" big chunks of time.
- NS_LOG_LOGIC ("Schedule dummy callback to be called in " << (time - Simulator::Now ()));
- m_stop = false;
- Simulator::Cancel (m_stopCallbackEvent);
- m_stopCallbackEvent = Simulator::Schedule (time - Simulator::Now (), &PyViz::CallbackStopSimulation, this);
-
- Ptr<SimulatorImpl> impl = Simulator::GetImplementation ();
- Ptr<VisualSimulatorImpl> visualImpl = DynamicCast<VisualSimulatorImpl> (impl);
- if (visualImpl)
- {
- visualImpl->RunRealSimulator ();
- }
- else
- {
- impl->Run ();
- }
-}
-
-bool PyViz::TransmissionSampleKey::operator < (PyViz::TransmissionSampleKey const &other) const
-{
- if (this->transmitter < other.transmitter)
- {
- return true;
- }
- if (this->transmitter != other.transmitter)
- {
- return false;
- }
- if (this->receiver < other.receiver)
- {
- return true;}
- if (this->receiver != other.receiver)
- {
- return false;
- }
- if (this->channel < other.channel)
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-bool PyViz::TransmissionSampleKey::operator == (PyViz::TransmissionSampleKey const &other) const
-{
- bool retval = (transmitter == other.transmitter) &&
- (receiver == other.receiver) &&
- (channel == other.channel);
- return retval;
-}
-
-
-PyViz::NetDeviceStatistics &
-PyViz::FindNetDeviceStatistics (int node, int interface)
-{
- std::map<uint32_t, std::vector<NetDeviceStatistics> >::iterator nodeStatsIter = m_nodesStatistics.find (node);
- std::vector<NetDeviceStatistics> *stats;
- if (nodeStatsIter == m_nodesStatistics.end ())
- {
- stats = &m_nodesStatistics[node];
- stats->resize (NodeList::GetNode (node)->GetNDevices ());
- }
- else
- {
- stats = &(nodeStatsIter->second);
- }
- NetDeviceStatistics &devStats = (*stats)[interface];
- return devStats;
-}
-
-bool PyViz::GetPacketCaptureOptions (uint32_t nodeId, const PacketCaptureOptions **outOptions) const
-{
- std::map<uint32_t, PacketCaptureOptions>::const_iterator iter = m_packetCaptureOptions.find (nodeId);
- if (iter == m_packetCaptureOptions.end ())
- {
- return false;
- }
- else
- {
- *outOptions = &iter->second;
- return true;
- }
-}
-
-bool PyViz::FilterPacket (Ptr<const Packet> packet, const PacketCaptureOptions &options)
-{
- switch (options.mode)
- {
- case PACKET_CAPTURE_DISABLED:
- return false;
-
- case PACKET_CAPTURE_FILTER_HEADERS_OR:
- {
- PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
- while (metadataIterator.HasNext ())
- {
- PacketMetadata::Item item = metadataIterator.Next ();
- if (options.headers.find (item.tid) != options.headers.end ())
- {
- return true;
- }
- }
- return false;
- }
-
- case PACKET_CAPTURE_FILTER_HEADERS_AND:
- {
- std::set<TypeId> missingHeaders (options.headers);
- PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
- while (metadataIterator.HasNext ())
- {
- PacketMetadata::Item item = metadataIterator.Next ();
- std::set<TypeId>::iterator missingIter = missingHeaders.find (item.tid);
- if (missingIter != missingHeaders.end ())
- {
- missingHeaders.erase (missingIter);
- }
- }
- if (missingHeaders.size () == 0)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- default:
- NS_FATAL_ERROR ("should not be reached");
- return false;
- }
-}
-
-void
-PyViz::TraceDevQueueDrop (std::string context, Ptr<const Packet> packet)
-{
- NS_LOG_FUNCTION (context << packet->GetUid ());
- std::vector<std::string> splitPath = PathSplit (context);
- int nodeIndex = atoi (splitPath[1].c_str ());
- Ptr<Node> node = NodeList::GetNode (nodeIndex);
-
- if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
- {
- // if the transmitting node is not "of interest", we still
- // record the transmission if it is a packet of interest.
- if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
- {
- NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
- return;
- }
- }
-
- // ---- "last packets"
- const PacketCaptureOptions *captureOptions;
- if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
- {
- LastPacketsSample &last = m_lastPackets[nodeIndex];
- PacketSample lastPacket;
- lastPacket.time = Simulator::Now ();
- lastPacket.packet = packet->Copy ();
- lastPacket.device = NULL;
- last.lastDroppedPackets.push_back (lastPacket);
- while (last.lastDroppedPackets.size () > captureOptions->numLastPackets)
- {
- last.lastDroppedPackets.erase (last.lastDroppedPackets.begin ());
- }
- }
-
- std::map<Ptr<Node>, uint32_t>::iterator iter = m_packetDrops.find (node);
- if (iter == m_packetDrops.end ())
- {
- m_packetDrops[node] = packet->GetSize ();
- }
- else
- {
- iter->second += packet->GetSize ();
- }
-}
-
-void
-PyViz::TraceIpv4Drop (std::string context, ns3::Ipv4Header const &hdr, Ptr<const Packet> packet,
- ns3::Ipv4L3Protocol::DropReason reason, Ptr<Ipv4> dummy_ipv4, uint32_t interface)
-{
- Ptr<Packet> packetCopy = packet->Copy ();
- packetCopy->AddHeader (hdr);
- TraceDevQueueDrop (context, packetCopy);
-}
-
-
- // --------- TX device tracing -------------------
-
-void
-PyViz::TraceNetDevTxCommon (std::string const &context, Ptr<const Packet> packet,
- Mac48Address const &destinationAddress)
-{
- NS_LOG_FUNCTION (context << packet->GetUid () << *packet);
-
- std::vector<std::string> splitPath = PathSplit (context);
- int nodeIndex = atoi (splitPath[1].c_str ());
- int devIndex = atoi (splitPath[3].c_str ());
- Ptr<Node> node = NodeList::GetNode (nodeIndex);
- Ptr<NetDevice> device = node->GetDevice (devIndex);
-
- // ---- statistics
- NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
- ++stats.transmittedPackets;
- stats.transmittedBytes += packet->GetSize ();
-
- // ---- "last packets"
- const PacketCaptureOptions *captureOptions;
- if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
- {
- LastPacketsSample &last = m_lastPackets[nodeIndex];
- TxPacketSample lastPacket;
- lastPacket.time = Simulator::Now ();
- lastPacket.packet = packet->Copy ();
- lastPacket.device = device;
- lastPacket.to = destinationAddress;
- last.lastTransmittedPackets.push_back (lastPacket);
- while (last.lastTransmittedPackets.size () > captureOptions->numLastPackets)
- {
- last.lastTransmittedPackets.erase (last.lastTransmittedPackets.begin ());
- }
- }
-
- // ---- transmissions records
-
- if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
- {
- // if the transmitting node is not "of interest", we still
- // record the transmission if it is a packet of interest.
- if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
- {
- NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
- return;
- }
- }
- else
- {
- // We will follow this packet throughout the network.
- m_packetsOfInterest[packet->GetUid ()] = Simulator::Now ();
- }
-
- TxRecordValue record = { Simulator::Now (), node, false };
- if (destinationAddress == device->GetBroadcast ())
- {
- record.isBroadcast = true;
- }
-
- m_txRecords[TxRecordKey (device->GetChannel (), packet->GetUid ())] = record;
-
- PyVizPacketTag tag;
- //packet->RemovePacketTag (tag);
- tag.m_packetId = packet->GetUid ();
- packet->AddByteTag (tag);
-}
-
-void
-PyViz::TraceNetDevTxWifi (std::string context, Ptr<const Packet> packet)
-{
- NS_LOG_FUNCTION (context << packet->GetUid () << *packet);
-
- /*
- * To DS From DS Address 1 Address 2 Address 3 Address 4
- *----------------------------------------------------------------------
- * 0 0 Destination Source BSSID N/A
- * 0 1 Destination BSSID Source N/A
- * 1 0 BSSID Source Destination N/A
- * 1 1 Receiver Transmitter Destination Source
- */
- WifiMacHeader hdr;
- NS_ABORT_IF (packet->PeekHeader (hdr) == 0);
- Mac48Address destinationAddress;
- if (hdr.IsToDs () && !hdr.IsFromDs ())
- {
- destinationAddress = hdr.GetAddr3 ();
- }
- else if (!hdr.IsToDs () && hdr.IsFromDs ())
- {
- destinationAddress = hdr.GetAddr1 ();
- }
- else if (!hdr.IsToDs () && !hdr.IsFromDs ())
- {
- destinationAddress = hdr.GetAddr1 ();
- }
- else
- {
- destinationAddress = hdr.GetAddr3 ();
- }
- TraceNetDevTxCommon (context, packet, destinationAddress);
-}
-
-
-void
-PyViz::TraceNetDevTxCsma (std::string context, Ptr<const Packet> packet)
-{
- EthernetHeader ethernetHeader;
- NS_ABORT_IF (packet->PeekHeader (ethernetHeader) == 0);
- TraceNetDevTxCommon (context, packet, ethernetHeader.GetDestination ());
-}
-
-void
-PyViz::TraceNetDevTxPointToPoint (std::string context, Ptr<const Packet> packet)
-{
- TraceNetDevTxCommon (context, packet, Mac48Address ());
-}
-
-
-
-
- // --------- RX device tracing -------------------
-
-void
-PyViz::TraceNetDevRxCommon (std::string const &context, Ptr<const Packet> packet, Mac48Address const &from)
-{
- uint32_t uid;
- PyVizPacketTag tag;
- if (packet->FindFirstMatchingByteTag (tag))
- {
- uid = tag.m_packetId;
- }
- else
- {
- //NS_ASSERT (0);
- NS_LOG_WARN ("Packet has no byte tag; wimax link?");
- uid = packet->GetUid ();
- }
-
- NS_LOG_FUNCTION (context << uid);
- std::vector<std::string> splitPath = PathSplit (context);
- int nodeIndex = atoi (splitPath[1].c_str ());
- int devIndex = atoi (splitPath[3].c_str ());
-
- // ---- statistics
- NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
- ++stats.receivedPackets;
- stats.receivedBytes += packet->GetSize ();
-
- Ptr<Node> node = NodeList::GetNode (nodeIndex);
- Ptr<NetDevice> device = node->GetDevice (devIndex);
-
- // ---- "last packets"
- const PacketCaptureOptions *captureOptions;
- if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
- {
- LastPacketsSample &last = m_lastPackets[nodeIndex];
- RxPacketSample lastPacket;
- lastPacket.time = Simulator::Now ();
- lastPacket.packet = packet->Copy ();
- lastPacket.device = device;
- lastPacket.from = from;
- last.lastReceivedPackets.push_back (lastPacket);
- while (last.lastReceivedPackets.size () > captureOptions->numLastPackets)
- {
- last.lastReceivedPackets.erase (last.lastReceivedPackets.begin ());
- }
- }
-
- // ---- transmissions
- if (m_packetsOfInterest.find (uid) == m_packetsOfInterest.end ())
- {
- NS_LOG_DEBUG ("RX Packet " << uid << " is not of interest");
- return;
- }
-
- Ptr<Channel> channel = device->GetChannel ();
-
- std::map<TxRecordKey, TxRecordValue>::iterator recordIter =
- m_txRecords.find (TxRecordKey (channel, uid));
-
- if (recordIter == m_txRecords.end ())
- {
- NS_LOG_DEBUG ("RX Packet " << uid << " was not transmitted?!");
- return;
- }
-
- TxRecordValue &record = recordIter->second;
-
- if (record.srcNode == node)
- {
- NS_LOG_WARN ("Node " << node->GetId () << " receiving back the same packet (UID=" << uid
- << ") it had previously transmitted, on the same channel!");
- return;
- }
-
- TransmissionSampleKey key = { record.srcNode, node, channel };
-
-#ifdef NS3_LOG_ENABLE
- NS_LOG_DEBUG("m_transmissionSamples begin:");
- if (g_log.IsEnabled (ns3::LOG_DEBUG))
- {
- for (std::map<TransmissionSampleKey,TransmissionSampleValue>::const_iterator iter
- = m_transmissionSamples.begin (); iter != m_transmissionSamples.end (); iter++)
- {
- NS_LOG_DEBUG(iter->first.transmitter<<"/"<<iter->first.transmitter->GetId () << ", "
- << iter->first.receiver<<"/"<<iter->first.receiver->GetId ()
- << ", " << iter->first.channel << " => " << iter->second.bytes << " (@ " << &iter->second << ")");
- }
- }
- NS_LOG_DEBUG("m_transmissionSamples end.");
-#endif
-
- std::map<TransmissionSampleKey,TransmissionSampleValue>::iterator
- iter = m_transmissionSamples.find (key);
-
- if (iter == m_transmissionSamples.end ())
- {
- TransmissionSampleValue sample = { packet->GetSize () };
- NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
- << key.receiver<<"/"<<key.receiver->GetId()
- << " channel " << channel << ": " << packet->GetSize ()
- << " bytes more. => new sample with " << packet->GetSize () << " bytes.");
- m_transmissionSamples[key] = sample;
- }
- else
- {
- TransmissionSampleValue &sample = iter->second;
- NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
- << key.receiver<<"/"<<key.receiver->GetId()
- << " channel " << channel << ": " << packet->GetSize ()
- << " bytes more. => sample " << &sample << " with bytes " << sample.bytes);
-
- sample.bytes += packet->GetSize ();
- }
-}
-
-void
-PyViz::TraceNetDevRxWifi (std::string context, Ptr<const Packet> packet)
-{
- NS_LOG_FUNCTION (context << packet->GetUid ());
-
-
- /*
- * To DS From DS Address 1 Address 2 Address 3 Address 4
- *----------------------------------------------------------------------
- * 0 0 Destination Source BSSID N/A
- * 0 1 Destination BSSID Source N/A
- * 1 0 BSSID Source Destination N/A
- * 1 1 Receiver Transmitter Destination Source
- */
- WifiMacHeader hdr;
- NS_ABORT_IF (packet->PeekHeader (hdr) == 0);
- Mac48Address sourceAddress;
- if (hdr.IsToDs () && !hdr.IsFromDs ())
- {
- sourceAddress = hdr.GetAddr2 ();
- }
- else if (!hdr.IsToDs () && hdr.IsFromDs ())
- {
- sourceAddress = hdr.GetAddr3 ();
- }
- else if (!hdr.IsToDs () && !hdr.IsFromDs ())
- {
- sourceAddress = hdr.GetAddr2 ();
- }
- else
- {
- sourceAddress = hdr.GetAddr4 ();
- }
-
- TraceNetDevRxCommon (context, packet, sourceAddress);
-}
-
-
-
-void
-PyViz::TraceNetDevRxCsma (std::string context, Ptr<const Packet> packet)
-{
- EthernetHeader ethernetHeader;
- NS_ABORT_IF (packet->PeekHeader (ethernetHeader) == 0);
- TraceNetDevRxCommon (context, packet, ethernetHeader.GetSource ());
-}
-
-void
-PyViz::TraceNetDevRxPointToPoint (std::string context, Ptr<const Packet> packet)
-{
- TraceNetDevRxCommon (context, packet, Mac48Address ());
-}
-
-void
-PyViz::TraceNetDevPromiscRxCsma (std::string context, Ptr<const Packet> packet)
-{
- EthernetHeader ethernetHeader;
- NS_ABORT_IF (packet->PeekHeader (ethernetHeader) == 0);
-
- NetDevice::PacketType packetType = NetDevice::PACKET_OTHERHOST; // FIXME
-
- // Other packet types are already being received by
- // TraceNetDevRxCsma; we don't want to receive them twice.
- if (packetType == NetDevice::PACKET_OTHERHOST)
- {
- TraceNetDevRxCommon (context, packet, ethernetHeader.GetDestination ());
- }
-}
-
-void
-PyViz::TraceNetDevTxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &destination)
-{
- NS_LOG_FUNCTION (context);
- TraceNetDevTxCommon (context, packet, destination);
-}
-
-void
-PyViz::TraceNetDevRxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &source)
-{
- NS_LOG_FUNCTION (context);
- TraceNetDevRxCommon (context, packet, source);
-}
-
-
- // ---------------------
-
-PyViz::TransmissionSampleList
-PyViz::GetTransmissionSamples () const
-{
- NS_LOG_DEBUG ("GetTransmissionSamples BEGIN");
- TransmissionSampleList list;
- for (std::map<TransmissionSampleKey, TransmissionSampleValue>::const_iterator
- iter = m_transmissionSamples.begin ();
- iter != m_transmissionSamples.end ();
- iter++)
- {
- TransmissionSample sample;
- sample.transmitter = iter->first.transmitter;
- sample.receiver = iter->first.receiver;
- sample.channel = iter->first.channel;
- sample.bytes = iter->second.bytes;
- NS_LOG_DEBUG ("from " << sample.transmitter->GetId() << " to " << sample.receiver->GetId()
- << ": " << sample.bytes << " bytes.");
- list.push_back (sample);
- }
- NS_LOG_DEBUG ("GetTransmissionSamples END");
- return list;
-}
-
-PyViz::PacketDropSampleList
-PyViz::GetPacketDropSamples () const
-{
- NS_LOG_DEBUG ("GetPacketDropSamples BEGIN");
- PacketDropSampleList list;
- for (std::map<Ptr<Node>, uint32_t>::const_iterator
- iter = m_packetDrops.begin ();
- iter != m_packetDrops.end ();
- iter++)
- {
- PacketDropSample sample;
- sample.transmitter = iter->first;
- sample.bytes = iter->second;
- NS_LOG_DEBUG ("in " << sample.transmitter->GetId()
- << ": " << sample.bytes << " bytes dropped.");
- list.push_back (sample);
- }
- NS_LOG_DEBUG ("GetPacketDropSamples END");
- return list;
-}
-
-void
-PyViz::SetNodesOfInterest (std::set<uint32_t> nodes)
-{
- m_nodesOfInterest = nodes;
-}
-
-std::vector<PyViz::NodeStatistics>
-PyViz::GetNodesStatistics () const
-{
- std::vector<PyViz::NodeStatistics> retval;
- for (std::map<uint32_t, std::vector<NetDeviceStatistics> >::const_iterator iter = m_nodesStatistics.begin ();
- iter != m_nodesStatistics.end (); iter++)
- {
- NodeStatistics stats = { iter->first, iter->second };
- retval.push_back (stats);
- }
- return retval;
-}
-
-
-PyViz::LastPacketsSample
-PyViz::GetLastPackets (uint32_t nodeId) const
-{
- NS_LOG_DEBUG ("GetLastPackets: " << nodeId);
-
- std::map<uint32_t, LastPacketsSample>::const_iterator
- iter = m_lastPackets.find(nodeId);
- if (iter != m_lastPackets.end ())
- {
- return iter->second;
- }
- else
- {
- return LastPacketsSample ();
- }
-}
-
-
-
-
-
-
-namespace
-{
- // Adapted from http://en.wikipedia.org/w/index.php?title=Line_clipping&oldid=248609574
- class FastClipping
- {
- public:
- struct Vector2
- {
- double x;
- double y;
- };
-
- Vector2 m_clipMin, m_clipMax;
-
- struct Line
- {
- Vector2 start, end;
- double dx, dy;
- };
-
- private:
-
- void ClipStartTop (Line &line)
- {
- line.start.x += line.dx * (m_clipMin.y - line.start.y) / line.dy;
- line.start.y = m_clipMin.y;
- }
-
- void ClipStartBottom (Line &line)
- {
- line.start.x += line.dx * (m_clipMax.y - line.start.y) / line.dy;
- line.start.y = m_clipMax.y;
- }
-
- void ClipStartRight (Line &line)
- {
- line.start.y += line.dy * (m_clipMax.x - line.start.x) / line.dx;
- line.start.x = m_clipMax.x;
- }
-
- void ClipStartLeft (Line &line)
- {
- line.start.y += line.dy * (m_clipMin.x - line.start.x) / line.dx;
- line.start.x = m_clipMin.x;
- }
-
- void ClipEndTop (Line &line)
- {
- line.end.x += line.dx * (m_clipMin.y - line.end.y) / line.dy;
- line.end.y = m_clipMin.y;
- }
-
- void ClipEndBottom (Line &line) {
- line.end.x += line.dx * (m_clipMax.y - line.end.y) / line.dy;
- line.end.y = m_clipMax.y;
- }
-
- void ClipEndRight (Line &line)
- {
- line.end.y += line.dy * (m_clipMax.x - line.end.x) / line.dx;
- line.end.x = m_clipMax.x;
- }
-
- void ClipEndLeft (Line &line)
- {
- line.end.y += line.dy * (m_clipMin.x - line.end.x) / line.dx;
- line.end.x = m_clipMin.x;
- }
-
- public:
- FastClipping (Vector2 clipMin, Vector2 clipMax)
- : m_clipMin (clipMin), m_clipMax (clipMax)
- {
- }
-
-
- bool ClipLine (Line &line)
- {
- uint8_t lineCode = 0;
-
- if (line.end.y < m_clipMin.y)
- lineCode |= 8;
- else if (line.end.y > m_clipMax.y)
- lineCode |= 4;
-
- if (line.end.x > m_clipMax.x)
- lineCode |= 2;
- else if (line.end.x < m_clipMin.x)
- lineCode |= 1;
-
- if (line.start.y < m_clipMin.y)
- lineCode |= 128;
- else if (line.start.y > m_clipMax.y)
- lineCode |= 64;
-
- if (line.start.x > m_clipMax.x)
- lineCode |= 32;
- else if (line.start.x < m_clipMin.x)
- lineCode |= 16;
-
- // 9 - 8 - A
- // | | |
- // 1 - 0 - 2
- // | | |
- // 5 - 4 - 6
- switch (lineCode)
- {
- // center
- case 0x00:
- return true;
-
- case 0x01:
- ClipEndLeft (line);
- return true;
-
- case 0x02:
- ClipEndRight (line);
- return true;
-
- case 0x04:
- ClipEndBottom (line);
- return true;
-
- case 0x05:
- ClipEndLeft (line);
- if (line.end.y > m_clipMax.y)
- ClipEndBottom (line);
- return true;
-
- case 0x06:
- ClipEndRight (line);
- if (line.end.y > m_clipMax.y)
- ClipEndBottom (line);
- return true;
-
- case 0x08:
- ClipEndTop (line);
- return true;
-
- case 0x09:
- ClipEndLeft (line);
- if (line.end.y < m_clipMin.y)
- ClipEndTop (line);
- return true;
-
- case 0x0A:
- ClipEndRight (line);
- if (line.end.y < m_clipMin.y)
- ClipEndTop (line);
- return true;
-
- // left
- case 0x10:
- ClipStartLeft (line);
- return true;
-
- case 0x12:
- ClipStartLeft (line);
- ClipEndRight (line);
- return true;
-
- case 0x14:
- ClipStartLeft (line);
- if (line.start.y > m_clipMax.y)
- return false;
- ClipEndBottom (line);
- return true;
-
- case 0x16:
- ClipStartLeft (line);
- if (line.start.y > m_clipMax.y)
- return false;
- ClipEndBottom (line);
- if (line.end.x > m_clipMax.x)
- ClipEndRight (line);
- return true;
-
- case 0x18:
- ClipStartLeft (line);
- if (line.start.y < m_clipMin.y)
- return false;
- ClipEndTop (line);
- return true;
-
- case 0x1A:
- ClipStartLeft (line);
- if (line.start.y < m_clipMin.y)
- return false;
- ClipEndTop (line);
- if (line.end.x > m_clipMax.x)
- ClipEndRight (line);
- return true;
-
- // right
- case 0x20:
- ClipStartRight (line);
- return true;
-
- case 0x21:
- ClipStartRight (line);
- ClipEndLeft (line);
- return true;
-
- case 0x24:
- ClipStartRight (line);
- if (line.start.y > m_clipMax.y)
- return false;
- ClipEndBottom (line);
- return true;
-
- case 0x25:
- ClipStartRight (line);
- if (line.start.y > m_clipMax.y)
- return false;
- ClipEndBottom (line);
- if (line.end.x < m_clipMin.x)
- ClipEndLeft (line);
- return true;
-
- case 0x28:
- ClipStartRight (line);
- if (line.start.y < m_clipMin.y)
- return false;
- ClipEndTop (line);
- return true;
-
- case 0x29:
- ClipStartRight (line);
- if (line.start.y < m_clipMin.y)
- return false;
- ClipEndTop (line);
- if (line.end.x < m_clipMin.x)
- ClipEndLeft (line);
- return true;
-
- // bottom
- case 0x40:
- ClipStartBottom (line);
- return true;
-
- case 0x41:
- ClipStartBottom (line);
- if (line.start.x < m_clipMin.x)
- return false;
- ClipEndLeft (line);
- if (line.end.y > m_clipMax.y)
- ClipEndBottom (line);
- return true;
-
- case 0x42:
- ClipStartBottom (line);
- if (line.start.x > m_clipMax.x)
- return false;
- ClipEndRight (line);
- return true;
-
- case 0x48:
- ClipStartBottom (line);
- ClipEndTop (line);
- return true;
-
- case 0x49:
- ClipStartBottom (line);
- if (line.start.x < m_clipMin.x)
- return false;
- ClipEndLeft (line);
- if (line.end.y < m_clipMin.y)
- ClipEndTop (line);
- return true;
-
- case 0x4A:
- ClipStartBottom (line);
- if (line.start.x > m_clipMax.x)
- return false;
- ClipEndRight (line);
- if (line.end.y < m_clipMin.y)
- ClipEndTop (line);
- return true;
-
- // bottom-left
- case 0x50:
- ClipStartLeft (line);
- if (line.start.y > m_clipMax.y)
- ClipStartBottom (line);
- return true;
-
- case 0x52:
- ClipEndRight (line);
- if (line.end.y > m_clipMax.y)
- return false;
- ClipStartBottom (line);
- if (line.start.x < m_clipMin.x)
- ClipStartLeft (line);
- return true;
-
- case 0x58:
- ClipEndTop (line);
- if (line.end.x < m_clipMin.x)
- return false;
- ClipStartBottom (line);
- if (line.start.x < m_clipMin.x)
- ClipStartLeft (line);
- return true;
-
- case 0x5A:
- ClipStartLeft (line);
- if (line.start.y < m_clipMin.y)
- return false;
- ClipEndRight (line);
- if (line.end.y > m_clipMax.y)
- return false;
- if (line.start.y > m_clipMax.y)
- ClipStartBottom (line);
- if (line.end.y < m_clipMin.y)
- ClipEndTop (line);
- return true;
-
- // bottom-right
- case 0x60:
- ClipStartRight (line);
- if (line.start.y > m_clipMax.y)
- ClipStartBottom (line);
- return true;
-
- case 0x61:
- ClipEndLeft (line);
- if (line.end.y > m_clipMax.y)
- return false;
- ClipStartBottom (line);
- if (line.start.x > m_clipMax.x)
- ClipStartRight (line);
- return true;
-
- case 0x68:
- ClipEndTop (line);
- if (line.end.x > m_clipMax.x)
- return false;
- ClipStartRight (line);
- if (line.start.y > m_clipMax.y)
- ClipStartBottom (line);
- return true;
-
- case 0x69:
- ClipEndLeft (line);
- if (line.end.y > m_clipMax.y)
- return false;
- ClipStartRight (line);
- if (line.start.y < m_clipMin.y)
- return false;
- if (line.end.y < m_clipMin.y)
- ClipEndTop (line);
- if (line.start.y > m_clipMax.y)
- ClipStartBottom (line);
- return true;
-
- // top
- case 0x80:
- ClipStartTop (line);
- return true;
-
- case 0x81:
- ClipStartTop (line);
- if (line.start.x < m_clipMin.x)
- return false;
- ClipEndLeft (line);
- return true;
-
- case 0x82:
- ClipStartTop (line);
- if (line.start.x > m_clipMax.x)
- return false;
- ClipEndRight (line);
- return true;
-
- case 0x84:
- ClipStartTop (line);
- ClipEndBottom (line);
- return true;
-
- case 0x85:
- ClipStartTop (line);
- if (line.start.x < m_clipMin.x)
- return false;
- ClipEndLeft (line);
- if (line.end.y > m_clipMax.y)
- ClipEndBottom (line);
- return true;
-
- case 0x86:
- ClipStartTop (line);
- if (line.start.x > m_clipMax.x)
- return false;
- ClipEndRight (line);
- if (line.end.y > m_clipMax.y)
- ClipEndBottom (line);
- return true;
-
- // top-left
- case 0x90:
- ClipStartLeft (line);
- if (line.start.y < m_clipMin.y)
- ClipStartTop (line);
- return true;
-
- case 0x92:
- ClipEndRight (line);
- if (line.end.y < m_clipMin.y)
- return false;
- ClipStartTop (line);
- if (line.start.x < m_clipMin.x)
- ClipStartLeft (line);
- return true;
-
- case 0x94:
- ClipEndBottom (line);
- if (line.end.x < m_clipMin.x)
- return false;
- ClipStartLeft (line);
- if (line.start.y < m_clipMin.y)
- ClipStartTop (line);
- return true;
-
- case 0x96:
- ClipStartLeft (line);
- if (line.start.y > m_clipMax.y)
- return false;
- ClipEndRight (line);
- if (line.end.y < m_clipMin.y)
- return false;
- if (line.start.y < m_clipMin.y)
- ClipStartTop (line);
- if (line.end.y > m_clipMax.y)
- ClipEndBottom (line);
- return true;
-
- // top-right
- case 0xA0:
- ClipStartRight (line);
- if (line.start.y < m_clipMin.y)
- ClipStartTop (line);
- return true;
-
- case 0xA1:
- ClipEndLeft (line);
- if (line.end.y < m_clipMin.y)
- return false;
- ClipStartTop (line);
- if (line.start.x > m_clipMax.x)
- ClipStartRight (line);
- return true;
-
- case 0xA4:
- ClipEndBottom (line);
- if (line.end.x > m_clipMax.x)
- return false;
- ClipStartRight (line);
- if (line.start.y < m_clipMin.y)
- ClipStartTop (line);
- return true;
-
- case 0xA5:
- ClipEndLeft (line);
- if (line.end.y < m_clipMin.y)
- return false;
- ClipStartRight (line);
- if (line.start.y > m_clipMax.y)
- return false;
- if (line.end.y > m_clipMax.y)
- ClipEndBottom (line);
- if (line.start.y < m_clipMin.y)
- ClipStartTop (line);
- return true;
- }
-
- return false;
- }
- };
-}
-
-void
-PyViz::LineClipping (double boundsX1, double boundsY1, double boundsX2, double boundsY2,
- double &lineX1, double &lineY1, double &lineX2, double &lineY2)
-{
- FastClipping::Vector2 clipMin = {boundsX1, boundsY1}, clipMax = {boundsX2, boundsY2};
- FastClipping::Line line = { { lineX1, lineY1 }, { lineX2, lineY2 }, (lineX2-lineX1), (lineY2-lineY1) };
-
- FastClipping clipper (clipMin, clipMax);
- clipper.ClipLine (line);
- lineX1 = line.start.x;
- lineX2 = line.end.x;
- lineY1 = line.start.y;
- lineY2 = line.end.y;
-}
-
-
-}
-
--- a/src/tools/visualizer/model/pyviz.h Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2008 INESC Porto
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * C++ helper functions for use by the python visualizer (for things
- * Python is too slow at).
- *
- * Author: Gustavo Carneiro <gjc@inescporto.pt>
- */
-#ifndef NS3_PYVIZ_H
-#define NS3_PYVIZ_H
-
-#include "ns3/nstime.h"
-#include "ns3/event-id.h"
-#include "ns3/node.h"
-#include "ns3/channel.h"
-#include "ns3/packet.h"
-#include "ns3/mac48-address.h"
-#include "ns3/ipv4-header.h"
-#include "ns3/ipv4-l3-protocol.h"
-
-#include <map>
-#include <set>
-
-namespace ns3 {
-
-/**
- * \brief helper class to be used by the visualizer
- * \internal
- *
- * This class is not meant to be used by simulations. It is only
- * meant to be used by the visualizer tool (PyViz). The only reason
- * it is public is because Python bindings for it are needed,
- * otherwise it should be considered private.
- **/
-class PyViz
-{
-public:
- PyViz ();
- ~PyViz ();
-
- void RegisterDropTracePath (std::string const &tracePath);
-
- void RegisterCsmaLikeDevice (std::string const &deviceTypeName);
- void RegisterWifiLikeDevice (std::string const &deviceTypeName);
- void RegisterPointToPointLikeDevice (std::string const &deviceTypeName);
-
- // Run simulation until a given (simulated, absolute) time is reached
- void SimulatorRunUntil (Time time);
-
- static void Pause (std::string const &message);
- std::vector<std::string> GetPauseMessages () const;
-
- struct TransmissionSample
- {
- Ptr<Node> transmitter;
- Ptr<Node> receiver; // NULL if broadcast
- Ptr<Channel> channel;
- uint32_t bytes;
- };
- typedef std::vector<TransmissionSample> TransmissionSampleList;
- TransmissionSampleList GetTransmissionSamples () const;
-
- struct PacketDropSample
- {
- Ptr<Node> transmitter;
- uint32_t bytes;
- };
- typedef std::vector<PacketDropSample> PacketDropSampleList;
- PacketDropSampleList GetPacketDropSamples () const;
-
-
- struct PacketSample
- {
- Time time;
- Ptr<Packet> packet;
- Ptr<NetDevice> device;
- };
- struct TxPacketSample : PacketSample
- {
- Mac48Address to;
- };
- struct RxPacketSample : PacketSample
- {
- Mac48Address from;
- };
-
- struct LastPacketsSample
- {
- std::vector<RxPacketSample> lastReceivedPackets;
- std::vector<TxPacketSample> lastTransmittedPackets;
- std::vector<PacketSample> lastDroppedPackets;
- };
- LastPacketsSample GetLastPackets (uint32_t nodeId) const;
-
-
- void SetNodesOfInterest (std::set<uint32_t> nodes);
-
- struct NetDeviceStatistics
- {
- NetDeviceStatistics () : transmittedBytes (0), receivedBytes (0),
- transmittedPackets (0), receivedPackets (0) {}
- uint64_t transmittedBytes;
- uint64_t receivedBytes;
- uint32_t transmittedPackets;
- uint32_t receivedPackets;
- };
-
- struct NodeStatistics
- {
- uint32_t nodeId;
- std::vector<NetDeviceStatistics> statistics;
- };
-
- std::vector<NodeStatistics> GetNodesStatistics () const;
-
- enum PacketCaptureMode {
- PACKET_CAPTURE_DISABLED=1, // packet capture is disabled
- PACKET_CAPTURE_FILTER_HEADERS_OR, // packet capture if any of the indicated headers is present
- PACKET_CAPTURE_FILTER_HEADERS_AND, // packet capture if all of the indicated headers are present
- };
-
- struct PacketCaptureOptions
- {
- std::set<TypeId> headers;
- uint32_t numLastPackets;
- PacketCaptureMode mode;
- };
-
- void SetPacketCaptureOptions (uint32_t nodeId, PacketCaptureOptions options);
-
-
- // Yes, I know, this is just a utility function, not really related to the class in any way.
-
- // -#- @lineX1(direction=inout); @lineY1(direction=inout); @lineX2(direction=inout); @lineY2(direction=inout) -#-
- static void LineClipping (double boundsX1, double boundsY1, double boundsX2, double boundsY2, double &lineX1, double &lineY1, double &lineX2, double &lineY2); // don't break this line or pybindgen will not be able to pick up the above annotation :(
-
-
-private:
-
- bool GetPacketCaptureOptions (uint32_t nodeId, const PacketCaptureOptions **outOptions) const;
- static bool FilterPacket (Ptr<const Packet> packet, const PacketCaptureOptions &options);
-
-
- typedef std::pair<Ptr<Channel>, uint32_t> TxRecordKey;
-
- struct TxRecordValue
- {
- Time time;
- Ptr<Node> srcNode;
- bool isBroadcast;
- };
-
- struct TransmissionSampleKey
- {
- bool operator < (TransmissionSampleKey const &other) const;
- bool operator == (TransmissionSampleKey const &other) const;
- Ptr<Node> transmitter;
- Ptr<Node> receiver; // NULL if broadcast
- Ptr<Channel> channel;
- };
-
- struct TransmissionSampleValue
- {
- uint32_t bytes;
- };
-
- // data
- std::map<uint32_t, PacketCaptureOptions> m_packetCaptureOptions;
- std::vector<std::string> m_pauseMessages;
- std::map<TxRecordKey, TxRecordValue> m_txRecords;
- std::map<TransmissionSampleKey, TransmissionSampleValue> m_transmissionSamples;
- std::map<Ptr<Node>, uint32_t> m_packetDrops;
- std::set<uint32_t> m_nodesOfInterest; // list of node IDs whose transmissions will be monitored
- std::map<uint32_t, Time> m_packetsOfInterest; // list of packet UIDs that will be monitored
- std::map<uint32_t, LastPacketsSample> m_lastPackets;
- std::map<uint32_t, std::vector<NetDeviceStatistics> > m_nodesStatistics;
-
- // Trace callbacks
- void TraceNetDevTxCommon (std::string const &context, Ptr<const Packet> packet, Mac48Address const &destination);
- void TraceNetDevRxCommon (std::string const &context, Ptr<const Packet> packet, Mac48Address const &source);
-
- void TraceNetDevTxWifi (std::string context, Ptr<const Packet> packet);
- void TraceNetDevRxWifi (std::string context, Ptr<const Packet> packet);
-
- void TraceDevQueueDrop (std::string context, Ptr<const Packet> packet);
- void TraceIpv4Drop (std::string context, ns3::Ipv4Header const &hdr, Ptr<const Packet> packet,
- ns3::Ipv4L3Protocol::DropReason reason, Ptr<Ipv4> dummy_ipv4, uint32_t interface);
-
- void TraceNetDevTxCsma (std::string context, Ptr<const Packet> packet);
- void TraceNetDevRxCsma (std::string context, Ptr<const Packet> packet);
- void TraceNetDevPromiscRxCsma (std::string context, Ptr<const Packet> packet);
-
- void TraceNetDevTxPointToPoint (std::string context, Ptr<const Packet> packet);
- void TraceNetDevRxPointToPoint (std::string context, Ptr<const Packet> packet);
-
- void TraceNetDevTxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &destination);
- void TraceNetDevRxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &source);
-
- inline NetDeviceStatistics & FindNetDeviceStatistics (int node, int interface);
-
- void DoPause (std::string const &message);
-
- bool m_stop;
- EventId m_stopCallbackEvent;
- void CallbackStopSimulation ();
-};
-
-
-}
-
-#endif /* NS3_PYVIZ_H */
--- a/src/tools/visualizer/model/visual-simulator-impl.cc Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2010 Gustavo Carneiro
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Gustavo Carneiro <gjcarneiro@gmail.com> <gjc@inescporto.pt>
- */
-#include <Python.h>
-#include "visual-simulator-impl.h"
-#include "ns3/default-simulator-impl.h"
-#include "ns3/log.h"
-
-NS_LOG_COMPONENT_DEFINE ("VisualSimulatorImpl");
-
-namespace ns3 {
-
-
-
-NS_OBJECT_ENSURE_REGISTERED (VisualSimulatorImpl);
-
-namespace
-{
- ObjectFactory
- GetDefaultSimulatorImplFactory ()
- {
- ObjectFactory factory;
- factory.SetTypeId (DefaultSimulatorImpl::GetTypeId ());
- return factory;
- }
-}
-
-
-TypeId
-VisualSimulatorImpl::GetTypeId (void)
-{
- static TypeId tid = TypeId ("ns3::VisualSimulatorImpl")
- .SetParent<SimulatorImpl> ()
- .AddConstructor<VisualSimulatorImpl> ()
- .AddAttribute ("SimulatorImplFactory",
- "Factory for the underlying simulator implementation used by the visualizer.",
- ObjectFactoryValue (GetDefaultSimulatorImplFactory ()),
- MakeObjectFactoryAccessor (&VisualSimulatorImpl::m_simulatorImplFactory),
- MakeObjectFactoryChecker ())
- ;
- return tid;
-}
-
-
-VisualSimulatorImpl::VisualSimulatorImpl ()
-{
-}
-
-VisualSimulatorImpl::~VisualSimulatorImpl ()
-{}
-
-void
-VisualSimulatorImpl::DoDispose (void)
-{
- if (m_simulator)
- {
- m_simulator->Dispose ();
- m_simulator = NULL;
- }
- SimulatorImpl::DoDispose ();
-}
-
-void
-VisualSimulatorImpl::NotifyConstructionCompleted ()
-{
- m_simulator = m_simulatorImplFactory.Create<SimulatorImpl> ();
-}
-
-
-void
-VisualSimulatorImpl::Destroy ()
-{
- m_simulator->Destroy ();
-}
-
-void
-VisualSimulatorImpl::SetScheduler (ObjectFactory schedulerFactory)
-{
- m_simulator->SetScheduler (schedulerFactory);
-}
-
-// System ID for non-distributed simulation is always zero
-uint32_t
-VisualSimulatorImpl::GetSystemId (void) const
-{
- return m_simulator->GetSystemId ();
-}
-
-bool
-VisualSimulatorImpl::IsFinished (void) const
-{
- return m_simulator->IsFinished ();
-}
-
-Time
-VisualSimulatorImpl::Next (void) const
-{
- return m_simulator->Next ();
-}
-
-void
-VisualSimulatorImpl::Run (void)
-{
- if (!Py_IsInitialized ())
- {
- const char *argv[] = {"python", NULL};
- Py_Initialize();
- PySys_SetArgv(1, (char**) argv);
- }
- PyRun_SimpleString(
- "import visualizer\n"
- "visualizer.start();\n"
- );
-}
-
-void
-VisualSimulatorImpl::RunOneEvent (void)
-{
- m_simulator->RunOneEvent ();
-}
-
-void
-VisualSimulatorImpl::Stop (void)
-{
- m_simulator->Stop ();
-}
-
-void
-VisualSimulatorImpl::Stop (Time const &time)
-{
- m_simulator->Stop (time);
-}
-
-//
-// Schedule an event for a _relative_ time in the future.
-//
-EventId
-VisualSimulatorImpl::Schedule (Time const &time, EventImpl *event)
-{
- return m_simulator->Schedule (time, event);
-}
-
-void
-VisualSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event)
-{
- m_simulator->ScheduleWithContext (context, time, event);
-}
-
-EventId
-VisualSimulatorImpl::ScheduleNow (EventImpl *event)
-{
- return m_simulator->ScheduleNow (event);
-}
-
-EventId
-VisualSimulatorImpl::ScheduleDestroy (EventImpl *event)
-{
- return m_simulator->ScheduleDestroy (event);
-}
-
-Time
-VisualSimulatorImpl::Now (void) const
-{
- return m_simulator->Now ();
-}
-
-Time
-VisualSimulatorImpl::GetDelayLeft (const EventId &id) const
-{
- return m_simulator->GetDelayLeft (id);
-}
-
-void
-VisualSimulatorImpl::Remove (const EventId &id)
-{
- m_simulator->Remove (id);
-}
-
-void
-VisualSimulatorImpl::Cancel (const EventId &id)
-{
- m_simulator->Cancel (id);
-}
-
-bool
-VisualSimulatorImpl::IsExpired (const EventId &ev) const
-{
- return m_simulator->IsExpired (ev);
-}
-
-Time
-VisualSimulatorImpl::GetMaximumSimulationTime (void) const
-{
- return m_simulator->GetMaximumSimulationTime ();
-}
-
-uint32_t
-VisualSimulatorImpl::GetContext (void) const
-{
- return m_simulator->GetContext ();
-}
-
-void
-VisualSimulatorImpl::RunRealSimulator (void)
-{
- m_simulator->Run ();
-}
-
-
-} // namespace ns3
-
-
--- a/src/tools/visualizer/model/visual-simulator-impl.h Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2010 Gustavo Carneiro
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Gustavo Carneiro <gjcarneiro@gmail.com>
- */
-
-#ifndef VISUAL_SIMULATOR_IMPL_H
-#define VISUAL_SIMULATOR_IMPL_H
-
-#include "ns3/simulator-impl.h"
-
-namespace ns3 {
-
-
-/**
- * \brief A replacement simulator that starts the visualizer
- * \internal
- *
- * To use this class, run any ns-3 simulation with the command-line
- * argument --SimulatorImplementationType=ns3::VisualSimulatorImpl.
- * This causes the visualizer (PyViz) to start automatically.
- **/
-class VisualSimulatorImpl : public SimulatorImpl
-{
-public:
- static TypeId GetTypeId (void);
-
- VisualSimulatorImpl ();
- ~VisualSimulatorImpl ();
-
- virtual void Destroy ();
- virtual bool IsFinished (void) const;
- virtual Time Next (void) const;
- virtual void Stop (void);
- virtual void Stop (Time const &time);
- virtual EventId Schedule (Time const &time, EventImpl *event);
- virtual void ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event);
- virtual EventId ScheduleNow (EventImpl *event);
- virtual EventId ScheduleDestroy (EventImpl *event);
- virtual void Remove (const EventId &ev);
- virtual void Cancel (const EventId &ev);
- virtual bool IsExpired (const EventId &ev) const;
- virtual void Run (void);
- virtual void RunOneEvent (void);
- virtual Time Now (void) const;
- virtual Time GetDelayLeft (const EventId &id) const;
- virtual Time GetMaximumSimulationTime (void) const;
- virtual void SetScheduler (ObjectFactory schedulerFactory);
- virtual uint32_t GetSystemId (void) const;
- virtual uint32_t GetContext (void) const;
-
- /// calls Run() in the wrapped simulator
- void RunRealSimulator (void);
-
-protected:
- void DoDispose ();
- void NotifyConstructionCompleted (void);
-
-private:
- Ptr<SimulatorImpl> GetSim ();
- Ptr<SimulatorImpl> m_simulator;
- ObjectFactory m_simulatorImplFactory;
-
-};
-
-} // namespace ns3
-
-#endif /* DEFAULT_SIMULATOR_IMPL_H */
--- a/src/tools/visualizer/model/visualizer-ideas.txt Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-- Add an Attribute browser plugin, simililar to Mathieu's GtkConfigStore;
- - Right click on a node -> Show Attributes;
- - Allow editing attributes too;
-- List of all nodes, navigator;
-- Represent individual NetDevices in Nodes;
-- Colorize flows; possible approaches:
- - Apply color based on hash function of ethertype, IP packet type, L4 destination port;
- - Programmatically marked flows;
- - Packet tags?
- - Present a GUI to show applications and set color for each one;
- - Problems:
- > How about multiple flows? How to represent them simultaneously?
-- Track down a Gtk+ bug preventing tooltips from working correctly with large zoom levels;
-- Possibly look for embedding an ipython shell as a widget inside the
- main window: http://ipython.scipy.org/moin/Cookbook/EmbeddingInGTK
-
--- a/src/tools/visualizer/visualizer/__init__.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-
-from core import start, register_plugin, set_bounds, add_initialization_hook
-
--- a/src/tools/visualizer/visualizer/base.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-import ns3
-import gobject
-import os.path
-import sys
-
-PIXELS_PER_METER = 3.0 # pixels-per-meter, at 100% zoom level
-
-class PyVizObject(gobject.GObject):
- __gtype_name__ = "PyVizObject"
-
- def tooltip_query(self, tooltip):
- tooltip.set_text("TODO: tooltip for %r" % self)
-
-class Link(PyVizObject):
- pass
-
-
-class InformationWindow(object):
- def update(self):
- raise NotImplementedError
-
-class NetDeviceTraits(object):
- def __init__(self, is_wireless=None, is_virtual=False):
- assert is_virtual or is_wireless is not None
- self.is_wireless = is_wireless
- self.is_virtual = is_virtual
-
-netdevice_traits = {
- ns3.PointToPointNetDevice: NetDeviceTraits(is_wireless=False),
- ns3.CsmaNetDevice: NetDeviceTraits(is_wireless=False),
- ns3.WifiNetDevice: NetDeviceTraits(is_wireless=True),
- ns3.BridgeNetDevice: NetDeviceTraits(is_virtual=True),
- ns3.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False),
- ns3.MeshPointDevice: NetDeviceTraits(is_virtual=True),
- ns3.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True),
- ns3.BaseStationNetDevice: NetDeviceTraits(is_wireless=True),
-}
-
-def lookup_netdevice_traits(class_type):
- try:
- return netdevice_traits[class_type]
- except KeyError:
- sys.stderr.write("WARNING: no NetDeviceTraits registered for device type %r; "
- "I will assume this is a non-virtual wireless device, "
- "but you should edit %r, variable 'netdevice_traits',"
- " to make sure.\n" % (class_type.__name__, __file__))
- t = NetDeviceTraits(is_virtual=False, is_wireless=True)
- netdevice_traits[class_type] = t
- return t
-
-def transform_distance_simulation_to_canvas(d):
- return d*PIXELS_PER_METER
-
-def transform_point_simulation_to_canvas(x, y):
- return x*PIXELS_PER_METER, y*PIXELS_PER_METER
-
-def transform_distance_canvas_to_simulation(d):
- return d/PIXELS_PER_METER
-
-def transform_point_canvas_to_simulation(x, y):
- return x/PIXELS_PER_METER, y/PIXELS_PER_METER
-
-
-
-
-plugins = []
-plugin_modules = {}
-
-def register_plugin(plugin_init_func, plugin_name=None, plugin_module=None):
- """
- Register a plugin.
-
- @param plugin: a callable object that will be invoked whenever a
- Visualizer object is created, like this: plugin(visualizer)
- """
- assert callable(plugin_init_func)
- plugins.append(plugin_init_func)
- if plugin_module is not None:
- plugin_modules[plugin_name] = plugin_module
-
-plugins_loaded = False
-def load_plugins():
- global plugins_loaded
- if plugins_loaded:
- return
- plugins_loaded = True
- plugins_dir = os.path.join(os.path.dirname(__file__), 'plugins')
- old_path = list(sys.path)
- sys.path.insert(0, plugins_dir)
- for filename in os.listdir(plugins_dir):
- name, ext = os.path.splitext(filename)
- if ext != '.py':
- continue
- try:
- plugin_module = __import__(name)
- except ImportError, ex:
- print >> sys.stderr, "Could not load plugin %r: %s" % (filename, str(ex))
- continue
- try:
- plugin_func = plugin_module.register
- except AttributeError:
- print >> sys.stderr, "Plugin %r has no 'register' function" % name
- else:
- #print >> sys.stderr, "Plugin %r registered" % name
- register_plugin(plugin_func, name, plugin_module)
- sys.path = old_path
-
--- a/src/tools/visualizer/visualizer/core.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1470 +0,0 @@
-# -*- Mode: python; coding: utf-8 -*-
-from __future__ import division
-#from __future__ import with_statement
-
-LAYOUT_ALGORITHM = 'neato' # ['neato'|'dot'|'twopi'|'circo'|'fdp'|'nop']
-REPRESENT_CHANNELS_AS_NODES = 1
-DEFAULT_NODE_SIZE = 3.0 # default node size in meters
-DEFAULT_TRANSMISSIONS_MEMORY = 5 # default number of of past intervals whose transmissions are remembered
-BITRATE_FONT_SIZE = 10
-
-# internal constants, normally not meant to be changed
-SAMPLE_PERIOD = 0.1
-PRIORITY_UPDATE_MODEL = -100
-PRIORITY_UPDATE_VIEW = 200
-
-import platform
-if platform.system() == "Windows":
- SHELL_FONT = "Lucida Console 9"
-else:
- SHELL_FONT = "Luxi Mono 10"
-
-
-import ns3
-import math
-import os
-import sys
-import gobject
-import time
-
-try:
- import pygraphviz
- import gtk
- import pango
- import goocanvas
- import cairo
- import threading
- import hud
- #import time
- import cairo
- from higcontainer import HIGContainer
- gobject.threads_init()
- try:
- import svgitem
- except ImportError:
- svgitem = None
-except ImportError, _import_error:
- import dummy_threading as threading
-else:
- _import_error = None
-
-try:
- import ipython_view
-except ImportError:
- ipython_view = None
-
-from base import InformationWindow, PyVizObject, Link, lookup_netdevice_traits, PIXELS_PER_METER
-from base import transform_distance_simulation_to_canvas, transform_point_simulation_to_canvas
-from base import transform_distance_canvas_to_simulation, transform_point_canvas_to_simulation
-from base import load_plugins, register_plugin, plugins
-
-PI_OVER_2 = math.pi/2
-PI_TIMES_2 = math.pi*2
-
-class Node(PyVizObject):
-
- __gsignals__ = {
-
- # signal emitted whenever a tooltip is about to be shown for the node
- # the first signal parameter is a python list of strings, to which information can be appended
- 'query-extra-tooltip-info': (gobject.SIGNAL_RUN_LAST, None, (object,)),
-
- }
-
- def __init__(self, visualizer, node_index):
- super(Node, self).__init__()
-
- self.visualizer = visualizer
- self.node_index = node_index
- self.canvas_item = goocanvas.Ellipse()
- self.canvas_item.set_data("pyviz-object", self)
- self.links = []
- self._has_mobility = None
- self._selected = False
- self._highlighted = False
- self._color = 0x808080ff
- self._size = DEFAULT_NODE_SIZE
- self.canvas_item.connect("enter-notify-event", self.on_enter_notify_event)
- self.canvas_item.connect("leave-notify-event", self.on_leave_notify_event)
- self.menu = None
- self.svg_item = None
- self.svg_align_x = None
- self.svg_align_y = None
- self._label = None
- self._label_canvas_item = None
-
- self._update_appearance() # call this last
-
- def set_svg_icon(self, file_base_name, width=None, height=None, align_x=0.5, align_y=0.5):
- """
- Set a background SVG icon for the node.
-
- @param file_base_name: base file name, including .svg
- extension, of the svg file. Place the file in the folder
- src/contrib/visualizer/resource.
-
- @param width: scale to the specified width, in meters
- @param width: scale to the specified height, in meters
-
- @param align_x: horizontal alignment of the icon relative to
- the node position, from 0 (icon fully to the left of the node)
- to 1.0 (icon fully to the right of the node)
-
- @param align_y: vertical alignment of the icon relative to the
- node position, from 0 (icon fully to the top of the node) to
- 1.0 (icon fully to the bottom of the node)
-
- """
- if width is None and height is None:
- raise ValueError("either width or height must be given")
- rsvg_handle = svgitem.rsvg_handle_factory(file_base_name)
- x = self.canvas_item.props.center_x
- y = self.canvas_item.props.center_y
- self.svg_item = svgitem.SvgItem(x, y, rsvg_handle)
- self.svg_item.props.parent = self.visualizer.canvas.get_root_item()
- self.svg_item.props.pointer_events = 0
- self.svg_item.lower(None)
- self.svg_item.props.visibility = goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD
- if width is not None:
- self.svg_item.props.width = transform_distance_simulation_to_canvas(width)
- if height is not None:
- self.svg_item.props.height = transform_distance_simulation_to_canvas(height)
-
- #threshold1 = 10.0/self.svg_item.props.height
- #threshold2 = 10.0/self.svg_item.props.width
- #self.svg_item.props.visibility_threshold = min(threshold1, threshold2)
-
- self.svg_align_x = align_x
- self.svg_align_y = align_y
- self._update_svg_position(x, y)
- self._update_appearance()
-
- def set_label(self, label):
- assert isinstance(label, basestring)
- self._label = label
- self._update_appearance()
-
- def _update_svg_position(self, x, y):
- w = self.svg_item.width
- h = self.svg_item.height
- self.svg_item.set_properties(x=(x - (1-self.svg_align_x)*w),
- y=(y - (1-self.svg_align_y)*h))
-
-
- def tooltip_query(self, tooltip):
- self.visualizer.simulation.lock.acquire()
- try:
- ns3_node = ns3.NodeList.GetNode(self.node_index)
- ipv4 = ns3_node.GetObject(ns3.Ipv4.GetTypeId())
- lines = ['<b><u>Node %i</u></b>' % self.node_index]
- lines.append('')
-
- self.emit("query-extra-tooltip-info", lines)
-
- mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
- if mob is not None:
- lines.append(' <b>Mobility Model</b>: %s' % mob.GetInstanceTypeId().GetName())
-
- for devI in range(ns3_node.GetNDevices()):
- lines.append('')
- lines.append(' <u>NetDevice %i:</u>' % devI)
- dev = ns3_node.GetDevice(devI)
- name = ns3.Names.FindName(dev)
- if name:
- lines.append(' <b>Name:</b> %s' % name)
- devname = dev.GetInstanceTypeId().GetName()
- lines.append(' <b>Type:</b> %s' % devname)
- if ipv4 is not None:
- ipv4_idx = ipv4.GetInterfaceForDevice(dev)
- if ipv4_idx != -1:
- addresses = [
- '%s/%s' % (ipv4.GetAddress(ipv4_idx, i).GetLocal(),
- ipv4.GetAddress(ipv4_idx, i).GetMask())
- for i in range(ipv4.GetNAddresses(ipv4_idx))]
- lines.append(' <b>IPv4 Addresses:</b> %s' % '; '.join(addresses))
-
- lines.append(' <b>MAC Address:</b> %s' % (dev.GetAddress(),))
-
- tooltip.set_markup('\n'.join(lines))
- finally:
- self.visualizer.simulation.lock.release()
-
- def on_enter_notify_event(self, view, target, event):
- self.highlighted = True
- def on_leave_notify_event(self, view, target, event):
- self.highlighted = False
-
- def _set_selected(self, value):
- self._selected = value
- self._update_appearance()
- def _get_selected(self):
- return self._selected
- selected = property(_get_selected, _set_selected)
-
- def _set_highlighted(self, value):
- self._highlighted = value
- self._update_appearance()
- def _get_highlighted(self):
- return self._highlighted
- highlighted = property(_get_highlighted, _set_highlighted)
-
- def set_size(self, size):
- self._size = size
- self._update_appearance()
-
- def _update_appearance(self):
- """Update the node aspect to reflect the selected/highlighted state"""
-
- size = transform_distance_simulation_to_canvas(self._size)
- if self.svg_item is not None:
- alpha = 0x80
- else:
- alpha = 0xff
- fill_color_rgba = (self._color & 0xffffff00) | alpha
- self.canvas_item.set_properties(radius_x=size, radius_y=size,
- fill_color_rgba=fill_color_rgba)
- if self._selected:
- line_width = size*.3
- else:
- line_width = size*.15
- if self.highlighted:
- stroke_color = 'yellow'
- else:
- stroke_color = 'black'
- self.canvas_item.set_properties(line_width=line_width, stroke_color=stroke_color)
-
- if self._label is not None:
- if self._label_canvas_item is None:
- self._label_canvas_item = goocanvas.Text(visibility_threshold=0.5,
- font="Sans Serif 10",
- fill_color_rgba=0x808080ff,
- alignment=pango.ALIGN_CENTER,
- anchor=gtk.ANCHOR_N,
- parent=self.visualizer.canvas.get_root_item(),
- pointer_events=0)
- self._label_canvas_item.lower(None)
-
- self._label_canvas_item.set_properties(visibility=goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD,
- text=self._label)
- self._update_position()
-
- def set_position(self, x, y):
- self.canvas_item.set_property("center_x", x)
- self.canvas_item.set_property("center_y", y)
- if self.svg_item is not None:
- self._update_svg_position(x, y)
-
- for link in self.links:
- link.update_points()
-
- if self._label_canvas_item is not None:
- self._label_canvas_item.set_properties(x=x, y=(y+self._size*3))
-
- def get_position(self):
- return (self.canvas_item.get_property("center_x"), self.canvas_item.get_property("center_y"))
-
- def _update_position(self):
- x, y = self.get_position()
- self.set_position(x, y)
-
- def set_color(self, color):
- if isinstance(color, str):
- color = gtk.gdk.color_parse(color)
- color = ((color.red>>8) << 24) | ((color.green>>8) << 16) | ((color.blue>>8) << 8) | 0xff
- self._color = color
- self._update_appearance()
-
- def add_link(self, link):
- assert isinstance(link, Link)
- self.links.append(link)
-
- def remove_link(self, link):
- assert isinstance(link, Link)
- self.links.remove(link)
-
- @property
- def has_mobility(self):
- if self._has_mobility is None:
- node = ns3.NodeList.GetNode(self.node_index)
- mobility = node.GetObject(ns3.MobilityModel.GetTypeId())
- self._has_mobility = (mobility is not None)
- return self._has_mobility
-
-
-class Channel(PyVizObject):
- def __init__(self, channel):
- self.channel = channel
- self.canvas_item = goocanvas.Ellipse(radius_x=30, radius_y=30,
- fill_color="white",
- stroke_color="grey", line_width=2.0,
- line_dash=goocanvas.LineDash([10.0, 10.0 ]),
- visibility=goocanvas.ITEM_VISIBLE)
- self.canvas_item.set_data("pyviz-object", self)
- self.links = []
-
- def set_position(self, x, y):
- self.canvas_item.set_property("center_x", x)
- self.canvas_item.set_property("center_y", y)
-
- for link in self.links:
- link.update_points()
-
- def get_position(self):
- return (self.canvas_item.get_property("center_x"), self.canvas_item.get_property("center_y"))
-
-
-class WiredLink(Link):
- def __init__(self, node1, node2):
- assert isinstance(node1, Node)
- assert isinstance(node2, (Node, Channel))
- self.node1 = node1
- self.node2 = node2
- self.canvas_item = goocanvas.Path(line_width=1.0, stroke_color="black")
- self.canvas_item.set_data("pyviz-object", self)
- self.node1.links.append(self)
- self.node2.links.append(self)
-
- def update_points(self):
- pos1_x, pos1_y = self.node1.get_position()
- pos2_x, pos2_y = self.node2.get_position()
- self.canvas_item.set_property("data", "M %r %r L %r %r" % (pos1_x, pos1_y, pos2_x, pos2_y))
-
-
-
-class SimulationThread(threading.Thread):
- def __init__(self, viz):
- super(SimulationThread, self).__init__()
- assert isinstance(viz, Visualizer)
- self.viz = viz # Visualizer object
- self.lock = threading.Lock()
- self.go = threading.Event()
- self.go.clear()
- self.target_time = 0 # in seconds
- self.quit = False
- self.sim_helper = ns3.PyViz()
- self.pause_messages = []
-
- def set_nodes_of_interest(self, nodes):
- self.lock.acquire()
- try:
- self.sim_helper.SetNodesOfInterest(nodes)
- finally:
- self.lock.release()
-
- def run(self):
- while not self.quit:
- #print "sim: Wait for go"
- self.go.wait() # wait until the main (view) thread gives us the go signal
- self.go.clear()
- if self.quit:
- break
- #self.go.clear()
- #print "sim: Acquire lock"
- self.lock.acquire()
- try:
- if 0:
- if ns3.Simulator.IsFinished():
- self.viz.play_button.set_sensitive(False)
- break
- #print "sim: Current time is %f; Run until: %f" % (ns3.Simulator.Now ().GetSeconds (), self.target_time)
- #if ns3.Simulator.Now ().GetSeconds () > self.target_time:
- # print "skipping, model is ahead of view!"
- self.sim_helper.SimulatorRunUntil(ns3.Seconds(self.target_time))
- #print "sim: Run until ended at current time: ", ns3.Simulator.Now ().GetSeconds ()
- self.pause_messages.extend(self.sim_helper.GetPauseMessages())
- gobject.idle_add(self.viz.update_model, priority=PRIORITY_UPDATE_MODEL)
- #print "sim: Run until: ", self.target_time, ": finished."
- finally:
- self.lock.release()
- #print "sim: Release lock, loop."
-
-# enumeration
-class ShowTransmissionsMode(object):
- __slots__ = []
-ShowTransmissionsMode.ALL = ShowTransmissionsMode()
-ShowTransmissionsMode.NONE = ShowTransmissionsMode()
-ShowTransmissionsMode.SELECTED = ShowTransmissionsMode()
-
-class Visualizer(gobject.GObject):
- INSTANCE = None
-
- if _import_error is None:
- __gsignals__ = {
-
- # signal emitted whenever a right-click-on-node popup menu is being constructed
- 'populate-node-menu': (gobject.SIGNAL_RUN_LAST, None, (object, gtk.Menu,)),
-
- # signal emitted after every simulation period (SAMPLE_PERIOD seconds of simulated time)
- # the simulation lock is acquired while the signal is emitted
- 'simulation-periodic-update': (gobject.SIGNAL_RUN_LAST, None, ()),
-
- # signal emitted right after the topology is scanned
- 'topology-scanned': (gobject.SIGNAL_RUN_LAST, None, ()),
-
- # signal emitted when it's time to update the view objects
- 'update-view': (gobject.SIGNAL_RUN_LAST, None, ()),
-
- }
-
- def __init__(self):
- assert Visualizer.INSTANCE is None
- Visualizer.INSTANCE = self
- super(Visualizer, self).__init__()
- self.nodes = {} # node index -> Node
- self.channels = {} # id(ns3.Channel) -> Channel
- self.window = None # toplevel window
- self.canvas = None # goocanvas.Canvas
- self.time_label = None # gtk.Label
- self.play_button = None # gtk.ToggleButton
- self.zoom = None # gtk.Adjustment
- self._scrolled_window = None # gtk.ScrolledWindow
-
- self.links_group = goocanvas.Group()
- self.channels_group = goocanvas.Group()
- self.nodes_group = goocanvas.Group()
-
- self._update_timeout_id = None
- self.simulation = SimulationThread(self)
- self.selected_node = None # node currently selected
- self.speed = 1.0
- self.information_windows = []
- self._transmission_arrows = []
- self._last_transmissions = []
- self._drop_arrows = []
- self._last_drops = []
- self._show_transmissions_mode = None
- self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
- self._panning_state = None
- self.node_size_adjustment = None
- self.transmissions_smoothing_adjustment = None
- self.sample_period = SAMPLE_PERIOD
- self.node_drag_state = None
- self.follow_node = None
- self.shell_window = None
-
- self.create_gui()
-
- for plugin in plugins:
- plugin(self)
-
- def set_show_transmissions_mode(self, mode):
- assert isinstance(mode, ShowTransmissionsMode)
- self._show_transmissions_mode = mode
- if self._show_transmissions_mode == ShowTransmissionsMode.ALL:
- self.simulation.set_nodes_of_interest(range(ns3.NodeList.GetNNodes()))
- elif self._show_transmissions_mode == ShowTransmissionsMode.NONE:
- self.simulation.set_nodes_of_interest([])
- elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
- if self.selected_node is None:
- self.simulation.set_nodes_of_interest([])
- else:
- self.simulation.set_nodes_of_interest([self.selected_node.node_index])
-
- def _create_advanced_controls(self):
- expander = gtk.Expander("Advanced")
- expander.show()
-
- main_vbox = gobject.new(gtk.VBox, border_width=8, visible=True)
- expander.add(main_vbox)
-
- main_hbox1 = gobject.new(gtk.HBox, border_width=8, visible=True)
- main_vbox.pack_start(main_hbox1)
-
- show_transmissions_group = HIGContainer("Show transmissions")
- show_transmissions_group.show()
- main_hbox1.pack_start(show_transmissions_group, False, False, 8)
-
- vbox = gtk.VBox(True, 4)
- vbox.show()
- show_transmissions_group.add(vbox)
-
- all_nodes = gtk.RadioButton(None)
- all_nodes.set_label("All nodes")
- all_nodes.set_active(True)
- all_nodes.show()
- vbox.add(all_nodes)
-
- selected_node = gtk.RadioButton(all_nodes)
- selected_node.show()
- selected_node.set_label("Selected node")
- selected_node.set_active(False)
- vbox.add(selected_node)
-
- no_node = gtk.RadioButton(all_nodes)
- no_node.show()
- no_node.set_label("Disabled")
- no_node.set_active(False)
- vbox.add(no_node)
-
- def toggled(radio):
- if radio.get_active():
- self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
- all_nodes.connect("toggled", toggled)
-
- def toggled(radio):
- if radio.get_active():
- self.set_show_transmissions_mode(ShowTransmissionsMode.NONE)
- no_node.connect("toggled", toggled)
-
- def toggled(radio):
- if radio.get_active():
- self.set_show_transmissions_mode(ShowTransmissionsMode.SELECTED)
- selected_node.connect("toggled", toggled)
-
-
- # -- misc settings
- misc_settings_group = HIGContainer("Misc Settings")
- misc_settings_group.show()
- main_hbox1.pack_start(misc_settings_group, False, False, 8)
- settings_hbox = gobject.new(gtk.HBox, border_width=8, visible=True)
- misc_settings_group.add(settings_hbox)
-
- # --> node size
- vbox = gobject.new(gtk.VBox, border_width=0, visible=True)
- scale = gobject.new(gtk.HScale, visible=True, digits=2)
- vbox.pack_start(scale, True, True, 0)
- vbox.pack_start(gobject.new(gtk.Label, label="Node Size", visible=True), True, True, 0)
- settings_hbox.pack_start(vbox, False, False, 6)
- self.node_size_adjustment = scale.get_adjustment()
- def node_size_changed(adj):
- for node in self.nodes.itervalues():
- node.set_size(adj.value)
- self.node_size_adjustment.connect("value-changed", node_size_changed)
- self.node_size_adjustment.set_all(DEFAULT_NODE_SIZE, 0.01, 20, 0.1)
-
- # --> transmissions smooth factor
- vbox = gobject.new(gtk.VBox, border_width=0, visible=True)
- scale = gobject.new(gtk.HScale, visible=True, digits=1)
- vbox.pack_start(scale, True, True, 0)
- vbox.pack_start(gobject.new(gtk.Label, label="Tx. Smooth Factor (s)", visible=True), True, True, 0)
- settings_hbox.pack_start(vbox, False, False, 6)
- self.transmissions_smoothing_adjustment = scale.get_adjustment()
- self.transmissions_smoothing_adjustment.set_all(DEFAULT_TRANSMISSIONS_MEMORY*0.1, 0.1, 10, 0.1)
-
- return expander
-
- class _PanningState(object):
- __slots__ = ['initial_mouse_pos', 'initial_canvas_pos', 'motion_signal']
-
- def _begin_panning(self, widget, event):
- self.canvas.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
- self._panning_state = self._PanningState()
- x, y, dummy = widget.window.get_pointer()
- self._panning_state.initial_mouse_pos = (x, y)
- x = self._scrolled_window.get_hadjustment().value
- y = self._scrolled_window.get_vadjustment().value
- self._panning_state.initial_canvas_pos = (x, y)
- self._panning_state.motion_signal = self.canvas.connect("motion-notify-event", self._panning_motion)
-
- def _end_panning(self, event):
- if self._panning_state is None:
- return
- self.canvas.window.set_cursor(None)
- self.canvas.disconnect(self._panning_state.motion_signal)
- self._panning_state = None
-
- def _panning_motion(self, widget, event):
- assert self._panning_state is not None
- if event.is_hint:
- x, y, dummy = widget.window.get_pointer()
- else:
- x, y = event.x, event.y
-
- hadj = self._scrolled_window.get_hadjustment()
- vadj = self._scrolled_window.get_vadjustment()
- mx0, my0 = self._panning_state.initial_mouse_pos
- cx0, cy0 = self._panning_state.initial_canvas_pos
-
- dx = x - mx0
- dy = y - my0
- hadj.value = cx0 - dx
- vadj.value = cy0 - dy
- return True
-
- def _canvas_button_press(self, widget, event):
- if event.button == 2:
- self._begin_panning(widget, event)
- return True
- return False
-
- def _canvas_button_release(self, dummy_widget, event):
- if event.button == 2:
- self._end_panning(event)
- return True
- return False
-
- def _canvas_scroll_event(self, dummy_widget, event):
- if event.direction == gtk.gdk.SCROLL_UP:
- self.zoom.value *= 1.25
- return True
- elif event.direction == gtk.gdk.SCROLL_DOWN:
- self.zoom.value /= 1.25
- return True
- return False
-
- def get_hadjustment(self):
- return self._scrolled_window.get_hadjustment()
- def get_vadjustment(self):
- return self._scrolled_window.get_vadjustment()
-
- def create_gui(self):
- self.window = gtk.Window()
- vbox = gtk.VBox(); vbox.show()
- self.window.add(vbox)
-
- # canvas
- self.canvas = goocanvas.Canvas()
- self.canvas.connect_after("button-press-event", self._canvas_button_press)
- self.canvas.connect_after("button-release-event", self._canvas_button_release)
- self.canvas.connect("scroll-event", self._canvas_scroll_event)
- self.canvas.props.has_tooltip = True
- self.canvas.connect("query-tooltip", self._canvas_tooltip_cb)
- self.canvas.show()
- sw = gtk.ScrolledWindow(); sw.show()
- self._scrolled_window = sw
- sw.add(self.canvas)
- vbox.pack_start(sw, True, True, 4)
- self.canvas.set_size_request(600, 450)
- self.canvas.set_bounds(-10000, -10000, 10000, 10000)
- self.canvas.scroll_to(0, 0)
-
-
- self.canvas.get_root_item().add_child(self.links_group)
- self.links_group.set_property("visibility", goocanvas.ITEM_VISIBLE)
-
- self.canvas.get_root_item().add_child(self.channels_group)
- self.channels_group.set_property("visibility", goocanvas.ITEM_VISIBLE)
- self.channels_group.raise_(self.links_group)
-
- self.canvas.get_root_item().add_child(self.nodes_group)
- self.nodes_group.set_property("visibility", goocanvas.ITEM_VISIBLE)
- self.nodes_group.raise_(self.channels_group)
-
- self.hud = hud.Axes(self)
-
- hbox = gtk.HBox(); hbox.show()
- vbox.pack_start(hbox, False, False, 4)
-
- # zoom
- zoom_adj = gtk.Adjustment(1.0, 0.01, 10.0, 0.02, 1.0, 0)
- self.zoom = zoom_adj
- def _zoom_changed(adj):
- self.canvas.set_scale(adj.value)
- zoom_adj.connect("value-changed", _zoom_changed)
- zoom = gtk.SpinButton(zoom_adj)
- zoom.set_digits(3)
- zoom.show()
- hbox.pack_start(gobject.new(gtk.Label, label=" Zoom:", visible=True), False, False, 4)
- hbox.pack_start(zoom, False, False, 4)
- _zoom_changed(zoom_adj)
-
- # speed
- speed_adj = gtk.Adjustment(1.0, 0.01, 10.0, 0.02, 1.0, 0)
- def _speed_changed(adj):
- self.speed = adj.value
- self.sample_period = SAMPLE_PERIOD*adj.value
- self._start_update_timer()
- speed_adj.connect("value-changed", _speed_changed)
- speed = gtk.SpinButton(speed_adj)
- speed.set_digits(3)
- speed.show()
- hbox.pack_start(gobject.new(gtk.Label, label=" Speed:", visible=True), False, False, 4)
- hbox.pack_start(speed, False, False, 4)
- _speed_changed(speed_adj)
-
- # Current time
- self.time_label = gobject.new(gtk.Label, label=" Speed:", visible=True)
- self.time_label.set_width_chars(20)
- hbox.pack_start(self.time_label, False, False, 4)
-
- # Screenshot button
- screenshot_button = gobject.new(gtk.Button,
- label="Snapshot",
- relief=gtk.RELIEF_NONE, focus_on_click=False,
- visible=True)
- hbox.pack_start(screenshot_button, False, False, 4)
-
- def load_button_icon(button, icon_name):
- try:
- import gnomedesktop
- except ImportError:
- sys.stderr.write("Could not load icon %s due to missing gnomedesktop Python module\n" % icon_name)
- else:
- icon = gnomedesktop.find_icon(gtk.icon_theme_get_default(), icon_name, 16, 0)
- if icon is not None:
- button.props.image = gobject.new(gtk.Image, file=icon, visible=True)
-
- load_button_icon(screenshot_button, "applets-screenshooter")
- screenshot_button.connect("clicked", self._take_screenshot)
-
- # Shell button
- if ipython_view is not None:
- shell_button = gobject.new(gtk.Button,
- label="Shell",
- relief=gtk.RELIEF_NONE, focus_on_click=False,
- visible=True)
- hbox.pack_start(shell_button, False, False, 4)
- load_button_icon(shell_button, "gnome-terminal")
- shell_button.connect("clicked", self._start_shell)
-
- # Play button
- self.play_button = gobject.new(gtk.ToggleButton,
- image=gobject.new(gtk.Image, stock=gtk.STOCK_MEDIA_PLAY, visible=True),
- label="Simulate (F3)",
- relief=gtk.RELIEF_NONE, focus_on_click=False,
- use_stock=True, visible=True)
- accel_group = gtk.AccelGroup()
- self.window.add_accel_group(accel_group)
- self.play_button.add_accelerator("clicked", accel_group,
- gtk.keysyms.F3, 0, gtk.ACCEL_VISIBLE)
- self.play_button.connect("toggled", self._on_play_button_toggled)
- hbox.pack_start(self.play_button, False, False, 4)
-
- self.canvas.get_root_item().connect("button-press-event", self.on_root_button_press_event)
-
- vbox.pack_start(self._create_advanced_controls(), False, False, 4)
-
- self.window.show()
-
- def scan_topology(self):
- print "scanning topology: %i nodes..." % (ns3.NodeList.GetNNodes(),)
- graph = pygraphviz.AGraph()
- seen_nodes = 0
- for nodeI in range(ns3.NodeList.GetNNodes()):
- seen_nodes += 1
- if seen_nodes == 100:
- print "scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns3.NodeList.GetNNodes())
- seen_nodes = 0
- node = ns3.NodeList.GetNode(nodeI)
- node_name = "Node %i" % nodeI
- node_view = self.get_node(nodeI)
-
- mobility = node.GetObject(ns3.MobilityModel.GetTypeId())
- if mobility is not None:
- node_view.set_color("red")
- pos = mobility.GetPosition()
- node_view.set_position(*transform_point_simulation_to_canvas(pos.x, pos.y))
- #print "node has mobility position -> ", "%f,%f" % (pos.x, pos.y)
- else:
- graph.add_node(node_name)
-
- for devI in range(node.GetNDevices()):
- device = node.GetDevice(devI)
- device_traits = lookup_netdevice_traits(type(device))
- if device_traits.is_wireless:
- continue
- if device_traits.is_virtual:
- continue
- channel = device.GetChannel()
- if channel.GetNDevices() > 2:
- if REPRESENT_CHANNELS_AS_NODES:
- # represent channels as white nodes
- if mobility is None:
- channel_name = "Channel %s" % id(channel)
- graph.add_edge(node_name, channel_name)
- self.get_channel(channel)
- self.create_link(self.get_node(nodeI), self.get_channel(channel))
- else:
- # don't represent channels, just add links between nodes in the same channel
- for otherDevI in range(channel.GetNDevices()):
- otherDev = channel.GetDevice(otherDevI)
- otherNode = otherDev.GetNode()
- otherNodeView = self.get_node(otherNode.GetId())
- if otherNode is not node:
- if mobility is None and not otherNodeView.has_mobility:
- other_node_name = "Node %i" % otherNode.GetId()
- graph.add_edge(node_name, other_node_name)
- self.create_link(self.get_node(nodeI), otherNodeView)
- else:
- for otherDevI in range(channel.GetNDevices()):
- otherDev = channel.GetDevice(otherDevI)
- otherNode = otherDev.GetNode()
- otherNodeView = self.get_node(otherNode.GetId())
- if otherNode is not node:
- if mobility is None and not otherNodeView.has_mobility:
- other_node_name = "Node %i" % otherNode.GetId()
- graph.add_edge(node_name, other_node_name)
- self.create_link(self.get_node(nodeI), otherNodeView)
-
- print "scanning topology: calling graphviz layout"
- graph.layout(LAYOUT_ALGORITHM)
- for node in graph.iternodes():
- #print node, "=>", node.attr['pos']
- node_type, node_id = node.split(' ')
- pos_x, pos_y = [float(s) for s in node.attr['pos'].split(',')]
- if node_type == 'Node':
- obj = self.nodes[int(node_id)]
- elif node_type == 'Channel':
- obj = self.channels[int(node_id)]
- obj.set_position(pos_x, pos_y)
-
- print "scanning topology: all done."
- self.emit("topology-scanned")
-
- def get_node(self, index):
- try:
- return self.nodes[index]
- except KeyError:
- node = Node(self, index)
- self.nodes[index] = node
- self.nodes_group.add_child(node.canvas_item)
- node.canvas_item.connect("button-press-event", self.on_node_button_press_event, node)
- node.canvas_item.connect("button-release-event", self.on_node_button_release_event, node)
- return node
-
- def get_channel(self, ns3_channel):
- try:
- return self.channels[id(ns3_channel)]
- except KeyError:
- channel = Channel(ns3_channel)
- self.channels[id(ns3_channel)] = channel
- self.channels_group.add_child(channel.canvas_item)
- return channel
-
- def create_link(self, node, node_or_channel):
- link = WiredLink(node, node_or_channel)
- self.links_group.add_child(link.canvas_item)
- link.canvas_item.lower(None)
-
- def update_view(self):
- #print "update_view"
-
- self.time_label.set_text("Time: %f s" % ns3.Simulator.Now().GetSeconds())
-
- self._update_node_positions()
-
- # Update information
- for info_win in self.information_windows:
- info_win.update()
-
- self._update_transmissions_view()
- self._update_drops_view()
-
- self.emit("update-view")
-
- def _update_node_positions(self):
- for node in self.nodes.itervalues():
- if node.has_mobility:
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- mobility = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
- if mobility is not None:
- pos = mobility.GetPosition()
- x, y = transform_point_simulation_to_canvas(pos.x, pos.y)
- node.set_position(x, y)
- if node is self.follow_node:
- hadj = self._scrolled_window.get_hadjustment()
- vadj = self._scrolled_window.get_vadjustment()
- px, py = self.canvas.convert_to_pixels(x, y)
- hadj.value = px - hadj.page_size/2
- vadj.value = py - vadj.page_size/2
-
- def center_on_node(self, node):
- if isinstance(node, ns3.Node):
- node = self.nodes[node.GetId()]
- elif isinstance(node, (int, long)):
- node = self.nodes[node]
- elif isinstance(node, Node):
- pass
- else:
- raise TypeError("expected int, viz.Node or ns3.Node, not %r" % node)
-
- x, y = node.get_position()
- hadj = self._scrolled_window.get_hadjustment()
- vadj = self._scrolled_window.get_vadjustment()
- px, py = self.canvas.convert_to_pixels(x, y)
- hadj.value = px - hadj.page_size/2
- vadj.value = py - vadj.page_size/2
-
-
- def update_model(self):
- self.simulation.lock.acquire()
- try:
- self.emit("simulation-periodic-update")
- finally:
- self.simulation.lock.release()
-
- def do_simulation_periodic_update(self):
- smooth_factor = int(self.transmissions_smoothing_adjustment.value*10)
-
- transmissions = self.simulation.sim_helper.GetTransmissionSamples()
- self._last_transmissions.append(transmissions)
- while len(self._last_transmissions) > smooth_factor:
- self._last_transmissions.pop(0)
-
- drops = self.simulation.sim_helper.GetPacketDropSamples()
- self._last_drops.append(drops)
- while len(self._last_drops) > smooth_factor:
- self._last_drops.pop(0)
-
- def _get_label_over_line_position(self, pos1_x, pos1_y, pos2_x, pos2_y):
- hadj = self._scrolled_window.get_hadjustment()
- vadj = self._scrolled_window.get_vadjustment()
- bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.value, vadj.value)
- bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.value + hadj.page_size,
- vadj.value + vadj.page_size)
- pos1_x, pos1_y, pos2_x, pos2_y = ns3.PyViz.LineClipping(bounds_x1, bounds_y1,
- bounds_x2, bounds_y2,
- pos1_x, pos1_y,
- pos2_x, pos2_y)
- return (pos1_x + pos2_x)/2, (pos1_y + pos2_y)/2
-
- def _update_transmissions_view(self):
- transmissions_average = {}
- for transmission_set in self._last_transmissions:
- for transmission in transmission_set:
- key = (transmission.transmitter.GetId(), transmission.receiver.GetId())
- rx_bytes, count = transmissions_average.get(key, (0, 0))
- rx_bytes += transmission.bytes
- count += 1
- transmissions_average[key] = rx_bytes, count
-
- old_arrows = self._transmission_arrows
- for arrow, label in old_arrows:
- arrow.set_property("visibility", goocanvas.ITEM_HIDDEN)
- label.set_property("visibility", goocanvas.ITEM_HIDDEN)
- new_arrows = []
-
- k = self.node_size_adjustment.value/5
-
- for (transmitter_id, receiver_id), (rx_bytes, rx_count) in transmissions_average.iteritems():
- transmitter = self.get_node(transmitter_id)
- receiver = self.get_node(receiver_id)
- try:
- arrow, label = old_arrows.pop()
- except IndexError:
- arrow = goocanvas.Polyline(line_width=2.0, stroke_color_rgba=0x00C000C0, close_path=False, end_arrow=True)
- arrow.set_property("parent", self.canvas.get_root_item())
- arrow.props.pointer_events = 0
- arrow.raise_(None)
-
- label = goocanvas.Text(parent=self.canvas.get_root_item(), pointer_events=0)
- label.raise_(None)
-
- arrow.set_property("visibility", goocanvas.ITEM_VISIBLE)
- line_width = max(0.1, math.log(float(rx_bytes)/rx_count/self.sample_period)*k)
- arrow.set_property("line-width", line_width)
-
- pos1_x, pos1_y = transmitter.get_position()
- pos2_x, pos2_y = receiver.get_position()
- points = goocanvas.Points([(pos1_x, pos1_y), (pos2_x, pos2_y)])
- arrow.set_property("points", points)
-
- kbps = float(rx_bytes*8)/1e3/rx_count/self.sample_period
- label.set_properties(visibility=goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD,
- visibility_threshold=0.5,
- font=("Sans Serif %f" % int(1+BITRATE_FONT_SIZE*k)))
- angle = math.atan2((pos2_y - pos1_y), (pos2_x - pos1_x))
- if -PI_OVER_2 <= angle <= PI_OVER_2:
- label.set_properties(text=("%.2f kbit/s →" % (kbps,)),
- alignment=pango.ALIGN_CENTER,
- anchor=gtk.ANCHOR_S,
- x=0, y=-line_width/2)
- M = cairo.Matrix()
- M.translate(*self._get_label_over_line_position(pos1_x, pos1_y, pos2_x, pos2_y))
- M.rotate(angle)
- label.set_transform(M)
- else:
- label.set_properties(text=("← %.2f kbit/s" % (kbps,)),
- alignment=pango.ALIGN_CENTER,
- anchor=gtk.ANCHOR_N,
- x=0, y=line_width/2)
- M = cairo.Matrix()
- M.translate(*self._get_label_over_line_position(pos1_x, pos1_y, pos2_x, pos2_y))
- M.rotate(angle)
- M.scale(-1, -1)
- label.set_transform(M)
-
- new_arrows.append((arrow, label))
-
- self._transmission_arrows = new_arrows + old_arrows
-
-
- def _update_drops_view(self):
- drops_average = {}
- for drop_set in self._last_drops:
- for drop in drop_set:
- key = drop.transmitter.GetId()
- drop_bytes, count = drops_average.get(key, (0, 0))
- drop_bytes += drop.bytes
- count += 1
- drops_average[key] = drop_bytes, count
-
- old_arrows = self._drop_arrows
- for arrow, label in old_arrows:
- arrow.set_property("visibility", goocanvas.ITEM_HIDDEN)
- label.set_property("visibility", goocanvas.ITEM_HIDDEN)
- new_arrows = []
-
- # get the coordinates for the edge of screen
- vadjustment = self._scrolled_window.get_vadjustment()
- bottom_y = vadjustment.value + vadjustment.page_size
- dummy, edge_y = self.canvas.convert_from_pixels(0, bottom_y)
-
- k = self.node_size_adjustment.value/5
-
- for transmitter_id, (drop_bytes, drop_count) in drops_average.iteritems():
- transmitter = self.get_node(transmitter_id)
- try:
- arrow, label = old_arrows.pop()
- except IndexError:
- arrow = goocanvas.Polyline(line_width=2.0, stroke_color_rgba=0xC00000C0, close_path=False, end_arrow=True)
- arrow.props.pointer_events = 0
- arrow.set_property("parent", self.canvas.get_root_item())
- arrow.raise_(None)
-
- label = goocanvas.Text()#, fill_color_rgba=0x00C000C0)
- label.props.pointer_events = 0
- label.set_property("parent", self.canvas.get_root_item())
- label.raise_(None)
-
- arrow.set_property("visibility", goocanvas.ITEM_VISIBLE)
- arrow.set_property("line-width", max(0.1, math.log(float(drop_bytes)/drop_count/self.sample_period)*k))
- pos1_x, pos1_y = transmitter.get_position()
- pos2_x, pos2_y = pos1_x, edge_y
- points = goocanvas.Points([(pos1_x, pos1_y), (pos2_x, pos2_y)])
- arrow.set_property("points", points)
-
- label.set_properties(visibility=goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD,
- visibility_threshold=0.5,
- font=("Sans Serif %i" % int(1+BITRATE_FONT_SIZE*k)),
- text=("%.2f kbit/s" % (float(drop_bytes*8)/1e3/drop_count/self.sample_period,)),
- alignment=pango.ALIGN_CENTER,
- x=(pos1_x + pos2_x)/2,
- y=(pos1_y + pos2_y)/2)
-
- new_arrows.append((arrow, label))
-
- self._drop_arrows = new_arrows + old_arrows
-
-
- def update_view_timeout(self):
- #print "view: update_view_timeout called at real time ", time.time()
-
- # while the simulator is busy, run the gtk event loop
- while not self.simulation.lock.acquire(False):
- while gtk.events_pending():
- gtk.main_iteration()
- pause_messages = self.simulation.pause_messages
- self.simulation.pause_messages = []
- try:
- self.update_view()
- self.simulation.target_time = ns3.Simulator.Now ().GetSeconds () + self.sample_period
- #print "view: target time set to %f" % self.simulation.target_time
- finally:
- self.simulation.lock.release()
-
- if pause_messages:
- #print pause_messages
- dialog = gtk.MessageDialog(parent=self.window, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_OK,
- message_format='\n'.join(pause_messages))
- dialog.connect("response", lambda d, r: d.destroy())
- dialog.show()
- self.play_button.set_active(False)
-
- # if we're paused, stop the update timer
- if not self.play_button.get_active():
- self._update_timeout_id = None
- return False
-
- #print "view: self.simulation.go.set()"
- self.simulation.go.set()
- #print "view: done."
- return True
-
- def _start_update_timer(self):
- if self._update_timeout_id is not None:
- gobject.source_remove(self._update_timeout_id)
- #print "start_update_timer"
- self._update_timeout_id = gobject.timeout_add(int(SAMPLE_PERIOD/min(self.speed, 1)*1e3),
- self.update_view_timeout,
- priority=PRIORITY_UPDATE_VIEW)
-
- def _on_play_button_toggled(self, button):
- if button.get_active():
- self._start_update_timer()
- else:
- if self._update_timeout_id is not None:
- gobject.source_remove(self._update_timeout_id)
-
- def _quit(self, *dummy_args):
- if self._update_timeout_id is not None:
- gobject.source_remove(self._update_timeout_id)
- self._update_timeout_id = None
- self.simulation.quit = True
- self.simulation.go.set()
- self.simulation.join()
- gtk.main_quit()
-
- def _monkey_patch_ipython(self):
- # The user may want to access the NS 3 simulation state, but
- # NS 3 is not thread safe, so it could cause serious problems.
- # To work around this, monkey-patch IPython to automatically
- # acquire and release the simulation lock around each code
- # that is executed.
-
- original_runcode = __IPYTHON__.runcode
- def runcode(ip, *args):
- #print "lock"
- self.simulation.lock.acquire()
- try:
- return original_runcode(*args)
- finally:
- #print "unlock"
- self.simulation.lock.release()
- import types
- __IPYTHON__.runcode = types.MethodType(runcode, __IPYTHON__)
-
- def autoscale_view(self):
- self._update_node_positions()
- positions = [node.get_position() for node in self.nodes.itervalues()]
- min_x, min_y = min(x for (x,y) in positions), min(y for (x,y) in positions)
- max_x, max_y = max(x for (x,y) in positions), max(y for (x,y) in positions)
- min_x_px, min_y_px = self.canvas.convert_to_pixels(min_x, min_y)
- max_x_px, max_y_px = self.canvas.convert_to_pixels(max_x, max_y)
- dx = max_x - min_x
- dy = max_y - min_y
- dx_px = max_x_px - min_x_px
- dy_px = max_y_px - min_y_px
- hadj = self._scrolled_window.get_hadjustment()
- vadj = self._scrolled_window.get_vadjustment()
- new_dx, new_dy = 1.5*dx_px, 1.5*dy_px
-
- if new_dx == 0 or new_dy == 0:
- return
-
- self.zoom.value = min(hadj.page_size/new_dx, vadj.page_size/new_dy)
-
- x1, y1 = self.canvas.convert_from_pixels(hadj.value, vadj.value)
- x2, y2 = self.canvas.convert_from_pixels(hadj.value+hadj.page_size, vadj.value+vadj.page_size)
- width = x2 - x1
- height = y2 - y1
- center_x = (min_x + max_x) / 2
- center_y = (min_y + max_y) / 2
-
- self.canvas.scroll_to(center_x - width/2, center_y - height/2)
-
- return False
-
- def start(self):
- self.scan_topology()
- self.window.connect("delete-event", self._quit)
- #self._start_update_timer()
- gobject.timeout_add(200, self.autoscale_view)
- self.simulation.start()
-
- try:
- __IPYTHON__
- except NameError:
- pass
- else:
- self._monkey_patch_ipython()
-
- gtk.main()
-
-
- def on_root_button_press_event(self, view, target, event):
- if event.button == 1:
- self.select_node(None)
- return True
-
- def on_node_button_press_event(self, view, target, event, node):
- if event.button == 1:
- self.select_node(node)
- return True
- elif event.button == 3:
- self.popup_node_menu(node, event)
- return True
- elif event.button == 2:
- self.begin_node_drag(node)
- return True
- return False
-
- def on_node_button_release_event(self, view, target, event, node):
- if event.button == 2:
- self.end_node_drag(node)
- return True
- return False
-
- class NodeDragState(object):
- def __init__(self, canvas_x0, canvas_y0, sim_x0, sim_y0):
- self.canvas_x0 = canvas_x0
- self.canvas_y0 = canvas_y0
- self.sim_x0 = sim_x0
- self.sim_y0 = sim_y0
- self.motion_signal = None
-
- def begin_node_drag(self, node):
- self.simulation.lock.acquire()
- try:
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
- if mob is None:
- return
- if self.node_drag_state is not None:
- return
- pos = mob.GetPosition()
- finally:
- self.simulation.lock.release()
- x, y, dummy = self.canvas.window.get_pointer()
- x0, y0 = self.canvas.convert_from_pixels(x, y)
- self.node_drag_state = self.NodeDragState(x0, y0, pos.x, pos.y)
- self.node_drag_state.motion_signal = node.canvas_item.connect("motion-notify-event", self.node_drag_motion, node)
-
- def node_drag_motion(self, item, targe_item, event, node):
- self.simulation.lock.acquire()
- try:
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
- if mob is None:
- return False
- if self.node_drag_state is None:
- return False
- x, y, dummy = self.canvas.window.get_pointer()
- canvas_x, canvas_y = self.canvas.convert_from_pixels(x, y)
- dx = (canvas_x - self.node_drag_state.canvas_x0)
- dy = (canvas_y - self.node_drag_state.canvas_y0)
- pos = mob.GetPosition()
- pos.x = self.node_drag_state.sim_x0 + transform_distance_canvas_to_simulation(dx)
- pos.y = self.node_drag_state.sim_y0 + transform_distance_canvas_to_simulation(dy)
- #print "SetPosition(%G, %G)" % (pos.x, pos.y)
- mob.SetPosition(pos)
- node.set_position(*transform_point_simulation_to_canvas(pos.x, pos.y))
- finally:
- self.simulation.lock.release()
- return True
-
- def end_node_drag(self, node):
- if self.node_drag_state is None:
- return
- node.canvas_item.disconnect(self.node_drag_state.motion_signal)
- self.node_drag_state = None
-
- def popup_node_menu(self, node, event):
- menu = gtk.Menu()
- self.emit("populate-node-menu", node, menu)
- menu.popup(None, None, None, event.button, event.time)
-
- def _update_ipython_selected_node(self):
- # If we are running under ipython -gthread, make this new
- # selected node available as a global 'selected_node'
- # variable.
- try:
- __IPYTHON__
- except NameError:
- pass
- else:
- if self.selected_node is None:
- ns3_node = None
- else:
- self.simulation.lock.acquire()
- try:
- ns3_node = ns3.NodeList.GetNode(self.selected_node.node_index)
- finally:
- self.simulation.lock.release()
- __IPYTHON__.user_ns['selected_node'] = ns3_node
-
-
- def select_node(self, node):
- if isinstance(node, ns3.Node):
- node = self.nodes[node.GetId()]
- elif isinstance(node, (int, long)):
- node = self.nodes[node]
- elif isinstance(node, Node):
- pass
- elif node is None:
- pass
- else:
- raise TypeError("expected None, int, viz.Node or ns3.Node, not %r" % node)
-
- if node is self.selected_node:
- return
-
- if self.selected_node is not None:
- self.selected_node.selected = False
- self.selected_node = node
- if self.selected_node is not None:
- self.selected_node.selected = True
-
- if self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
- if self.selected_node is None:
- self.simulation.set_nodes_of_interest([])
- else:
- self.simulation.set_nodes_of_interest([self.selected_node.node_index])
-
- self._update_ipython_selected_node()
-
-
- def add_information_window(self, info_win):
- self.information_windows.append(info_win)
- self.simulation.lock.acquire()
- try:
- info_win.update()
- finally:
- self.simulation.lock.release()
-
- def remove_information_window(self, info_win):
- self.information_windows.remove(info_win)
-
- def _canvas_tooltip_cb(self, canvas, x, y, keyboard_mode, tooltip):
- #print "tooltip query: ", x, y
- hadj = self._scrolled_window.get_hadjustment()
- vadj = self._scrolled_window.get_vadjustment()
- x, y = self.canvas.convert_from_pixels(hadj.value + x, vadj.value + y)
- item = self.canvas.get_item_at(x, y, True)
- #print "items at (%f, %f): %r | keyboard_mode=%r" % (x, y, item, keyboard_mode)
- if not item:
- return False
- while item is not None:
- obj = item.get_data("pyviz-object")
- if obj is not None:
- obj.tooltip_query(tooltip)
- return True
- item = item.props.parent
- return False
-
- def _get_export_file_name(self):
- sel = gtk.FileChooserDialog("Save...", self.canvas.get_toplevel(),
- gtk.FILE_CHOOSER_ACTION_SAVE,
- (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_SAVE, gtk.RESPONSE_OK))
- sel.set_default_response(gtk.RESPONSE_OK)
- sel.set_local_only(True)
- sel.set_do_overwrite_confirmation(True)
- sel.set_current_name("Unnamed.pdf")
-
- filter = gtk.FileFilter()
- filter.set_name("Embedded PostScript")
- filter.add_mime_type("image/x-eps")
- sel.add_filter(filter)
-
- filter = gtk.FileFilter()
- filter.set_name("Portable Document Graphics")
- filter.add_mime_type("application/pdf")
- sel.add_filter(filter)
-
- filter = gtk.FileFilter()
- filter.set_name("Scalable Vector Graphics")
- filter.add_mime_type("image/svg+xml")
- sel.add_filter(filter)
-
- resp = sel.run()
- if resp != gtk.RESPONSE_OK:
- sel.destroy()
- return None
-
- file_name = sel.get_filename()
- sel.destroy()
- return file_name
-
- def _take_screenshot(self, dummy_button):
- #print "Cheese!"
- file_name = self._get_export_file_name()
- if file_name is None:
- return
-
- # figure out the correct bounding box for what is visible on screen
- x1 = self._scrolled_window.get_hadjustment().value
- y1 = self._scrolled_window.get_vadjustment().value
- x2 = x1 + self._scrolled_window.get_hadjustment().page_size
- y2 = y1 + self._scrolled_window.get_vadjustment().page_size
- bounds = goocanvas.Bounds()
- bounds.x1, bounds.y1 = self.canvas.convert_from_pixels(x1, y1)
- bounds.x2, bounds.y2 = self.canvas.convert_from_pixels(x2, y2)
- dest_width = bounds.x2 - bounds.x1
- dest_height = bounds.y2 - bounds.y1
- #print bounds.x1, bounds.y1, " -> ", bounds.x2, bounds.y2
-
- dummy, extension = os.path.splitext(file_name)
- extension = extension.lower()
- if extension == '.eps':
- surface = cairo.PSSurface(file_name, dest_width, dest_height)
- elif extension == '.pdf':
- surface = cairo.PDFSurface(file_name, dest_width, dest_height)
- elif extension == '.svg':
- surface = cairo.SVGSurface(file_name, dest_width, dest_height)
- else:
- dialog = gtk.MessageDialog(parent = self.canvas.get_toplevel(),
- flags = gtk.DIALOG_DESTROY_WITH_PARENT,
- type = gtk.MESSAGE_ERROR,
- buttons = gtk.BUTTONS_OK,
- message_format = "Unknown extension '%s' (valid extensions are '.eps', '.svg', and '.pdf')"
- % (extension,))
- dialog.run()
- dialog.destroy()
- return
-
- # draw the canvas to a printing context
- cr = cairo.Context(surface)
- cr.translate(-bounds.x1, -bounds.y1)
- self.canvas.render(cr, bounds, self.zoom.value)
- cr.show_page()
- surface.finish()
-
- def set_follow_node(self, node):
- if isinstance(node, ns3.Node):
- node = self.nodes[node.GetId()]
- self.follow_node = node
-
- def _start_shell(self, dummy_button):
- if self.shell_window is not None:
- self.shell_window.present()
- return
-
- self.shell_window = gtk.Window()
- self.shell_window.set_size_request(750,550)
- self.shell_window.set_resizable(True)
- scrolled_window = gtk.ScrolledWindow()
- scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
- ipython = ipython_view.IPythonView()
- ipython.modify_font(pango.FontDescription(SHELL_FONT))
- ipython.set_wrap_mode(gtk.WRAP_CHAR)
- ipython.show()
- scrolled_window.add(ipython)
- scrolled_window.show()
- self.shell_window.add(scrolled_window)
- self.shell_window.show()
- self.shell_window.connect('destroy', self._on_shell_window_destroy)
-
- self._update_ipython_selected_node()
- __IPYTHON__.user_ns['viz'] = self
-
-
- def _on_shell_window_destroy(self, window):
- self.shell_window = None
-
-
-initialization_hooks = []
-
-def add_initialization_hook(hook, *args):
- """
- Adds a callback to be called after
- the visualizer is initialized, like this::
- initialization_hook(visualizer, *args)
- """
- global initialization_hooks
- initialization_hooks.append((hook, args))
-
-
-def set_bounds(x1, y1, x2, y2):
- assert x2>x1
- assert y2>y1
- def hook(viz):
- cx1, cy1 = transform_point_simulation_to_canvas(x1, y1)
- cx2, cy2 = transform_point_simulation_to_canvas(x2, y2)
- viz.canvas.set_bounds(cx1, cy1, cx2, cy2)
- add_initialization_hook(hook)
-
-
-def start():
- assert Visualizer.INSTANCE is None
- if _import_error is not None:
- import sys
- print >> sys.stderr, "No visualization support (%s)." % (str(_import_error),)
- ns3.Simulator.Run()
- return
- load_plugins()
- viz = Visualizer()
- for hook, args in initialization_hooks:
- gobject.idle_add(hook, viz, *args)
- ns3.Packet.EnablePrinting()
- viz.start()
--- a/src/tools/visualizer/visualizer/higcontainer.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-import gtk
-import gobject
-try:
- from gazpacho.widgets.base.base import SimpleContainerAdaptor
-except ImportError:
- pass
-
-#root_library = 'hig'
-
-
-class HIGContainer(gtk.Bin):
- __gtype_name__ = 'HIGContainer'
- __gproperties__ = {
- 'title': (str, 'Group Title', 'the group title',
- '', gobject.PARAM_READWRITE|gobject.PARAM_CONSTRUCT),
- }
-
- def __init__(self, title=None):
- self.__title_text = None
- gtk.widget_push_composite_child()
- self.__title = gobject.new(gtk.Label, visible=True, xalign=0, yalign=0.5)
- self.__indent = gobject.new(gtk.Label, visible=True, label=' ')
- gtk.widget_pop_composite_child()
- gtk.Bin.__init__(self)
- self.__title.set_parent(self)
- self.__indent.set_parent(self)
- if title is not None:
- self.props.title = title
-
- def do_size_request(self, requisition):
- title_req = gtk.gdk.Rectangle(0, 0, *self.__title.size_request())
- indent_req = gtk.gdk.Rectangle(0, 0, *self.__indent.size_request())
- if self.child is None:
- child_req = gtk.gdk.Rectangle()
- else:
- child_req = gtk.gdk.Rectangle(0, 0, *self.child.size_request())
- requisition.height = (title_req.height + 6 +
- max(child_req.height, indent_req.height))
- requisition.width = max(title_req.width, indent_req.width + child_req.width)
-
- def do_size_allocate(self, allocation):
- self.allocation = allocation
-
- ## title
- title_req = gtk.gdk.Rectangle(0, 0, *self.__title.get_child_requisition())
- title_alloc = gtk.gdk.Rectangle()
- title_alloc.x = allocation.x
- title_alloc.y = allocation.y
- title_alloc.width = min(title_req.width, allocation.width)
- title_alloc.height = min(title_req.height, allocation.height)
- self.__title.size_allocate(title_alloc)
-
- ## child
- if self.child is None:
- return
- indent_req = gtk.gdk.Rectangle(0, 0, *self.__indent.get_child_requisition())
- child_req = gtk.gdk.Rectangle(0, 0, *self.child.get_child_requisition())
- child_alloc = gtk.gdk.Rectangle()
- child_alloc.x = allocation.x + indent_req.width
- child_alloc.y = allocation.y + title_alloc.height + 6
- child_alloc.width = allocation.width - indent_req.width
- child_alloc.height = allocation.height - 6 - title_alloc.height
- self.child.size_allocate(child_alloc)
-
- def do_forall(self, internal, callback, data):
- if internal:
- callback(self.__title, data)
- callback(self.__indent, data)
- if self.child is not None:
- callback(self.child, data)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'title':
- self.__title.set_markup('<span weight="bold">%s</span>' %
- gobject.markup_escape_text(value))
- self.__title_text = value
- else:
- raise AttributeError, 'unknown property %s' % pspec.name
-
- def do_get_property(self, pspec):
- if pspec.name == 'title':
- return self.__title_text
- else:
- raise AttributeError, 'unknown property %s' % pspec.name
-
-if __name__ == '__main__':
- frame = gtk.Frame()
- group = gobject.new(HIGContainer, title="Hello")
- frame.add(group)
- check = gtk.CheckButton("foobar")
- group.add(check)
- w = gtk.Window()
- w.add(frame)
- w.show_all()
- w.connect("destroy", lambda w: gtk.main_quit())
- gtk.main()
-
--- a/src/tools/visualizer/visualizer/hud.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-import goocanvas
-import core
-import math
-import pango
-import gtk
-
-
-class Axes(object):
- def __init__(self, viz):
- self.viz = viz
- self.color = 0x8080C0FF
- self.hlines = goocanvas.Path(parent=viz.canvas.get_root_item(), stroke_color_rgba=self.color)
- self.hlines.lower(None)
- self.vlines = goocanvas.Path(parent=viz.canvas.get_root_item(), stroke_color_rgba=self.color)
- self.vlines.lower(None)
- self.labels = []
- hadj = self.viz.get_hadjustment()
- vadj = self.viz.get_vadjustment()
- def update(adj):
- if self.visible:
- self.update_view()
- hadj.connect("value-changed", update)
- vadj.connect("value-changed", update)
- hadj.connect("changed", update)
- vadj.connect("changed", update)
- self.visible = True
- self.update_view()
-
- def set_visible(self, visible):
- self.visible = visible
- if self.visible:
- self.hlines.props.visibility = goocanvas.ITEM_VISIBLE
- self.vlines.props.visibility = goocanvas.ITEM_VISIBLE
- else:
- self.hlines.props.visibility = goocanvas.ITEM_HIDDEN
- self.vlines.props.visibility = goocanvas.ITEM_HIDDEN
- for label in self.labels:
- label.props.visibility = goocanvas.ITEM_HIDDEN
-
- def _compute_divisions(self, xi, xf):
- assert xf > xi
- dx = xf - xi
- size = dx
- ndiv = 5
- text_width = dx/ndiv/2
-
- def rint(x):
- return math.floor(x+0.5)
-
- dx_over_ndiv = dx / ndiv
- for n in range(5): # iterate 5 times to find optimum division size
- #/* div: length of each division */
- tbe = math.log10(dx_over_ndiv)#; /* looking for approx. 'ndiv' divisions in a length 'dx' */
- div = pow(10, rint(tbe))#; /* div: power of 10 closest to dx/ndiv */
- if math.fabs(div/2 - dx_over_ndiv) < math.fabs(div - dx_over_ndiv): #/* test if div/2 is closer to dx/ndiv */
- div /= 2
- elif math.fabs(div*2 - dx_over_ndiv) < math.fabs(div - dx_over_ndiv):
- div *= 2 # /* test if div*2 is closer to dx/ndiv */
- x0 = div*math.ceil(xi / div) - div
- if n > 1:
- ndiv = rint(size / text_width)
- return x0, div
-
-
- def update_view(self):
- if self.viz.zoom is None:
- return
-
- unused_labels = self.labels
- self.labels = []
- for label in unused_labels:
- label.set_property("visibility", goocanvas.ITEM_HIDDEN)
- def get_label():
- try:
- label = unused_labels.pop(0)
- except IndexError:
- label = goocanvas.Text(parent=self.viz.canvas.get_root_item(), stroke_color_rgba=self.color)
- else:
- label.set_property("visibility", goocanvas.ITEM_VISIBLE)
- label.lower(None)
- self.labels.append(label)
- return label
-
- hadj = self.viz.get_hadjustment()
- vadj = self.viz.get_vadjustment()
- zoom = self.viz.zoom.value
- offset = 10/zoom
-
- x1, y1 = self.viz.canvas.convert_from_pixels(hadj.value, vadj.value)
- x2, y2 = self.viz.canvas.convert_from_pixels(hadj.value + hadj.page_size, vadj.value + vadj.page_size)
- line_width = 5.0/self.viz.zoom.value
-
- # draw the horizontal axis
- self.hlines.set_property("line-width", line_width)
- yc = y2 - line_width/2
-
- sim_x1 = x1/core.PIXELS_PER_METER
- sim_x2 = x2/core.PIXELS_PER_METER
- x0, xdiv = self._compute_divisions(sim_x1, sim_x2)
- path = ["M %r %r L %r %r" % (x1, yc, x2, yc)]
- x = x0
- while x < sim_x2:
- path.append("M %r %r L %r %r" % (core.PIXELS_PER_METER*x, yc - offset, core.PIXELS_PER_METER*x, yc))
- label = get_label()
- label.set_properties(font=("Sans Serif %f" % int(12/zoom)),
- text=("%G" % x),
- fill_color_rgba=self.color,
- alignment=pango.ALIGN_CENTER,
- anchor=gtk.ANCHOR_S,
- x=core.PIXELS_PER_METER*x,
- y=(yc - offset))
- x += xdiv
- del x
-
- self.hlines.set_property("data", " ".join(path))
-
- # draw the vertical axis
- self.vlines.set_property("line-width", line_width)
- xc = x1 + line_width/2
-
- sim_y1 = y1/core.PIXELS_PER_METER
- sim_y2 = y2/core.PIXELS_PER_METER
-
-
- y0, ydiv = self._compute_divisions(sim_y1, sim_y2)
- path = ["M %r %r L %r %r" % (xc, y1, xc, y2)]
- y = y0
- while y < sim_y2:
- path.append("M %r %r L %r %r" % (xc, core.PIXELS_PER_METER*y, xc + offset, core.PIXELS_PER_METER*y))
- label = get_label()
- label.set_properties(font=("Sans Serif %f" % int(12/zoom)),
- text=("%G" % y),
- fill_color_rgba=self.color,
- alignment=pango.ALIGN_LEFT,
- anchor=gtk.ANCHOR_W,
- x=xc + offset,
- y=core.PIXELS_PER_METER*y)
- y += ydiv
-
- self.vlines.set_property("data", " ".join(path))
-
-
-
- self.labels.extend(unused_labels)
--- a/src/tools/visualizer/visualizer/ipython_view.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +0,0 @@
-"""
-Backend to the console plugin.
-
-@author: Eitan Isaacson
-@organization: IBM Corporation
-@copyright: Copyright (c) 2007 IBM Corporation
-@license: BSD
-
-All rights reserved. This program and the accompanying materials are made
-available under the terms of the BSD which accompanies this distribution, and
-is available at U{http://www.opensource.org/licenses/bsd-license.php}
-"""
-# this file is a modified version of source code from the Accerciser project
-# http://live.gnome.org/accerciser
-
-import gtk
-import re
-import sys
-import os
-import pango
-from StringIO import StringIO
-import IPython
-
-ansi_colors = {'0;30': 'Black',
- '0;31': 'Red',
- '0;32': 'Green',
- '0;33': 'Brown',
- '0;34': 'Blue',
- '0;35': 'Purple',
- '0;36': 'Cyan',
- '0;37': 'LightGray',
- '1;30': 'DarkGray',
- '1;31': 'DarkRed',
- '1;32': 'SeaGreen',
- '1;33': 'Yellow',
- '1;34': 'LightBlue',
- '1;35': 'MediumPurple',
- '1;36': 'LightCyan',
- '1;37': 'White'}
-
-class IterableIPShell:
- def __init__(self,argv=None,user_ns=None,user_global_ns=None,
- cin=None, cout=None,cerr=None, input_func=None):
- if input_func:
- IPython.iplib.raw_input_original = input_func
- if cin:
- IPython.Shell.Term.cin = cin
- if cout:
- IPython.Shell.Term.cout = cout
- if cerr:
- IPython.Shell.Term.cerr = cerr
-
- if argv is None:
- argv=[]
-
- # This is to get rid of the blockage that occurs during
- # IPython.Shell.InteractiveShell.user_setup()
- IPython.iplib.raw_input = lambda x: None
-
- self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
- os.environ['TERM'] = 'dumb'
- excepthook = sys.excepthook
- self.IP = IPython.Shell.make_IPython(argv,user_ns=user_ns,
- user_global_ns=user_global_ns,
- embedded=True,
- shell_class=IPython.Shell.InteractiveShell)
- self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd),
- header='IPython system call: ',
- verbose=self.IP.rc.system_verbose)
- sys.excepthook = excepthook
- self.iter_more = 0
- self.history_level = 0
- self.complete_sep = re.compile('[\s\{\}\[\]\(\)]')
-
- def execute(self):
- self.history_level = 0
- orig_stdout = sys.stdout
- sys.stdout = IPython.Shell.Term.cout
- try:
- line = self.IP.raw_input(None, self.iter_more)
- if self.IP.autoindent:
- self.IP.readline_startup_hook(None)
- except KeyboardInterrupt:
- self.IP.write('\nKeyboardInterrupt\n')
- self.IP.resetbuffer()
- # keep cache in sync with the prompt counter:
- self.IP.outputcache.prompt_count -= 1
-
- if self.IP.autoindent:
- self.IP.indent_current_nsp = 0
- self.iter_more = 0
- except:
- self.IP.showtraceback()
- else:
- self.iter_more = self.IP.push(line)
- if (self.IP.SyntaxTB.last_syntax_error and
- self.IP.rc.autoedit_syntax):
- self.IP.edit_syntax_error()
- if self.iter_more:
- self.prompt = str(self.IP.outputcache.prompt2).strip()
- if self.IP.autoindent:
- self.IP.readline_startup_hook(self.IP.pre_readline)
- else:
- self.prompt = str(self.IP.outputcache.prompt1).strip()
- sys.stdout = orig_stdout
-
- def historyBack(self):
- self.history_level -= 1
- return self._getHistory()
-
- def historyForward(self):
- self.history_level += 1
- return self._getHistory()
-
- def _getHistory(self):
- try:
- rv = self.IP.user_ns['In'][self.history_level].strip('\n')
- except IndexError:
- self.history_level = 0
- rv = ''
- return rv
-
- def updateNamespace(self, ns_dict):
- self.IP.user_ns.update(ns_dict)
-
- def complete(self, line):
- split_line = self.complete_sep.split(line)
- possibilities = self.IP.complete(split_line[-1])
- if possibilities:
- common_prefix = reduce(self._commonPrefix, possibilities)
- completed = line[:-len(split_line[-1])]+common_prefix
- else:
- completed = line
- return completed, possibilities
-
- def _commonPrefix(self, str1, str2):
- for i in range(len(str1)):
- if not str2.startswith(str1[:i+1]):
- return str1[:i]
- return str1
-
- def shell(self, cmd,verbose=0,debug=0,header=''):
- stat = 0
- if verbose or debug: print header+cmd
- # flush stdout so we don't mangle python's buffering
- if not debug:
- input, output = os.popen4(cmd)
- print output.read()
- output.close()
- input.close()
-
-class ConsoleView(gtk.TextView):
- def __init__(self):
- gtk.TextView.__init__(self)
- self.modify_font(pango.FontDescription('Mono'))
- self.set_cursor_visible(True)
- self.text_buffer = self.get_buffer()
- self.mark = self.text_buffer.create_mark('scroll_mark',
- self.text_buffer.get_end_iter(),
- False)
- for code in ansi_colors:
- self.text_buffer.create_tag(code,
- foreground=ansi_colors[code],
- weight=700)
- self.text_buffer.create_tag('0')
- self.text_buffer.create_tag('notouch', editable=False)
- self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
- self.line_start = \
- self.text_buffer.create_mark('line_start',
- self.text_buffer.get_end_iter(), True
- )
- self.connect('key-press-event', self._onKeypress)
- self.last_cursor_pos = 0
-
- def write(self, text, editable=False):
- segments = self.color_pat.split(text)
- segment = segments.pop(0)
- start_mark = self.text_buffer.create_mark(None,
- self.text_buffer.get_end_iter(),
- True)
- self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
-
- if segments:
- ansi_tags = self.color_pat.findall(text)
- for tag in ansi_tags:
- i = segments.index(tag)
- self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(),
- segments[i+1], tag)
- segments.pop(i)
- if not editable:
- self.text_buffer.apply_tag_by_name('notouch',
- self.text_buffer.get_iter_at_mark(start_mark),
- self.text_buffer.get_end_iter())
- self.text_buffer.delete_mark(start_mark)
- self.scroll_mark_onscreen(self.mark)
-
- def showPrompt(self, prompt):
- self.write(prompt)
- self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
-
- def changeLine(self, text):
- iter = self.text_buffer.get_iter_at_mark(self.line_start)
- iter.forward_to_line_end()
- self.text_buffer.delete(self.text_buffer.get_iter_at_mark(self.line_start), iter)
- self.write(text, True)
-
- def getCurrentLine(self):
- rv = self.text_buffer.get_slice(self.text_buffer.get_iter_at_mark(self.line_start),
- self.text_buffer.get_end_iter(), False)
- return rv
-
- def showReturned(self, text):
- iter = self.text_buffer.get_iter_at_mark(self.line_start)
- iter.forward_to_line_end()
- self.text_buffer.apply_tag_by_name('notouch',
- self.text_buffer.get_iter_at_mark(self.line_start),
- iter)
- self.write('\n'+text)
- if text:
- self.write('\n')
- self.showPrompt(self.prompt)
- self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
- self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
-
- def _onKeypress(self, obj, event):
- if not event.string:
- return
- insert_mark = self.text_buffer.get_insert()
- insert_iter = self.text_buffer.get_iter_at_mark(insert_mark)
- selection_mark = self.text_buffer.get_selection_bound()
- selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
- start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
- if start_iter.compare(insert_iter) <= 0 and \
- start_iter.compare(selection_iter) <= 0:
- return
- elif start_iter.compare(insert_iter) > 0 and \
- start_iter.compare(selection_iter) > 0:
- self.text_buffer.place_cursor(start_iter)
- elif insert_iter.compare(selection_iter) < 0:
- self.text_buffer.move_mark(insert_mark, start_iter)
- elif insert_iter.compare(selection_iter) > 0:
- self.text_buffer.move_mark(selection_mark, start_iter)
-
-
-class IPythonView(ConsoleView, IterableIPShell):
- def __init__(self):
- ConsoleView.__init__(self)
- self.cout = StringIO()
- IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout,
- input_func=self.raw_input)
- self.connect('key_press_event', self.keyPress)
- self.execute()
- self.cout.truncate(0)
- self.showPrompt(self.prompt)
- self.interrupt = False
-
- def raw_input(self, prompt=''):
- if self.interrupt:
- self.interrupt = False
- raise KeyboardInterrupt
- return self.getCurrentLine()
-
- def keyPress(self, widget, event):
- if event.state & gtk.gdk.CONTROL_MASK and event.keyval == 99:
- self.interrupt = True
- self._processLine()
- return True
- elif event.keyval == gtk.keysyms.Return:
- self._processLine()
- return True
- elif event.keyval == gtk.keysyms.Up:
- self.changeLine(self.historyBack())
- return True
- elif event.keyval == gtk.keysyms.Down:
- self.changeLine(self.historyForward())
- return True
- elif event.keyval == gtk.keysyms.Tab:
- if not self.getCurrentLine().strip():
- return False
- completed, possibilities = self.complete(self.getCurrentLine())
- if len(possibilities) > 1:
- slice = self.getCurrentLine()
- self.write('\n')
- for symbol in possibilities:
- self.write(symbol+'\n')
- self.showPrompt(self.prompt)
- self.changeLine(completed or slice)
- return True
-
- def _processLine(self):
- self.history_pos = 0
- self.execute()
- rv = self.cout.getvalue()
- if rv: rv = rv.strip('\n')
- self.showReturned(rv)
- self.cout.truncate(0)
--- a/src/tools/visualizer/visualizer/plugins/interface_statistics.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-import gtk
-import ns3
-from visualizer.base import InformationWindow
-
-NODE_STATISTICS_MEMORY = 10
-
-
-class StatisticsCollector(object):
- """
- Collects interface statistics for all nodes.
- """
-
- class NetDevStats(object):
- __slots__ = ['rxPackets', 'rxBytes', 'txPackets', 'txBytes',
- 'rxPacketRate', 'rxBitRate', 'txPacketRate', 'txBitRate']
-
- def __init__(self, visualizer):
- self.node_statistics = {} # nodeid -> list(raw statistics)
- self.visualizer = visualizer
-
- def simulation_periodic_update(self, viz):
- nodes_statistics = viz.simulation.sim_helper.GetNodesStatistics()
- for stats in nodes_statistics:
- try:
- raw_stats_list = self.node_statistics[stats.nodeId]
- except KeyError:
- raw_stats_list = []
- self.node_statistics[stats.nodeId] = raw_stats_list
- raw_stats_list.append(stats.statistics)
- while len(raw_stats_list) > NODE_STATISTICS_MEMORY:
- raw_stats_list.pop(0)
-
- def get_interface_statistics(self, nodeId):
- try:
- raw_stats_list = self.node_statistics[nodeId]
- except KeyError:
- return []
-
- if len(raw_stats_list) < NODE_STATISTICS_MEMORY:
- return []
- assert len(raw_stats_list) == NODE_STATISTICS_MEMORY
- tx_packets1 = [] # transmitted packets, one value per interface
- rx_packets1 = []
- tx_bytes1 = []
- rx_bytes1 = []
- for iface, stats in enumerate(raw_stats_list[0]):
- tx_packets1.append(stats.transmittedPackets)
- tx_bytes1.append(stats.transmittedBytes)
- rx_packets1.append(stats.receivedPackets)
- rx_bytes1.append(stats.receivedBytes)
-
- retval = []
-
- k = self.visualizer.sample_period*(NODE_STATISTICS_MEMORY-1)
- for iface, stats in enumerate(raw_stats_list[-1]):
- outStat = self.NetDevStats()
- outStat.txPackets = stats.transmittedPackets
- outStat.txBytes = stats.transmittedBytes
- outStat.rxPackets = stats.receivedPackets
- outStat.rxBytes = stats.receivedBytes
-
- outStat.txPacketRate = (stats.transmittedPackets - tx_packets1[iface])/k
- outStat.rxPacketRate = (stats.receivedPackets - rx_packets1[iface])/k
- outStat.txBitRate = (stats.transmittedBytes - tx_bytes1[iface])*8/k
- outStat.rxBitRate = (stats.receivedBytes - rx_bytes1[iface])*8/k
- retval.append(outStat)
- return retval
-
-
-class ShowInterfaceStatistics(InformationWindow):
- (
- COLUMN_INTERFACE,
-
- COLUMN_TX_PACKETS,
- COLUMN_TX_BYTES,
- COLUMN_TX_PACKET_RATE,
- COLUMN_TX_BIT_RATE,
-
- COLUMN_RX_PACKETS,
- COLUMN_RX_BYTES,
- COLUMN_RX_PACKET_RATE,
- COLUMN_RX_BIT_RATE,
-
- ) = range(9)
-
- def __init__(self, visualizer, node_index, statistics_collector):
- InformationWindow.__init__(self)
- self.win = gtk.Dialog(parent=visualizer.window,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
- buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
- self.win.connect("response", self._response_cb)
- self.win.set_title("Statistics for node %i" % node_index)
- self.visualizer = visualizer
- self.statistics_collector = statistics_collector
- self.node_index = node_index
- self.viz_node = visualizer.get_node(node_index)
-
- self.table_model = gtk.ListStore(*([str]*13))
-
- treeview = gtk.TreeView(self.table_model)
- treeview.show()
- self.win.vbox.add(treeview)
-
- def add_column(descr, colid):
- column = gtk.TreeViewColumn(descr, gtk.CellRendererText(), text=colid)
- treeview.append_column(column)
-
- add_column("Interface", self.COLUMN_INTERFACE)
-
- add_column("Tx Packets", self.COLUMN_TX_PACKETS)
- add_column("Tx Bytes", self.COLUMN_TX_BYTES)
- add_column("Tx pkt/1s", self.COLUMN_TX_PACKET_RATE)
- add_column("Tx bit/1s", self.COLUMN_TX_BIT_RATE)
-
- add_column("Rx Packets", self.COLUMN_RX_PACKETS)
- add_column("Rx Bytes", self.COLUMN_RX_BYTES)
- add_column("Rx pkt/1s", self.COLUMN_RX_PACKET_RATE)
- add_column("Rx bit/1s", self.COLUMN_RX_BIT_RATE)
-
- self.visualizer.add_information_window(self)
- self.win.show()
-
- def _response_cb(self, win, response):
- self.win.destroy()
- self.visualizer.remove_information_window(self)
-
- def update(self):
- node = ns3.NodeList.GetNode(self.node_index)
- stats_list = self.statistics_collector.get_interface_statistics(self.node_index)
- self.table_model.clear()
- for iface, stats in enumerate(stats_list):
- tree_iter = self.table_model.append()
- netdevice = node.GetDevice(iface)
- interface_name = ns3.Names.FindName(netdevice)
- if not interface_name:
- interface_name = "(interface %i)" % iface
- self.table_model.set(tree_iter,
- self.COLUMN_INTERFACE, interface_name,
-
- self.COLUMN_TX_PACKETS, str(stats.txPackets),
- self.COLUMN_TX_BYTES, str(stats.txBytes),
- self.COLUMN_TX_PACKET_RATE, str(stats.txPacketRate),
- self.COLUMN_TX_BIT_RATE, str(stats.txBitRate),
-
- self.COLUMN_RX_PACKETS, str(stats.rxPackets),
- self.COLUMN_RX_BYTES, str(stats.rxBytes),
- self.COLUMN_RX_PACKET_RATE, str(stats.rxPacketRate),
- self.COLUMN_RX_BIT_RATE, str(stats.rxBitRate)
- )
-
-
-def populate_node_menu(viz, node, menu, statistics_collector):
-
- menu_item = gtk.MenuItem("Show Interface Statistics")
- menu_item.show()
-
- def _show_it(dummy_menu_item):
- ShowInterfaceStatistics(viz, node.node_index, statistics_collector)
-
- menu_item.connect("activate", _show_it)
- menu.add(menu_item)
-
-
-def register(viz):
- statistics_collector = StatisticsCollector(viz)
- viz.connect("populate-node-menu", populate_node_menu, statistics_collector)
- viz.connect("simulation-periodic-update", statistics_collector.simulation_periodic_update)
--- a/src/tools/visualizer/visualizer/plugins/ipv4_routing_table.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-import gtk
-import ns3
-from visualizer.base import InformationWindow
-
-class ShowIpv4RoutingTable(InformationWindow):
- (
- COLUMN_DESTINATION,
- COLUMN_NEXT_HOP,
- COLUMN_INTERFACE,
- COLUMN_TYPE,
- COLUMN_PRIO
- ) = range(5)
-
- def __init__(self, visualizer, node_index):
- InformationWindow.__init__(self)
- self.win = gtk.Dialog(parent=visualizer.window,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
- buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
- self.win.connect("response", self._response_cb)
- self.win.set_title("IPv4 routing table for node %i" % node_index)
- self.visualizer = visualizer
- self.node_index = node_index
-
- self.table_model = gtk.ListStore(str, str, str, str, int)
-
- treeview = gtk.TreeView(self.table_model)
- treeview.show()
- sw = gtk.ScrolledWindow()
- sw.set_properties(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
- vscrollbar_policy=gtk.POLICY_AUTOMATIC)
- sw.show()
- sw.add(treeview)
- self.win.vbox.add(sw)
- self.win.set_default_size(600, 300)
-
- # Dest.
- column = gtk.TreeViewColumn('Destination', gtk.CellRendererText(),
- text=self.COLUMN_DESTINATION)
- treeview.append_column(column)
-
- # Next hop
- column = gtk.TreeViewColumn('Next hop', gtk.CellRendererText(),
- text=self.COLUMN_NEXT_HOP)
- treeview.append_column(column)
-
- # Interface
- column = gtk.TreeViewColumn('Interface', gtk.CellRendererText(),
- text=self.COLUMN_INTERFACE)
- treeview.append_column(column)
-
- # Type
- column = gtk.TreeViewColumn('Type', gtk.CellRendererText(),
- text=self.COLUMN_TYPE)
- treeview.append_column(column)
-
- # Prio
- column = gtk.TreeViewColumn('Prio', gtk.CellRendererText(),
- text=self.COLUMN_PRIO)
- treeview.append_column(column)
-
- self.visualizer.add_information_window(self)
- self.win.show()
-
- def _response_cb(self, win, response):
- self.win.destroy()
- self.visualizer.remove_information_window(self)
-
- def update(self):
- node = ns3.NodeList.GetNode(self.node_index)
- ipv4 = node.GetObject(ns3.Ipv4.GetTypeId())
- routing = ipv4.GetRoutingProtocol()
- if routing is None:
- return
-
- routing_protocols = [] # list of (protocol, type_string, priority)
-
- if isinstance(routing, ns3.Ipv4StaticRouting):
- ipv4_routing = routing_protocols.append((routing, "static", 0))
- elif isinstance(routing, ns3.Ipv4ListRouting):
- list_routing = routing
- for rI in range(list_routing.GetNRoutingProtocols()):
- routing, prio = list_routing.GetRoutingProtocol(rI)
- if isinstance(routing, ns3.Ipv4StaticRouting):
- routing_protocols.append((routing, "static", prio))
- elif isinstance(routing, ns3.Ipv4GlobalRouting):
- routing_protocols.append((routing, "global", prio))
- if not routing_protocols:
- return
-
- self.table_model.clear()
- for route_proto, type_string, prio in routing_protocols:
- for routeI in range(route_proto.GetNRoutes()):
- route = route_proto.GetRoute(routeI)
- tree_iter = self.table_model.append()
- netdevice = ipv4.GetNetDevice(route.GetInterface())
- if netdevice is None:
- interface_name = 'lo'
- else:
- interface_name = ns3.Names.FindName(netdevice)
- if not interface_name:
- interface_name = "(interface %i)" % route.GetInterface()
- self.table_model.set(tree_iter,
- self.COLUMN_DESTINATION, str(route.GetDest()),
- self.COLUMN_NEXT_HOP, str(route.GetGateway()),
- self.COLUMN_INTERFACE, interface_name,
- self.COLUMN_TYPE, type_string,
- self.COLUMN_PRIO, prio)
-
-
-def populate_node_menu(viz, node, menu):
- menu_item = gtk.MenuItem("Show IPv4 Routing Table")
- menu_item.show()
-
- def _show_ipv4_routing_table(dummy_menu_item):
- ShowIpv4RoutingTable(viz, node.node_index)
-
- menu_item.connect("activate", _show_ipv4_routing_table)
- menu.add(menu_item)
-
-def register(viz):
- viz.connect("populate-node-menu", populate_node_menu)
--- a/src/tools/visualizer/visualizer/plugins/olsr.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-import gtk
-import ns3
-from visualizer.base import InformationWindow
-
-class ShowOlsrRoutingTable(InformationWindow):
- (
- COLUMN_DESTINATION,
- COLUMN_NEXT_HOP,
- COLUMN_INTERFACE,
- COLUMN_NUM_HOPS,
- ) = range(4)
-
- def __init__(self, visualizer, node_index):
- InformationWindow.__init__(self)
- self.win = gtk.Dialog(parent=visualizer.window,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
- buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
- self.win.set_default_size(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/2)
- self.win.connect("response", self._response_cb)
- self.win.set_title("OLSR routing table for node %i" % node_index)
- self.visualizer = visualizer
- self.node_index = node_index
-
- self.table_model = gtk.ListStore(str, str, str, int)
-
- treeview = gtk.TreeView(self.table_model)
- treeview.show()
- sw = gtk.ScrolledWindow()
- sw.set_properties(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
- vscrollbar_policy=gtk.POLICY_AUTOMATIC)
- sw.show()
- sw.add(treeview)
- self.win.vbox.add(sw)
-
- # Dest.
- column = gtk.TreeViewColumn('Destination', gtk.CellRendererText(),
- text=self.COLUMN_DESTINATION)
- treeview.append_column(column)
-
- # Next hop
- column = gtk.TreeViewColumn('Next hop', gtk.CellRendererText(),
- text=self.COLUMN_NEXT_HOP)
- treeview.append_column(column)
-
- # Interface
- column = gtk.TreeViewColumn('Interface', gtk.CellRendererText(),
- text=self.COLUMN_INTERFACE)
- treeview.append_column(column)
-
- # Num. Hops
- column = gtk.TreeViewColumn('Num. Hops', gtk.CellRendererText(),
- text=self.COLUMN_NUM_HOPS)
- treeview.append_column(column)
-
- self.visualizer.add_information_window(self)
- self.win.show()
-
- def _response_cb(self, win, response):
- self.win.destroy()
- self.visualizer.remove_information_window(self)
-
- def update(self):
- node = ns3.NodeList.GetNode(self.node_index)
- olsr = node.GetObject(ns3.olsr.RoutingProtocol.GetTypeId())
- ipv4 = node.GetObject(ns3.Ipv4.GetTypeId())
- if olsr is None:
- return
- self.table_model.clear()
- for route in olsr.GetRoutingTableEntries():
- tree_iter = self.table_model.append()
- netdevice = ipv4.GetNetDevice(route.interface)
- if netdevice is None:
- interface_name = 'lo'
- else:
- interface_name = ns3.Names.FindName(netdevice)
- if not interface_name:
- interface_name = "(interface %i)" % route.interface
- self.table_model.set(tree_iter,
- self.COLUMN_DESTINATION, str(route.destAddr),
- self.COLUMN_NEXT_HOP, str(route.nextAddr),
- self.COLUMN_INTERFACE, interface_name,
- self.COLUMN_NUM_HOPS, route.distance)
-
-
-def populate_node_menu(viz, node, menu):
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- olsr = ns3_node.GetObject(ns3.olsr.RoutingProtocol.GetTypeId())
- if olsr is None:
- print "No OLSR"
- return
-
- menu_item = gtk.MenuItem("Show OLSR Routing Table")
- menu_item.show()
-
- def _show_ipv4_routing_table(dummy_menu_item):
- ShowOlsrRoutingTable(viz, node.node_index)
-
- menu_item.connect("activate", _show_ipv4_routing_table)
- menu.add(menu_item)
-
-def register(viz):
- viz.connect("populate-node-menu", populate_node_menu)
--- a/src/tools/visualizer/visualizer/plugins/show_last_packets.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-import gobject
-import gtk
-import ns3
-from visualizer.base import InformationWindow
-from visualizer.higcontainer import HIGContainer
-from kiwi.ui.objectlist import ObjectList, Column
-
-class ShowLastPackets(InformationWindow):
- class PacketList(gtk.ScrolledWindow):
- (
- COLUMN_TIME,
- COLUMN_INTERFACE,
- COLUMN_SIZE,
- COLUMN_CONTENTS,
- ) = range(4)
-
- def __init__(self):
- super(ShowLastPackets.PacketList, self).__init__()
- self.set_properties(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
- vscrollbar_policy=gtk.POLICY_AUTOMATIC)
- self.table_model = gtk.ListStore(*([str]*4))
- treeview = gtk.TreeView(self.table_model)
- treeview.show()
- self.add(treeview)
-
- def add_column(descr, colid):
- column = gtk.TreeViewColumn(descr, gtk.CellRendererText(), text=colid)
- treeview.append_column(column)
-
- add_column("Time", self.COLUMN_TIME)
- add_column("Interface", self.COLUMN_INTERFACE)
- add_column("Size", self.COLUMN_SIZE)
- add_column("Contents", self.COLUMN_CONTENTS)
-
- def update(self, node, packet_list):
- self.table_model.clear()
- for sample in packet_list:
- tree_iter = self.table_model.append()
- if sample.device is None:
- interface_name = "(unknown)"
- else:
- interface_name = ns3.Names.FindName(sample.device)
- if not interface_name:
- interface_name = "(interface %i)" % sample.device.GetIfIndex()
- self.table_model.set(tree_iter,
- self.COLUMN_TIME, str(sample.time.GetSeconds()),
- self.COLUMN_INTERFACE, interface_name,
- self.COLUMN_SIZE, str(sample.packet.GetSize ()),
- self.COLUMN_CONTENTS, str(sample.packet)
- )
-
-
- def __init__(self, visualizer, node_index):
- InformationWindow.__init__(self)
- self.win = gtk.Dialog(parent=visualizer.window,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
- buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
- self.win.connect("response", self._response_cb)
- self.win.set_title("Last packets for node %i" % node_index)
- self.visualizer = visualizer
- self.viz_node = visualizer.get_node(node_index)
- self.node = ns3.NodeList.GetNode(node_index)
-
- def smart_expand(expander, vbox):
- if expander.get_expanded():
- vbox.set_child_packing(expander, expand=True, fill=True, padding=0, pack_type=gtk.PACK_START)
- else:
- vbox.set_child_packing(expander, expand=False, fill=False, padding=0, pack_type=gtk.PACK_START)
-
- main_hbox = gtk.HBox(False, 4)
- main_hbox.show()
- main_vbox = gtk.VBox(False, 4)
- main_vbox.show()
- self.win.vbox.add(main_hbox)
- main_hbox.add(main_vbox)
-
- self.tx_list = self.PacketList()
- self.tx_list.show()
- group = gtk.Expander("Last transmitted packets")
- group.show()
- group.add(self.tx_list)
- main_vbox.pack_start(group, expand=False, fill=False)
- group.connect_after("activate", smart_expand, main_vbox)
-
- self.rx_list = self.PacketList()
- self.rx_list.show()
- group = gtk.Expander("Last received packets")
- group.show()
- group.add(self.rx_list)
- main_vbox.pack_start(group, expand=False, fill=False)
- group.connect_after("activate", smart_expand, main_vbox)
-
- self.drop_list = self.PacketList()
- self.drop_list.show()
- group = gtk.Expander("Last dropped packets")
- group.show()
- group.add(self.drop_list)
- main_vbox.pack_start(group, expand=False, fill=False)
- group.connect_after("activate", smart_expand, main_vbox)
-
-
- # Packet Filter
-
- # - options
- self.packet_capture_options = ns3.PyViz.PacketCaptureOptions()
- self.packet_capture_options.numLastPackets = 100
-
- packet_filter_vbox = gtk.VBox(False, 4)
- packet_filter_vbox.show()
- main_hbox.add(packet_filter_vbox)
-
- sel_buttons_box = gtk.HButtonBox()
- sel_buttons_box.show()
- packet_filter_vbox.pack_start(sel_buttons_box, False, False, 4)
- select_all_button = gobject.new(gtk.Button, label="Sel. All", visible=True)
- select_none_button = gobject.new(gtk.Button, label="Sel. None", visible=True)
- sel_buttons_box.add(select_all_button)
- sel_buttons_box.add(select_none_button)
-
- self.packet_filter_widget = ObjectList([
- Column('selected', title="Sel.", data_type=bool, editable=True),
- Column('name', title="Header"),
- ], sortable=True)
- self.packet_filter_widget.show()
- packet_filter_vbox.pack_start(self.packet_filter_widget, True, True, 4)
-
- class TypeIdConfig(object):
- __slots__ = ['name', 'selected', 'typeid']
-
- self.packet_filter_list = [] # list of TypeIdConfig instances
-
- Header = ns3.TypeId.LookupByName("ns3::Header")
- Trailer = ns3.TypeId.LookupByName("ns3::Trailer")
- for typeid_i in range(ns3.TypeId.GetRegisteredN()):
- typeid = ns3.TypeId.GetRegistered(typeid_i)
- # check if this is a header or trailer subtype
- typeid_tmp = typeid
- type_is_good = False
- while 1:
- if typeid_tmp == Header or typeid_tmp == Trailer:
- type_is_good = True
- break
- if typeid_tmp.HasParent():
- typeid_tmp = typeid_tmp.GetParent()
- else:
- break
- if not type_is_good:
- continue
- if typeid in [Header, Trailer]:
- continue
- c = TypeIdConfig()
- c.selected = True
- c.name = typeid.GetName()
- c.typeid = typeid
- self.packet_filter_list.append(c)
- self.packet_filter_widget.add_list(self.packet_filter_list)
-
- def update_capture_options():
- if self.op_AND_button.props.active:
- self.packet_capture_options.mode = ns3.PyViz.PACKET_CAPTURE_FILTER_HEADERS_AND
- else:
- self.packet_capture_options.mode = ns3.PyViz.PACKET_CAPTURE_FILTER_HEADERS_OR
- self.packet_capture_options.numLastPackets = 100
- self.packet_capture_options.headers = [c.typeid for c in self.packet_filter_list if c.selected]
- self.visualizer.simulation.lock.acquire()
- try:
- self.visualizer.simulation.sim_helper.SetPacketCaptureOptions(
- self.node.GetId(), self.packet_capture_options)
- finally:
- self.visualizer.simulation.lock.release()
-
- def sel_all_cb(bt):
- for c in self.packet_filter_list:
- c.selected = True
- self.packet_filter_widget.refresh()
- update_capture_options()
-
- def sel_none_cb(bt):
- for c in self.packet_filter_list:
- c.selected = False
- self.packet_filter_widget.refresh()
- update_capture_options()
-
- select_all_button.connect("clicked", sel_all_cb)
- select_none_button.connect("clicked", sel_none_cb)
-
- op_buttons_box = gtk.HButtonBox()
- op_buttons_box.show()
- packet_filter_vbox.pack_start(op_buttons_box, False, False, 4)
- self.op_AND_button = gobject.new(gtk.RadioButton, label="AND", visible=True)
- self.op_OR_button = gobject.new(gtk.RadioButton, label="OR", visible=True, group=self.op_AND_button)
- op_buttons_box.add(self.op_AND_button)
- op_buttons_box.add(self.op_OR_button)
- self.op_OR_button.props.active = True
-
- self.op_AND_button.connect("toggled", lambda b: update_capture_options())
-
- def cell_edited(l, obj, attribute):
- update_capture_options()
- self.packet_filter_widget.connect("cell-edited", cell_edited)
-
- update_capture_options()
-
- self.visualizer.add_information_window(self)
- self.win.set_default_size(600, 300)
- self.win.show()
-
- def _response_cb(self, win, response):
- self.win.destroy()
- self.visualizer.remove_information_window(self)
-
- def update(self):
- last_packets = self.visualizer.simulation.sim_helper.GetLastPackets(self.node.GetId())
-
- self.tx_list.update(self.node, last_packets.lastTransmittedPackets)
- self.rx_list.update(self.node, last_packets.lastReceivedPackets)
- self.drop_list.update(self.node, last_packets.lastDroppedPackets)
-
-
-def populate_node_menu(viz, node, menu):
- menu_item = gtk.MenuItem("Show Last Packets")
- menu_item.show()
-
- def _show_it(dummy_menu_item):
- ShowLastPackets(viz, node.node_index)
-
- menu_item.connect("activate", _show_it)
- menu.add(menu_item)
-
-def register(viz):
- viz.connect("populate-node-menu", populate_node_menu)
--- a/src/tools/visualizer/visualizer/plugins/wifi_intrastructure_link.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-import math
-import ns3
-import goocanvas
-from visualizer.base import Link, transform_distance_canvas_to_simulation
-
-class WifiLink(Link):
- def __init__(self, parent_canvas_item, sta, dev):
- self.node1 = sta
- self.dev = dev
- self.node2 = None # ap
- self.canvas_item = goocanvas.Group(parent=parent_canvas_item)
- self.invisible_line = goocanvas.Polyline(parent=self.canvas_item,
- line_width=25.0,
- visibility=goocanvas.ITEM_HIDDEN)
- self.visible_line = goocanvas.Polyline(parent=self.canvas_item,
- line_width=1.0,
- stroke_color_rgba=0xC00000FF,
- line_dash=goocanvas.LineDash([2.0, 2.0 ]))
- self.invisible_line.props.pointer_events = (goocanvas.EVENTS_STROKE_MASK
- |goocanvas.EVENTS_FILL_MASK
- |goocanvas.EVENTS_PAINTED_MASK)
- self.canvas_item.set_data("pyviz-object", self)
- self.canvas_item.lower(None)
- self.set_ap(None)
-
- def set_ap(self, ap):
- if ap is self.node2:
- return
- if self.node2 is not None:
- self.node2.remove_link(self)
- self.node2 = ap
- if self.node2 is None:
- self.canvas_item.set_property("visibility", goocanvas.ITEM_HIDDEN)
- else:
- self.node2.add_link(self)
- self.canvas_item.set_property("visibility", goocanvas.ITEM_VISIBLE)
- self.update_points()
-
- def update_points(self):
- if self.node2 is None:
- return
- pos1_x, pos1_y = self.node1.get_position()
- pos2_x, pos2_y = self.node2.get_position()
- points = goocanvas.Points([(pos1_x, pos1_y), (pos2_x, pos2_y)])
- self.visible_line.set_property("points", points)
- self.invisible_line.set_property("points", points)
-
- def destroy(self):
- self.canvas_item.destroy()
- self.node1 = None
- self.node2 = None
-
- def tooltip_query(self, tooltip):
- pos1_x, pos1_y = self.node1.get_position()
- pos2_x, pos2_y = self.node2.get_position()
- dx = pos2_x - pos1_x
- dy = pos2_y - pos1_y
- d = transform_distance_canvas_to_simulation(math.sqrt(dx*dx + dy*dy))
- mac = self.dev.GetMac()
- tooltip.set_text(("WiFi link between STA Node %i and AP Node %i; distance=%.2f m.\n"
- "SSID: %s\n"
- "BSSID: %s")
- % (self.node1.node_index, self.node2.node_index, d,
- mac.GetSsid(), mac.GetBssid()))
-
-
-class WifiLinkMonitor(object):
- def __init__(self, dummy_viz):
- self.access_points = {} # bssid -> node
- self.stations = [] # list of (sta_netdevice, viz_node, wifi_link)
-
- def scan_nodes(self, viz):
- for (sta_netdevice, viz_node, wifi_link) in self.stations:
- wifi_link.destroy()
-
- self.access_points = {}
- self.stations = []
-
- for node in viz.nodes.itervalues():
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- for devI in range(ns3_node.GetNDevices()):
- dev = ns3_node.GetDevice(devI)
- if not isinstance(dev, ns3.WifiNetDevice):
- continue
- wifi_mac = dev.GetMac()
- if isinstance(wifi_mac, ns3.StaWifiMac):
- wifi_link = WifiLink(viz.links_group, node, dev)
- self.stations.append((dev, node, wifi_link))
- elif isinstance(wifi_mac, ns3.ApWifiMac):
- bssid = ns3.Mac48Address.ConvertFrom(dev.GetAddress())
- self.access_points[str(bssid)] = node
- #print "APs: ", self.access_points
- #print "STAs: ", self.stations
-
- def simulation_periodic_update(self, viz):
- for (sta_netdevice, viz_node, wifi_link) in self.stations:
- if not sta_netdevice.IsLinkUp():
- wifi_link.set_ap(None)
- continue
- bssid = str(sta_netdevice.GetMac().GetBssid())
- if bssid == '00:00:00:00:00:00':
- wifi_link.set_ap(None)
- continue
- ap = self.access_points[bssid]
- wifi_link.set_ap(ap)
-
- def update_view(self, viz):
- for (dummy_sta_netdevice, dummy_viz_node, wifi_link) in self.stations:
- if wifi_link is not None:
- wifi_link.update_points()
-
-
-def register(viz):
- link_monitor = WifiLinkMonitor(viz)
- viz.connect("simulation-periodic-update", link_monitor.simulation_periodic_update)
- viz.connect("update-view", link_monitor.update_view)
- viz.connect("topology-scanned", link_monitor.scan_nodes)
--- a/src/tools/visualizer/visualizer/resource/Basurero_Palm_Z22.svg Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,311 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="122.87033"
- height="185.93257"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="0.46"
- sodipodi:docname="Basurero_Palm_Z22.svg"
- inkscape:output_extension="org.inkscape.output.svg.inkscape"
- version="1.0">
- <defs
- id="defs4">
- <linearGradient
- id="linearGradient3237">
- <stop
- style="stop-color: rgb(156, 156, 156); stop-opacity: 1;"
- offset="0"
- id="stop3239" />
- <stop
- id="stop3245"
- offset="0.5"
- style="stop-color: rgb(220, 220, 220); stop-opacity: 1;" />
- <stop
- style="stop-color: rgb(168, 168, 168); stop-opacity: 1;"
- offset="1"
- id="stop3241" />
- </linearGradient>
- <linearGradient
- id="linearGradient2911">
- <stop
- style="stop-color: rgb(175, 193, 225); stop-opacity: 1;"
- offset="0"
- id="stop2913" />
- <stop
- style="stop-color: rgb(92, 144, 233); stop-opacity: 1;"
- offset="1"
- id="stop2915" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient2911"
- id="linearGradient3229"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-89.3787,74.9628)"
- x1="157.91194"
- y1="149.28284"
- x2="151.2318"
- y2="223.88245" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3237"
- id="linearGradient3243"
- x1="59.830921"
- y1="241.51917"
- x2="200.76509"
- y2="179.29376"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-89.3787,74.9628)" />
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="0.59688333"
- inkscape:cx="428.4488"
- inkscape:cy="185.26469"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- inkscape:window-width="1280"
- inkscape:window-height="753"
- inkscape:window-x="0"
- inkscape:window-y="47"
- showgrid="false"
- showguides="true"
- inkscape:guide-bbox="true" />
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <cc:license
- rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
- </cc:Work>
- <cc:License
- rdf:about="http://creativecommons.org/licenses/publicdomain/">
- <cc:permits
- rdf:resource="http://creativecommons.org/ns#Reproduction" />
- <cc:permits
- rdf:resource="http://creativecommons.org/ns#Distribution" />
- <cc:permits
- rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
- </cc:License>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Capa 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-160.08253,-45.555814)">
- <g
- id="g3261"
- inkscape:export-filename="/home/e288288/imagen/svg/palm_z22.png"
- inkscape:export-xdpi="75"
- inkscape:export-ydpi="75"
- transform="translate(89.3787,-74.9628)">
- <rect
- ry="22.210958"
- rx="22.210958"
- y="120.88235"
- x="71.067566"
- height="185.20511"
- width="122.14287"
- id="rect2176"
- style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
- <rect
- style="fill:url(#linearGradient3243);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- id="rect2856"
- width="119.34706"
- height="182.73219"
- x="72.215469"
- y="121.8688"
- rx="20.444592"
- ry="20.444592" />
- <rect
- ry="18.259377"
- rx="18.259377"
- y="124.17456"
- x="74.340469"
- height="178.12067"
- width="115.09706"
- id="rect3235"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
- <rect
- ry="6.9516835"
- rx="6.9516835"
- y="135.9494"
- x="84.825104"
- height="125.89838"
- width="94.6278"
- id="rect2839"
- style="fill:#e3e3e3;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#a4a4a4;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- id="rect2841"
- width="81.335205"
- height="111.10477"
- x="91.471397"
- y="142.06659"
- rx="1.7201494"
- ry="1.7201494" />
- <rect
- ry="0"
- rx="0"
- y="143.58203"
- x="92.920067"
- height="79.936684"
- width="78.437866"
- id="rect2843"
- style="fill:url(#linearGradient3229);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
- <g
- id="g3257">
- <path
- style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a2a2a2;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- d="M 73.133883,261.125 L 73.133883,279.3125 L 74.196383,279.3125 C 79.236007,279.3125 83.290129,275.25837 83.290133,270.21875 C 83.290133,265.17913 79.236011,261.125 74.196383,261.125 L 73.133883,261.125 z"
- id="rect2875" />
- <rect
- style="fill:#164532;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- id="rect2884"
- width="1.8988454"
- height="5.4946771"
- x="78.096237"
- y="267.47141" />
- </g>
- <g
- transform="translate(-3.8147e-6,0)"
- id="g3095">
- <rect
- ry="10.619836"
- rx="10.619836"
- y="272.72806"
- x="89.104172"
- height="21.239672"
- width="86.069664"
- id="rect2847"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.10249996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
- <path
- id="rect2845"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.10249996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- d="M 129.26628,274.47992 L 135.01173,274.47992 C 139.92459,274.47992 143.87971,278.43504 143.87971,283.34789 C 143.87971,288.26075 139.92459,292.21587 135.01173,292.21587 L 129.26628,292.21587 C 124.35342,292.21587 120.39831,288.26075 120.39831,283.34789 C 120.39831,278.43504 124.35342,274.47992 129.26628,274.47992 z M 127.49374,268.95493 L 136.78426,268.95493 C 144.72845,268.95493 151.12396,275.37419 151.12396,283.34789 C 151.12396,291.3216 144.72845,297.74086 136.78426,297.74086 L 127.49374,297.74086 C 119.54955,297.74086 113.15404,291.3216 113.15404,283.34789 C 113.15404,275.37419 119.54955,268.95493 127.49374,268.95493 z" />
- <path
- sodipodi:type="arc"
- style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.17324996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- id="path2873"
- sodipodi:cx="99.667305"
- sodipodi:cy="282.88821"
- sodipodi:rx="8.7876797"
- sodipodi:ry="8.7876797"
- d="M 108.45498,282.88821 A 8.7876797,8.7876797 0 1 1 90.879625,282.88821 A 8.7876797,8.7876797 0 1 1 108.45498,282.88821 z"
- transform="matrix(0.939699,0,0,0.939699,5.30354,17.5183)" />
- <path
- transform="matrix(0.939699,0,0,0.939699,70.8358,17.5183)"
- d="M 108.45498,282.88821 A 8.7876797,8.7876797 0 1 1 90.879625,282.88821 A 8.7876797,8.7876797 0 1 1 108.45498,282.88821 z"
- sodipodi:ry="8.7876797"
- sodipodi:rx="8.7876797"
- sodipodi:cy="282.88821"
- sodipodi:cx="99.667305"
- id="path2896"
- style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.17324996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- sodipodi:type="arc" />
- </g>
- <g
- transform="translate(-138.895,0)"
- id="g3076">
- <g
- transform="translate(-8.39025,0)"
- id="g3042">
- <path
- id="path3044"
- style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72750002;stroke-linecap:round;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- d="M 251.74434,230.02968 L 247.09281,226.05818 L 242.23893,230.0407 C 243.96351,230.02965 244.22246,229.99149 244.24454,230.64788 L 244.24454,233.6507 C 244.24454,234.04213 244.55966,234.35725 244.95109,234.35725 L 249.19037,234.35725 C 249.5818,234.35725 249.89692,234.04213 249.89692,233.6507 L 249.89692,230.64788"
- sodipodi:nodetypes="ccccccccc" />
- <rect
- style="opacity:1;fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72750002;stroke-linecap:round;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- id="rect3046"
- width="1.1260595"
- height="2.2521191"
- x="246.4286"
- y="232.10513" />
- </g>
- <g
- transform="matrix(0.847116,0,0,0.847116,36.3844,36.8906)"
- id="g3048">
- <path
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
- d="M 243.32987,241.79807 L 234.14142,241.79807"
- id="path3050" />
- <path
- id="path3052"
- d="M 239.3129,244.33722 L 235.75172,244.33722"
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
- d="M 239.3129,246.43478 L 235.75172,246.43478"
- id="path3054" />
- <path
- id="path3056"
- d="M 239.48636,248.88562 L 234.09189,248.88562 L 234.09189,243.45405"
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
- sodipodi:nodetypes="ccc" />
- <path
- style="opacity:1;fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.858796;stroke-linecap:square;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- d="M 241.24351,243.98638 L 241.24351,246.04888 L 240.43101,246.04888 L 241.96226,247.58013 L 243.49351,246.04888 L 242.64976,246.04888 L 242.64976,243.98638 L 241.24351,243.98638 z"
- id="path3058" />
- </g>
- <path
- id="path3060"
- d="M 245.43681,225.79037 L 245.43681,252.3742"
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- d="M 298.33953,225.79037 L 298.33953,252.3742"
- id="path3062" />
- <g
- transform="matrix(0.842444,-0.225732,0.225732,0.842444,-7.44249,107.397)"
- id="g3064">
- <path
- sodipodi:type="arc"
- style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.16912997;stroke-linecap:square;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- id="path3066"
- sodipodi:cx="293.76904"
- sodipodi:cy="243.16701"
- sodipodi:rx="2.9365864"
- sodipodi:ry="2.9365864"
- d="M 296.70563,243.16701 A 2.9365864,2.9365864 0 1 1 290.83246,243.16701 A 2.9365864,2.9365864 0 1 1 296.70563,243.16701 z"
- transform="matrix(0.81203,0,0,0.81203,68.3571,45.3769)" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.14657998px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
- d="M 304.01429,244.66842 L 300.87837,246.47894"
- id="path3068" />
- </g>
- <path
- d="M 304.43441,227.375 C 302.53928,227.375 301.00444,228.90984 301.00443,230.80498 C 301.00443,232.67076 302.49414,234.18843 304.34866,234.23495 L 305.6349,231.97689 L 306.17798,232.2913 L 305.77781,230.69064 L 304.14858,231.09081 L 304.72024,231.43381 L 303.54833,233.40604 C 302.71926,232.84537 302.17634,231.87806 302.17634,230.80498 C 302.17635,229.33317 303.23075,228.15568 304.60591,227.83233 L 304.83804,227.41022 C 304.59686,227.39462 304.55861,227.375 304.43441,227.375 z M 305.15315,234.23495 C 307.04829,234.23495 308.58312,232.70011 308.58312,230.80498 C 308.58312,228.93918 307.09342,227.42152 305.23891,227.375 L 303.95265,229.63306 L 303.40958,229.31865 L 303.80975,230.91931 L 305.43898,230.51915 L 304.86732,230.17615 L 306.03923,228.2039 C 306.8683,228.76457 307.41122,229.73189 307.41122,230.80498 C 307.41121,232.27677 306.35681,233.45426 304.98165,233.77762 L 304.74953,234.19973 C 304.99069,234.21533 305.02895,234.23495 305.15315,234.23495 z"
- style="fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.228;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
- id="path3070" />
- <path
- id="path3072"
- d="M 275.27017,248.65837 L 275.27017,252.84071"
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- d="M 275.27017,225.34016 L 275.27017,227.98729"
- id="path3074" />
- </g>
- </g>
- </g>
-</svg>
--- a/src/tools/visualizer/visualizer/resource/adriankierman_cell_phone_tower.svg Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="54.71582" height="243.43661" id="svg5560" sodipodi:version="0.32" inkscape:version="0.45.1" version="1.0" sodipodi:docbase="/root/workspace/svg/clipart" sodipodi:docname="simple_cellular_tower.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape">
- <defs id="defs5562"/>
- <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" gridtolerance="10000" guidetolerance="10" objecttolerance="10" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.35" inkscape:cx="375" inkscape:cy="520" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="826" inkscape:window-height="622" inkscape:window-x="5" inkscape:window-y="73"/>
- <metadata id="metadata5565">
- <rdf:RDF>
- <cc:Work rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-241.214, -213.501)">
- <g id="g5542" transform="translate(-505.802, 139.945)">
- <rect y="74.055664" x="769.73621" height="242.43661" width="10.101525" id="rect4253" style="opacity: 0.535519; fill: rgb(102, 102, 102); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;"/>
- <g transform="matrix(-1, 0, 0, 1, 1549.23, 0)" id="g5232">
- <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5226" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
- <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5228" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
- </g>
- <g transform="matrix(-1, 0, 0, 1, 1549.25, 32.9924)" id="g5236">
- <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5238" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
- <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5240" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
- </g>
- <g transform="translate(-0.48229, 0.313456)" id="g5242">
- <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5244" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
- <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5246" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
- </g>
- <g transform="translate(-0.50263, 33.3059)" id="g5248">
- <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5250" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
- <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5252" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
- </g>
- <path transform="translate(-3.01015, 3.03046)" d="M 776.80727 152.84756 A 7.0710678 12.12183 0 1 1 762.66514,152.84756 A 7.0710678 12.12183 0 1 1 776.80727 152.84756 z" sodipodi:ry="12.12183" sodipodi:rx="7.0710678" sodipodi:cy="152.84756" sodipodi:cx="769.73621" id="path5254" style="opacity: 1; fill: rgb(128, 128, 128); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" sodipodi:type="arc"/>
- <path transform="translate(11.1117, -46.467)" d="M 776.80727 152.84756 A 7.0710678 12.12183 0 1 1 762.66514,152.84756 A 7.0710678 12.12183 0 1 1 776.80727 152.84756 z" sodipodi:ry="12.12183" sodipodi:rx="7.0710678" sodipodi:cy="152.84756" sodipodi:cx="769.73621" id="path5256" style="opacity: 1; fill: rgb(128, 128, 128); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" sodipodi:type="arc"/>
- <path transform="translate(11.132, 3.03045)" d="M 776.80727 152.84756 A 7.0710678 12.12183 0 1 1 762.66514,152.84756 A 7.0710678 12.12183 0 1 1 776.80727 152.84756 z" sodipodi:ry="12.12183" sodipodi:rx="7.0710678" sodipodi:cy="152.84756" sodipodi:cx="769.73621" id="path5258" style="opacity: 1; fill: rgb(128, 128, 128); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" sodipodi:type="arc"/>
- </g>
- </g>
-</svg>
\ No newline at end of file
--- a/src/tools/visualizer/visualizer/resource/bobocal_Yellow_Bus.svg Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0" width="993.7254" height="310.89276" id="svg2160">
- <defs id="defs2162"/>
- <g transform="translate(-31.7463, -366.985)" id="layer1">
- <g id="g2386">
- <path d="M 32.325515,677.29858 L 1024.8925,677.29858" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 1.15842px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1;" id="path2175"/>
- <path d="M 268.79664,628.66538 A 35.70126,35.70126 0 1 1 273.83521,598.26515 L 239.54393,608.19934 z" transform="translate(34.5496)" style="opacity: 0; fill: rgb(230, 230, 230); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path2177"/>
- <path d="M 89.0625,367.875 C 69.163607,367.875 53.15625,383.75548 53.15625,403.46875 L 53.15625,609.15625 C 53.15625,628.86953 69.163611,644.75 89.0625,644.75 L 975.40625,644.75 C 995.30514,644.75 1011.3125,628.86955 1011.3125,609.15625 L 1011.3125,403.46875 C 1011.3125,402.85271 1011.3121,402.23319 1011.2813,401.625 L 1011.2813,552 C 1011.2805,553.76879 1009.8625,555.1875 1008.0938,555.1875 L 990.90625,555.1875 C 989.13747,555.18752 987.6875,553.76879 987.6875,552 L 987.6875,399.5625 C 987.6875,397.79372 989.13746,396.375 990.90625,396.375 L 1008.0938,396.375 C 1009.3388,396.375 1010.3796,397.08915 1010.9063,398.125 C 1008.321,380.9619 993.47184,367.875 975.40625,367.875 L 89.0625,367.875 z M 846,388.46875 L 897.875,388.46875 C 898.5113,388.46875 899.11956,388.53428 899.71875,388.65625 C 900.30819,388.77624 900.8956,388.96112 901.4375,389.1875 C 901.44596,389.19107 901.4603,389.18391 901.46875,389.1875 C 902.01063,389.41591 902.51759,389.70788 903,390.03125 C 903.97724,390.69034 904.84091,391.55401 905.5,392.53125 C 905.82337,393.01366 906.11534,393.52062 906.34375,394.0625 C 906.34734,394.07095 906.34018,394.08529 906.34375,394.09375 C 906.57013,394.63565 906.75501,395.22307 906.875,395.8125 C 906.9024,395.94709 906.9159,396.08303 906.9375,396.21875 C 907.6293,391.82302 911.40379,388.46876 916,388.46875 L 967.875,388.46875 C 972.96536,388.46875 977.06251,392.56592 977.0625,397.65625 L 977.0625,616.53125 C 977.06251,621.62157 972.96535,625.71873 967.875,625.71875 L 916,625.71875 C 911.38062,625.71872 907.57016,622.36596 906.90625,617.9375 C 906.87063,618.14482 906.85874,618.35754 906.8125,618.5625 C 906.69252,619.09427 906.55109,619.63312 906.34375,620.125 C 906.23319,620.38729 906.10226,620.65719 905.96875,620.90625 C 905.96211,620.9185 905.94419,620.92528 905.9375,620.9375 C 905.7964,621.19791 905.66477,621.44319 905.5,621.6875 C 905.00568,622.42043 904.39885,623.06421 903.71875,623.625 C 902.58525,624.55966 901.21674,625.22631 899.71875,625.53125 C 899.11956,625.65323 898.51129,625.71875 897.875,625.71875 L 846,625.71875 C 845.37436,625.71875 844.74612,625.64927 844.15625,625.53125 C 844.14649,625.52926 844.13475,625.53327 844.125,625.53125 C 843.23571,625.35022 842.3994,625.04152 841.625,624.625 C 841.61734,624.62085 841.6014,624.62917 841.59375,624.625 C 841.08026,624.34677 840.60429,623.99242 840.15625,623.625 C 840.15031,623.62011 840.13092,623.62991 840.125,623.625 C 839.66523,623.24588 839.28415,622.83582 838.90625,622.375 C 838.71932,622.1483 838.53977,621.93181 838.375,621.6875 C 838.205,621.43544 838.05102,621.17541 837.90625,620.90625 C 837.76515,620.64585 837.64716,620.39998 837.53125,620.125 C 837.29555,619.56583 837.12204,618.98496 837,618.375 C 836.88198,617.78513 836.8125,617.15689 836.8125,616.53125 L 836.8125,397.65625 C 836.8125,397.01995 836.87803,396.41169 837,395.8125 C 837.06297,395.50315 837.12571,395.20327 837.21875,394.90625 C 837.30505,394.62758 837.41993,394.36021 837.53125,394.09375 C 837.53493,394.08503 837.52755,394.07121 837.53125,394.0625 C 837.64716,393.78752 837.76515,393.54165 837.90625,393.28125 C 838.05132,393.01352 838.20493,392.75069 838.375,392.5 C 838.53977,392.25569 838.71932,392.0392 838.90625,391.8125 C 839.6626,390.89524 840.56851,390.12884 841.625,389.5625 C 841.8854,389.4214 842.13127,389.30341 842.40625,389.1875 C 842.89813,388.98016 843.43698,388.83873 843.96875,388.71875 C 844.61866,388.57397 845.30518,388.46875 846,388.46875 z M 169.15625,389.03125 L 272.09375,389.03125 C 277.1841,389.03125 281.28125,393.12841 281.28125,398.21875 L 281.28125,464.53125 C 281.28124,469.62158 277.18409,473.71875 272.09375,473.71875 L 169.15625,473.71875 C 164.06591,473.71876 159.96875,469.62159 159.96875,464.53125 L 159.96875,398.21875 C 159.96875,393.12839 164.06591,389.03125 169.15625,389.03125 z M 305.3125,389.03125 L 408.28125,389.03125 C 413.37158,389.03125 417.46875,393.12841 417.46875,398.21875 L 417.46875,464.53125 C 417.46876,469.62158 413.37159,473.71875 408.28125,473.71875 L 305.3125,473.71875 C 300.22218,473.71876 296.125,469.62159 296.125,464.53125 L 296.125,398.21875 C 296.125,393.12839 300.22216,389.03125 305.3125,389.03125 z M 441.46875,389.03125 L 544.4375,389.03125 C 549.52786,389.03125 553.625,393.12841 553.625,398.21875 L 553.625,464.53125 C 553.62501,469.62158 549.52784,473.71875 544.4375,473.71875 L 441.46875,473.71875 C 436.37843,473.71876 432.28125,469.62159 432.28125,464.53125 L 432.28125,398.21875 C 432.28125,393.12839 436.37841,389.03125 441.46875,389.03125 z M 577.65625,389.03125 L 680.59375,389.03125 C 685.68408,389.03125 689.78125,393.12841 689.78125,398.21875 L 689.78125,464.53125 C 689.78123,469.62158 685.68409,473.71875 680.59375,473.71875 L 577.65625,473.71875 C 572.56589,473.71876 568.4375,469.62159 568.4375,464.53125 L 568.4375,398.21875 C 568.4375,393.12839 572.56591,389.03125 577.65625,389.03125 z M 713.8125,389.03125 L 816.78125,389.03125 C 821.87158,389.03125 825.96875,393.12841 825.96875,398.21875 L 825.96875,464.53125 C 825.96873,469.62158 821.87159,473.71875 816.78125,473.71875 L 713.8125,473.71875 C 708.72214,473.71876 704.625,469.62159 704.625,464.53125 L 704.625,398.21875 C 704.625,393.12839 708.72216,389.03125 713.8125,389.03125 z " style="fill: rgb(255, 255, 0); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77992; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect3179"/>
- <path d="M 177.12517,635.35797 A 27.063858,27.063858 0 1 1 229.40853,635.35797" transform="matrix(2.19149, 0, 0, 2.19149, -207.641, -748.676)" style="opacity: 1; fill: rgb(77, 77, 77); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 2.00004; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3167"/>
- <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(1.80851, 0, 0, 1.80851, -129.794, -508.03)" style="opacity: 1; fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3152"/>
- <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(0.787234, 0, 0, 0.787234, 77.7979, 133.692)" style="opacity: 1; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3156"/>
- <path d="M 268.79664,628.66538 A 35.70126,35.70126 0 1 1 273.83521,598.26515 L 239.54393,608.19934 z" transform="translate(560.207)" style="opacity: 0; fill: rgb(230, 230, 230); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3169"/>
- <path d="M 177.12517,635.35797 A 27.063858,27.063858 0 1 1 229.40853,635.35797" transform="matrix(2.19149, 0, 0, 2.19149, 318.017, -748.676)" style="opacity: 1; fill: rgb(77, 77, 77); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 2.00004; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3171"/>
- <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(1.80851, 0, 0, 1.80851, 395.864, -508.03)" style="opacity: 1; fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3173"/>
- <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(0.787234, 0, 0, 0.787234, 603.456, 133.692)" style="opacity: 1; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3175"/>
- <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="159.95827" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect3181"/>
- <rect width="23.578625" height="158.81502" rx="3.1927617" ry="3.1927617" x="987.69922" y="396.37573" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.00874; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4170"/>
- <rect width="40.307938" height="41.459484" rx="4.8945279" ry="5.6405392" x="980.63293" y="608.1994" style="opacity: 1; fill: rgb(40, 11, 11); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4176"/>
- <rect width="114.01376" height="41.459484" rx="4.8945279" ry="5.6405392" x="47.217747" y="608.1994" style="opacity: 1; fill: rgb(40, 11, 11); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4178"/>
- <rect width="161.23149" height="78.312439" rx="7.9438462" ry="7.9438462" x="499.61023" y="560.98157" style="opacity: 1; fill: none; fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4184"/>
- <rect width="161.23149" height="78.312439" rx="7.9438462" ry="7.9438462" x="330.31717" y="560.98157" style="opacity: 1; fill: none; fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4186"/>
- <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="296.12302" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2197"/>
- <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="432.28775" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2199"/>
- <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="568.45251" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2201"/>
- <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="704.61719" y="388.48038" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2203"/>
- <g transform="translate(-0.000273234, 0.000265655)" id="g2378">
- <g id="g2370">
- <path d="M 915.98701,388.48039 C 910.89667,388.48039 906.79951,392.57753 906.79951,397.66789 L 906.79951,616.54289 C 906.79951,621.63323 910.89665,625.73036 915.98701,625.73039 L 967.86201,625.73039 C 972.95235,625.73039 977.04952,621.63321 977.04951,616.54289 L 977.04951,397.66789 C 977.04951,392.57755 972.95237,388.48039 967.86201,388.48039 L 915.98701,388.48039 z M 924.04951,397.69914 L 960.95576,397.69914 C 966.04613,397.69914 970.14326,401.7963 970.14326,406.88664 L 970.14326,519.79289 C 970.14327,524.8832 966.0461,528.98039 960.95576,528.98039 L 924.04951,528.98039 C 918.95915,528.98041 914.86201,524.88323 914.86201,519.79289 L 914.86201,406.88664 C 914.86201,401.79632 918.95917,397.69914 924.04951,397.69914 z " style="fill: rgb(255, 255, 0); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path2351"/>
- <rect width="55.279369" height="131.2885" rx="9.1883392" ry="9.1883392" x="914.87238" y="397.70074" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2353"/>
- </g>
- <g id="g2374">
- <path d="M 845.9886,388.48039 C 840.89826,388.48039 836.8011,392.57753 836.8011,397.66789 L 836.8011,616.54289 C 836.8011,621.63323 840.89824,625.73036 845.9886,625.73039 L 897.8636,625.73039 C 902.95394,625.73039 907.05111,621.63321 907.0511,616.54289 L 907.0511,397.66789 C 907.0511,392.57755 902.95396,388.48039 897.8636,388.48039 L 845.9886,388.48039 z M 854.0511,397.69914 L 890.95735,397.69914 C 896.04772,397.69914 900.14485,401.7963 900.14485,406.88664 L 900.14485,519.79289 C 900.14486,524.8832 896.04769,528.98039 890.95735,528.98039 L 854.0511,528.98039 C 848.96074,528.98041 844.8636,524.88323 844.8636,519.79289 L 844.8636,406.88664 C 844.8636,401.79632 848.96076,397.69914 854.0511,397.69914 z " style="fill: rgb(255, 255, 0); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path2284"/>
- <rect width="55.279369" height="131.2885" rx="9.1883392" ry="9.1883392" x="844.87396" y="397.70074" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2286"/>
- </g>
- </g>
- </g>
- </g>
-</svg>
\ No newline at end of file
--- a/src/tools/visualizer/visualizer/resource/thilakarathna_Bus_Halt.svg Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="178.37129" height="264.19806" id="svg6213" sodipodi:version="0.32" inkscape:version="0.45" version="1.0" sodipodi:docbase="/home/fahad/Desktop" sodipodi:docname="thilakarathna_Bus_Halt.svg" inkscape:export-filename="/home/fahad/Desktop/Bus_Halt.png" inkscape:export-xdpi="150" inkscape:export-ydpi="150" inkscape:output_extension="org.inkscape.output.svg.inkscape" sodipodi:modified="TRUE">
- <defs id="defs6215">
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient5498" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.83731, 0, 0, 0.83731, 122.117, -209.238)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" id="linearGradient5456">
- <stop style="stop-color: rgb(0, 255, 255); stop-opacity: 1;" offset="0" id="stop5458"/>
- <stop style="stop-color: rgb(0, 255, 255); stop-opacity: 0;" offset="1" id="stop5460"/>
- </linearGradient>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient5496" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.508315, 0, 0, 0.508315, 196.577, -737.854)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6269" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6282" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6312" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6314" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6331" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6344" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6373" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6375" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient1928" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient1941" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient2296" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient2312" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
- </defs>
- <sodipodi:namedview inkscape:document-units="mm" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.86831672" inkscape:cx="303.71381" inkscape:cy="154.70921" inkscape:current-layer="layer1" id="namedview6217" inkscape:window-width="872" inkscape:window-height="622" inkscape:window-x="25" inkscape:window-y="49"/>
- <metadata id="metadata6219">
- <rdf:RDF>
- <cc:Work rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
- <dc:title>Bus Halt</dc:title>
- <dc:date>07 th June 2008</dc:date>
- <dc:creator>
- <cc:Agent>
- <dc:title>Kenneth Thilakarathna - UCSC - LK</dc:title>
- </cc:Agent>
- </dc:creator>
- <cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/>
- <dc:subject>
- <rdf:Bag>
- <rdf:li>bus-stop</rdf:li>
- <rdf:li>bus-halt</rdf:li>
- <rdf:li>bus stop</rdf:li>
- <rdf:li>bus halt</rdf:li>
- </rdf:Bag>
- </dc:subject>
- </cc:Work>
- <cc:License rdf:about="http://web.resource.org/cc/PublicDomain">
- <cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
- <cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
- <cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
- </cc:License>
- </rdf:RDF>
- </metadata>
- <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-323.107, -221.199)">
- <g id="g2314">
- <rect y="305.73587" x="399.18127" height="80.035286" width="59.441422" id="rect5464" style="fill: url(#linearGradient2312) rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 0.87758; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
- <g transform="matrix(0.102737, 0, 0, 0.102737, 376.38, 502.333)" id="g5414">
- <path sodipodi:type="arc" style="fill: rgb(10, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 4.53543; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" id="path5416" sodipodi:cx="600" sodipodi:cy="-992.12592" sodipodi:rx="168" sodipodi:ry="38.267715" d="M 768 -992.12592 A 168 38.267715 0 1 1 432,-992.12592 A 168 38.267715 0 1 1 768 -992.12592 z" transform="translate(-0.5, 5.75398)"/>
- <path style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 86.0315; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 595.50002,-946.1042 C 595.50002,-742.00971 595.50002,-742.00971 595.50002,-742.00971" id="path5418"/>
- </g>
- <g transform="matrix(0.0922068, 0, 0, 0.0922068, 376.384, 471.043)" id="g5420">
- <path sodipodi:type="arc" style="fill: rgb(10, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 4.53543; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" id="path5422" sodipodi:cx="600" sodipodi:cy="-992.12592" sodipodi:rx="168" sodipodi:ry="38.267715" d="M 768 -992.12592 A 168 38.267715 0 1 1 432,-992.12592 A 168 38.267715 0 1 1 768 -992.12592 z" transform="translate(-0.5, 5.75398)"/>
- <path style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 86.0315; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 595.50002,-946.1042 C 595.50002,-742.00971 595.50002,-742.00971 595.50002,-742.00971" id="path5424"/>
- </g>
- <g transform="matrix(0.141346, 0, 0, 0.141346, 360.279, 565.272)" id="g5394">
- <path sodipodi:type="arc" style="fill: rgb(10, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 4.53543; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" id="path5390" sodipodi:cx="600" sodipodi:cy="-992.12592" sodipodi:rx="168" sodipodi:ry="38.267715" d="M 768 -992.12592 A 168 38.267715 0 1 1 432,-992.12592 A 168 38.267715 0 1 1 768 -992.12592 z" transform="translate(-0.5, 5.75398)"/>
- <path style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 86.0315; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 595.50002,-946.1042 C 595.50002,-742.00971 595.50002,-742.00971 595.50002,-742.00971" id="path5392"/>
- </g>
- <path sodipodi:end="6.2814937" sodipodi:start="3.1458674" transform="matrix(0.139174, 0, 0, 0.125355, 348.828, 471.175)" d="M -143.99452,-1250.2431 A 600,701.57483 0 0 1 1055.9991,-1248.4308 L 456,-1247.244 z" sodipodi:ry="701.57483" sodipodi:rx="600" sodipodi:cy="-1247.244" sodipodi:cx="456" id="path5398" style="fill: rgb(85, 34, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 86.0315; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" sodipodi:type="arc"/>
- <path id="path5402" d="M 495.51107,320.20041 C 495.51107,479.43124 495.51107,479.43124 495.51107,479.43124" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 11.9325; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
- <path id="path5410" d="M 478.53868,320.4603 C 478.53868,448.7526 478.53868,448.7526 478.53868,448.7526" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 10.7107; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
- <path id="path5412" d="M 462.94693,320.38103 C 462.94693,400.73806 462.94693,400.73806 462.94693,400.73806" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 8.47674; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
- <rect y="321.36346" x="390.69467" height="131.83618" width="97.913445" id="rect5454" style="fill: url(#linearGradient2296) rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 1.44557; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
- <g transform="matrix(0.162414, 0, 0, 0.162414, 396.455, 615.534)" id="g5378">
- <g id="g5366" transform="translate(-556.499, -494.074)">
- <g transform="matrix(0.996807, 0.0798454, -0.0798454, 0.996807, -118.094, -58.9951)" id="g5360">
- <g id="g5341" transform="matrix(0.999743, -0.022669, 0.022669, 0.999743, 34.3179, 14.9971)">
- <path transform="matrix(0.998587, 0.0531485, -0.0531485, 0.998587, -560.394, 98.4307)" d="M 1248,-1479.685 L 1086.5899,-1467.0142 L 963.49616,-1572.1888 L 950.8254,-1733.5989 L 1056,-1856.6927 L 1217.4101,-1869.3634 L 1340.5038,-1764.1888 L 1353.1746,-1602.7788 L 1248,-1479.685 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="true" sodipodi:arg2="1.4924566" sodipodi:arg1="1.0997575" sodipodi:r2="171.14047" sodipodi:r1="211.54124" sodipodi:cy="-1668.1888" sodipodi:cx="1152" sodipodi:sides="8" id="path4558" style="fill: rgb(255, 0, 0);" sodipodi:type="star"/>
- <g transform="matrix(0.998587, 0.0531485, -0.0531485, 0.998587, -79.0917, -38.1975)" id="g5338">
- <path sodipodi:type="star" style="fill: rgb(255, 255, 255);" id="path4566" sodipodi:sides="8" sodipodi:cx="1152" sodipodi:cy="-1668.1888" sodipodi:r1="211.54124" sodipodi:r2="171.14047" sodipodi:arg1="1.0997575" sodipodi:arg2="1.4924566" inkscape:flatsided="true" inkscape:rounded="0" inkscape:randomized="0" d="M 1248,-1479.685 L 1086.5899,-1467.0142 L 963.49616,-1572.1888 L 950.8254,-1733.5989 L 1056,-1856.6927 L 1217.4101,-1869.3634 L 1340.5038,-1764.1888 L 1353.1746,-1602.7788 L 1248,-1479.685 z " transform="matrix(0.928634, 0, 0, 0.928634, -391.436, 43.3049)"/>
- </g>
- </g>
- </g>
- <path id="text5346" d="M 607.79673,-1572.4732 C 610.28949,-1572.4731 612.17962,-1573.021 613.46715,-1574.1167 C 614.75459,-1575.2124 615.39833,-1576.8286 615.39837,-1578.9654 C 615.39833,-1581.0746 614.75459,-1582.6771 613.46715,-1583.7729 C 612.17962,-1584.896 610.28949,-1585.4575 607.79673,-1585.4576 L 599.04458,-1585.4576 L 599.04458,-1572.4732 L 607.79673,-1572.4732 M 608.3309,-1545.6414 C 611.50849,-1545.6414 613.8917,-1546.3125 615.48055,-1547.6548 C 617.09672,-1548.9971 617.90482,-1551.0242 617.90486,-1553.7361 C 617.90482,-1556.3933 617.11041,-1558.3793 615.52164,-1559.6942 C 613.93279,-1561.0364 611.53588,-1561.7076 608.3309,-1561.7076 L 599.04458,-1561.7076 L 599.04458,-1545.6414 L 608.3309,-1545.6414 M 623.0411,-1567.7067 C 626.43782,-1566.7205 629.06757,-1564.8989 630.93037,-1562.2418 C 632.79306,-1559.5846 633.72443,-1556.3248 633.72449,-1552.4623 C 633.72443,-1546.5454 631.72472,-1542.1351 627.72536,-1539.2314 C 623.72589,-1536.3277 617.64458,-1534.8759 609.48142,-1534.8759 L 583.22495,-1534.8759 L 583.22495,-1596.2231 L 606.97494,-1596.2231 C 615.49421,-1596.2231 621.65769,-1594.9356 625.46541,-1592.3607 C 629.30042,-1589.7857 631.21794,-1585.663 631.218,-1579.9926 C 631.21794,-1577.0067 630.51942,-1574.4591 629.12241,-1572.3499 C 627.7253,-1570.268 625.6982,-1568.7202 623.0411,-1567.7067 M 647.32526,-1596.2231 L 663.14489,-1596.2231 L 663.14489,-1559.4476 C 663.14486,-1554.3799 663.96666,-1550.7503 665.61028,-1548.5588 C 667.28125,-1546.3947 669.99318,-1545.3127 673.74609,-1545.3127 C 677.52633,-1545.3127 680.23826,-1546.3947 681.8819,-1548.5588 C 683.55285,-1550.7503 684.38834,-1554.3799 684.38839,-1559.4476 L 684.38839,-1596.2231 L 700.20801,-1596.2231 L 700.20801,-1559.4476 C 700.20795,-1550.7639 698.03019,-1544.2991 693.67471,-1540.0532 C 689.31913,-1535.8072 682.67626,-1533.6842 673.74609,-1533.6842 C 664.84325,-1533.6842 658.21408,-1535.8072 653.85856,-1540.0532 C 649.50302,-1544.2991 647.32525,-1550.7639 647.32526,-1559.4476 L 647.32526,-1596.2231 M 758.39137,-1594.2919 L 758.39137,-1581.3075 C 755.02194,-1582.8141 751.73475,-1583.9509 748.52978,-1584.718 C 745.32473,-1585.4849 742.29777,-1585.8684 739.4489,-1585.8685 C 735.6686,-1585.8684 732.87449,-1585.3479 731.06656,-1584.3071 C 729.25858,-1583.2661 728.3546,-1581.6499 728.35462,-1579.4584 C 728.3546,-1577.8148 728.95725,-1576.5273 730.16258,-1575.596 C 731.39525,-1574.692 733.61411,-1573.9113 736.81915,-1573.2539 L 743.5579,-1571.8979 C 750.37879,-1570.5282 755.22739,-1568.4463 758.10374,-1565.6522 C 760.97998,-1562.8581 762.41813,-1558.8861 762.41818,-1553.7361 C 762.41813,-1546.97 760.40472,-1541.9296 756.37796,-1538.615 C 752.37849,-1535.3278 746.2561,-1533.6842 738.01076,-1533.6842 C 734.12088,-1533.6842 730.21734,-1534.0541 726.30012,-1534.7937 C 722.38287,-1535.5333 718.46563,-1536.629 714.5484,-1538.0809 L 714.5484,-1551.4351 C 718.46563,-1549.3532 722.2459,-1547.7781 725.88922,-1546.7098 C 729.5599,-1545.6688 733.09363,-1545.1483 736.49043,-1545.1483 C 739.94195,-1545.1483 742.5854,-1545.7236 744.42079,-1546.8741 C 746.2561,-1548.0246 747.17377,-1549.6682 747.17381,-1551.8049 C 747.17377,-1553.7224 746.54373,-1555.2017 745.28368,-1556.2426 C 744.05094,-1557.2835 741.57185,-1558.2149 737.8464,-1559.0367 L 731.72399,-1560.3927 C 725.58788,-1561.7076 721.09538,-1563.8031 718.24649,-1566.6795 C 715.42498,-1569.5557 714.01422,-1573.4319 714.01423,-1578.3079 C 714.01422,-1584.4166 715.98654,-1589.1145 719.93118,-1592.4018 C 723.8758,-1595.6889 729.54621,-1597.3325 736.94242,-1597.3326 C 740.31176,-1597.3325 743.77701,-1597.0723 747.33817,-1596.5519 C 750.89926,-1596.0587 754.58365,-1595.3054 758.39137,-1594.2919 M 596.9079,-1489.1017 L 596.9079,-1476.1172 C 593.53848,-1477.6238 590.25129,-1478.7606 587.04631,-1479.5277 C 583.84126,-1480.2947 580.81431,-1480.6782 577.96544,-1480.6782 C 574.18513,-1480.6782 571.39102,-1480.1577 569.58309,-1479.1168 C 567.77511,-1478.0758 566.87113,-1476.4596 566.87115,-1474.2682 C 566.87113,-1472.6246 567.47378,-1471.3371 568.67911,-1470.4057 C 569.91179,-1469.5017 572.13064,-1468.721 575.33568,-1468.0636 L 582.07443,-1466.7076 C 588.89532,-1465.3379 593.74393,-1463.2561 596.62027,-1460.462 C 599.49651,-1457.6678 600.93466,-1453.6958 600.93471,-1448.5459 C 600.93466,-1441.7797 598.92125,-1436.7394 594.89449,-1433.4248 C 590.89503,-1430.1376 584.77263,-1428.494 576.52729,-1428.494 C 572.63742,-1428.494 568.73387,-1428.8638 564.81666,-1429.6034 C 560.8994,-1430.343 556.98216,-1431.4388 553.06493,-1432.8906 L 553.06493,-1446.2449 C 556.98216,-1444.1629 560.76243,-1442.5878 564.40576,-1441.5195 C 568.07644,-1440.4786 571.61017,-1439.9581 575.00696,-1439.9581 C 578.45848,-1439.9581 581.10193,-1440.5333 582.93732,-1441.6839 C 584.77263,-1442.8344 585.69031,-1444.478 585.69035,-1446.6147 C 585.69031,-1448.5322 585.06026,-1450.0114 583.80021,-1451.0524 C 582.56747,-1452.0933 580.08838,-1453.0247 576.36293,-1453.8465 L 570.24053,-1455.2025 C 564.10441,-1456.5173 559.61192,-1458.6129 556.76303,-1461.4892 C 553.94151,-1464.3655 552.53076,-1468.2416 552.53076,-1473.1177 C 552.53076,-1479.2263 554.50307,-1483.9243 558.44772,-1487.2115 C 562.39233,-1490.4987 568.06274,-1492.1423 575.45895,-1492.1423 C 578.82829,-1492.1423 582.29354,-1491.882 585.85471,-1491.3616 C 589.41579,-1490.8685 593.10019,-1490.1152 596.9079,-1489.1017 M 607.5502,-1491.0329 L 664.08995,-1491.0329 L 664.08995,-1479.0757 L 643.75043,-1479.0757 L 643.75043,-1429.6856 L 627.93081,-1429.6856 L 627.93081,-1479.0757 L 607.5502,-1479.0757 L 607.5502,-1491.0329 M 700.24911,-1480.6782 C 695.42786,-1480.6782 691.68867,-1478.8976 689.03155,-1475.3365 C 686.37438,-1471.7754 685.04581,-1466.7624 685.04583,-1460.2976 C 685.04581,-1453.8602 686.37438,-1448.8609 689.03155,-1445.2998 C 691.68867,-1441.7386 695.42786,-1439.9581 700.24911,-1439.9581 C 705.09768,-1439.9581 708.85056,-1441.7386 711.50775,-1445.2998 C 714.16485,-1448.8609 715.49342,-1453.8602 715.49347,-1460.2976 C 715.49342,-1466.7624 714.16485,-1471.7754 711.50775,-1475.3365 C 708.85056,-1478.8976 705.09768,-1480.6782 700.24911,-1480.6782 M 700.24911,-1492.1423 C 710.11065,-1492.1423 717.83555,-1489.3207 723.42383,-1483.6778 C 729.012,-1478.0347 731.80611,-1470.2413 731.80618,-1460.2976 C 731.80611,-1450.3812 729.012,-1442.6015 723.42383,-1436.9585 C 717.83555,-1431.3155 710.11065,-1428.494 700.24911,-1428.494 C 690.41489,-1428.494 682.68999,-1431.3155 677.07438,-1436.9585 C 671.48614,-1442.6015 668.69203,-1450.3812 668.69203,-1460.2976 C 668.69203,-1470.2413 671.48614,-1478.0347 677.07438,-1483.6778 C 682.68999,-1489.3207 690.41489,-1492.1423 700.24911,-1492.1423 M 743.72226,-1491.0329 L 769.97873,-1491.0329 C 777.78578,-1491.0328 783.7712,-1489.2934 787.93503,-1485.8145 C 792.12615,-1482.3629 794.22174,-1477.4321 794.22179,-1471.0221 C 794.22174,-1464.5846 792.12615,-1459.6264 787.93503,-1456.1475 C 783.7712,-1452.6959 777.78578,-1450.9702 769.97873,-1450.9702 L 759.54188,-1450.9702 L 759.54188,-1429.6856 L 743.72226,-1429.6856 L 743.72226,-1491.0329 M 759.54188,-1479.5688 L 759.54188,-1462.4343 L 768.29404,-1462.4343 C 771.36205,-1462.4343 773.73157,-1463.1739 775.4026,-1464.6531 C 777.07355,-1466.1597 777.90905,-1468.2827 777.90909,-1471.0221 C 777.90905,-1473.7614 777.07355,-1475.8707 775.4026,-1477.3499 C 773.73157,-1478.8291 771.36205,-1479.5687 768.29404,-1479.5688 L 759.54188,-1479.5688" style="font-size: 84.1522px; font-style: normal; font-weight: bold; fill: rgb(255, 0, 0); fill-opacity: 1; stroke: none; stroke-width: 1px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; font-family: Bitstream Vera Sans;"/>
- </g>
- <path style="fill: none; fill-opacity: 1; fill-rule: evenodd; stroke: rgb(252, 0, 0); stroke-width: 25.7953; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 115.5,-1811.5058 C 115.5,-842.05694 115.5,-842.05694 115.5,-842.05694" id="path5376"/>
- </g>
- </g>
- </g>
-</svg>
\ No newline at end of file
--- a/src/tools/visualizer/visualizer/svgitem.py Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-import gobject
-import rsvg
-#import cairo
-import goocanvas
-import os.path
-
-
-class SvgItem(goocanvas.ItemSimple):
- # setup our custom properties
- __gproperties__ = {
- 'x': (float, # property type
- 'X', # property nick name
- 'The x coordinate of a SVG image', # property description
- -10e6, # property minimum value
- 10e6, # property maximum value
- 0, # property default value
- gobject.PARAM_READWRITE), # property flags
-
- 'y': (float,
- 'Y',
- 'The y coordinate of a SVG image',
- -10e6,
- 10e6,
- 0,
- gobject.PARAM_READWRITE),
-
- 'width': (float,
- 'Width',
- 'The width of the SVG Image',
- 0,
- 10e6,
- 0,
- gobject.PARAM_READWRITE),
-
- 'height': (float,
- 'Height',
- 'The width of the SVG Image',
- 0,
- 10e6,
- 0,
- gobject.PARAM_READWRITE),
- }
-
- def __init__(self, x, y, rsvg_handle, **kwargs):
- super(SvgItem, self).__init__(**kwargs)
- assert isinstance(rsvg_handle, rsvg.Handle)
- self.x = x
- self.y = y
- self.sx = 1.0
- self.sy = 1.0
- self.handle = rsvg_handle
- self.width = self.handle.props.width
- self.height = self.handle.props.height
- self.custom_width = None
- self.custom_height = None
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'x':
- self.x = value
-
- # make sure we update the display
- self.changed(True)
-
- elif pspec.name == 'y':
- self.y = value
-
- # make sure we update the display
- self.changed(True)
-
- elif pspec.name == 'width':
- self.custom_width = value
- self._size_changed()
-
- # make sure we update the display
- self.changed(True)
-
- elif pspec.name == 'height':
- self.custom_height = value
- self._size_changed()
-
- # make sure we update the display
- self.changed(True)
-
- else:
- raise AttributeError, 'unknown property %s' % pspec.name
-
- def _size_changed(self):
- if self.custom_width is None and self.custom_height is None:
- self.width = self.handle.props.width
- self.height = self.handle.props.height
- self.sx = 1.0
- self.sy = 1.0
- elif self.custom_width is not None and self.custom_height is None:
- self.width = self.custom_width
- self.sx = self.custom_width / self.handle.props.width
- self.sy = self.sx
- self.height = self.handle.props.height*self.sy
- elif self.custom_width is None and self.custom_height is not None:
- self.height = self.custom_height
- self.sy = self.custom_height / self.handle.props.height
- self.sx = self.sy
- self.width = self.handle.props.width*self.sx
- else:
- self.width = self.custom_width
- self.height = self.custom_height
- self.sx = self.custom_width / self.handle.props.width
- self.sy = self.custom_height / self.handle.props.height
-
- def do_get_property(self, pspec):
- if pspec.name == 'x':
- return self.x
-
- elif pspec.name == 'y':
- return self.y
-
- elif pspec.name == 'width':
- self.width = self.handle.props.width
- self.height = self.handle.props.height
-
- return self.width
-
- elif pspec.name == 'height':
- return self.height
-
- else:
- raise AttributeError, 'unknown property %s' % pspec.name
-
- def do_simple_paint(self, cr, bounds):
- cr.translate(self.x, self.y)
- cr.scale(self.sx, self.sy)
- self.handle.render_cairo(cr)
-
- def do_simple_update(self, cr):
- self.bounds_x1 = float(self.x)
- self.bounds_y1 = float(self.y)
- self.bounds_x2 = float(self.x + self.width)
- self.bounds_y2 = float(self.y + self.height)
-
- def do_simple_is_item_at(self, x, y, cr, is_pointer_event):
- if ((x < self.x) or (x > self.x + self.width)) or ((y < self.y) or (y > self.y + self.height)):
- return False
- else:
- return True
-
-
-_rsvg_cache = dict()
-
-def rsvg_handle_factory(base_file_name):
- try:
- return _rsvg_cache[base_file_name]
- except KeyError:
- full_path = os.path.join(os.path.dirname(__file__), 'resource', base_file_name)
- rsvg_handle = rsvg.Handle(full_path)
- _rsvg_cache[base_file_name] = rsvg_handle
- return rsvg_handle
-
--- a/src/tools/visualizer/wscript Thu Mar 24 10:32:51 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-def build(bld):
- headers = bld.new_task_gen('ns3header')
- headers.module = 'visualizer'
- headers.source = [
- ]
-
- module = bld.create_ns3_module('visualizer', ['core'])
- if not bld.env['ENABLE_PYTHON_BINDINGS']:
- return
-
- module.features.append('pyembed')
- module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
- module.includes = '.'
-
- if bld.env['ENABLE_PYTHON_BINDINGS']:
- module.source = [
- 'model/pyviz.cc',
- 'model/visual-simulator-impl.cc',
- ]
- headers.source.append('model/pyviz.h')
- else:
- module.source = [
- ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/doc/readme.txt Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,9 @@
+NS-3 PyViz is a live simulation visualizer, meaning that it uses no
+trace files. It can be most useful for debugging purposes, i.e. to
+figure out if mobility models are what you expect, where packets are
+being dropped, etc. There's also a builtin interactive python console
+that can be used to debug the state of the running objects. Although
+it is mostly written in Python, it works both with Python and pure C++
+simulations.
+
+For more information, see http://www.nsnam.org/wiki/index.php/PyViz
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/examples/readme.txt Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,3 @@
+For activating the visualizer, with any example, just pass the option
+--SimulatorImplementationType=ns3::VisualSimulatorImpl to it, assuming
+the script uses ns-3's command line parser (class CommandLine).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/model/pyviz.cc Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,1406 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INESC Porto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ */
+
+#include <stdlib.h>
+#include "pyviz.h"
+#include "ns3/simulator.h"
+#include "ns3/config.h"
+#include "ns3/node-list.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/ppp-header.h"
+#include "ns3/wifi-mac-header.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/log.h"
+#include "ns3/abort.h"
+
+#include "visual-simulator-impl.h"
+
+#include <sstream>
+
+NS_LOG_COMPONENT_DEFINE ("PyViz");
+#define NUM_LAST_PACKETS 10
+
+static
+std::vector<std::string>
+PathSplit (std::string str)
+{
+ std::vector<std::string> results;
+ size_t cutAt;
+ while ((cutAt = str.find_first_of('/')) != str.npos)
+ {
+ if(cutAt > 0)
+ {
+ results.push_back(str.substr(0,cutAt));
+ }
+ str = str.substr(cutAt+1);
+ }
+ if (str.length() > 0)
+ {
+ results.push_back(str);
+ }
+ return results;
+}
+
+
+namespace ns3 {
+
+static PyViz* g_visualizer = NULL;
+
+
+
+struct PyVizPacketTag : public Tag
+{
+ static TypeId GetTypeId (void);
+ virtual TypeId GetInstanceTypeId (void) const;
+ virtual uint32_t GetSerializedSize (void) const;
+ virtual void Serialize (TagBuffer buf) const;
+ virtual void Deserialize (TagBuffer buf);
+ virtual void Print (std::ostream &os) const;
+ PyVizPacketTag ();
+
+ uint32_t m_packetId;
+};
+
+
+TypeId
+PyVizPacketTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::PyVizPacketTag")
+ .SetParent<Tag> ()
+ .AddConstructor<PyVizPacketTag> ()
+ ;
+ return tid;
+}
+TypeId
+PyVizPacketTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+uint32_t
+PyVizPacketTag::GetSerializedSize (void) const
+{
+ return 4;
+}
+void
+PyVizPacketTag::Serialize (TagBuffer buf) const
+{
+ buf.WriteU32 (m_packetId);
+}
+void
+PyVizPacketTag::Deserialize (TagBuffer buf)
+{
+ m_packetId = buf.ReadU32 ();
+}
+void
+PyVizPacketTag::Print (std::ostream &os) const
+{
+ os << "PacketId=" << m_packetId;
+}
+PyVizPacketTag::PyVizPacketTag ()
+ : Tag ()
+{}
+
+
+
+PyViz::PyViz ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ NS_ASSERT (g_visualizer == NULL);
+ g_visualizer = this;
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/MacTx",
+ MakeCallback (&PyViz::TraceNetDevTxWifi, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx",
+ MakeCallback (&PyViz::TraceNetDevRxWifi, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacTx",
+ MakeCallback (&PyViz::TraceNetDevTxCsma, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacRx",
+ MakeCallback (&PyViz::TraceNetDevRxCsma, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacPromiscRx",
+ MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop",
+ MakeCallback (&PyViz::TraceDevQueueDrop, this));
+
+ Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Drop",
+ MakeCallback (&PyViz::TraceIpv4Drop, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/MacTx",
+ MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/MacRx",
+ MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Tx",
+ MakeCallback (&PyViz::TraceNetDevTxWimax, this));
+
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Rx",
+ MakeCallback (&PyViz::TraceNetDevRxWimax, this));
+
+}
+
+void
+PyViz::RegisterCsmaLikeDevice (std::string const &deviceTypeName)
+{
+ TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
+
+ std::ostringstream sstream;
+ sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/MacTx";
+ Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxCsma, this));
+
+ sstream.str ("");
+ sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
+ Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxCsma, this));
+
+ sstream.str ("");
+ sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/PromiscRx";
+ Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
+}
+
+void
+PyViz::RegisterWifiLikeDevice (std::string const &deviceTypeName)
+{
+ TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
+
+ std::ostringstream sstream;
+ sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Tx";
+ Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxWifi, this));
+
+ sstream.str ("");
+ sstream <<"/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
+ Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxWifi, this));
+}
+
+void
+PyViz::RegisterPointToPointLikeDevice (std::string const &deviceTypeName)
+{
+ TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
+
+ std::ostringstream sstream;
+ sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
+ Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
+
+ sstream.str ("");
+ sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
+ Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
+}
+
+void
+PyViz::SetPacketCaptureOptions (uint32_t nodeId, PacketCaptureOptions options)
+{
+ NS_LOG_DEBUG (" SetPacketCaptureOptions " << nodeId
+ << " PacketCaptureOptions (headers size = " << options.headers.size ()
+ << " mode = " << options.mode << " numLastPackets = " << options.numLastPackets
+ << ")");
+ m_packetCaptureOptions[nodeId] = options;
+}
+
+void
+PyViz::RegisterDropTracePath (std::string const &tracePath)
+{
+ Config::Connect (tracePath, MakeCallback (&PyViz::TraceDevQueueDrop, this));
+}
+
+PyViz::~PyViz ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ NS_ASSERT (g_visualizer == this);
+ g_visualizer = NULL;
+}
+
+void PyViz::DoPause (std::string const &message)
+{
+ m_pauseMessages.push_back (message);
+ m_stop = true;
+ NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": Have "
+ << g_visualizer->m_pauseMessages.size () << " pause messages");
+}
+
+void PyViz::Pause (std::string const &message)
+{
+ NS_ASSERT (g_visualizer);
+ g_visualizer->DoPause (message);
+}
+
+std::vector<std::string>
+PyViz::GetPauseMessages () const
+{
+ NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": GetPauseMessages: have "
+ << g_visualizer->m_pauseMessages.size () << " pause messages");
+ return m_pauseMessages;
+}
+
+
+void
+PyViz::CallbackStopSimulation ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ Simulator::Stop (Seconds (0)); // Stop right now
+ m_stop = true;
+}
+
+void
+PyViz::SimulatorRunUntil (Time time)
+{
+ NS_LOG_LOGIC ("SimulatorRunUntil " << time << " (now is " << Simulator::Now () << ")");
+
+ m_pauseMessages.clear ();
+ m_transmissionSamples.clear ();
+ m_packetDrops.clear ();
+
+ Time expirationTime = Simulator::Now () - Seconds (10);
+
+ // Clear very old transmission records
+ for (std::map<TxRecordKey, TxRecordValue>::iterator iter = m_txRecords.begin ();
+ iter != m_txRecords.end ();)
+ {
+ if (iter->second.time < expirationTime)
+ {
+ m_txRecords.erase (iter++);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+
+ // Clear very old packets of interest
+ for (std::map<uint32_t, Time>::iterator iter = m_packetsOfInterest.begin ();
+ iter != m_packetsOfInterest.end ();)
+ {
+ if (iter->second < expirationTime)
+ {
+ m_packetsOfInterest.erase (iter++);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+
+ if (Simulator::Now () >= time)
+ {
+ return;
+ }
+ // Schedule a dummy callback function for the target time, to make
+ // sure we stop at the right time. Otherwise, simulations with few
+ // events just appear to "jump" big chunks of time.
+ NS_LOG_LOGIC ("Schedule dummy callback to be called in " << (time - Simulator::Now ()));
+ m_stop = false;
+ Simulator::Cancel (m_stopCallbackEvent);
+ m_stopCallbackEvent = Simulator::Schedule (time - Simulator::Now (), &PyViz::CallbackStopSimulation, this);
+
+ Ptr<SimulatorImpl> impl = Simulator::GetImplementation ();
+ Ptr<VisualSimulatorImpl> visualImpl = DynamicCast<VisualSimulatorImpl> (impl);
+ if (visualImpl)
+ {
+ visualImpl->RunRealSimulator ();
+ }
+ else
+ {
+ impl->Run ();
+ }
+}
+
+bool PyViz::TransmissionSampleKey::operator < (PyViz::TransmissionSampleKey const &other) const
+{
+ if (this->transmitter < other.transmitter)
+ {
+ return true;
+ }
+ if (this->transmitter != other.transmitter)
+ {
+ return false;
+ }
+ if (this->receiver < other.receiver)
+ {
+ return true;}
+ if (this->receiver != other.receiver)
+ {
+ return false;
+ }
+ if (this->channel < other.channel)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PyViz::TransmissionSampleKey::operator == (PyViz::TransmissionSampleKey const &other) const
+{
+ bool retval = (transmitter == other.transmitter) &&
+ (receiver == other.receiver) &&
+ (channel == other.channel);
+ return retval;
+}
+
+
+PyViz::NetDeviceStatistics &
+PyViz::FindNetDeviceStatistics (int node, int interface)
+{
+ std::map<uint32_t, std::vector<NetDeviceStatistics> >::iterator nodeStatsIter = m_nodesStatistics.find (node);
+ std::vector<NetDeviceStatistics> *stats;
+ if (nodeStatsIter == m_nodesStatistics.end ())
+ {
+ stats = &m_nodesStatistics[node];
+ stats->resize (NodeList::GetNode (node)->GetNDevices ());
+ }
+ else
+ {
+ stats = &(nodeStatsIter->second);
+ }
+ NetDeviceStatistics &devStats = (*stats)[interface];
+ return devStats;
+}
+
+bool PyViz::GetPacketCaptureOptions (uint32_t nodeId, const PacketCaptureOptions **outOptions) const
+{
+ std::map<uint32_t, PacketCaptureOptions>::const_iterator iter = m_packetCaptureOptions.find (nodeId);
+ if (iter == m_packetCaptureOptions.end ())
+ {
+ return false;
+ }
+ else
+ {
+ *outOptions = &iter->second;
+ return true;
+ }
+}
+
+bool PyViz::FilterPacket (Ptr<const Packet> packet, const PacketCaptureOptions &options)
+{
+ switch (options.mode)
+ {
+ case PACKET_CAPTURE_DISABLED:
+ return false;
+
+ case PACKET_CAPTURE_FILTER_HEADERS_OR:
+ {
+ PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
+ while (metadataIterator.HasNext ())
+ {
+ PacketMetadata::Item item = metadataIterator.Next ();
+ if (options.headers.find (item.tid) != options.headers.end ())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ case PACKET_CAPTURE_FILTER_HEADERS_AND:
+ {
+ std::set<TypeId> missingHeaders (options.headers);
+ PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
+ while (metadataIterator.HasNext ())
+ {
+ PacketMetadata::Item item = metadataIterator.Next ();
+ std::set<TypeId>::iterator missingIter = missingHeaders.find (item.tid);
+ if (missingIter != missingHeaders.end ())
+ {
+ missingHeaders.erase (missingIter);
+ }
+ }
+ if (missingHeaders.size () == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ default:
+ NS_FATAL_ERROR ("should not be reached");
+ return false;
+ }
+}
+
+void
+PyViz::TraceDevQueueDrop (std::string context, Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (context << packet->GetUid ());
+ std::vector<std::string> splitPath = PathSplit (context);
+ int nodeIndex = atoi (splitPath[1].c_str ());
+ Ptr<Node> node = NodeList::GetNode (nodeIndex);
+
+ if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
+ {
+ // if the transmitting node is not "of interest", we still
+ // record the transmission if it is a packet of interest.
+ if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
+ {
+ NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
+ return;
+ }
+ }
+
+ // ---- "last packets"
+ const PacketCaptureOptions *captureOptions;
+ if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
+ {
+ LastPacketsSample &last = m_lastPackets[nodeIndex];
+ PacketSample lastPacket;
+ lastPacket.time = Simulator::Now ();
+ lastPacket.packet = packet->Copy ();
+ lastPacket.device = NULL;
+ last.lastDroppedPackets.push_back (lastPacket);
+ while (last.lastDroppedPackets.size () > captureOptions->numLastPackets)
+ {
+ last.lastDroppedPackets.erase (last.lastDroppedPackets.begin ());
+ }
+ }
+
+ std::map<Ptr<Node>, uint32_t>::iterator iter = m_packetDrops.find (node);
+ if (iter == m_packetDrops.end ())
+ {
+ m_packetDrops[node] = packet->GetSize ();
+ }
+ else
+ {
+ iter->second += packet->GetSize ();
+ }
+}
+
+void
+PyViz::TraceIpv4Drop (std::string context, ns3::Ipv4Header const &hdr, Ptr<const Packet> packet,
+ ns3::Ipv4L3Protocol::DropReason reason, Ptr<Ipv4> dummy_ipv4, uint32_t interface)
+{
+ Ptr<Packet> packetCopy = packet->Copy ();
+ packetCopy->AddHeader (hdr);
+ TraceDevQueueDrop (context, packetCopy);
+}
+
+
+ // --------- TX device tracing -------------------
+
+void
+PyViz::TraceNetDevTxCommon (std::string const &context, Ptr<const Packet> packet,
+ Mac48Address const &destinationAddress)
+{
+ NS_LOG_FUNCTION (context << packet->GetUid () << *packet);
+
+ std::vector<std::string> splitPath = PathSplit (context);
+ int nodeIndex = atoi (splitPath[1].c_str ());
+ int devIndex = atoi (splitPath[3].c_str ());
+ Ptr<Node> node = NodeList::GetNode (nodeIndex);
+ Ptr<NetDevice> device = node->GetDevice (devIndex);
+
+ // ---- statistics
+ NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
+ ++stats.transmittedPackets;
+ stats.transmittedBytes += packet->GetSize ();
+
+ // ---- "last packets"
+ const PacketCaptureOptions *captureOptions;
+ if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
+ {
+ LastPacketsSample &last = m_lastPackets[nodeIndex];
+ TxPacketSample lastPacket;
+ lastPacket.time = Simulator::Now ();
+ lastPacket.packet = packet->Copy ();
+ lastPacket.device = device;
+ lastPacket.to = destinationAddress;
+ last.lastTransmittedPackets.push_back (lastPacket);
+ while (last.lastTransmittedPackets.size () > captureOptions->numLastPackets)
+ {
+ last.lastTransmittedPackets.erase (last.lastTransmittedPackets.begin ());
+ }
+ }
+
+ // ---- transmissions records
+
+ if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
+ {
+ // if the transmitting node is not "of interest", we still
+ // record the transmission if it is a packet of interest.
+ if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
+ {
+ NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
+ return;
+ }
+ }
+ else
+ {
+ // We will follow this packet throughout the network.
+ m_packetsOfInterest[packet->GetUid ()] = Simulator::Now ();
+ }
+
+ TxRecordValue record = { Simulator::Now (), node, false };
+ if (destinationAddress == device->GetBroadcast ())
+ {
+ record.isBroadcast = true;
+ }
+
+ m_txRecords[TxRecordKey (device->GetChannel (), packet->GetUid ())] = record;
+
+ PyVizPacketTag tag;
+ //packet->RemovePacketTag (tag);
+ tag.m_packetId = packet->GetUid ();
+ packet->AddByteTag (tag);
+}
+
+void
+PyViz::TraceNetDevTxWifi (std::string context, Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (context << packet->GetUid () << *packet);
+
+ /*
+ * To DS From DS Address 1 Address 2 Address 3 Address 4
+ *----------------------------------------------------------------------
+ * 0 0 Destination Source BSSID N/A
+ * 0 1 Destination BSSID Source N/A
+ * 1 0 BSSID Source Destination N/A
+ * 1 1 Receiver Transmitter Destination Source
+ */
+ WifiMacHeader hdr;
+ NS_ABORT_IF (packet->PeekHeader (hdr) == 0);
+ Mac48Address destinationAddress;
+ if (hdr.IsToDs () && !hdr.IsFromDs ())
+ {
+ destinationAddress = hdr.GetAddr3 ();
+ }
+ else if (!hdr.IsToDs () && hdr.IsFromDs ())
+ {
+ destinationAddress = hdr.GetAddr1 ();
+ }
+ else if (!hdr.IsToDs () && !hdr.IsFromDs ())
+ {
+ destinationAddress = hdr.GetAddr1 ();
+ }
+ else
+ {
+ destinationAddress = hdr.GetAddr3 ();
+ }
+ TraceNetDevTxCommon (context, packet, destinationAddress);
+}
+
+
+void
+PyViz::TraceNetDevTxCsma (std::string context, Ptr<const Packet> packet)
+{
+ EthernetHeader ethernetHeader;
+ NS_ABORT_IF (packet->PeekHeader (ethernetHeader) == 0);
+ TraceNetDevTxCommon (context, packet, ethernetHeader.GetDestination ());
+}
+
+void
+PyViz::TraceNetDevTxPointToPoint (std::string context, Ptr<const Packet> packet)
+{
+ TraceNetDevTxCommon (context, packet, Mac48Address ());
+}
+
+
+
+
+ // --------- RX device tracing -------------------
+
+void
+PyViz::TraceNetDevRxCommon (std::string const &context, Ptr<const Packet> packet, Mac48Address const &from)
+{
+ uint32_t uid;
+ PyVizPacketTag tag;
+ if (packet->FindFirstMatchingByteTag (tag))
+ {
+ uid = tag.m_packetId;
+ }
+ else
+ {
+ //NS_ASSERT (0);
+ NS_LOG_WARN ("Packet has no byte tag; wimax link?");
+ uid = packet->GetUid ();
+ }
+
+ NS_LOG_FUNCTION (context << uid);
+ std::vector<std::string> splitPath = PathSplit (context);
+ int nodeIndex = atoi (splitPath[1].c_str ());
+ int devIndex = atoi (splitPath[3].c_str ());
+
+ // ---- statistics
+ NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
+ ++stats.receivedPackets;
+ stats.receivedBytes += packet->GetSize ();
+
+ Ptr<Node> node = NodeList::GetNode (nodeIndex);
+ Ptr<NetDevice> device = node->GetDevice (devIndex);
+
+ // ---- "last packets"
+ const PacketCaptureOptions *captureOptions;
+ if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
+ {
+ LastPacketsSample &last = m_lastPackets[nodeIndex];
+ RxPacketSample lastPacket;
+ lastPacket.time = Simulator::Now ();
+ lastPacket.packet = packet->Copy ();
+ lastPacket.device = device;
+ lastPacket.from = from;
+ last.lastReceivedPackets.push_back (lastPacket);
+ while (last.lastReceivedPackets.size () > captureOptions->numLastPackets)
+ {
+ last.lastReceivedPackets.erase (last.lastReceivedPackets.begin ());
+ }
+ }
+
+ // ---- transmissions
+ if (m_packetsOfInterest.find (uid) == m_packetsOfInterest.end ())
+ {
+ NS_LOG_DEBUG ("RX Packet " << uid << " is not of interest");
+ return;
+ }
+
+ Ptr<Channel> channel = device->GetChannel ();
+
+ std::map<TxRecordKey, TxRecordValue>::iterator recordIter =
+ m_txRecords.find (TxRecordKey (channel, uid));
+
+ if (recordIter == m_txRecords.end ())
+ {
+ NS_LOG_DEBUG ("RX Packet " << uid << " was not transmitted?!");
+ return;
+ }
+
+ TxRecordValue &record = recordIter->second;
+
+ if (record.srcNode == node)
+ {
+ NS_LOG_WARN ("Node " << node->GetId () << " receiving back the same packet (UID=" << uid
+ << ") it had previously transmitted, on the same channel!");
+ return;
+ }
+
+ TransmissionSampleKey key = { record.srcNode, node, channel };
+
+#ifdef NS3_LOG_ENABLE
+ NS_LOG_DEBUG("m_transmissionSamples begin:");
+ if (g_log.IsEnabled (ns3::LOG_DEBUG))
+ {
+ for (std::map<TransmissionSampleKey,TransmissionSampleValue>::const_iterator iter
+ = m_transmissionSamples.begin (); iter != m_transmissionSamples.end (); iter++)
+ {
+ NS_LOG_DEBUG(iter->first.transmitter<<"/"<<iter->first.transmitter->GetId () << ", "
+ << iter->first.receiver<<"/"<<iter->first.receiver->GetId ()
+ << ", " << iter->first.channel << " => " << iter->second.bytes << " (@ " << &iter->second << ")");
+ }
+ }
+ NS_LOG_DEBUG("m_transmissionSamples end.");
+#endif
+
+ std::map<TransmissionSampleKey,TransmissionSampleValue>::iterator
+ iter = m_transmissionSamples.find (key);
+
+ if (iter == m_transmissionSamples.end ())
+ {
+ TransmissionSampleValue sample = { packet->GetSize () };
+ NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
+ << key.receiver<<"/"<<key.receiver->GetId()
+ << " channel " << channel << ": " << packet->GetSize ()
+ << " bytes more. => new sample with " << packet->GetSize () << " bytes.");
+ m_transmissionSamples[key] = sample;
+ }
+ else
+ {
+ TransmissionSampleValue &sample = iter->second;
+ NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
+ << key.receiver<<"/"<<key.receiver->GetId()
+ << " channel " << channel << ": " << packet->GetSize ()
+ << " bytes more. => sample " << &sample << " with bytes " << sample.bytes);
+
+ sample.bytes += packet->GetSize ();
+ }
+}
+
+void
+PyViz::TraceNetDevRxWifi (std::string context, Ptr<const Packet> packet)
+{
+ NS_LOG_FUNCTION (context << packet->GetUid ());
+
+
+ /*
+ * To DS From DS Address 1 Address 2 Address 3 Address 4
+ *----------------------------------------------------------------------
+ * 0 0 Destination Source BSSID N/A
+ * 0 1 Destination BSSID Source N/A
+ * 1 0 BSSID Source Destination N/A
+ * 1 1 Receiver Transmitter Destination Source
+ */
+ WifiMacHeader hdr;
+ NS_ABORT_IF (packet->PeekHeader (hdr) == 0);
+ Mac48Address sourceAddress;
+ if (hdr.IsToDs () && !hdr.IsFromDs ())
+ {
+ sourceAddress = hdr.GetAddr2 ();
+ }
+ else if (!hdr.IsToDs () && hdr.IsFromDs ())
+ {
+ sourceAddress = hdr.GetAddr3 ();
+ }
+ else if (!hdr.IsToDs () && !hdr.IsFromDs ())
+ {
+ sourceAddress = hdr.GetAddr2 ();
+ }
+ else
+ {
+ sourceAddress = hdr.GetAddr4 ();
+ }
+
+ TraceNetDevRxCommon (context, packet, sourceAddress);
+}
+
+
+
+void
+PyViz::TraceNetDevRxCsma (std::string context, Ptr<const Packet> packet)
+{
+ EthernetHeader ethernetHeader;
+ NS_ABORT_IF (packet->PeekHeader (ethernetHeader) == 0);
+ TraceNetDevRxCommon (context, packet, ethernetHeader.GetSource ());
+}
+
+void
+PyViz::TraceNetDevRxPointToPoint (std::string context, Ptr<const Packet> packet)
+{
+ TraceNetDevRxCommon (context, packet, Mac48Address ());
+}
+
+void
+PyViz::TraceNetDevPromiscRxCsma (std::string context, Ptr<const Packet> packet)
+{
+ EthernetHeader ethernetHeader;
+ NS_ABORT_IF (packet->PeekHeader (ethernetHeader) == 0);
+
+ NetDevice::PacketType packetType = NetDevice::PACKET_OTHERHOST; // FIXME
+
+ // Other packet types are already being received by
+ // TraceNetDevRxCsma; we don't want to receive them twice.
+ if (packetType == NetDevice::PACKET_OTHERHOST)
+ {
+ TraceNetDevRxCommon (context, packet, ethernetHeader.GetDestination ());
+ }
+}
+
+void
+PyViz::TraceNetDevTxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &destination)
+{
+ NS_LOG_FUNCTION (context);
+ TraceNetDevTxCommon (context, packet, destination);
+}
+
+void
+PyViz::TraceNetDevRxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &source)
+{
+ NS_LOG_FUNCTION (context);
+ TraceNetDevRxCommon (context, packet, source);
+}
+
+
+ // ---------------------
+
+PyViz::TransmissionSampleList
+PyViz::GetTransmissionSamples () const
+{
+ NS_LOG_DEBUG ("GetTransmissionSamples BEGIN");
+ TransmissionSampleList list;
+ for (std::map<TransmissionSampleKey, TransmissionSampleValue>::const_iterator
+ iter = m_transmissionSamples.begin ();
+ iter != m_transmissionSamples.end ();
+ iter++)
+ {
+ TransmissionSample sample;
+ sample.transmitter = iter->first.transmitter;
+ sample.receiver = iter->first.receiver;
+ sample.channel = iter->first.channel;
+ sample.bytes = iter->second.bytes;
+ NS_LOG_DEBUG ("from " << sample.transmitter->GetId() << " to " << sample.receiver->GetId()
+ << ": " << sample.bytes << " bytes.");
+ list.push_back (sample);
+ }
+ NS_LOG_DEBUG ("GetTransmissionSamples END");
+ return list;
+}
+
+PyViz::PacketDropSampleList
+PyViz::GetPacketDropSamples () const
+{
+ NS_LOG_DEBUG ("GetPacketDropSamples BEGIN");
+ PacketDropSampleList list;
+ for (std::map<Ptr<Node>, uint32_t>::const_iterator
+ iter = m_packetDrops.begin ();
+ iter != m_packetDrops.end ();
+ iter++)
+ {
+ PacketDropSample sample;
+ sample.transmitter = iter->first;
+ sample.bytes = iter->second;
+ NS_LOG_DEBUG ("in " << sample.transmitter->GetId()
+ << ": " << sample.bytes << " bytes dropped.");
+ list.push_back (sample);
+ }
+ NS_LOG_DEBUG ("GetPacketDropSamples END");
+ return list;
+}
+
+void
+PyViz::SetNodesOfInterest (std::set<uint32_t> nodes)
+{
+ m_nodesOfInterest = nodes;
+}
+
+std::vector<PyViz::NodeStatistics>
+PyViz::GetNodesStatistics () const
+{
+ std::vector<PyViz::NodeStatistics> retval;
+ for (std::map<uint32_t, std::vector<NetDeviceStatistics> >::const_iterator iter = m_nodesStatistics.begin ();
+ iter != m_nodesStatistics.end (); iter++)
+ {
+ NodeStatistics stats = { iter->first, iter->second };
+ retval.push_back (stats);
+ }
+ return retval;
+}
+
+
+PyViz::LastPacketsSample
+PyViz::GetLastPackets (uint32_t nodeId) const
+{
+ NS_LOG_DEBUG ("GetLastPackets: " << nodeId);
+
+ std::map<uint32_t, LastPacketsSample>::const_iterator
+ iter = m_lastPackets.find(nodeId);
+ if (iter != m_lastPackets.end ())
+ {
+ return iter->second;
+ }
+ else
+ {
+ return LastPacketsSample ();
+ }
+}
+
+
+
+
+
+
+namespace
+{
+ // Adapted from http://en.wikipedia.org/w/index.php?title=Line_clipping&oldid=248609574
+ class FastClipping
+ {
+ public:
+ struct Vector2
+ {
+ double x;
+ double y;
+ };
+
+ Vector2 m_clipMin, m_clipMax;
+
+ struct Line
+ {
+ Vector2 start, end;
+ double dx, dy;
+ };
+
+ private:
+
+ void ClipStartTop (Line &line)
+ {
+ line.start.x += line.dx * (m_clipMin.y - line.start.y) / line.dy;
+ line.start.y = m_clipMin.y;
+ }
+
+ void ClipStartBottom (Line &line)
+ {
+ line.start.x += line.dx * (m_clipMax.y - line.start.y) / line.dy;
+ line.start.y = m_clipMax.y;
+ }
+
+ void ClipStartRight (Line &line)
+ {
+ line.start.y += line.dy * (m_clipMax.x - line.start.x) / line.dx;
+ line.start.x = m_clipMax.x;
+ }
+
+ void ClipStartLeft (Line &line)
+ {
+ line.start.y += line.dy * (m_clipMin.x - line.start.x) / line.dx;
+ line.start.x = m_clipMin.x;
+ }
+
+ void ClipEndTop (Line &line)
+ {
+ line.end.x += line.dx * (m_clipMin.y - line.end.y) / line.dy;
+ line.end.y = m_clipMin.y;
+ }
+
+ void ClipEndBottom (Line &line) {
+ line.end.x += line.dx * (m_clipMax.y - line.end.y) / line.dy;
+ line.end.y = m_clipMax.y;
+ }
+
+ void ClipEndRight (Line &line)
+ {
+ line.end.y += line.dy * (m_clipMax.x - line.end.x) / line.dx;
+ line.end.x = m_clipMax.x;
+ }
+
+ void ClipEndLeft (Line &line)
+ {
+ line.end.y += line.dy * (m_clipMin.x - line.end.x) / line.dx;
+ line.end.x = m_clipMin.x;
+ }
+
+ public:
+ FastClipping (Vector2 clipMin, Vector2 clipMax)
+ : m_clipMin (clipMin), m_clipMax (clipMax)
+ {
+ }
+
+
+ bool ClipLine (Line &line)
+ {
+ uint8_t lineCode = 0;
+
+ if (line.end.y < m_clipMin.y)
+ lineCode |= 8;
+ else if (line.end.y > m_clipMax.y)
+ lineCode |= 4;
+
+ if (line.end.x > m_clipMax.x)
+ lineCode |= 2;
+ else if (line.end.x < m_clipMin.x)
+ lineCode |= 1;
+
+ if (line.start.y < m_clipMin.y)
+ lineCode |= 128;
+ else if (line.start.y > m_clipMax.y)
+ lineCode |= 64;
+
+ if (line.start.x > m_clipMax.x)
+ lineCode |= 32;
+ else if (line.start.x < m_clipMin.x)
+ lineCode |= 16;
+
+ // 9 - 8 - A
+ // | | |
+ // 1 - 0 - 2
+ // | | |
+ // 5 - 4 - 6
+ switch (lineCode)
+ {
+ // center
+ case 0x00:
+ return true;
+
+ case 0x01:
+ ClipEndLeft (line);
+ return true;
+
+ case 0x02:
+ ClipEndRight (line);
+ return true;
+
+ case 0x04:
+ ClipEndBottom (line);
+ return true;
+
+ case 0x05:
+ ClipEndLeft (line);
+ if (line.end.y > m_clipMax.y)
+ ClipEndBottom (line);
+ return true;
+
+ case 0x06:
+ ClipEndRight (line);
+ if (line.end.y > m_clipMax.y)
+ ClipEndBottom (line);
+ return true;
+
+ case 0x08:
+ ClipEndTop (line);
+ return true;
+
+ case 0x09:
+ ClipEndLeft (line);
+ if (line.end.y < m_clipMin.y)
+ ClipEndTop (line);
+ return true;
+
+ case 0x0A:
+ ClipEndRight (line);
+ if (line.end.y < m_clipMin.y)
+ ClipEndTop (line);
+ return true;
+
+ // left
+ case 0x10:
+ ClipStartLeft (line);
+ return true;
+
+ case 0x12:
+ ClipStartLeft (line);
+ ClipEndRight (line);
+ return true;
+
+ case 0x14:
+ ClipStartLeft (line);
+ if (line.start.y > m_clipMax.y)
+ return false;
+ ClipEndBottom (line);
+ return true;
+
+ case 0x16:
+ ClipStartLeft (line);
+ if (line.start.y > m_clipMax.y)
+ return false;
+ ClipEndBottom (line);
+ if (line.end.x > m_clipMax.x)
+ ClipEndRight (line);
+ return true;
+
+ case 0x18:
+ ClipStartLeft (line);
+ if (line.start.y < m_clipMin.y)
+ return false;
+ ClipEndTop (line);
+ return true;
+
+ case 0x1A:
+ ClipStartLeft (line);
+ if (line.start.y < m_clipMin.y)
+ return false;
+ ClipEndTop (line);
+ if (line.end.x > m_clipMax.x)
+ ClipEndRight (line);
+ return true;
+
+ // right
+ case 0x20:
+ ClipStartRight (line);
+ return true;
+
+ case 0x21:
+ ClipStartRight (line);
+ ClipEndLeft (line);
+ return true;
+
+ case 0x24:
+ ClipStartRight (line);
+ if (line.start.y > m_clipMax.y)
+ return false;
+ ClipEndBottom (line);
+ return true;
+
+ case 0x25:
+ ClipStartRight (line);
+ if (line.start.y > m_clipMax.y)
+ return false;
+ ClipEndBottom (line);
+ if (line.end.x < m_clipMin.x)
+ ClipEndLeft (line);
+ return true;
+
+ case 0x28:
+ ClipStartRight (line);
+ if (line.start.y < m_clipMin.y)
+ return false;
+ ClipEndTop (line);
+ return true;
+
+ case 0x29:
+ ClipStartRight (line);
+ if (line.start.y < m_clipMin.y)
+ return false;
+ ClipEndTop (line);
+ if (line.end.x < m_clipMin.x)
+ ClipEndLeft (line);
+ return true;
+
+ // bottom
+ case 0x40:
+ ClipStartBottom (line);
+ return true;
+
+ case 0x41:
+ ClipStartBottom (line);
+ if (line.start.x < m_clipMin.x)
+ return false;
+ ClipEndLeft (line);
+ if (line.end.y > m_clipMax.y)
+ ClipEndBottom (line);
+ return true;
+
+ case 0x42:
+ ClipStartBottom (line);
+ if (line.start.x > m_clipMax.x)
+ return false;
+ ClipEndRight (line);
+ return true;
+
+ case 0x48:
+ ClipStartBottom (line);
+ ClipEndTop (line);
+ return true;
+
+ case 0x49:
+ ClipStartBottom (line);
+ if (line.start.x < m_clipMin.x)
+ return false;
+ ClipEndLeft (line);
+ if (line.end.y < m_clipMin.y)
+ ClipEndTop (line);
+ return true;
+
+ case 0x4A:
+ ClipStartBottom (line);
+ if (line.start.x > m_clipMax.x)
+ return false;
+ ClipEndRight (line);
+ if (line.end.y < m_clipMin.y)
+ ClipEndTop (line);
+ return true;
+
+ // bottom-left
+ case 0x50:
+ ClipStartLeft (line);
+ if (line.start.y > m_clipMax.y)
+ ClipStartBottom (line);
+ return true;
+
+ case 0x52:
+ ClipEndRight (line);
+ if (line.end.y > m_clipMax.y)
+ return false;
+ ClipStartBottom (line);
+ if (line.start.x < m_clipMin.x)
+ ClipStartLeft (line);
+ return true;
+
+ case 0x58:
+ ClipEndTop (line);
+ if (line.end.x < m_clipMin.x)
+ return false;
+ ClipStartBottom (line);
+ if (line.start.x < m_clipMin.x)
+ ClipStartLeft (line);
+ return true;
+
+ case 0x5A:
+ ClipStartLeft (line);
+ if (line.start.y < m_clipMin.y)
+ return false;
+ ClipEndRight (line);
+ if (line.end.y > m_clipMax.y)
+ return false;
+ if (line.start.y > m_clipMax.y)
+ ClipStartBottom (line);
+ if (line.end.y < m_clipMin.y)
+ ClipEndTop (line);
+ return true;
+
+ // bottom-right
+ case 0x60:
+ ClipStartRight (line);
+ if (line.start.y > m_clipMax.y)
+ ClipStartBottom (line);
+ return true;
+
+ case 0x61:
+ ClipEndLeft (line);
+ if (line.end.y > m_clipMax.y)
+ return false;
+ ClipStartBottom (line);
+ if (line.start.x > m_clipMax.x)
+ ClipStartRight (line);
+ return true;
+
+ case 0x68:
+ ClipEndTop (line);
+ if (line.end.x > m_clipMax.x)
+ return false;
+ ClipStartRight (line);
+ if (line.start.y > m_clipMax.y)
+ ClipStartBottom (line);
+ return true;
+
+ case 0x69:
+ ClipEndLeft (line);
+ if (line.end.y > m_clipMax.y)
+ return false;
+ ClipStartRight (line);
+ if (line.start.y < m_clipMin.y)
+ return false;
+ if (line.end.y < m_clipMin.y)
+ ClipEndTop (line);
+ if (line.start.y > m_clipMax.y)
+ ClipStartBottom (line);
+ return true;
+
+ // top
+ case 0x80:
+ ClipStartTop (line);
+ return true;
+
+ case 0x81:
+ ClipStartTop (line);
+ if (line.start.x < m_clipMin.x)
+ return false;
+ ClipEndLeft (line);
+ return true;
+
+ case 0x82:
+ ClipStartTop (line);
+ if (line.start.x > m_clipMax.x)
+ return false;
+ ClipEndRight (line);
+ return true;
+
+ case 0x84:
+ ClipStartTop (line);
+ ClipEndBottom (line);
+ return true;
+
+ case 0x85:
+ ClipStartTop (line);
+ if (line.start.x < m_clipMin.x)
+ return false;
+ ClipEndLeft (line);
+ if (line.end.y > m_clipMax.y)
+ ClipEndBottom (line);
+ return true;
+
+ case 0x86:
+ ClipStartTop (line);
+ if (line.start.x > m_clipMax.x)
+ return false;
+ ClipEndRight (line);
+ if (line.end.y > m_clipMax.y)
+ ClipEndBottom (line);
+ return true;
+
+ // top-left
+ case 0x90:
+ ClipStartLeft (line);
+ if (line.start.y < m_clipMin.y)
+ ClipStartTop (line);
+ return true;
+
+ case 0x92:
+ ClipEndRight (line);
+ if (line.end.y < m_clipMin.y)
+ return false;
+ ClipStartTop (line);
+ if (line.start.x < m_clipMin.x)
+ ClipStartLeft (line);
+ return true;
+
+ case 0x94:
+ ClipEndBottom (line);
+ if (line.end.x < m_clipMin.x)
+ return false;
+ ClipStartLeft (line);
+ if (line.start.y < m_clipMin.y)
+ ClipStartTop (line);
+ return true;
+
+ case 0x96:
+ ClipStartLeft (line);
+ if (line.start.y > m_clipMax.y)
+ return false;
+ ClipEndRight (line);
+ if (line.end.y < m_clipMin.y)
+ return false;
+ if (line.start.y < m_clipMin.y)
+ ClipStartTop (line);
+ if (line.end.y > m_clipMax.y)
+ ClipEndBottom (line);
+ return true;
+
+ // top-right
+ case 0xA0:
+ ClipStartRight (line);
+ if (line.start.y < m_clipMin.y)
+ ClipStartTop (line);
+ return true;
+
+ case 0xA1:
+ ClipEndLeft (line);
+ if (line.end.y < m_clipMin.y)
+ return false;
+ ClipStartTop (line);
+ if (line.start.x > m_clipMax.x)
+ ClipStartRight (line);
+ return true;
+
+ case 0xA4:
+ ClipEndBottom (line);
+ if (line.end.x > m_clipMax.x)
+ return false;
+ ClipStartRight (line);
+ if (line.start.y < m_clipMin.y)
+ ClipStartTop (line);
+ return true;
+
+ case 0xA5:
+ ClipEndLeft (line);
+ if (line.end.y < m_clipMin.y)
+ return false;
+ ClipStartRight (line);
+ if (line.start.y > m_clipMax.y)
+ return false;
+ if (line.end.y > m_clipMax.y)
+ ClipEndBottom (line);
+ if (line.start.y < m_clipMin.y)
+ ClipStartTop (line);
+ return true;
+ }
+
+ return false;
+ }
+ };
+}
+
+void
+PyViz::LineClipping (double boundsX1, double boundsY1, double boundsX2, double boundsY2,
+ double &lineX1, double &lineY1, double &lineX2, double &lineY2)
+{
+ FastClipping::Vector2 clipMin = {boundsX1, boundsY1}, clipMax = {boundsX2, boundsY2};
+ FastClipping::Line line = { { lineX1, lineY1 }, { lineX2, lineY2 }, (lineX2-lineX1), (lineY2-lineY1) };
+
+ FastClipping clipper (clipMin, clipMax);
+ clipper.ClipLine (line);
+ lineX1 = line.start.x;
+ lineX2 = line.end.x;
+ lineY1 = line.start.y;
+ lineY2 = line.end.y;
+}
+
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/model/pyviz.h Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,225 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INESC Porto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * C++ helper functions for use by the python visualizer (for things
+ * Python is too slow at).
+ *
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ */
+#ifndef NS3_PYVIZ_H
+#define NS3_PYVIZ_H
+
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/packet.h"
+#include "ns3/mac48-address.h"
+#include "ns3/ipv4-header.h"
+#include "ns3/ipv4-l3-protocol.h"
+
+#include <map>
+#include <set>
+
+namespace ns3 {
+
+/**
+ * \brief helper class to be used by the visualizer
+ * \internal
+ *
+ * This class is not meant to be used by simulations. It is only
+ * meant to be used by the visualizer tool (PyViz). The only reason
+ * it is public is because Python bindings for it are needed,
+ * otherwise it should be considered private.
+ **/
+class PyViz
+{
+public:
+ PyViz ();
+ ~PyViz ();
+
+ void RegisterDropTracePath (std::string const &tracePath);
+
+ void RegisterCsmaLikeDevice (std::string const &deviceTypeName);
+ void RegisterWifiLikeDevice (std::string const &deviceTypeName);
+ void RegisterPointToPointLikeDevice (std::string const &deviceTypeName);
+
+ // Run simulation until a given (simulated, absolute) time is reached
+ void SimulatorRunUntil (Time time);
+
+ static void Pause (std::string const &message);
+ std::vector<std::string> GetPauseMessages () const;
+
+ struct TransmissionSample
+ {
+ Ptr<Node> transmitter;
+ Ptr<Node> receiver; // NULL if broadcast
+ Ptr<Channel> channel;
+ uint32_t bytes;
+ };
+ typedef std::vector<TransmissionSample> TransmissionSampleList;
+ TransmissionSampleList GetTransmissionSamples () const;
+
+ struct PacketDropSample
+ {
+ Ptr<Node> transmitter;
+ uint32_t bytes;
+ };
+ typedef std::vector<PacketDropSample> PacketDropSampleList;
+ PacketDropSampleList GetPacketDropSamples () const;
+
+
+ struct PacketSample
+ {
+ Time time;
+ Ptr<Packet> packet;
+ Ptr<NetDevice> device;
+ };
+ struct TxPacketSample : PacketSample
+ {
+ Mac48Address to;
+ };
+ struct RxPacketSample : PacketSample
+ {
+ Mac48Address from;
+ };
+
+ struct LastPacketsSample
+ {
+ std::vector<RxPacketSample> lastReceivedPackets;
+ std::vector<TxPacketSample> lastTransmittedPackets;
+ std::vector<PacketSample> lastDroppedPackets;
+ };
+ LastPacketsSample GetLastPackets (uint32_t nodeId) const;
+
+
+ void SetNodesOfInterest (std::set<uint32_t> nodes);
+
+ struct NetDeviceStatistics
+ {
+ NetDeviceStatistics () : transmittedBytes (0), receivedBytes (0),
+ transmittedPackets (0), receivedPackets (0) {}
+ uint64_t transmittedBytes;
+ uint64_t receivedBytes;
+ uint32_t transmittedPackets;
+ uint32_t receivedPackets;
+ };
+
+ struct NodeStatistics
+ {
+ uint32_t nodeId;
+ std::vector<NetDeviceStatistics> statistics;
+ };
+
+ std::vector<NodeStatistics> GetNodesStatistics () const;
+
+ enum PacketCaptureMode {
+ PACKET_CAPTURE_DISABLED=1, // packet capture is disabled
+ PACKET_CAPTURE_FILTER_HEADERS_OR, // packet capture if any of the indicated headers is present
+ PACKET_CAPTURE_FILTER_HEADERS_AND, // packet capture if all of the indicated headers are present
+ };
+
+ struct PacketCaptureOptions
+ {
+ std::set<TypeId> headers;
+ uint32_t numLastPackets;
+ PacketCaptureMode mode;
+ };
+
+ void SetPacketCaptureOptions (uint32_t nodeId, PacketCaptureOptions options);
+
+
+ // Yes, I know, this is just a utility function, not really related to the class in any way.
+
+ // -#- @lineX1(direction=inout); @lineY1(direction=inout); @lineX2(direction=inout); @lineY2(direction=inout) -#-
+ static void LineClipping (double boundsX1, double boundsY1, double boundsX2, double boundsY2, double &lineX1, double &lineY1, double &lineX2, double &lineY2); // don't break this line or pybindgen will not be able to pick up the above annotation :(
+
+
+private:
+
+ bool GetPacketCaptureOptions (uint32_t nodeId, const PacketCaptureOptions **outOptions) const;
+ static bool FilterPacket (Ptr<const Packet> packet, const PacketCaptureOptions &options);
+
+
+ typedef std::pair<Ptr<Channel>, uint32_t> TxRecordKey;
+
+ struct TxRecordValue
+ {
+ Time time;
+ Ptr<Node> srcNode;
+ bool isBroadcast;
+ };
+
+ struct TransmissionSampleKey
+ {
+ bool operator < (TransmissionSampleKey const &other) const;
+ bool operator == (TransmissionSampleKey const &other) const;
+ Ptr<Node> transmitter;
+ Ptr<Node> receiver; // NULL if broadcast
+ Ptr<Channel> channel;
+ };
+
+ struct TransmissionSampleValue
+ {
+ uint32_t bytes;
+ };
+
+ // data
+ std::map<uint32_t, PacketCaptureOptions> m_packetCaptureOptions;
+ std::vector<std::string> m_pauseMessages;
+ std::map<TxRecordKey, TxRecordValue> m_txRecords;
+ std::map<TransmissionSampleKey, TransmissionSampleValue> m_transmissionSamples;
+ std::map<Ptr<Node>, uint32_t> m_packetDrops;
+ std::set<uint32_t> m_nodesOfInterest; // list of node IDs whose transmissions will be monitored
+ std::map<uint32_t, Time> m_packetsOfInterest; // list of packet UIDs that will be monitored
+ std::map<uint32_t, LastPacketsSample> m_lastPackets;
+ std::map<uint32_t, std::vector<NetDeviceStatistics> > m_nodesStatistics;
+
+ // Trace callbacks
+ void TraceNetDevTxCommon (std::string const &context, Ptr<const Packet> packet, Mac48Address const &destination);
+ void TraceNetDevRxCommon (std::string const &context, Ptr<const Packet> packet, Mac48Address const &source);
+
+ void TraceNetDevTxWifi (std::string context, Ptr<const Packet> packet);
+ void TraceNetDevRxWifi (std::string context, Ptr<const Packet> packet);
+
+ void TraceDevQueueDrop (std::string context, Ptr<const Packet> packet);
+ void TraceIpv4Drop (std::string context, ns3::Ipv4Header const &hdr, Ptr<const Packet> packet,
+ ns3::Ipv4L3Protocol::DropReason reason, Ptr<Ipv4> dummy_ipv4, uint32_t interface);
+
+ void TraceNetDevTxCsma (std::string context, Ptr<const Packet> packet);
+ void TraceNetDevRxCsma (std::string context, Ptr<const Packet> packet);
+ void TraceNetDevPromiscRxCsma (std::string context, Ptr<const Packet> packet);
+
+ void TraceNetDevTxPointToPoint (std::string context, Ptr<const Packet> packet);
+ void TraceNetDevRxPointToPoint (std::string context, Ptr<const Packet> packet);
+
+ void TraceNetDevTxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &destination);
+ void TraceNetDevRxWimax (std::string context, Ptr<const Packet> packet, Mac48Address const &source);
+
+ inline NetDeviceStatistics & FindNetDeviceStatistics (int node, int interface);
+
+ void DoPause (std::string const &message);
+
+ bool m_stop;
+ EventId m_stopCallbackEvent;
+ void CallbackStopSimulation ();
+};
+
+
+}
+
+#endif /* NS3_PYVIZ_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/model/visual-simulator-impl.cc Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,228 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Gustavo Carneiro
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Gustavo Carneiro <gjcarneiro@gmail.com> <gjc@inescporto.pt>
+ */
+#include <Python.h>
+#include "visual-simulator-impl.h"
+#include "ns3/default-simulator-impl.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("VisualSimulatorImpl");
+
+namespace ns3 {
+
+
+
+NS_OBJECT_ENSURE_REGISTERED (VisualSimulatorImpl);
+
+namespace
+{
+ ObjectFactory
+ GetDefaultSimulatorImplFactory ()
+ {
+ ObjectFactory factory;
+ factory.SetTypeId (DefaultSimulatorImpl::GetTypeId ());
+ return factory;
+ }
+}
+
+
+TypeId
+VisualSimulatorImpl::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::VisualSimulatorImpl")
+ .SetParent<SimulatorImpl> ()
+ .AddConstructor<VisualSimulatorImpl> ()
+ .AddAttribute ("SimulatorImplFactory",
+ "Factory for the underlying simulator implementation used by the visualizer.",
+ ObjectFactoryValue (GetDefaultSimulatorImplFactory ()),
+ MakeObjectFactoryAccessor (&VisualSimulatorImpl::m_simulatorImplFactory),
+ MakeObjectFactoryChecker ())
+ ;
+ return tid;
+}
+
+
+VisualSimulatorImpl::VisualSimulatorImpl ()
+{
+}
+
+VisualSimulatorImpl::~VisualSimulatorImpl ()
+{}
+
+void
+VisualSimulatorImpl::DoDispose (void)
+{
+ if (m_simulator)
+ {
+ m_simulator->Dispose ();
+ m_simulator = NULL;
+ }
+ SimulatorImpl::DoDispose ();
+}
+
+void
+VisualSimulatorImpl::NotifyConstructionCompleted ()
+{
+ m_simulator = m_simulatorImplFactory.Create<SimulatorImpl> ();
+}
+
+
+void
+VisualSimulatorImpl::Destroy ()
+{
+ m_simulator->Destroy ();
+}
+
+void
+VisualSimulatorImpl::SetScheduler (ObjectFactory schedulerFactory)
+{
+ m_simulator->SetScheduler (schedulerFactory);
+}
+
+// System ID for non-distributed simulation is always zero
+uint32_t
+VisualSimulatorImpl::GetSystemId (void) const
+{
+ return m_simulator->GetSystemId ();
+}
+
+bool
+VisualSimulatorImpl::IsFinished (void) const
+{
+ return m_simulator->IsFinished ();
+}
+
+Time
+VisualSimulatorImpl::Next (void) const
+{
+ return m_simulator->Next ();
+}
+
+void
+VisualSimulatorImpl::Run (void)
+{
+ if (!Py_IsInitialized ())
+ {
+ const char *argv[] = {"python", NULL};
+ Py_Initialize();
+ PySys_SetArgv(1, (char**) argv);
+ }
+ PyRun_SimpleString(
+ "import visualizer\n"
+ "visualizer.start();\n"
+ );
+}
+
+void
+VisualSimulatorImpl::RunOneEvent (void)
+{
+ m_simulator->RunOneEvent ();
+}
+
+void
+VisualSimulatorImpl::Stop (void)
+{
+ m_simulator->Stop ();
+}
+
+void
+VisualSimulatorImpl::Stop (Time const &time)
+{
+ m_simulator->Stop (time);
+}
+
+//
+// Schedule an event for a _relative_ time in the future.
+//
+EventId
+VisualSimulatorImpl::Schedule (Time const &time, EventImpl *event)
+{
+ return m_simulator->Schedule (time, event);
+}
+
+void
+VisualSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event)
+{
+ m_simulator->ScheduleWithContext (context, time, event);
+}
+
+EventId
+VisualSimulatorImpl::ScheduleNow (EventImpl *event)
+{
+ return m_simulator->ScheduleNow (event);
+}
+
+EventId
+VisualSimulatorImpl::ScheduleDestroy (EventImpl *event)
+{
+ return m_simulator->ScheduleDestroy (event);
+}
+
+Time
+VisualSimulatorImpl::Now (void) const
+{
+ return m_simulator->Now ();
+}
+
+Time
+VisualSimulatorImpl::GetDelayLeft (const EventId &id) const
+{
+ return m_simulator->GetDelayLeft (id);
+}
+
+void
+VisualSimulatorImpl::Remove (const EventId &id)
+{
+ m_simulator->Remove (id);
+}
+
+void
+VisualSimulatorImpl::Cancel (const EventId &id)
+{
+ m_simulator->Cancel (id);
+}
+
+bool
+VisualSimulatorImpl::IsExpired (const EventId &ev) const
+{
+ return m_simulator->IsExpired (ev);
+}
+
+Time
+VisualSimulatorImpl::GetMaximumSimulationTime (void) const
+{
+ return m_simulator->GetMaximumSimulationTime ();
+}
+
+uint32_t
+VisualSimulatorImpl::GetContext (void) const
+{
+ return m_simulator->GetContext ();
+}
+
+void
+VisualSimulatorImpl::RunRealSimulator (void)
+{
+ m_simulator->Run ();
+}
+
+
+} // namespace ns3
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/model/visual-simulator-impl.h Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 Gustavo Carneiro
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Gustavo Carneiro <gjcarneiro@gmail.com>
+ */
+
+#ifndef VISUAL_SIMULATOR_IMPL_H
+#define VISUAL_SIMULATOR_IMPL_H
+
+#include "ns3/simulator-impl.h"
+
+namespace ns3 {
+
+
+/**
+ * \brief A replacement simulator that starts the visualizer
+ * \internal
+ *
+ * To use this class, run any ns-3 simulation with the command-line
+ * argument --SimulatorImplementationType=ns3::VisualSimulatorImpl.
+ * This causes the visualizer (PyViz) to start automatically.
+ **/
+class VisualSimulatorImpl : public SimulatorImpl
+{
+public:
+ static TypeId GetTypeId (void);
+
+ VisualSimulatorImpl ();
+ ~VisualSimulatorImpl ();
+
+ virtual void Destroy ();
+ virtual bool IsFinished (void) const;
+ virtual Time Next (void) const;
+ virtual void Stop (void);
+ virtual void Stop (Time const &time);
+ virtual EventId Schedule (Time const &time, EventImpl *event);
+ virtual void ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event);
+ virtual EventId ScheduleNow (EventImpl *event);
+ virtual EventId ScheduleDestroy (EventImpl *event);
+ virtual void Remove (const EventId &ev);
+ virtual void Cancel (const EventId &ev);
+ virtual bool IsExpired (const EventId &ev) const;
+ virtual void Run (void);
+ virtual void RunOneEvent (void);
+ virtual Time Now (void) const;
+ virtual Time GetDelayLeft (const EventId &id) const;
+ virtual Time GetMaximumSimulationTime (void) const;
+ virtual void SetScheduler (ObjectFactory schedulerFactory);
+ virtual uint32_t GetSystemId (void) const;
+ virtual uint32_t GetContext (void) const;
+
+ /// calls Run() in the wrapped simulator
+ void RunRealSimulator (void);
+
+protected:
+ void DoDispose ();
+ void NotifyConstructionCompleted (void);
+
+private:
+ Ptr<SimulatorImpl> GetSim ();
+ Ptr<SimulatorImpl> m_simulator;
+ ObjectFactory m_simulatorImplFactory;
+
+};
+
+} // namespace ns3
+
+#endif /* DEFAULT_SIMULATOR_IMPL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/model/visualizer-ideas.txt Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,16 @@
+- Add an Attribute browser plugin, simililar to Mathieu's GtkConfigStore;
+ - Right click on a node -> Show Attributes;
+ - Allow editing attributes too;
+- List of all nodes, navigator;
+- Represent individual NetDevices in Nodes;
+- Colorize flows; possible approaches:
+ - Apply color based on hash function of ethertype, IP packet type, L4 destination port;
+ - Programmatically marked flows;
+ - Packet tags?
+ - Present a GUI to show applications and set color for each one;
+ - Problems:
+ > How about multiple flows? How to represent them simultaneously?
+- Track down a Gtk+ bug preventing tooltips from working correctly with large zoom levels;
+- Possibly look for embedding an ipython shell as a widget inside the
+ main window: http://ipython.scipy.org/moin/Cookbook/EmbeddingInGTK
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/__init__.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,3 @@
+
+from core import start, register_plugin, set_bounds, add_initialization_hook
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/base.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,107 @@
+import ns3
+import gobject
+import os.path
+import sys
+
+PIXELS_PER_METER = 3.0 # pixels-per-meter, at 100% zoom level
+
+class PyVizObject(gobject.GObject):
+ __gtype_name__ = "PyVizObject"
+
+ def tooltip_query(self, tooltip):
+ tooltip.set_text("TODO: tooltip for %r" % self)
+
+class Link(PyVizObject):
+ pass
+
+
+class InformationWindow(object):
+ def update(self):
+ raise NotImplementedError
+
+class NetDeviceTraits(object):
+ def __init__(self, is_wireless=None, is_virtual=False):
+ assert is_virtual or is_wireless is not None
+ self.is_wireless = is_wireless
+ self.is_virtual = is_virtual
+
+netdevice_traits = {
+ ns3.PointToPointNetDevice: NetDeviceTraits(is_wireless=False),
+ ns3.CsmaNetDevice: NetDeviceTraits(is_wireless=False),
+ ns3.WifiNetDevice: NetDeviceTraits(is_wireless=True),
+ ns3.BridgeNetDevice: NetDeviceTraits(is_virtual=True),
+ ns3.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False),
+ ns3.MeshPointDevice: NetDeviceTraits(is_virtual=True),
+ ns3.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True),
+ ns3.BaseStationNetDevice: NetDeviceTraits(is_wireless=True),
+}
+
+def lookup_netdevice_traits(class_type):
+ try:
+ return netdevice_traits[class_type]
+ except KeyError:
+ sys.stderr.write("WARNING: no NetDeviceTraits registered for device type %r; "
+ "I will assume this is a non-virtual wireless device, "
+ "but you should edit %r, variable 'netdevice_traits',"
+ " to make sure.\n" % (class_type.__name__, __file__))
+ t = NetDeviceTraits(is_virtual=False, is_wireless=True)
+ netdevice_traits[class_type] = t
+ return t
+
+def transform_distance_simulation_to_canvas(d):
+ return d*PIXELS_PER_METER
+
+def transform_point_simulation_to_canvas(x, y):
+ return x*PIXELS_PER_METER, y*PIXELS_PER_METER
+
+def transform_distance_canvas_to_simulation(d):
+ return d/PIXELS_PER_METER
+
+def transform_point_canvas_to_simulation(x, y):
+ return x/PIXELS_PER_METER, y/PIXELS_PER_METER
+
+
+
+
+plugins = []
+plugin_modules = {}
+
+def register_plugin(plugin_init_func, plugin_name=None, plugin_module=None):
+ """
+ Register a plugin.
+
+ @param plugin: a callable object that will be invoked whenever a
+ Visualizer object is created, like this: plugin(visualizer)
+ """
+ assert callable(plugin_init_func)
+ plugins.append(plugin_init_func)
+ if plugin_module is not None:
+ plugin_modules[plugin_name] = plugin_module
+
+plugins_loaded = False
+def load_plugins():
+ global plugins_loaded
+ if plugins_loaded:
+ return
+ plugins_loaded = True
+ plugins_dir = os.path.join(os.path.dirname(__file__), 'plugins')
+ old_path = list(sys.path)
+ sys.path.insert(0, plugins_dir)
+ for filename in os.listdir(plugins_dir):
+ name, ext = os.path.splitext(filename)
+ if ext != '.py':
+ continue
+ try:
+ plugin_module = __import__(name)
+ except ImportError, ex:
+ print >> sys.stderr, "Could not load plugin %r: %s" % (filename, str(ex))
+ continue
+ try:
+ plugin_func = plugin_module.register
+ except AttributeError:
+ print >> sys.stderr, "Plugin %r has no 'register' function" % name
+ else:
+ #print >> sys.stderr, "Plugin %r registered" % name
+ register_plugin(plugin_func, name, plugin_module)
+ sys.path = old_path
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/core.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,1470 @@
+# -*- Mode: python; coding: utf-8 -*-
+from __future__ import division
+#from __future__ import with_statement
+
+LAYOUT_ALGORITHM = 'neato' # ['neato'|'dot'|'twopi'|'circo'|'fdp'|'nop']
+REPRESENT_CHANNELS_AS_NODES = 1
+DEFAULT_NODE_SIZE = 3.0 # default node size in meters
+DEFAULT_TRANSMISSIONS_MEMORY = 5 # default number of of past intervals whose transmissions are remembered
+BITRATE_FONT_SIZE = 10
+
+# internal constants, normally not meant to be changed
+SAMPLE_PERIOD = 0.1
+PRIORITY_UPDATE_MODEL = -100
+PRIORITY_UPDATE_VIEW = 200
+
+import platform
+if platform.system() == "Windows":
+ SHELL_FONT = "Lucida Console 9"
+else:
+ SHELL_FONT = "Luxi Mono 10"
+
+
+import ns3
+import math
+import os
+import sys
+import gobject
+import time
+
+try:
+ import pygraphviz
+ import gtk
+ import pango
+ import goocanvas
+ import cairo
+ import threading
+ import hud
+ #import time
+ import cairo
+ from higcontainer import HIGContainer
+ gobject.threads_init()
+ try:
+ import svgitem
+ except ImportError:
+ svgitem = None
+except ImportError, _import_error:
+ import dummy_threading as threading
+else:
+ _import_error = None
+
+try:
+ import ipython_view
+except ImportError:
+ ipython_view = None
+
+from base import InformationWindow, PyVizObject, Link, lookup_netdevice_traits, PIXELS_PER_METER
+from base import transform_distance_simulation_to_canvas, transform_point_simulation_to_canvas
+from base import transform_distance_canvas_to_simulation, transform_point_canvas_to_simulation
+from base import load_plugins, register_plugin, plugins
+
+PI_OVER_2 = math.pi/2
+PI_TIMES_2 = math.pi*2
+
+class Node(PyVizObject):
+
+ __gsignals__ = {
+
+ # signal emitted whenever a tooltip is about to be shown for the node
+ # the first signal parameter is a python list of strings, to which information can be appended
+ 'query-extra-tooltip-info': (gobject.SIGNAL_RUN_LAST, None, (object,)),
+
+ }
+
+ def __init__(self, visualizer, node_index):
+ super(Node, self).__init__()
+
+ self.visualizer = visualizer
+ self.node_index = node_index
+ self.canvas_item = goocanvas.Ellipse()
+ self.canvas_item.set_data("pyviz-object", self)
+ self.links = []
+ self._has_mobility = None
+ self._selected = False
+ self._highlighted = False
+ self._color = 0x808080ff
+ self._size = DEFAULT_NODE_SIZE
+ self.canvas_item.connect("enter-notify-event", self.on_enter_notify_event)
+ self.canvas_item.connect("leave-notify-event", self.on_leave_notify_event)
+ self.menu = None
+ self.svg_item = None
+ self.svg_align_x = None
+ self.svg_align_y = None
+ self._label = None
+ self._label_canvas_item = None
+
+ self._update_appearance() # call this last
+
+ def set_svg_icon(self, file_base_name, width=None, height=None, align_x=0.5, align_y=0.5):
+ """
+ Set a background SVG icon for the node.
+
+ @param file_base_name: base file name, including .svg
+ extension, of the svg file. Place the file in the folder
+ src/contrib/visualizer/resource.
+
+ @param width: scale to the specified width, in meters
+ @param width: scale to the specified height, in meters
+
+ @param align_x: horizontal alignment of the icon relative to
+ the node position, from 0 (icon fully to the left of the node)
+ to 1.0 (icon fully to the right of the node)
+
+ @param align_y: vertical alignment of the icon relative to the
+ node position, from 0 (icon fully to the top of the node) to
+ 1.0 (icon fully to the bottom of the node)
+
+ """
+ if width is None and height is None:
+ raise ValueError("either width or height must be given")
+ rsvg_handle = svgitem.rsvg_handle_factory(file_base_name)
+ x = self.canvas_item.props.center_x
+ y = self.canvas_item.props.center_y
+ self.svg_item = svgitem.SvgItem(x, y, rsvg_handle)
+ self.svg_item.props.parent = self.visualizer.canvas.get_root_item()
+ self.svg_item.props.pointer_events = 0
+ self.svg_item.lower(None)
+ self.svg_item.props.visibility = goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD
+ if width is not None:
+ self.svg_item.props.width = transform_distance_simulation_to_canvas(width)
+ if height is not None:
+ self.svg_item.props.height = transform_distance_simulation_to_canvas(height)
+
+ #threshold1 = 10.0/self.svg_item.props.height
+ #threshold2 = 10.0/self.svg_item.props.width
+ #self.svg_item.props.visibility_threshold = min(threshold1, threshold2)
+
+ self.svg_align_x = align_x
+ self.svg_align_y = align_y
+ self._update_svg_position(x, y)
+ self._update_appearance()
+
+ def set_label(self, label):
+ assert isinstance(label, basestring)
+ self._label = label
+ self._update_appearance()
+
+ def _update_svg_position(self, x, y):
+ w = self.svg_item.width
+ h = self.svg_item.height
+ self.svg_item.set_properties(x=(x - (1-self.svg_align_x)*w),
+ y=(y - (1-self.svg_align_y)*h))
+
+
+ def tooltip_query(self, tooltip):
+ self.visualizer.simulation.lock.acquire()
+ try:
+ ns3_node = ns3.NodeList.GetNode(self.node_index)
+ ipv4 = ns3_node.GetObject(ns3.Ipv4.GetTypeId())
+ lines = ['<b><u>Node %i</u></b>' % self.node_index]
+ lines.append('')
+
+ self.emit("query-extra-tooltip-info", lines)
+
+ mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ if mob is not None:
+ lines.append(' <b>Mobility Model</b>: %s' % mob.GetInstanceTypeId().GetName())
+
+ for devI in range(ns3_node.GetNDevices()):
+ lines.append('')
+ lines.append(' <u>NetDevice %i:</u>' % devI)
+ dev = ns3_node.GetDevice(devI)
+ name = ns3.Names.FindName(dev)
+ if name:
+ lines.append(' <b>Name:</b> %s' % name)
+ devname = dev.GetInstanceTypeId().GetName()
+ lines.append(' <b>Type:</b> %s' % devname)
+ if ipv4 is not None:
+ ipv4_idx = ipv4.GetInterfaceForDevice(dev)
+ if ipv4_idx != -1:
+ addresses = [
+ '%s/%s' % (ipv4.GetAddress(ipv4_idx, i).GetLocal(),
+ ipv4.GetAddress(ipv4_idx, i).GetMask())
+ for i in range(ipv4.GetNAddresses(ipv4_idx))]
+ lines.append(' <b>IPv4 Addresses:</b> %s' % '; '.join(addresses))
+
+ lines.append(' <b>MAC Address:</b> %s' % (dev.GetAddress(),))
+
+ tooltip.set_markup('\n'.join(lines))
+ finally:
+ self.visualizer.simulation.lock.release()
+
+ def on_enter_notify_event(self, view, target, event):
+ self.highlighted = True
+ def on_leave_notify_event(self, view, target, event):
+ self.highlighted = False
+
+ def _set_selected(self, value):
+ self._selected = value
+ self._update_appearance()
+ def _get_selected(self):
+ return self._selected
+ selected = property(_get_selected, _set_selected)
+
+ def _set_highlighted(self, value):
+ self._highlighted = value
+ self._update_appearance()
+ def _get_highlighted(self):
+ return self._highlighted
+ highlighted = property(_get_highlighted, _set_highlighted)
+
+ def set_size(self, size):
+ self._size = size
+ self._update_appearance()
+
+ def _update_appearance(self):
+ """Update the node aspect to reflect the selected/highlighted state"""
+
+ size = transform_distance_simulation_to_canvas(self._size)
+ if self.svg_item is not None:
+ alpha = 0x80
+ else:
+ alpha = 0xff
+ fill_color_rgba = (self._color & 0xffffff00) | alpha
+ self.canvas_item.set_properties(radius_x=size, radius_y=size,
+ fill_color_rgba=fill_color_rgba)
+ if self._selected:
+ line_width = size*.3
+ else:
+ line_width = size*.15
+ if self.highlighted:
+ stroke_color = 'yellow'
+ else:
+ stroke_color = 'black'
+ self.canvas_item.set_properties(line_width=line_width, stroke_color=stroke_color)
+
+ if self._label is not None:
+ if self._label_canvas_item is None:
+ self._label_canvas_item = goocanvas.Text(visibility_threshold=0.5,
+ font="Sans Serif 10",
+ fill_color_rgba=0x808080ff,
+ alignment=pango.ALIGN_CENTER,
+ anchor=gtk.ANCHOR_N,
+ parent=self.visualizer.canvas.get_root_item(),
+ pointer_events=0)
+ self._label_canvas_item.lower(None)
+
+ self._label_canvas_item.set_properties(visibility=goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD,
+ text=self._label)
+ self._update_position()
+
+ def set_position(self, x, y):
+ self.canvas_item.set_property("center_x", x)
+ self.canvas_item.set_property("center_y", y)
+ if self.svg_item is not None:
+ self._update_svg_position(x, y)
+
+ for link in self.links:
+ link.update_points()
+
+ if self._label_canvas_item is not None:
+ self._label_canvas_item.set_properties(x=x, y=(y+self._size*3))
+
+ def get_position(self):
+ return (self.canvas_item.get_property("center_x"), self.canvas_item.get_property("center_y"))
+
+ def _update_position(self):
+ x, y = self.get_position()
+ self.set_position(x, y)
+
+ def set_color(self, color):
+ if isinstance(color, str):
+ color = gtk.gdk.color_parse(color)
+ color = ((color.red>>8) << 24) | ((color.green>>8) << 16) | ((color.blue>>8) << 8) | 0xff
+ self._color = color
+ self._update_appearance()
+
+ def add_link(self, link):
+ assert isinstance(link, Link)
+ self.links.append(link)
+
+ def remove_link(self, link):
+ assert isinstance(link, Link)
+ self.links.remove(link)
+
+ @property
+ def has_mobility(self):
+ if self._has_mobility is None:
+ node = ns3.NodeList.GetNode(self.node_index)
+ mobility = node.GetObject(ns3.MobilityModel.GetTypeId())
+ self._has_mobility = (mobility is not None)
+ return self._has_mobility
+
+
+class Channel(PyVizObject):
+ def __init__(self, channel):
+ self.channel = channel
+ self.canvas_item = goocanvas.Ellipse(radius_x=30, radius_y=30,
+ fill_color="white",
+ stroke_color="grey", line_width=2.0,
+ line_dash=goocanvas.LineDash([10.0, 10.0 ]),
+ visibility=goocanvas.ITEM_VISIBLE)
+ self.canvas_item.set_data("pyviz-object", self)
+ self.links = []
+
+ def set_position(self, x, y):
+ self.canvas_item.set_property("center_x", x)
+ self.canvas_item.set_property("center_y", y)
+
+ for link in self.links:
+ link.update_points()
+
+ def get_position(self):
+ return (self.canvas_item.get_property("center_x"), self.canvas_item.get_property("center_y"))
+
+
+class WiredLink(Link):
+ def __init__(self, node1, node2):
+ assert isinstance(node1, Node)
+ assert isinstance(node2, (Node, Channel))
+ self.node1 = node1
+ self.node2 = node2
+ self.canvas_item = goocanvas.Path(line_width=1.0, stroke_color="black")
+ self.canvas_item.set_data("pyviz-object", self)
+ self.node1.links.append(self)
+ self.node2.links.append(self)
+
+ def update_points(self):
+ pos1_x, pos1_y = self.node1.get_position()
+ pos2_x, pos2_y = self.node2.get_position()
+ self.canvas_item.set_property("data", "M %r %r L %r %r" % (pos1_x, pos1_y, pos2_x, pos2_y))
+
+
+
+class SimulationThread(threading.Thread):
+ def __init__(self, viz):
+ super(SimulationThread, self).__init__()
+ assert isinstance(viz, Visualizer)
+ self.viz = viz # Visualizer object
+ self.lock = threading.Lock()
+ self.go = threading.Event()
+ self.go.clear()
+ self.target_time = 0 # in seconds
+ self.quit = False
+ self.sim_helper = ns3.PyViz()
+ self.pause_messages = []
+
+ def set_nodes_of_interest(self, nodes):
+ self.lock.acquire()
+ try:
+ self.sim_helper.SetNodesOfInterest(nodes)
+ finally:
+ self.lock.release()
+
+ def run(self):
+ while not self.quit:
+ #print "sim: Wait for go"
+ self.go.wait() # wait until the main (view) thread gives us the go signal
+ self.go.clear()
+ if self.quit:
+ break
+ #self.go.clear()
+ #print "sim: Acquire lock"
+ self.lock.acquire()
+ try:
+ if 0:
+ if ns3.Simulator.IsFinished():
+ self.viz.play_button.set_sensitive(False)
+ break
+ #print "sim: Current time is %f; Run until: %f" % (ns3.Simulator.Now ().GetSeconds (), self.target_time)
+ #if ns3.Simulator.Now ().GetSeconds () > self.target_time:
+ # print "skipping, model is ahead of view!"
+ self.sim_helper.SimulatorRunUntil(ns3.Seconds(self.target_time))
+ #print "sim: Run until ended at current time: ", ns3.Simulator.Now ().GetSeconds ()
+ self.pause_messages.extend(self.sim_helper.GetPauseMessages())
+ gobject.idle_add(self.viz.update_model, priority=PRIORITY_UPDATE_MODEL)
+ #print "sim: Run until: ", self.target_time, ": finished."
+ finally:
+ self.lock.release()
+ #print "sim: Release lock, loop."
+
+# enumeration
+class ShowTransmissionsMode(object):
+ __slots__ = []
+ShowTransmissionsMode.ALL = ShowTransmissionsMode()
+ShowTransmissionsMode.NONE = ShowTransmissionsMode()
+ShowTransmissionsMode.SELECTED = ShowTransmissionsMode()
+
+class Visualizer(gobject.GObject):
+ INSTANCE = None
+
+ if _import_error is None:
+ __gsignals__ = {
+
+ # signal emitted whenever a right-click-on-node popup menu is being constructed
+ 'populate-node-menu': (gobject.SIGNAL_RUN_LAST, None, (object, gtk.Menu,)),
+
+ # signal emitted after every simulation period (SAMPLE_PERIOD seconds of simulated time)
+ # the simulation lock is acquired while the signal is emitted
+ 'simulation-periodic-update': (gobject.SIGNAL_RUN_LAST, None, ()),
+
+ # signal emitted right after the topology is scanned
+ 'topology-scanned': (gobject.SIGNAL_RUN_LAST, None, ()),
+
+ # signal emitted when it's time to update the view objects
+ 'update-view': (gobject.SIGNAL_RUN_LAST, None, ()),
+
+ }
+
+ def __init__(self):
+ assert Visualizer.INSTANCE is None
+ Visualizer.INSTANCE = self
+ super(Visualizer, self).__init__()
+ self.nodes = {} # node index -> Node
+ self.channels = {} # id(ns3.Channel) -> Channel
+ self.window = None # toplevel window
+ self.canvas = None # goocanvas.Canvas
+ self.time_label = None # gtk.Label
+ self.play_button = None # gtk.ToggleButton
+ self.zoom = None # gtk.Adjustment
+ self._scrolled_window = None # gtk.ScrolledWindow
+
+ self.links_group = goocanvas.Group()
+ self.channels_group = goocanvas.Group()
+ self.nodes_group = goocanvas.Group()
+
+ self._update_timeout_id = None
+ self.simulation = SimulationThread(self)
+ self.selected_node = None # node currently selected
+ self.speed = 1.0
+ self.information_windows = []
+ self._transmission_arrows = []
+ self._last_transmissions = []
+ self._drop_arrows = []
+ self._last_drops = []
+ self._show_transmissions_mode = None
+ self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
+ self._panning_state = None
+ self.node_size_adjustment = None
+ self.transmissions_smoothing_adjustment = None
+ self.sample_period = SAMPLE_PERIOD
+ self.node_drag_state = None
+ self.follow_node = None
+ self.shell_window = None
+
+ self.create_gui()
+
+ for plugin in plugins:
+ plugin(self)
+
+ def set_show_transmissions_mode(self, mode):
+ assert isinstance(mode, ShowTransmissionsMode)
+ self._show_transmissions_mode = mode
+ if self._show_transmissions_mode == ShowTransmissionsMode.ALL:
+ self.simulation.set_nodes_of_interest(range(ns3.NodeList.GetNNodes()))
+ elif self._show_transmissions_mode == ShowTransmissionsMode.NONE:
+ self.simulation.set_nodes_of_interest([])
+ elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
+ if self.selected_node is None:
+ self.simulation.set_nodes_of_interest([])
+ else:
+ self.simulation.set_nodes_of_interest([self.selected_node.node_index])
+
+ def _create_advanced_controls(self):
+ expander = gtk.Expander("Advanced")
+ expander.show()
+
+ main_vbox = gobject.new(gtk.VBox, border_width=8, visible=True)
+ expander.add(main_vbox)
+
+ main_hbox1 = gobject.new(gtk.HBox, border_width=8, visible=True)
+ main_vbox.pack_start(main_hbox1)
+
+ show_transmissions_group = HIGContainer("Show transmissions")
+ show_transmissions_group.show()
+ main_hbox1.pack_start(show_transmissions_group, False, False, 8)
+
+ vbox = gtk.VBox(True, 4)
+ vbox.show()
+ show_transmissions_group.add(vbox)
+
+ all_nodes = gtk.RadioButton(None)
+ all_nodes.set_label("All nodes")
+ all_nodes.set_active(True)
+ all_nodes.show()
+ vbox.add(all_nodes)
+
+ selected_node = gtk.RadioButton(all_nodes)
+ selected_node.show()
+ selected_node.set_label("Selected node")
+ selected_node.set_active(False)
+ vbox.add(selected_node)
+
+ no_node = gtk.RadioButton(all_nodes)
+ no_node.show()
+ no_node.set_label("Disabled")
+ no_node.set_active(False)
+ vbox.add(no_node)
+
+ def toggled(radio):
+ if radio.get_active():
+ self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
+ all_nodes.connect("toggled", toggled)
+
+ def toggled(radio):
+ if radio.get_active():
+ self.set_show_transmissions_mode(ShowTransmissionsMode.NONE)
+ no_node.connect("toggled", toggled)
+
+ def toggled(radio):
+ if radio.get_active():
+ self.set_show_transmissions_mode(ShowTransmissionsMode.SELECTED)
+ selected_node.connect("toggled", toggled)
+
+
+ # -- misc settings
+ misc_settings_group = HIGContainer("Misc Settings")
+ misc_settings_group.show()
+ main_hbox1.pack_start(misc_settings_group, False, False, 8)
+ settings_hbox = gobject.new(gtk.HBox, border_width=8, visible=True)
+ misc_settings_group.add(settings_hbox)
+
+ # --> node size
+ vbox = gobject.new(gtk.VBox, border_width=0, visible=True)
+ scale = gobject.new(gtk.HScale, visible=True, digits=2)
+ vbox.pack_start(scale, True, True, 0)
+ vbox.pack_start(gobject.new(gtk.Label, label="Node Size", visible=True), True, True, 0)
+ settings_hbox.pack_start(vbox, False, False, 6)
+ self.node_size_adjustment = scale.get_adjustment()
+ def node_size_changed(adj):
+ for node in self.nodes.itervalues():
+ node.set_size(adj.value)
+ self.node_size_adjustment.connect("value-changed", node_size_changed)
+ self.node_size_adjustment.set_all(DEFAULT_NODE_SIZE, 0.01, 20, 0.1)
+
+ # --> transmissions smooth factor
+ vbox = gobject.new(gtk.VBox, border_width=0, visible=True)
+ scale = gobject.new(gtk.HScale, visible=True, digits=1)
+ vbox.pack_start(scale, True, True, 0)
+ vbox.pack_start(gobject.new(gtk.Label, label="Tx. Smooth Factor (s)", visible=True), True, True, 0)
+ settings_hbox.pack_start(vbox, False, False, 6)
+ self.transmissions_smoothing_adjustment = scale.get_adjustment()
+ self.transmissions_smoothing_adjustment.set_all(DEFAULT_TRANSMISSIONS_MEMORY*0.1, 0.1, 10, 0.1)
+
+ return expander
+
+ class _PanningState(object):
+ __slots__ = ['initial_mouse_pos', 'initial_canvas_pos', 'motion_signal']
+
+ def _begin_panning(self, widget, event):
+ self.canvas.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
+ self._panning_state = self._PanningState()
+ x, y, dummy = widget.window.get_pointer()
+ self._panning_state.initial_mouse_pos = (x, y)
+ x = self._scrolled_window.get_hadjustment().value
+ y = self._scrolled_window.get_vadjustment().value
+ self._panning_state.initial_canvas_pos = (x, y)
+ self._panning_state.motion_signal = self.canvas.connect("motion-notify-event", self._panning_motion)
+
+ def _end_panning(self, event):
+ if self._panning_state is None:
+ return
+ self.canvas.window.set_cursor(None)
+ self.canvas.disconnect(self._panning_state.motion_signal)
+ self._panning_state = None
+
+ def _panning_motion(self, widget, event):
+ assert self._panning_state is not None
+ if event.is_hint:
+ x, y, dummy = widget.window.get_pointer()
+ else:
+ x, y = event.x, event.y
+
+ hadj = self._scrolled_window.get_hadjustment()
+ vadj = self._scrolled_window.get_vadjustment()
+ mx0, my0 = self._panning_state.initial_mouse_pos
+ cx0, cy0 = self._panning_state.initial_canvas_pos
+
+ dx = x - mx0
+ dy = y - my0
+ hadj.value = cx0 - dx
+ vadj.value = cy0 - dy
+ return True
+
+ def _canvas_button_press(self, widget, event):
+ if event.button == 2:
+ self._begin_panning(widget, event)
+ return True
+ return False
+
+ def _canvas_button_release(self, dummy_widget, event):
+ if event.button == 2:
+ self._end_panning(event)
+ return True
+ return False
+
+ def _canvas_scroll_event(self, dummy_widget, event):
+ if event.direction == gtk.gdk.SCROLL_UP:
+ self.zoom.value *= 1.25
+ return True
+ elif event.direction == gtk.gdk.SCROLL_DOWN:
+ self.zoom.value /= 1.25
+ return True
+ return False
+
+ def get_hadjustment(self):
+ return self._scrolled_window.get_hadjustment()
+ def get_vadjustment(self):
+ return self._scrolled_window.get_vadjustment()
+
+ def create_gui(self):
+ self.window = gtk.Window()
+ vbox = gtk.VBox(); vbox.show()
+ self.window.add(vbox)
+
+ # canvas
+ self.canvas = goocanvas.Canvas()
+ self.canvas.connect_after("button-press-event", self._canvas_button_press)
+ self.canvas.connect_after("button-release-event", self._canvas_button_release)
+ self.canvas.connect("scroll-event", self._canvas_scroll_event)
+ self.canvas.props.has_tooltip = True
+ self.canvas.connect("query-tooltip", self._canvas_tooltip_cb)
+ self.canvas.show()
+ sw = gtk.ScrolledWindow(); sw.show()
+ self._scrolled_window = sw
+ sw.add(self.canvas)
+ vbox.pack_start(sw, True, True, 4)
+ self.canvas.set_size_request(600, 450)
+ self.canvas.set_bounds(-10000, -10000, 10000, 10000)
+ self.canvas.scroll_to(0, 0)
+
+
+ self.canvas.get_root_item().add_child(self.links_group)
+ self.links_group.set_property("visibility", goocanvas.ITEM_VISIBLE)
+
+ self.canvas.get_root_item().add_child(self.channels_group)
+ self.channels_group.set_property("visibility", goocanvas.ITEM_VISIBLE)
+ self.channels_group.raise_(self.links_group)
+
+ self.canvas.get_root_item().add_child(self.nodes_group)
+ self.nodes_group.set_property("visibility", goocanvas.ITEM_VISIBLE)
+ self.nodes_group.raise_(self.channels_group)
+
+ self.hud = hud.Axes(self)
+
+ hbox = gtk.HBox(); hbox.show()
+ vbox.pack_start(hbox, False, False, 4)
+
+ # zoom
+ zoom_adj = gtk.Adjustment(1.0, 0.01, 10.0, 0.02, 1.0, 0)
+ self.zoom = zoom_adj
+ def _zoom_changed(adj):
+ self.canvas.set_scale(adj.value)
+ zoom_adj.connect("value-changed", _zoom_changed)
+ zoom = gtk.SpinButton(zoom_adj)
+ zoom.set_digits(3)
+ zoom.show()
+ hbox.pack_start(gobject.new(gtk.Label, label=" Zoom:", visible=True), False, False, 4)
+ hbox.pack_start(zoom, False, False, 4)
+ _zoom_changed(zoom_adj)
+
+ # speed
+ speed_adj = gtk.Adjustment(1.0, 0.01, 10.0, 0.02, 1.0, 0)
+ def _speed_changed(adj):
+ self.speed = adj.value
+ self.sample_period = SAMPLE_PERIOD*adj.value
+ self._start_update_timer()
+ speed_adj.connect("value-changed", _speed_changed)
+ speed = gtk.SpinButton(speed_adj)
+ speed.set_digits(3)
+ speed.show()
+ hbox.pack_start(gobject.new(gtk.Label, label=" Speed:", visible=True), False, False, 4)
+ hbox.pack_start(speed, False, False, 4)
+ _speed_changed(speed_adj)
+
+ # Current time
+ self.time_label = gobject.new(gtk.Label, label=" Speed:", visible=True)
+ self.time_label.set_width_chars(20)
+ hbox.pack_start(self.time_label, False, False, 4)
+
+ # Screenshot button
+ screenshot_button = gobject.new(gtk.Button,
+ label="Snapshot",
+ relief=gtk.RELIEF_NONE, focus_on_click=False,
+ visible=True)
+ hbox.pack_start(screenshot_button, False, False, 4)
+
+ def load_button_icon(button, icon_name):
+ try:
+ import gnomedesktop
+ except ImportError:
+ sys.stderr.write("Could not load icon %s due to missing gnomedesktop Python module\n" % icon_name)
+ else:
+ icon = gnomedesktop.find_icon(gtk.icon_theme_get_default(), icon_name, 16, 0)
+ if icon is not None:
+ button.props.image = gobject.new(gtk.Image, file=icon, visible=True)
+
+ load_button_icon(screenshot_button, "applets-screenshooter")
+ screenshot_button.connect("clicked", self._take_screenshot)
+
+ # Shell button
+ if ipython_view is not None:
+ shell_button = gobject.new(gtk.Button,
+ label="Shell",
+ relief=gtk.RELIEF_NONE, focus_on_click=False,
+ visible=True)
+ hbox.pack_start(shell_button, False, False, 4)
+ load_button_icon(shell_button, "gnome-terminal")
+ shell_button.connect("clicked", self._start_shell)
+
+ # Play button
+ self.play_button = gobject.new(gtk.ToggleButton,
+ image=gobject.new(gtk.Image, stock=gtk.STOCK_MEDIA_PLAY, visible=True),
+ label="Simulate (F3)",
+ relief=gtk.RELIEF_NONE, focus_on_click=False,
+ use_stock=True, visible=True)
+ accel_group = gtk.AccelGroup()
+ self.window.add_accel_group(accel_group)
+ self.play_button.add_accelerator("clicked", accel_group,
+ gtk.keysyms.F3, 0, gtk.ACCEL_VISIBLE)
+ self.play_button.connect("toggled", self._on_play_button_toggled)
+ hbox.pack_start(self.play_button, False, False, 4)
+
+ self.canvas.get_root_item().connect("button-press-event", self.on_root_button_press_event)
+
+ vbox.pack_start(self._create_advanced_controls(), False, False, 4)
+
+ self.window.show()
+
+ def scan_topology(self):
+ print "scanning topology: %i nodes..." % (ns3.NodeList.GetNNodes(),)
+ graph = pygraphviz.AGraph()
+ seen_nodes = 0
+ for nodeI in range(ns3.NodeList.GetNNodes()):
+ seen_nodes += 1
+ if seen_nodes == 100:
+ print "scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns3.NodeList.GetNNodes())
+ seen_nodes = 0
+ node = ns3.NodeList.GetNode(nodeI)
+ node_name = "Node %i" % nodeI
+ node_view = self.get_node(nodeI)
+
+ mobility = node.GetObject(ns3.MobilityModel.GetTypeId())
+ if mobility is not None:
+ node_view.set_color("red")
+ pos = mobility.GetPosition()
+ node_view.set_position(*transform_point_simulation_to_canvas(pos.x, pos.y))
+ #print "node has mobility position -> ", "%f,%f" % (pos.x, pos.y)
+ else:
+ graph.add_node(node_name)
+
+ for devI in range(node.GetNDevices()):
+ device = node.GetDevice(devI)
+ device_traits = lookup_netdevice_traits(type(device))
+ if device_traits.is_wireless:
+ continue
+ if device_traits.is_virtual:
+ continue
+ channel = device.GetChannel()
+ if channel.GetNDevices() > 2:
+ if REPRESENT_CHANNELS_AS_NODES:
+ # represent channels as white nodes
+ if mobility is None:
+ channel_name = "Channel %s" % id(channel)
+ graph.add_edge(node_name, channel_name)
+ self.get_channel(channel)
+ self.create_link(self.get_node(nodeI), self.get_channel(channel))
+ else:
+ # don't represent channels, just add links between nodes in the same channel
+ for otherDevI in range(channel.GetNDevices()):
+ otherDev = channel.GetDevice(otherDevI)
+ otherNode = otherDev.GetNode()
+ otherNodeView = self.get_node(otherNode.GetId())
+ if otherNode is not node:
+ if mobility is None and not otherNodeView.has_mobility:
+ other_node_name = "Node %i" % otherNode.GetId()
+ graph.add_edge(node_name, other_node_name)
+ self.create_link(self.get_node(nodeI), otherNodeView)
+ else:
+ for otherDevI in range(channel.GetNDevices()):
+ otherDev = channel.GetDevice(otherDevI)
+ otherNode = otherDev.GetNode()
+ otherNodeView = self.get_node(otherNode.GetId())
+ if otherNode is not node:
+ if mobility is None and not otherNodeView.has_mobility:
+ other_node_name = "Node %i" % otherNode.GetId()
+ graph.add_edge(node_name, other_node_name)
+ self.create_link(self.get_node(nodeI), otherNodeView)
+
+ print "scanning topology: calling graphviz layout"
+ graph.layout(LAYOUT_ALGORITHM)
+ for node in graph.iternodes():
+ #print node, "=>", node.attr['pos']
+ node_type, node_id = node.split(' ')
+ pos_x, pos_y = [float(s) for s in node.attr['pos'].split(',')]
+ if node_type == 'Node':
+ obj = self.nodes[int(node_id)]
+ elif node_type == 'Channel':
+ obj = self.channels[int(node_id)]
+ obj.set_position(pos_x, pos_y)
+
+ print "scanning topology: all done."
+ self.emit("topology-scanned")
+
+ def get_node(self, index):
+ try:
+ return self.nodes[index]
+ except KeyError:
+ node = Node(self, index)
+ self.nodes[index] = node
+ self.nodes_group.add_child(node.canvas_item)
+ node.canvas_item.connect("button-press-event", self.on_node_button_press_event, node)
+ node.canvas_item.connect("button-release-event", self.on_node_button_release_event, node)
+ return node
+
+ def get_channel(self, ns3_channel):
+ try:
+ return self.channels[id(ns3_channel)]
+ except KeyError:
+ channel = Channel(ns3_channel)
+ self.channels[id(ns3_channel)] = channel
+ self.channels_group.add_child(channel.canvas_item)
+ return channel
+
+ def create_link(self, node, node_or_channel):
+ link = WiredLink(node, node_or_channel)
+ self.links_group.add_child(link.canvas_item)
+ link.canvas_item.lower(None)
+
+ def update_view(self):
+ #print "update_view"
+
+ self.time_label.set_text("Time: %f s" % ns3.Simulator.Now().GetSeconds())
+
+ self._update_node_positions()
+
+ # Update information
+ for info_win in self.information_windows:
+ info_win.update()
+
+ self._update_transmissions_view()
+ self._update_drops_view()
+
+ self.emit("update-view")
+
+ def _update_node_positions(self):
+ for node in self.nodes.itervalues():
+ if node.has_mobility:
+ ns3_node = ns3.NodeList.GetNode(node.node_index)
+ mobility = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ if mobility is not None:
+ pos = mobility.GetPosition()
+ x, y = transform_point_simulation_to_canvas(pos.x, pos.y)
+ node.set_position(x, y)
+ if node is self.follow_node:
+ hadj = self._scrolled_window.get_hadjustment()
+ vadj = self._scrolled_window.get_vadjustment()
+ px, py = self.canvas.convert_to_pixels(x, y)
+ hadj.value = px - hadj.page_size/2
+ vadj.value = py - vadj.page_size/2
+
+ def center_on_node(self, node):
+ if isinstance(node, ns3.Node):
+ node = self.nodes[node.GetId()]
+ elif isinstance(node, (int, long)):
+ node = self.nodes[node]
+ elif isinstance(node, Node):
+ pass
+ else:
+ raise TypeError("expected int, viz.Node or ns3.Node, not %r" % node)
+
+ x, y = node.get_position()
+ hadj = self._scrolled_window.get_hadjustment()
+ vadj = self._scrolled_window.get_vadjustment()
+ px, py = self.canvas.convert_to_pixels(x, y)
+ hadj.value = px - hadj.page_size/2
+ vadj.value = py - vadj.page_size/2
+
+
+ def update_model(self):
+ self.simulation.lock.acquire()
+ try:
+ self.emit("simulation-periodic-update")
+ finally:
+ self.simulation.lock.release()
+
+ def do_simulation_periodic_update(self):
+ smooth_factor = int(self.transmissions_smoothing_adjustment.value*10)
+
+ transmissions = self.simulation.sim_helper.GetTransmissionSamples()
+ self._last_transmissions.append(transmissions)
+ while len(self._last_transmissions) > smooth_factor:
+ self._last_transmissions.pop(0)
+
+ drops = self.simulation.sim_helper.GetPacketDropSamples()
+ self._last_drops.append(drops)
+ while len(self._last_drops) > smooth_factor:
+ self._last_drops.pop(0)
+
+ def _get_label_over_line_position(self, pos1_x, pos1_y, pos2_x, pos2_y):
+ hadj = self._scrolled_window.get_hadjustment()
+ vadj = self._scrolled_window.get_vadjustment()
+ bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.value, vadj.value)
+ bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.value + hadj.page_size,
+ vadj.value + vadj.page_size)
+ pos1_x, pos1_y, pos2_x, pos2_y = ns3.PyViz.LineClipping(bounds_x1, bounds_y1,
+ bounds_x2, bounds_y2,
+ pos1_x, pos1_y,
+ pos2_x, pos2_y)
+ return (pos1_x + pos2_x)/2, (pos1_y + pos2_y)/2
+
+ def _update_transmissions_view(self):
+ transmissions_average = {}
+ for transmission_set in self._last_transmissions:
+ for transmission in transmission_set:
+ key = (transmission.transmitter.GetId(), transmission.receiver.GetId())
+ rx_bytes, count = transmissions_average.get(key, (0, 0))
+ rx_bytes += transmission.bytes
+ count += 1
+ transmissions_average[key] = rx_bytes, count
+
+ old_arrows = self._transmission_arrows
+ for arrow, label in old_arrows:
+ arrow.set_property("visibility", goocanvas.ITEM_HIDDEN)
+ label.set_property("visibility", goocanvas.ITEM_HIDDEN)
+ new_arrows = []
+
+ k = self.node_size_adjustment.value/5
+
+ for (transmitter_id, receiver_id), (rx_bytes, rx_count) in transmissions_average.iteritems():
+ transmitter = self.get_node(transmitter_id)
+ receiver = self.get_node(receiver_id)
+ try:
+ arrow, label = old_arrows.pop()
+ except IndexError:
+ arrow = goocanvas.Polyline(line_width=2.0, stroke_color_rgba=0x00C000C0, close_path=False, end_arrow=True)
+ arrow.set_property("parent", self.canvas.get_root_item())
+ arrow.props.pointer_events = 0
+ arrow.raise_(None)
+
+ label = goocanvas.Text(parent=self.canvas.get_root_item(), pointer_events=0)
+ label.raise_(None)
+
+ arrow.set_property("visibility", goocanvas.ITEM_VISIBLE)
+ line_width = max(0.1, math.log(float(rx_bytes)/rx_count/self.sample_period)*k)
+ arrow.set_property("line-width", line_width)
+
+ pos1_x, pos1_y = transmitter.get_position()
+ pos2_x, pos2_y = receiver.get_position()
+ points = goocanvas.Points([(pos1_x, pos1_y), (pos2_x, pos2_y)])
+ arrow.set_property("points", points)
+
+ kbps = float(rx_bytes*8)/1e3/rx_count/self.sample_period
+ label.set_properties(visibility=goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD,
+ visibility_threshold=0.5,
+ font=("Sans Serif %f" % int(1+BITRATE_FONT_SIZE*k)))
+ angle = math.atan2((pos2_y - pos1_y), (pos2_x - pos1_x))
+ if -PI_OVER_2 <= angle <= PI_OVER_2:
+ label.set_properties(text=("%.2f kbit/s →" % (kbps,)),
+ alignment=pango.ALIGN_CENTER,
+ anchor=gtk.ANCHOR_S,
+ x=0, y=-line_width/2)
+ M = cairo.Matrix()
+ M.translate(*self._get_label_over_line_position(pos1_x, pos1_y, pos2_x, pos2_y))
+ M.rotate(angle)
+ label.set_transform(M)
+ else:
+ label.set_properties(text=("← %.2f kbit/s" % (kbps,)),
+ alignment=pango.ALIGN_CENTER,
+ anchor=gtk.ANCHOR_N,
+ x=0, y=line_width/2)
+ M = cairo.Matrix()
+ M.translate(*self._get_label_over_line_position(pos1_x, pos1_y, pos2_x, pos2_y))
+ M.rotate(angle)
+ M.scale(-1, -1)
+ label.set_transform(M)
+
+ new_arrows.append((arrow, label))
+
+ self._transmission_arrows = new_arrows + old_arrows
+
+
+ def _update_drops_view(self):
+ drops_average = {}
+ for drop_set in self._last_drops:
+ for drop in drop_set:
+ key = drop.transmitter.GetId()
+ drop_bytes, count = drops_average.get(key, (0, 0))
+ drop_bytes += drop.bytes
+ count += 1
+ drops_average[key] = drop_bytes, count
+
+ old_arrows = self._drop_arrows
+ for arrow, label in old_arrows:
+ arrow.set_property("visibility", goocanvas.ITEM_HIDDEN)
+ label.set_property("visibility", goocanvas.ITEM_HIDDEN)
+ new_arrows = []
+
+ # get the coordinates for the edge of screen
+ vadjustment = self._scrolled_window.get_vadjustment()
+ bottom_y = vadjustment.value + vadjustment.page_size
+ dummy, edge_y = self.canvas.convert_from_pixels(0, bottom_y)
+
+ k = self.node_size_adjustment.value/5
+
+ for transmitter_id, (drop_bytes, drop_count) in drops_average.iteritems():
+ transmitter = self.get_node(transmitter_id)
+ try:
+ arrow, label = old_arrows.pop()
+ except IndexError:
+ arrow = goocanvas.Polyline(line_width=2.0, stroke_color_rgba=0xC00000C0, close_path=False, end_arrow=True)
+ arrow.props.pointer_events = 0
+ arrow.set_property("parent", self.canvas.get_root_item())
+ arrow.raise_(None)
+
+ label = goocanvas.Text()#, fill_color_rgba=0x00C000C0)
+ label.props.pointer_events = 0
+ label.set_property("parent", self.canvas.get_root_item())
+ label.raise_(None)
+
+ arrow.set_property("visibility", goocanvas.ITEM_VISIBLE)
+ arrow.set_property("line-width", max(0.1, math.log(float(drop_bytes)/drop_count/self.sample_period)*k))
+ pos1_x, pos1_y = transmitter.get_position()
+ pos2_x, pos2_y = pos1_x, edge_y
+ points = goocanvas.Points([(pos1_x, pos1_y), (pos2_x, pos2_y)])
+ arrow.set_property("points", points)
+
+ label.set_properties(visibility=goocanvas.ITEM_VISIBLE_ABOVE_THRESHOLD,
+ visibility_threshold=0.5,
+ font=("Sans Serif %i" % int(1+BITRATE_FONT_SIZE*k)),
+ text=("%.2f kbit/s" % (float(drop_bytes*8)/1e3/drop_count/self.sample_period,)),
+ alignment=pango.ALIGN_CENTER,
+ x=(pos1_x + pos2_x)/2,
+ y=(pos1_y + pos2_y)/2)
+
+ new_arrows.append((arrow, label))
+
+ self._drop_arrows = new_arrows + old_arrows
+
+
+ def update_view_timeout(self):
+ #print "view: update_view_timeout called at real time ", time.time()
+
+ # while the simulator is busy, run the gtk event loop
+ while not self.simulation.lock.acquire(False):
+ while gtk.events_pending():
+ gtk.main_iteration()
+ pause_messages = self.simulation.pause_messages
+ self.simulation.pause_messages = []
+ try:
+ self.update_view()
+ self.simulation.target_time = ns3.Simulator.Now ().GetSeconds () + self.sample_period
+ #print "view: target time set to %f" % self.simulation.target_time
+ finally:
+ self.simulation.lock.release()
+
+ if pause_messages:
+ #print pause_messages
+ dialog = gtk.MessageDialog(parent=self.window, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_OK,
+ message_format='\n'.join(pause_messages))
+ dialog.connect("response", lambda d, r: d.destroy())
+ dialog.show()
+ self.play_button.set_active(False)
+
+ # if we're paused, stop the update timer
+ if not self.play_button.get_active():
+ self._update_timeout_id = None
+ return False
+
+ #print "view: self.simulation.go.set()"
+ self.simulation.go.set()
+ #print "view: done."
+ return True
+
+ def _start_update_timer(self):
+ if self._update_timeout_id is not None:
+ gobject.source_remove(self._update_timeout_id)
+ #print "start_update_timer"
+ self._update_timeout_id = gobject.timeout_add(int(SAMPLE_PERIOD/min(self.speed, 1)*1e3),
+ self.update_view_timeout,
+ priority=PRIORITY_UPDATE_VIEW)
+
+ def _on_play_button_toggled(self, button):
+ if button.get_active():
+ self._start_update_timer()
+ else:
+ if self._update_timeout_id is not None:
+ gobject.source_remove(self._update_timeout_id)
+
+ def _quit(self, *dummy_args):
+ if self._update_timeout_id is not None:
+ gobject.source_remove(self._update_timeout_id)
+ self._update_timeout_id = None
+ self.simulation.quit = True
+ self.simulation.go.set()
+ self.simulation.join()
+ gtk.main_quit()
+
+ def _monkey_patch_ipython(self):
+ # The user may want to access the NS 3 simulation state, but
+ # NS 3 is not thread safe, so it could cause serious problems.
+ # To work around this, monkey-patch IPython to automatically
+ # acquire and release the simulation lock around each code
+ # that is executed.
+
+ original_runcode = __IPYTHON__.runcode
+ def runcode(ip, *args):
+ #print "lock"
+ self.simulation.lock.acquire()
+ try:
+ return original_runcode(*args)
+ finally:
+ #print "unlock"
+ self.simulation.lock.release()
+ import types
+ __IPYTHON__.runcode = types.MethodType(runcode, __IPYTHON__)
+
+ def autoscale_view(self):
+ self._update_node_positions()
+ positions = [node.get_position() for node in self.nodes.itervalues()]
+ min_x, min_y = min(x for (x,y) in positions), min(y for (x,y) in positions)
+ max_x, max_y = max(x for (x,y) in positions), max(y for (x,y) in positions)
+ min_x_px, min_y_px = self.canvas.convert_to_pixels(min_x, min_y)
+ max_x_px, max_y_px = self.canvas.convert_to_pixels(max_x, max_y)
+ dx = max_x - min_x
+ dy = max_y - min_y
+ dx_px = max_x_px - min_x_px
+ dy_px = max_y_px - min_y_px
+ hadj = self._scrolled_window.get_hadjustment()
+ vadj = self._scrolled_window.get_vadjustment()
+ new_dx, new_dy = 1.5*dx_px, 1.5*dy_px
+
+ if new_dx == 0 or new_dy == 0:
+ return
+
+ self.zoom.value = min(hadj.page_size/new_dx, vadj.page_size/new_dy)
+
+ x1, y1 = self.canvas.convert_from_pixels(hadj.value, vadj.value)
+ x2, y2 = self.canvas.convert_from_pixels(hadj.value+hadj.page_size, vadj.value+vadj.page_size)
+ width = x2 - x1
+ height = y2 - y1
+ center_x = (min_x + max_x) / 2
+ center_y = (min_y + max_y) / 2
+
+ self.canvas.scroll_to(center_x - width/2, center_y - height/2)
+
+ return False
+
+ def start(self):
+ self.scan_topology()
+ self.window.connect("delete-event", self._quit)
+ #self._start_update_timer()
+ gobject.timeout_add(200, self.autoscale_view)
+ self.simulation.start()
+
+ try:
+ __IPYTHON__
+ except NameError:
+ pass
+ else:
+ self._monkey_patch_ipython()
+
+ gtk.main()
+
+
+ def on_root_button_press_event(self, view, target, event):
+ if event.button == 1:
+ self.select_node(None)
+ return True
+
+ def on_node_button_press_event(self, view, target, event, node):
+ if event.button == 1:
+ self.select_node(node)
+ return True
+ elif event.button == 3:
+ self.popup_node_menu(node, event)
+ return True
+ elif event.button == 2:
+ self.begin_node_drag(node)
+ return True
+ return False
+
+ def on_node_button_release_event(self, view, target, event, node):
+ if event.button == 2:
+ self.end_node_drag(node)
+ return True
+ return False
+
+ class NodeDragState(object):
+ def __init__(self, canvas_x0, canvas_y0, sim_x0, sim_y0):
+ self.canvas_x0 = canvas_x0
+ self.canvas_y0 = canvas_y0
+ self.sim_x0 = sim_x0
+ self.sim_y0 = sim_y0
+ self.motion_signal = None
+
+ def begin_node_drag(self, node):
+ self.simulation.lock.acquire()
+ try:
+ ns3_node = ns3.NodeList.GetNode(node.node_index)
+ mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ if mob is None:
+ return
+ if self.node_drag_state is not None:
+ return
+ pos = mob.GetPosition()
+ finally:
+ self.simulation.lock.release()
+ x, y, dummy = self.canvas.window.get_pointer()
+ x0, y0 = self.canvas.convert_from_pixels(x, y)
+ self.node_drag_state = self.NodeDragState(x0, y0, pos.x, pos.y)
+ self.node_drag_state.motion_signal = node.canvas_item.connect("motion-notify-event", self.node_drag_motion, node)
+
+ def node_drag_motion(self, item, targe_item, event, node):
+ self.simulation.lock.acquire()
+ try:
+ ns3_node = ns3.NodeList.GetNode(node.node_index)
+ mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ if mob is None:
+ return False
+ if self.node_drag_state is None:
+ return False
+ x, y, dummy = self.canvas.window.get_pointer()
+ canvas_x, canvas_y = self.canvas.convert_from_pixels(x, y)
+ dx = (canvas_x - self.node_drag_state.canvas_x0)
+ dy = (canvas_y - self.node_drag_state.canvas_y0)
+ pos = mob.GetPosition()
+ pos.x = self.node_drag_state.sim_x0 + transform_distance_canvas_to_simulation(dx)
+ pos.y = self.node_drag_state.sim_y0 + transform_distance_canvas_to_simulation(dy)
+ #print "SetPosition(%G, %G)" % (pos.x, pos.y)
+ mob.SetPosition(pos)
+ node.set_position(*transform_point_simulation_to_canvas(pos.x, pos.y))
+ finally:
+ self.simulation.lock.release()
+ return True
+
+ def end_node_drag(self, node):
+ if self.node_drag_state is None:
+ return
+ node.canvas_item.disconnect(self.node_drag_state.motion_signal)
+ self.node_drag_state = None
+
+ def popup_node_menu(self, node, event):
+ menu = gtk.Menu()
+ self.emit("populate-node-menu", node, menu)
+ menu.popup(None, None, None, event.button, event.time)
+
+ def _update_ipython_selected_node(self):
+ # If we are running under ipython -gthread, make this new
+ # selected node available as a global 'selected_node'
+ # variable.
+ try:
+ __IPYTHON__
+ except NameError:
+ pass
+ else:
+ if self.selected_node is None:
+ ns3_node = None
+ else:
+ self.simulation.lock.acquire()
+ try:
+ ns3_node = ns3.NodeList.GetNode(self.selected_node.node_index)
+ finally:
+ self.simulation.lock.release()
+ __IPYTHON__.user_ns['selected_node'] = ns3_node
+
+
+ def select_node(self, node):
+ if isinstance(node, ns3.Node):
+ node = self.nodes[node.GetId()]
+ elif isinstance(node, (int, long)):
+ node = self.nodes[node]
+ elif isinstance(node, Node):
+ pass
+ elif node is None:
+ pass
+ else:
+ raise TypeError("expected None, int, viz.Node or ns3.Node, not %r" % node)
+
+ if node is self.selected_node:
+ return
+
+ if self.selected_node is not None:
+ self.selected_node.selected = False
+ self.selected_node = node
+ if self.selected_node is not None:
+ self.selected_node.selected = True
+
+ if self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
+ if self.selected_node is None:
+ self.simulation.set_nodes_of_interest([])
+ else:
+ self.simulation.set_nodes_of_interest([self.selected_node.node_index])
+
+ self._update_ipython_selected_node()
+
+
+ def add_information_window(self, info_win):
+ self.information_windows.append(info_win)
+ self.simulation.lock.acquire()
+ try:
+ info_win.update()
+ finally:
+ self.simulation.lock.release()
+
+ def remove_information_window(self, info_win):
+ self.information_windows.remove(info_win)
+
+ def _canvas_tooltip_cb(self, canvas, x, y, keyboard_mode, tooltip):
+ #print "tooltip query: ", x, y
+ hadj = self._scrolled_window.get_hadjustment()
+ vadj = self._scrolled_window.get_vadjustment()
+ x, y = self.canvas.convert_from_pixels(hadj.value + x, vadj.value + y)
+ item = self.canvas.get_item_at(x, y, True)
+ #print "items at (%f, %f): %r | keyboard_mode=%r" % (x, y, item, keyboard_mode)
+ if not item:
+ return False
+ while item is not None:
+ obj = item.get_data("pyviz-object")
+ if obj is not None:
+ obj.tooltip_query(tooltip)
+ return True
+ item = item.props.parent
+ return False
+
+ def _get_export_file_name(self):
+ sel = gtk.FileChooserDialog("Save...", self.canvas.get_toplevel(),
+ gtk.FILE_CHOOSER_ACTION_SAVE,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_SAVE, gtk.RESPONSE_OK))
+ sel.set_default_response(gtk.RESPONSE_OK)
+ sel.set_local_only(True)
+ sel.set_do_overwrite_confirmation(True)
+ sel.set_current_name("Unnamed.pdf")
+
+ filter = gtk.FileFilter()
+ filter.set_name("Embedded PostScript")
+ filter.add_mime_type("image/x-eps")
+ sel.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Portable Document Graphics")
+ filter.add_mime_type("application/pdf")
+ sel.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Scalable Vector Graphics")
+ filter.add_mime_type("image/svg+xml")
+ sel.add_filter(filter)
+
+ resp = sel.run()
+ if resp != gtk.RESPONSE_OK:
+ sel.destroy()
+ return None
+
+ file_name = sel.get_filename()
+ sel.destroy()
+ return file_name
+
+ def _take_screenshot(self, dummy_button):
+ #print "Cheese!"
+ file_name = self._get_export_file_name()
+ if file_name is None:
+ return
+
+ # figure out the correct bounding box for what is visible on screen
+ x1 = self._scrolled_window.get_hadjustment().value
+ y1 = self._scrolled_window.get_vadjustment().value
+ x2 = x1 + self._scrolled_window.get_hadjustment().page_size
+ y2 = y1 + self._scrolled_window.get_vadjustment().page_size
+ bounds = goocanvas.Bounds()
+ bounds.x1, bounds.y1 = self.canvas.convert_from_pixels(x1, y1)
+ bounds.x2, bounds.y2 = self.canvas.convert_from_pixels(x2, y2)
+ dest_width = bounds.x2 - bounds.x1
+ dest_height = bounds.y2 - bounds.y1
+ #print bounds.x1, bounds.y1, " -> ", bounds.x2, bounds.y2
+
+ dummy, extension = os.path.splitext(file_name)
+ extension = extension.lower()
+ if extension == '.eps':
+ surface = cairo.PSSurface(file_name, dest_width, dest_height)
+ elif extension == '.pdf':
+ surface = cairo.PDFSurface(file_name, dest_width, dest_height)
+ elif extension == '.svg':
+ surface = cairo.SVGSurface(file_name, dest_width, dest_height)
+ else:
+ dialog = gtk.MessageDialog(parent = self.canvas.get_toplevel(),
+ flags = gtk.DIALOG_DESTROY_WITH_PARENT,
+ type = gtk.MESSAGE_ERROR,
+ buttons = gtk.BUTTONS_OK,
+ message_format = "Unknown extension '%s' (valid extensions are '.eps', '.svg', and '.pdf')"
+ % (extension,))
+ dialog.run()
+ dialog.destroy()
+ return
+
+ # draw the canvas to a printing context
+ cr = cairo.Context(surface)
+ cr.translate(-bounds.x1, -bounds.y1)
+ self.canvas.render(cr, bounds, self.zoom.value)
+ cr.show_page()
+ surface.finish()
+
+ def set_follow_node(self, node):
+ if isinstance(node, ns3.Node):
+ node = self.nodes[node.GetId()]
+ self.follow_node = node
+
+ def _start_shell(self, dummy_button):
+ if self.shell_window is not None:
+ self.shell_window.present()
+ return
+
+ self.shell_window = gtk.Window()
+ self.shell_window.set_size_request(750,550)
+ self.shell_window.set_resizable(True)
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
+ ipython = ipython_view.IPythonView()
+ ipython.modify_font(pango.FontDescription(SHELL_FONT))
+ ipython.set_wrap_mode(gtk.WRAP_CHAR)
+ ipython.show()
+ scrolled_window.add(ipython)
+ scrolled_window.show()
+ self.shell_window.add(scrolled_window)
+ self.shell_window.show()
+ self.shell_window.connect('destroy', self._on_shell_window_destroy)
+
+ self._update_ipython_selected_node()
+ __IPYTHON__.user_ns['viz'] = self
+
+
+ def _on_shell_window_destroy(self, window):
+ self.shell_window = None
+
+
+initialization_hooks = []
+
+def add_initialization_hook(hook, *args):
+ """
+ Adds a callback to be called after
+ the visualizer is initialized, like this::
+ initialization_hook(visualizer, *args)
+ """
+ global initialization_hooks
+ initialization_hooks.append((hook, args))
+
+
+def set_bounds(x1, y1, x2, y2):
+ assert x2>x1
+ assert y2>y1
+ def hook(viz):
+ cx1, cy1 = transform_point_simulation_to_canvas(x1, y1)
+ cx2, cy2 = transform_point_simulation_to_canvas(x2, y2)
+ viz.canvas.set_bounds(cx1, cy1, cx2, cy2)
+ add_initialization_hook(hook)
+
+
+def start():
+ assert Visualizer.INSTANCE is None
+ if _import_error is not None:
+ import sys
+ print >> sys.stderr, "No visualization support (%s)." % (str(_import_error),)
+ ns3.Simulator.Run()
+ return
+ load_plugins()
+ viz = Visualizer()
+ for hook, args in initialization_hooks:
+ gobject.idle_add(hook, viz, *args)
+ ns3.Packet.EnablePrinting()
+ viz.start()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/higcontainer.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,97 @@
+import gtk
+import gobject
+try:
+ from gazpacho.widgets.base.base import SimpleContainerAdaptor
+except ImportError:
+ pass
+
+#root_library = 'hig'
+
+
+class HIGContainer(gtk.Bin):
+ __gtype_name__ = 'HIGContainer'
+ __gproperties__ = {
+ 'title': (str, 'Group Title', 'the group title',
+ '', gobject.PARAM_READWRITE|gobject.PARAM_CONSTRUCT),
+ }
+
+ def __init__(self, title=None):
+ self.__title_text = None
+ gtk.widget_push_composite_child()
+ self.__title = gobject.new(gtk.Label, visible=True, xalign=0, yalign=0.5)
+ self.__indent = gobject.new(gtk.Label, visible=True, label=' ')
+ gtk.widget_pop_composite_child()
+ gtk.Bin.__init__(self)
+ self.__title.set_parent(self)
+ self.__indent.set_parent(self)
+ if title is not None:
+ self.props.title = title
+
+ def do_size_request(self, requisition):
+ title_req = gtk.gdk.Rectangle(0, 0, *self.__title.size_request())
+ indent_req = gtk.gdk.Rectangle(0, 0, *self.__indent.size_request())
+ if self.child is None:
+ child_req = gtk.gdk.Rectangle()
+ else:
+ child_req = gtk.gdk.Rectangle(0, 0, *self.child.size_request())
+ requisition.height = (title_req.height + 6 +
+ max(child_req.height, indent_req.height))
+ requisition.width = max(title_req.width, indent_req.width + child_req.width)
+
+ def do_size_allocate(self, allocation):
+ self.allocation = allocation
+
+ ## title
+ title_req = gtk.gdk.Rectangle(0, 0, *self.__title.get_child_requisition())
+ title_alloc = gtk.gdk.Rectangle()
+ title_alloc.x = allocation.x
+ title_alloc.y = allocation.y
+ title_alloc.width = min(title_req.width, allocation.width)
+ title_alloc.height = min(title_req.height, allocation.height)
+ self.__title.size_allocate(title_alloc)
+
+ ## child
+ if self.child is None:
+ return
+ indent_req = gtk.gdk.Rectangle(0, 0, *self.__indent.get_child_requisition())
+ child_req = gtk.gdk.Rectangle(0, 0, *self.child.get_child_requisition())
+ child_alloc = gtk.gdk.Rectangle()
+ child_alloc.x = allocation.x + indent_req.width
+ child_alloc.y = allocation.y + title_alloc.height + 6
+ child_alloc.width = allocation.width - indent_req.width
+ child_alloc.height = allocation.height - 6 - title_alloc.height
+ self.child.size_allocate(child_alloc)
+
+ def do_forall(self, internal, callback, data):
+ if internal:
+ callback(self.__title, data)
+ callback(self.__indent, data)
+ if self.child is not None:
+ callback(self.child, data)
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'title':
+ self.__title.set_markup('<span weight="bold">%s</span>' %
+ gobject.markup_escape_text(value))
+ self.__title_text = value
+ else:
+ raise AttributeError, 'unknown property %s' % pspec.name
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'title':
+ return self.__title_text
+ else:
+ raise AttributeError, 'unknown property %s' % pspec.name
+
+if __name__ == '__main__':
+ frame = gtk.Frame()
+ group = gobject.new(HIGContainer, title="Hello")
+ frame.add(group)
+ check = gtk.CheckButton("foobar")
+ group.add(check)
+ w = gtk.Window()
+ w.add(frame)
+ w.show_all()
+ w.connect("destroy", lambda w: gtk.main_quit())
+ gtk.main()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/hud.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,144 @@
+import goocanvas
+import core
+import math
+import pango
+import gtk
+
+
+class Axes(object):
+ def __init__(self, viz):
+ self.viz = viz
+ self.color = 0x8080C0FF
+ self.hlines = goocanvas.Path(parent=viz.canvas.get_root_item(), stroke_color_rgba=self.color)
+ self.hlines.lower(None)
+ self.vlines = goocanvas.Path(parent=viz.canvas.get_root_item(), stroke_color_rgba=self.color)
+ self.vlines.lower(None)
+ self.labels = []
+ hadj = self.viz.get_hadjustment()
+ vadj = self.viz.get_vadjustment()
+ def update(adj):
+ if self.visible:
+ self.update_view()
+ hadj.connect("value-changed", update)
+ vadj.connect("value-changed", update)
+ hadj.connect("changed", update)
+ vadj.connect("changed", update)
+ self.visible = True
+ self.update_view()
+
+ def set_visible(self, visible):
+ self.visible = visible
+ if self.visible:
+ self.hlines.props.visibility = goocanvas.ITEM_VISIBLE
+ self.vlines.props.visibility = goocanvas.ITEM_VISIBLE
+ else:
+ self.hlines.props.visibility = goocanvas.ITEM_HIDDEN
+ self.vlines.props.visibility = goocanvas.ITEM_HIDDEN
+ for label in self.labels:
+ label.props.visibility = goocanvas.ITEM_HIDDEN
+
+ def _compute_divisions(self, xi, xf):
+ assert xf > xi
+ dx = xf - xi
+ size = dx
+ ndiv = 5
+ text_width = dx/ndiv/2
+
+ def rint(x):
+ return math.floor(x+0.5)
+
+ dx_over_ndiv = dx / ndiv
+ for n in range(5): # iterate 5 times to find optimum division size
+ #/* div: length of each division */
+ tbe = math.log10(dx_over_ndiv)#; /* looking for approx. 'ndiv' divisions in a length 'dx' */
+ div = pow(10, rint(tbe))#; /* div: power of 10 closest to dx/ndiv */
+ if math.fabs(div/2 - dx_over_ndiv) < math.fabs(div - dx_over_ndiv): #/* test if div/2 is closer to dx/ndiv */
+ div /= 2
+ elif math.fabs(div*2 - dx_over_ndiv) < math.fabs(div - dx_over_ndiv):
+ div *= 2 # /* test if div*2 is closer to dx/ndiv */
+ x0 = div*math.ceil(xi / div) - div
+ if n > 1:
+ ndiv = rint(size / text_width)
+ return x0, div
+
+
+ def update_view(self):
+ if self.viz.zoom is None:
+ return
+
+ unused_labels = self.labels
+ self.labels = []
+ for label in unused_labels:
+ label.set_property("visibility", goocanvas.ITEM_HIDDEN)
+ def get_label():
+ try:
+ label = unused_labels.pop(0)
+ except IndexError:
+ label = goocanvas.Text(parent=self.viz.canvas.get_root_item(), stroke_color_rgba=self.color)
+ else:
+ label.set_property("visibility", goocanvas.ITEM_VISIBLE)
+ label.lower(None)
+ self.labels.append(label)
+ return label
+
+ hadj = self.viz.get_hadjustment()
+ vadj = self.viz.get_vadjustment()
+ zoom = self.viz.zoom.value
+ offset = 10/zoom
+
+ x1, y1 = self.viz.canvas.convert_from_pixels(hadj.value, vadj.value)
+ x2, y2 = self.viz.canvas.convert_from_pixels(hadj.value + hadj.page_size, vadj.value + vadj.page_size)
+ line_width = 5.0/self.viz.zoom.value
+
+ # draw the horizontal axis
+ self.hlines.set_property("line-width", line_width)
+ yc = y2 - line_width/2
+
+ sim_x1 = x1/core.PIXELS_PER_METER
+ sim_x2 = x2/core.PIXELS_PER_METER
+ x0, xdiv = self._compute_divisions(sim_x1, sim_x2)
+ path = ["M %r %r L %r %r" % (x1, yc, x2, yc)]
+ x = x0
+ while x < sim_x2:
+ path.append("M %r %r L %r %r" % (core.PIXELS_PER_METER*x, yc - offset, core.PIXELS_PER_METER*x, yc))
+ label = get_label()
+ label.set_properties(font=("Sans Serif %f" % int(12/zoom)),
+ text=("%G" % x),
+ fill_color_rgba=self.color,
+ alignment=pango.ALIGN_CENTER,
+ anchor=gtk.ANCHOR_S,
+ x=core.PIXELS_PER_METER*x,
+ y=(yc - offset))
+ x += xdiv
+ del x
+
+ self.hlines.set_property("data", " ".join(path))
+
+ # draw the vertical axis
+ self.vlines.set_property("line-width", line_width)
+ xc = x1 + line_width/2
+
+ sim_y1 = y1/core.PIXELS_PER_METER
+ sim_y2 = y2/core.PIXELS_PER_METER
+
+
+ y0, ydiv = self._compute_divisions(sim_y1, sim_y2)
+ path = ["M %r %r L %r %r" % (xc, y1, xc, y2)]
+ y = y0
+ while y < sim_y2:
+ path.append("M %r %r L %r %r" % (xc, core.PIXELS_PER_METER*y, xc + offset, core.PIXELS_PER_METER*y))
+ label = get_label()
+ label.set_properties(font=("Sans Serif %f" % int(12/zoom)),
+ text=("%G" % y),
+ fill_color_rgba=self.color,
+ alignment=pango.ALIGN_LEFT,
+ anchor=gtk.ANCHOR_W,
+ x=xc + offset,
+ y=core.PIXELS_PER_METER*y)
+ y += ydiv
+
+ self.vlines.set_property("data", " ".join(path))
+
+
+
+ self.labels.extend(unused_labels)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/ipython_view.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,296 @@
+"""
+Backend to the console plugin.
+
+@author: Eitan Isaacson
+@organization: IBM Corporation
+@copyright: Copyright (c) 2007 IBM Corporation
+@license: BSD
+
+All rights reserved. This program and the accompanying materials are made
+available under the terms of the BSD which accompanies this distribution, and
+is available at U{http://www.opensource.org/licenses/bsd-license.php}
+"""
+# this file is a modified version of source code from the Accerciser project
+# http://live.gnome.org/accerciser
+
+import gtk
+import re
+import sys
+import os
+import pango
+from StringIO import StringIO
+import IPython
+
+ansi_colors = {'0;30': 'Black',
+ '0;31': 'Red',
+ '0;32': 'Green',
+ '0;33': 'Brown',
+ '0;34': 'Blue',
+ '0;35': 'Purple',
+ '0;36': 'Cyan',
+ '0;37': 'LightGray',
+ '1;30': 'DarkGray',
+ '1;31': 'DarkRed',
+ '1;32': 'SeaGreen',
+ '1;33': 'Yellow',
+ '1;34': 'LightBlue',
+ '1;35': 'MediumPurple',
+ '1;36': 'LightCyan',
+ '1;37': 'White'}
+
+class IterableIPShell:
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,
+ cin=None, cout=None,cerr=None, input_func=None):
+ if input_func:
+ IPython.iplib.raw_input_original = input_func
+ if cin:
+ IPython.Shell.Term.cin = cin
+ if cout:
+ IPython.Shell.Term.cout = cout
+ if cerr:
+ IPython.Shell.Term.cerr = cerr
+
+ if argv is None:
+ argv=[]
+
+ # This is to get rid of the blockage that occurs during
+ # IPython.Shell.InteractiveShell.user_setup()
+ IPython.iplib.raw_input = lambda x: None
+
+ self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
+ os.environ['TERM'] = 'dumb'
+ excepthook = sys.excepthook
+ self.IP = IPython.Shell.make_IPython(argv,user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ embedded=True,
+ shell_class=IPython.Shell.InteractiveShell)
+ self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd),
+ header='IPython system call: ',
+ verbose=self.IP.rc.system_verbose)
+ sys.excepthook = excepthook
+ self.iter_more = 0
+ self.history_level = 0
+ self.complete_sep = re.compile('[\s\{\}\[\]\(\)]')
+
+ def execute(self):
+ self.history_level = 0
+ orig_stdout = sys.stdout
+ sys.stdout = IPython.Shell.Term.cout
+ try:
+ line = self.IP.raw_input(None, self.iter_more)
+ if self.IP.autoindent:
+ self.IP.readline_startup_hook(None)
+ except KeyboardInterrupt:
+ self.IP.write('\nKeyboardInterrupt\n')
+ self.IP.resetbuffer()
+ # keep cache in sync with the prompt counter:
+ self.IP.outputcache.prompt_count -= 1
+
+ if self.IP.autoindent:
+ self.IP.indent_current_nsp = 0
+ self.iter_more = 0
+ except:
+ self.IP.showtraceback()
+ else:
+ self.iter_more = self.IP.push(line)
+ if (self.IP.SyntaxTB.last_syntax_error and
+ self.IP.rc.autoedit_syntax):
+ self.IP.edit_syntax_error()
+ if self.iter_more:
+ self.prompt = str(self.IP.outputcache.prompt2).strip()
+ if self.IP.autoindent:
+ self.IP.readline_startup_hook(self.IP.pre_readline)
+ else:
+ self.prompt = str(self.IP.outputcache.prompt1).strip()
+ sys.stdout = orig_stdout
+
+ def historyBack(self):
+ self.history_level -= 1
+ return self._getHistory()
+
+ def historyForward(self):
+ self.history_level += 1
+ return self._getHistory()
+
+ def _getHistory(self):
+ try:
+ rv = self.IP.user_ns['In'][self.history_level].strip('\n')
+ except IndexError:
+ self.history_level = 0
+ rv = ''
+ return rv
+
+ def updateNamespace(self, ns_dict):
+ self.IP.user_ns.update(ns_dict)
+
+ def complete(self, line):
+ split_line = self.complete_sep.split(line)
+ possibilities = self.IP.complete(split_line[-1])
+ if possibilities:
+ common_prefix = reduce(self._commonPrefix, possibilities)
+ completed = line[:-len(split_line[-1])]+common_prefix
+ else:
+ completed = line
+ return completed, possibilities
+
+ def _commonPrefix(self, str1, str2):
+ for i in range(len(str1)):
+ if not str2.startswith(str1[:i+1]):
+ return str1[:i]
+ return str1
+
+ def shell(self, cmd,verbose=0,debug=0,header=''):
+ stat = 0
+ if verbose or debug: print header+cmd
+ # flush stdout so we don't mangle python's buffering
+ if not debug:
+ input, output = os.popen4(cmd)
+ print output.read()
+ output.close()
+ input.close()
+
+class ConsoleView(gtk.TextView):
+ def __init__(self):
+ gtk.TextView.__init__(self)
+ self.modify_font(pango.FontDescription('Mono'))
+ self.set_cursor_visible(True)
+ self.text_buffer = self.get_buffer()
+ self.mark = self.text_buffer.create_mark('scroll_mark',
+ self.text_buffer.get_end_iter(),
+ False)
+ for code in ansi_colors:
+ self.text_buffer.create_tag(code,
+ foreground=ansi_colors[code],
+ weight=700)
+ self.text_buffer.create_tag('0')
+ self.text_buffer.create_tag('notouch', editable=False)
+ self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
+ self.line_start = \
+ self.text_buffer.create_mark('line_start',
+ self.text_buffer.get_end_iter(), True
+ )
+ self.connect('key-press-event', self._onKeypress)
+ self.last_cursor_pos = 0
+
+ def write(self, text, editable=False):
+ segments = self.color_pat.split(text)
+ segment = segments.pop(0)
+ start_mark = self.text_buffer.create_mark(None,
+ self.text_buffer.get_end_iter(),
+ True)
+ self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
+
+ if segments:
+ ansi_tags = self.color_pat.findall(text)
+ for tag in ansi_tags:
+ i = segments.index(tag)
+ self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(),
+ segments[i+1], tag)
+ segments.pop(i)
+ if not editable:
+ self.text_buffer.apply_tag_by_name('notouch',
+ self.text_buffer.get_iter_at_mark(start_mark),
+ self.text_buffer.get_end_iter())
+ self.text_buffer.delete_mark(start_mark)
+ self.scroll_mark_onscreen(self.mark)
+
+ def showPrompt(self, prompt):
+ self.write(prompt)
+ self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
+
+ def changeLine(self, text):
+ iter = self.text_buffer.get_iter_at_mark(self.line_start)
+ iter.forward_to_line_end()
+ self.text_buffer.delete(self.text_buffer.get_iter_at_mark(self.line_start), iter)
+ self.write(text, True)
+
+ def getCurrentLine(self):
+ rv = self.text_buffer.get_slice(self.text_buffer.get_iter_at_mark(self.line_start),
+ self.text_buffer.get_end_iter(), False)
+ return rv
+
+ def showReturned(self, text):
+ iter = self.text_buffer.get_iter_at_mark(self.line_start)
+ iter.forward_to_line_end()
+ self.text_buffer.apply_tag_by_name('notouch',
+ self.text_buffer.get_iter_at_mark(self.line_start),
+ iter)
+ self.write('\n'+text)
+ if text:
+ self.write('\n')
+ self.showPrompt(self.prompt)
+ self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
+ self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
+
+ def _onKeypress(self, obj, event):
+ if not event.string:
+ return
+ insert_mark = self.text_buffer.get_insert()
+ insert_iter = self.text_buffer.get_iter_at_mark(insert_mark)
+ selection_mark = self.text_buffer.get_selection_bound()
+ selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
+ start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
+ if start_iter.compare(insert_iter) <= 0 and \
+ start_iter.compare(selection_iter) <= 0:
+ return
+ elif start_iter.compare(insert_iter) > 0 and \
+ start_iter.compare(selection_iter) > 0:
+ self.text_buffer.place_cursor(start_iter)
+ elif insert_iter.compare(selection_iter) < 0:
+ self.text_buffer.move_mark(insert_mark, start_iter)
+ elif insert_iter.compare(selection_iter) > 0:
+ self.text_buffer.move_mark(selection_mark, start_iter)
+
+
+class IPythonView(ConsoleView, IterableIPShell):
+ def __init__(self):
+ ConsoleView.__init__(self)
+ self.cout = StringIO()
+ IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout,
+ input_func=self.raw_input)
+ self.connect('key_press_event', self.keyPress)
+ self.execute()
+ self.cout.truncate(0)
+ self.showPrompt(self.prompt)
+ self.interrupt = False
+
+ def raw_input(self, prompt=''):
+ if self.interrupt:
+ self.interrupt = False
+ raise KeyboardInterrupt
+ return self.getCurrentLine()
+
+ def keyPress(self, widget, event):
+ if event.state & gtk.gdk.CONTROL_MASK and event.keyval == 99:
+ self.interrupt = True
+ self._processLine()
+ return True
+ elif event.keyval == gtk.keysyms.Return:
+ self._processLine()
+ return True
+ elif event.keyval == gtk.keysyms.Up:
+ self.changeLine(self.historyBack())
+ return True
+ elif event.keyval == gtk.keysyms.Down:
+ self.changeLine(self.historyForward())
+ return True
+ elif event.keyval == gtk.keysyms.Tab:
+ if not self.getCurrentLine().strip():
+ return False
+ completed, possibilities = self.complete(self.getCurrentLine())
+ if len(possibilities) > 1:
+ slice = self.getCurrentLine()
+ self.write('\n')
+ for symbol in possibilities:
+ self.write(symbol+'\n')
+ self.showPrompt(self.prompt)
+ self.changeLine(completed or slice)
+ return True
+
+ def _processLine(self):
+ self.history_pos = 0
+ self.execute()
+ rv = self.cout.getvalue()
+ if rv: rv = rv.strip('\n')
+ self.showReturned(rv)
+ self.cout.truncate(0)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/plugins/interface_statistics.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,167 @@
+import gtk
+import ns3
+from visualizer.base import InformationWindow
+
+NODE_STATISTICS_MEMORY = 10
+
+
+class StatisticsCollector(object):
+ """
+ Collects interface statistics for all nodes.
+ """
+
+ class NetDevStats(object):
+ __slots__ = ['rxPackets', 'rxBytes', 'txPackets', 'txBytes',
+ 'rxPacketRate', 'rxBitRate', 'txPacketRate', 'txBitRate']
+
+ def __init__(self, visualizer):
+ self.node_statistics = {} # nodeid -> list(raw statistics)
+ self.visualizer = visualizer
+
+ def simulation_periodic_update(self, viz):
+ nodes_statistics = viz.simulation.sim_helper.GetNodesStatistics()
+ for stats in nodes_statistics:
+ try:
+ raw_stats_list = self.node_statistics[stats.nodeId]
+ except KeyError:
+ raw_stats_list = []
+ self.node_statistics[stats.nodeId] = raw_stats_list
+ raw_stats_list.append(stats.statistics)
+ while len(raw_stats_list) > NODE_STATISTICS_MEMORY:
+ raw_stats_list.pop(0)
+
+ def get_interface_statistics(self, nodeId):
+ try:
+ raw_stats_list = self.node_statistics[nodeId]
+ except KeyError:
+ return []
+
+ if len(raw_stats_list) < NODE_STATISTICS_MEMORY:
+ return []
+ assert len(raw_stats_list) == NODE_STATISTICS_MEMORY
+ tx_packets1 = [] # transmitted packets, one value per interface
+ rx_packets1 = []
+ tx_bytes1 = []
+ rx_bytes1 = []
+ for iface, stats in enumerate(raw_stats_list[0]):
+ tx_packets1.append(stats.transmittedPackets)
+ tx_bytes1.append(stats.transmittedBytes)
+ rx_packets1.append(stats.receivedPackets)
+ rx_bytes1.append(stats.receivedBytes)
+
+ retval = []
+
+ k = self.visualizer.sample_period*(NODE_STATISTICS_MEMORY-1)
+ for iface, stats in enumerate(raw_stats_list[-1]):
+ outStat = self.NetDevStats()
+ outStat.txPackets = stats.transmittedPackets
+ outStat.txBytes = stats.transmittedBytes
+ outStat.rxPackets = stats.receivedPackets
+ outStat.rxBytes = stats.receivedBytes
+
+ outStat.txPacketRate = (stats.transmittedPackets - tx_packets1[iface])/k
+ outStat.rxPacketRate = (stats.receivedPackets - rx_packets1[iface])/k
+ outStat.txBitRate = (stats.transmittedBytes - tx_bytes1[iface])*8/k
+ outStat.rxBitRate = (stats.receivedBytes - rx_bytes1[iface])*8/k
+ retval.append(outStat)
+ return retval
+
+
+class ShowInterfaceStatistics(InformationWindow):
+ (
+ COLUMN_INTERFACE,
+
+ COLUMN_TX_PACKETS,
+ COLUMN_TX_BYTES,
+ COLUMN_TX_PACKET_RATE,
+ COLUMN_TX_BIT_RATE,
+
+ COLUMN_RX_PACKETS,
+ COLUMN_RX_BYTES,
+ COLUMN_RX_PACKET_RATE,
+ COLUMN_RX_BIT_RATE,
+
+ ) = range(9)
+
+ def __init__(self, visualizer, node_index, statistics_collector):
+ InformationWindow.__init__(self)
+ self.win = gtk.Dialog(parent=visualizer.window,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
+ buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ self.win.connect("response", self._response_cb)
+ self.win.set_title("Statistics for node %i" % node_index)
+ self.visualizer = visualizer
+ self.statistics_collector = statistics_collector
+ self.node_index = node_index
+ self.viz_node = visualizer.get_node(node_index)
+
+ self.table_model = gtk.ListStore(*([str]*13))
+
+ treeview = gtk.TreeView(self.table_model)
+ treeview.show()
+ self.win.vbox.add(treeview)
+
+ def add_column(descr, colid):
+ column = gtk.TreeViewColumn(descr, gtk.CellRendererText(), text=colid)
+ treeview.append_column(column)
+
+ add_column("Interface", self.COLUMN_INTERFACE)
+
+ add_column("Tx Packets", self.COLUMN_TX_PACKETS)
+ add_column("Tx Bytes", self.COLUMN_TX_BYTES)
+ add_column("Tx pkt/1s", self.COLUMN_TX_PACKET_RATE)
+ add_column("Tx bit/1s", self.COLUMN_TX_BIT_RATE)
+
+ add_column("Rx Packets", self.COLUMN_RX_PACKETS)
+ add_column("Rx Bytes", self.COLUMN_RX_BYTES)
+ add_column("Rx pkt/1s", self.COLUMN_RX_PACKET_RATE)
+ add_column("Rx bit/1s", self.COLUMN_RX_BIT_RATE)
+
+ self.visualizer.add_information_window(self)
+ self.win.show()
+
+ def _response_cb(self, win, response):
+ self.win.destroy()
+ self.visualizer.remove_information_window(self)
+
+ def update(self):
+ node = ns3.NodeList.GetNode(self.node_index)
+ stats_list = self.statistics_collector.get_interface_statistics(self.node_index)
+ self.table_model.clear()
+ for iface, stats in enumerate(stats_list):
+ tree_iter = self.table_model.append()
+ netdevice = node.GetDevice(iface)
+ interface_name = ns3.Names.FindName(netdevice)
+ if not interface_name:
+ interface_name = "(interface %i)" % iface
+ self.table_model.set(tree_iter,
+ self.COLUMN_INTERFACE, interface_name,
+
+ self.COLUMN_TX_PACKETS, str(stats.txPackets),
+ self.COLUMN_TX_BYTES, str(stats.txBytes),
+ self.COLUMN_TX_PACKET_RATE, str(stats.txPacketRate),
+ self.COLUMN_TX_BIT_RATE, str(stats.txBitRate),
+
+ self.COLUMN_RX_PACKETS, str(stats.rxPackets),
+ self.COLUMN_RX_BYTES, str(stats.rxBytes),
+ self.COLUMN_RX_PACKET_RATE, str(stats.rxPacketRate),
+ self.COLUMN_RX_BIT_RATE, str(stats.rxBitRate)
+ )
+
+
+def populate_node_menu(viz, node, menu, statistics_collector):
+
+ menu_item = gtk.MenuItem("Show Interface Statistics")
+ menu_item.show()
+
+ def _show_it(dummy_menu_item):
+ ShowInterfaceStatistics(viz, node.node_index, statistics_collector)
+
+ menu_item.connect("activate", _show_it)
+ menu.add(menu_item)
+
+
+def register(viz):
+ statistics_collector = StatisticsCollector(viz)
+ viz.connect("populate-node-menu", populate_node_menu, statistics_collector)
+ viz.connect("simulation-periodic-update", statistics_collector.simulation_periodic_update)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/plugins/ipv4_routing_table.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,121 @@
+import gtk
+import ns3
+from visualizer.base import InformationWindow
+
+class ShowIpv4RoutingTable(InformationWindow):
+ (
+ COLUMN_DESTINATION,
+ COLUMN_NEXT_HOP,
+ COLUMN_INTERFACE,
+ COLUMN_TYPE,
+ COLUMN_PRIO
+ ) = range(5)
+
+ def __init__(self, visualizer, node_index):
+ InformationWindow.__init__(self)
+ self.win = gtk.Dialog(parent=visualizer.window,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
+ buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ self.win.connect("response", self._response_cb)
+ self.win.set_title("IPv4 routing table for node %i" % node_index)
+ self.visualizer = visualizer
+ self.node_index = node_index
+
+ self.table_model = gtk.ListStore(str, str, str, str, int)
+
+ treeview = gtk.TreeView(self.table_model)
+ treeview.show()
+ sw = gtk.ScrolledWindow()
+ sw.set_properties(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
+ vscrollbar_policy=gtk.POLICY_AUTOMATIC)
+ sw.show()
+ sw.add(treeview)
+ self.win.vbox.add(sw)
+ self.win.set_default_size(600, 300)
+
+ # Dest.
+ column = gtk.TreeViewColumn('Destination', gtk.CellRendererText(),
+ text=self.COLUMN_DESTINATION)
+ treeview.append_column(column)
+
+ # Next hop
+ column = gtk.TreeViewColumn('Next hop', gtk.CellRendererText(),
+ text=self.COLUMN_NEXT_HOP)
+ treeview.append_column(column)
+
+ # Interface
+ column = gtk.TreeViewColumn('Interface', gtk.CellRendererText(),
+ text=self.COLUMN_INTERFACE)
+ treeview.append_column(column)
+
+ # Type
+ column = gtk.TreeViewColumn('Type', gtk.CellRendererText(),
+ text=self.COLUMN_TYPE)
+ treeview.append_column(column)
+
+ # Prio
+ column = gtk.TreeViewColumn('Prio', gtk.CellRendererText(),
+ text=self.COLUMN_PRIO)
+ treeview.append_column(column)
+
+ self.visualizer.add_information_window(self)
+ self.win.show()
+
+ def _response_cb(self, win, response):
+ self.win.destroy()
+ self.visualizer.remove_information_window(self)
+
+ def update(self):
+ node = ns3.NodeList.GetNode(self.node_index)
+ ipv4 = node.GetObject(ns3.Ipv4.GetTypeId())
+ routing = ipv4.GetRoutingProtocol()
+ if routing is None:
+ return
+
+ routing_protocols = [] # list of (protocol, type_string, priority)
+
+ if isinstance(routing, ns3.Ipv4StaticRouting):
+ ipv4_routing = routing_protocols.append((routing, "static", 0))
+ elif isinstance(routing, ns3.Ipv4ListRouting):
+ list_routing = routing
+ for rI in range(list_routing.GetNRoutingProtocols()):
+ routing, prio = list_routing.GetRoutingProtocol(rI)
+ if isinstance(routing, ns3.Ipv4StaticRouting):
+ routing_protocols.append((routing, "static", prio))
+ elif isinstance(routing, ns3.Ipv4GlobalRouting):
+ routing_protocols.append((routing, "global", prio))
+ if not routing_protocols:
+ return
+
+ self.table_model.clear()
+ for route_proto, type_string, prio in routing_protocols:
+ for routeI in range(route_proto.GetNRoutes()):
+ route = route_proto.GetRoute(routeI)
+ tree_iter = self.table_model.append()
+ netdevice = ipv4.GetNetDevice(route.GetInterface())
+ if netdevice is None:
+ interface_name = 'lo'
+ else:
+ interface_name = ns3.Names.FindName(netdevice)
+ if not interface_name:
+ interface_name = "(interface %i)" % route.GetInterface()
+ self.table_model.set(tree_iter,
+ self.COLUMN_DESTINATION, str(route.GetDest()),
+ self.COLUMN_NEXT_HOP, str(route.GetGateway()),
+ self.COLUMN_INTERFACE, interface_name,
+ self.COLUMN_TYPE, type_string,
+ self.COLUMN_PRIO, prio)
+
+
+def populate_node_menu(viz, node, menu):
+ menu_item = gtk.MenuItem("Show IPv4 Routing Table")
+ menu_item.show()
+
+ def _show_ipv4_routing_table(dummy_menu_item):
+ ShowIpv4RoutingTable(viz, node.node_index)
+
+ menu_item.connect("activate", _show_ipv4_routing_table)
+ menu.add(menu_item)
+
+def register(viz):
+ viz.connect("populate-node-menu", populate_node_menu)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/plugins/olsr.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,102 @@
+import gtk
+import ns3
+from visualizer.base import InformationWindow
+
+class ShowOlsrRoutingTable(InformationWindow):
+ (
+ COLUMN_DESTINATION,
+ COLUMN_NEXT_HOP,
+ COLUMN_INTERFACE,
+ COLUMN_NUM_HOPS,
+ ) = range(4)
+
+ def __init__(self, visualizer, node_index):
+ InformationWindow.__init__(self)
+ self.win = gtk.Dialog(parent=visualizer.window,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
+ buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ self.win.set_default_size(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/2)
+ self.win.connect("response", self._response_cb)
+ self.win.set_title("OLSR routing table for node %i" % node_index)
+ self.visualizer = visualizer
+ self.node_index = node_index
+
+ self.table_model = gtk.ListStore(str, str, str, int)
+
+ treeview = gtk.TreeView(self.table_model)
+ treeview.show()
+ sw = gtk.ScrolledWindow()
+ sw.set_properties(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
+ vscrollbar_policy=gtk.POLICY_AUTOMATIC)
+ sw.show()
+ sw.add(treeview)
+ self.win.vbox.add(sw)
+
+ # Dest.
+ column = gtk.TreeViewColumn('Destination', gtk.CellRendererText(),
+ text=self.COLUMN_DESTINATION)
+ treeview.append_column(column)
+
+ # Next hop
+ column = gtk.TreeViewColumn('Next hop', gtk.CellRendererText(),
+ text=self.COLUMN_NEXT_HOP)
+ treeview.append_column(column)
+
+ # Interface
+ column = gtk.TreeViewColumn('Interface', gtk.CellRendererText(),
+ text=self.COLUMN_INTERFACE)
+ treeview.append_column(column)
+
+ # Num. Hops
+ column = gtk.TreeViewColumn('Num. Hops', gtk.CellRendererText(),
+ text=self.COLUMN_NUM_HOPS)
+ treeview.append_column(column)
+
+ self.visualizer.add_information_window(self)
+ self.win.show()
+
+ def _response_cb(self, win, response):
+ self.win.destroy()
+ self.visualizer.remove_information_window(self)
+
+ def update(self):
+ node = ns3.NodeList.GetNode(self.node_index)
+ olsr = node.GetObject(ns3.olsr.RoutingProtocol.GetTypeId())
+ ipv4 = node.GetObject(ns3.Ipv4.GetTypeId())
+ if olsr is None:
+ return
+ self.table_model.clear()
+ for route in olsr.GetRoutingTableEntries():
+ tree_iter = self.table_model.append()
+ netdevice = ipv4.GetNetDevice(route.interface)
+ if netdevice is None:
+ interface_name = 'lo'
+ else:
+ interface_name = ns3.Names.FindName(netdevice)
+ if not interface_name:
+ interface_name = "(interface %i)" % route.interface
+ self.table_model.set(tree_iter,
+ self.COLUMN_DESTINATION, str(route.destAddr),
+ self.COLUMN_NEXT_HOP, str(route.nextAddr),
+ self.COLUMN_INTERFACE, interface_name,
+ self.COLUMN_NUM_HOPS, route.distance)
+
+
+def populate_node_menu(viz, node, menu):
+ ns3_node = ns3.NodeList.GetNode(node.node_index)
+ olsr = ns3_node.GetObject(ns3.olsr.RoutingProtocol.GetTypeId())
+ if olsr is None:
+ print "No OLSR"
+ return
+
+ menu_item = gtk.MenuItem("Show OLSR Routing Table")
+ menu_item.show()
+
+ def _show_ipv4_routing_table(dummy_menu_item):
+ ShowOlsrRoutingTable(viz, node.node_index)
+
+ menu_item.connect("activate", _show_ipv4_routing_table)
+ menu.add(menu_item)
+
+def register(viz):
+ viz.connect("populate-node-menu", populate_node_menu)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/plugins/show_last_packets.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,231 @@
+import gobject
+import gtk
+import ns3
+from visualizer.base import InformationWindow
+from visualizer.higcontainer import HIGContainer
+from kiwi.ui.objectlist import ObjectList, Column
+
+class ShowLastPackets(InformationWindow):
+ class PacketList(gtk.ScrolledWindow):
+ (
+ COLUMN_TIME,
+ COLUMN_INTERFACE,
+ COLUMN_SIZE,
+ COLUMN_CONTENTS,
+ ) = range(4)
+
+ def __init__(self):
+ super(ShowLastPackets.PacketList, self).__init__()
+ self.set_properties(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
+ vscrollbar_policy=gtk.POLICY_AUTOMATIC)
+ self.table_model = gtk.ListStore(*([str]*4))
+ treeview = gtk.TreeView(self.table_model)
+ treeview.show()
+ self.add(treeview)
+
+ def add_column(descr, colid):
+ column = gtk.TreeViewColumn(descr, gtk.CellRendererText(), text=colid)
+ treeview.append_column(column)
+
+ add_column("Time", self.COLUMN_TIME)
+ add_column("Interface", self.COLUMN_INTERFACE)
+ add_column("Size", self.COLUMN_SIZE)
+ add_column("Contents", self.COLUMN_CONTENTS)
+
+ def update(self, node, packet_list):
+ self.table_model.clear()
+ for sample in packet_list:
+ tree_iter = self.table_model.append()
+ if sample.device is None:
+ interface_name = "(unknown)"
+ else:
+ interface_name = ns3.Names.FindName(sample.device)
+ if not interface_name:
+ interface_name = "(interface %i)" % sample.device.GetIfIndex()
+ self.table_model.set(tree_iter,
+ self.COLUMN_TIME, str(sample.time.GetSeconds()),
+ self.COLUMN_INTERFACE, interface_name,
+ self.COLUMN_SIZE, str(sample.packet.GetSize ()),
+ self.COLUMN_CONTENTS, str(sample.packet)
+ )
+
+
+ def __init__(self, visualizer, node_index):
+ InformationWindow.__init__(self)
+ self.win = gtk.Dialog(parent=visualizer.window,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_NO_SEPARATOR,
+ buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ self.win.connect("response", self._response_cb)
+ self.win.set_title("Last packets for node %i" % node_index)
+ self.visualizer = visualizer
+ self.viz_node = visualizer.get_node(node_index)
+ self.node = ns3.NodeList.GetNode(node_index)
+
+ def smart_expand(expander, vbox):
+ if expander.get_expanded():
+ vbox.set_child_packing(expander, expand=True, fill=True, padding=0, pack_type=gtk.PACK_START)
+ else:
+ vbox.set_child_packing(expander, expand=False, fill=False, padding=0, pack_type=gtk.PACK_START)
+
+ main_hbox = gtk.HBox(False, 4)
+ main_hbox.show()
+ main_vbox = gtk.VBox(False, 4)
+ main_vbox.show()
+ self.win.vbox.add(main_hbox)
+ main_hbox.add(main_vbox)
+
+ self.tx_list = self.PacketList()
+ self.tx_list.show()
+ group = gtk.Expander("Last transmitted packets")
+ group.show()
+ group.add(self.tx_list)
+ main_vbox.pack_start(group, expand=False, fill=False)
+ group.connect_after("activate", smart_expand, main_vbox)
+
+ self.rx_list = self.PacketList()
+ self.rx_list.show()
+ group = gtk.Expander("Last received packets")
+ group.show()
+ group.add(self.rx_list)
+ main_vbox.pack_start(group, expand=False, fill=False)
+ group.connect_after("activate", smart_expand, main_vbox)
+
+ self.drop_list = self.PacketList()
+ self.drop_list.show()
+ group = gtk.Expander("Last dropped packets")
+ group.show()
+ group.add(self.drop_list)
+ main_vbox.pack_start(group, expand=False, fill=False)
+ group.connect_after("activate", smart_expand, main_vbox)
+
+
+ # Packet Filter
+
+ # - options
+ self.packet_capture_options = ns3.PyViz.PacketCaptureOptions()
+ self.packet_capture_options.numLastPackets = 100
+
+ packet_filter_vbox = gtk.VBox(False, 4)
+ packet_filter_vbox.show()
+ main_hbox.add(packet_filter_vbox)
+
+ sel_buttons_box = gtk.HButtonBox()
+ sel_buttons_box.show()
+ packet_filter_vbox.pack_start(sel_buttons_box, False, False, 4)
+ select_all_button = gobject.new(gtk.Button, label="Sel. All", visible=True)
+ select_none_button = gobject.new(gtk.Button, label="Sel. None", visible=True)
+ sel_buttons_box.add(select_all_button)
+ sel_buttons_box.add(select_none_button)
+
+ self.packet_filter_widget = ObjectList([
+ Column('selected', title="Sel.", data_type=bool, editable=True),
+ Column('name', title="Header"),
+ ], sortable=True)
+ self.packet_filter_widget.show()
+ packet_filter_vbox.pack_start(self.packet_filter_widget, True, True, 4)
+
+ class TypeIdConfig(object):
+ __slots__ = ['name', 'selected', 'typeid']
+
+ self.packet_filter_list = [] # list of TypeIdConfig instances
+
+ Header = ns3.TypeId.LookupByName("ns3::Header")
+ Trailer = ns3.TypeId.LookupByName("ns3::Trailer")
+ for typeid_i in range(ns3.TypeId.GetRegisteredN()):
+ typeid = ns3.TypeId.GetRegistered(typeid_i)
+ # check if this is a header or trailer subtype
+ typeid_tmp = typeid
+ type_is_good = False
+ while 1:
+ if typeid_tmp == Header or typeid_tmp == Trailer:
+ type_is_good = True
+ break
+ if typeid_tmp.HasParent():
+ typeid_tmp = typeid_tmp.GetParent()
+ else:
+ break
+ if not type_is_good:
+ continue
+ if typeid in [Header, Trailer]:
+ continue
+ c = TypeIdConfig()
+ c.selected = True
+ c.name = typeid.GetName()
+ c.typeid = typeid
+ self.packet_filter_list.append(c)
+ self.packet_filter_widget.add_list(self.packet_filter_list)
+
+ def update_capture_options():
+ if self.op_AND_button.props.active:
+ self.packet_capture_options.mode = ns3.PyViz.PACKET_CAPTURE_FILTER_HEADERS_AND
+ else:
+ self.packet_capture_options.mode = ns3.PyViz.PACKET_CAPTURE_FILTER_HEADERS_OR
+ self.packet_capture_options.numLastPackets = 100
+ self.packet_capture_options.headers = [c.typeid for c in self.packet_filter_list if c.selected]
+ self.visualizer.simulation.lock.acquire()
+ try:
+ self.visualizer.simulation.sim_helper.SetPacketCaptureOptions(
+ self.node.GetId(), self.packet_capture_options)
+ finally:
+ self.visualizer.simulation.lock.release()
+
+ def sel_all_cb(bt):
+ for c in self.packet_filter_list:
+ c.selected = True
+ self.packet_filter_widget.refresh()
+ update_capture_options()
+
+ def sel_none_cb(bt):
+ for c in self.packet_filter_list:
+ c.selected = False
+ self.packet_filter_widget.refresh()
+ update_capture_options()
+
+ select_all_button.connect("clicked", sel_all_cb)
+ select_none_button.connect("clicked", sel_none_cb)
+
+ op_buttons_box = gtk.HButtonBox()
+ op_buttons_box.show()
+ packet_filter_vbox.pack_start(op_buttons_box, False, False, 4)
+ self.op_AND_button = gobject.new(gtk.RadioButton, label="AND", visible=True)
+ self.op_OR_button = gobject.new(gtk.RadioButton, label="OR", visible=True, group=self.op_AND_button)
+ op_buttons_box.add(self.op_AND_button)
+ op_buttons_box.add(self.op_OR_button)
+ self.op_OR_button.props.active = True
+
+ self.op_AND_button.connect("toggled", lambda b: update_capture_options())
+
+ def cell_edited(l, obj, attribute):
+ update_capture_options()
+ self.packet_filter_widget.connect("cell-edited", cell_edited)
+
+ update_capture_options()
+
+ self.visualizer.add_information_window(self)
+ self.win.set_default_size(600, 300)
+ self.win.show()
+
+ def _response_cb(self, win, response):
+ self.win.destroy()
+ self.visualizer.remove_information_window(self)
+
+ def update(self):
+ last_packets = self.visualizer.simulation.sim_helper.GetLastPackets(self.node.GetId())
+
+ self.tx_list.update(self.node, last_packets.lastTransmittedPackets)
+ self.rx_list.update(self.node, last_packets.lastReceivedPackets)
+ self.drop_list.update(self.node, last_packets.lastDroppedPackets)
+
+
+def populate_node_menu(viz, node, menu):
+ menu_item = gtk.MenuItem("Show Last Packets")
+ menu_item.show()
+
+ def _show_it(dummy_menu_item):
+ ShowLastPackets(viz, node.node_index)
+
+ menu_item.connect("activate", _show_it)
+ menu.add(menu_item)
+
+def register(viz):
+ viz.connect("populate-node-menu", populate_node_menu)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,117 @@
+import math
+import ns3
+import goocanvas
+from visualizer.base import Link, transform_distance_canvas_to_simulation
+
+class WifiLink(Link):
+ def __init__(self, parent_canvas_item, sta, dev):
+ self.node1 = sta
+ self.dev = dev
+ self.node2 = None # ap
+ self.canvas_item = goocanvas.Group(parent=parent_canvas_item)
+ self.invisible_line = goocanvas.Polyline(parent=self.canvas_item,
+ line_width=25.0,
+ visibility=goocanvas.ITEM_HIDDEN)
+ self.visible_line = goocanvas.Polyline(parent=self.canvas_item,
+ line_width=1.0,
+ stroke_color_rgba=0xC00000FF,
+ line_dash=goocanvas.LineDash([2.0, 2.0 ]))
+ self.invisible_line.props.pointer_events = (goocanvas.EVENTS_STROKE_MASK
+ |goocanvas.EVENTS_FILL_MASK
+ |goocanvas.EVENTS_PAINTED_MASK)
+ self.canvas_item.set_data("pyviz-object", self)
+ self.canvas_item.lower(None)
+ self.set_ap(None)
+
+ def set_ap(self, ap):
+ if ap is self.node2:
+ return
+ if self.node2 is not None:
+ self.node2.remove_link(self)
+ self.node2 = ap
+ if self.node2 is None:
+ self.canvas_item.set_property("visibility", goocanvas.ITEM_HIDDEN)
+ else:
+ self.node2.add_link(self)
+ self.canvas_item.set_property("visibility", goocanvas.ITEM_VISIBLE)
+ self.update_points()
+
+ def update_points(self):
+ if self.node2 is None:
+ return
+ pos1_x, pos1_y = self.node1.get_position()
+ pos2_x, pos2_y = self.node2.get_position()
+ points = goocanvas.Points([(pos1_x, pos1_y), (pos2_x, pos2_y)])
+ self.visible_line.set_property("points", points)
+ self.invisible_line.set_property("points", points)
+
+ def destroy(self):
+ self.canvas_item.destroy()
+ self.node1 = None
+ self.node2 = None
+
+ def tooltip_query(self, tooltip):
+ pos1_x, pos1_y = self.node1.get_position()
+ pos2_x, pos2_y = self.node2.get_position()
+ dx = pos2_x - pos1_x
+ dy = pos2_y - pos1_y
+ d = transform_distance_canvas_to_simulation(math.sqrt(dx*dx + dy*dy))
+ mac = self.dev.GetMac()
+ tooltip.set_text(("WiFi link between STA Node %i and AP Node %i; distance=%.2f m.\n"
+ "SSID: %s\n"
+ "BSSID: %s")
+ % (self.node1.node_index, self.node2.node_index, d,
+ mac.GetSsid(), mac.GetBssid()))
+
+
+class WifiLinkMonitor(object):
+ def __init__(self, dummy_viz):
+ self.access_points = {} # bssid -> node
+ self.stations = [] # list of (sta_netdevice, viz_node, wifi_link)
+
+ def scan_nodes(self, viz):
+ for (sta_netdevice, viz_node, wifi_link) in self.stations:
+ wifi_link.destroy()
+
+ self.access_points = {}
+ self.stations = []
+
+ for node in viz.nodes.itervalues():
+ ns3_node = ns3.NodeList.GetNode(node.node_index)
+ for devI in range(ns3_node.GetNDevices()):
+ dev = ns3_node.GetDevice(devI)
+ if not isinstance(dev, ns3.WifiNetDevice):
+ continue
+ wifi_mac = dev.GetMac()
+ if isinstance(wifi_mac, ns3.StaWifiMac):
+ wifi_link = WifiLink(viz.links_group, node, dev)
+ self.stations.append((dev, node, wifi_link))
+ elif isinstance(wifi_mac, ns3.ApWifiMac):
+ bssid = ns3.Mac48Address.ConvertFrom(dev.GetAddress())
+ self.access_points[str(bssid)] = node
+ #print "APs: ", self.access_points
+ #print "STAs: ", self.stations
+
+ def simulation_periodic_update(self, viz):
+ for (sta_netdevice, viz_node, wifi_link) in self.stations:
+ if not sta_netdevice.IsLinkUp():
+ wifi_link.set_ap(None)
+ continue
+ bssid = str(sta_netdevice.GetMac().GetBssid())
+ if bssid == '00:00:00:00:00:00':
+ wifi_link.set_ap(None)
+ continue
+ ap = self.access_points[bssid]
+ wifi_link.set_ap(ap)
+
+ def update_view(self, viz):
+ for (dummy_sta_netdevice, dummy_viz_node, wifi_link) in self.stations:
+ if wifi_link is not None:
+ wifi_link.update_points()
+
+
+def register(viz):
+ link_monitor = WifiLinkMonitor(viz)
+ viz.connect("simulation-periodic-update", link_monitor.simulation_periodic_update)
+ viz.connect("update-view", link_monitor.update_view)
+ viz.connect("topology-scanned", link_monitor.scan_nodes)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/resource/Basurero_Palm_Z22.svg Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="122.87033"
+ height="185.93257"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="Basurero_Palm_Z22.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3237">
+ <stop
+ style="stop-color: rgb(156, 156, 156); stop-opacity: 1;"
+ offset="0"
+ id="stop3239" />
+ <stop
+ id="stop3245"
+ offset="0.5"
+ style="stop-color: rgb(220, 220, 220); stop-opacity: 1;" />
+ <stop
+ style="stop-color: rgb(168, 168, 168); stop-opacity: 1;"
+ offset="1"
+ id="stop3241" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2911">
+ <stop
+ style="stop-color: rgb(175, 193, 225); stop-opacity: 1;"
+ offset="0"
+ id="stop2913" />
+ <stop
+ style="stop-color: rgb(92, 144, 233); stop-opacity: 1;"
+ offset="1"
+ id="stop2915" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2911"
+ id="linearGradient3229"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-89.3787,74.9628)"
+ x1="157.91194"
+ y1="149.28284"
+ x2="151.2318"
+ y2="223.88245" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3237"
+ id="linearGradient3243"
+ x1="59.830921"
+ y1="241.51917"
+ x2="200.76509"
+ y2="179.29376"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-89.3787,74.9628)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.59688333"
+ inkscape:cx="428.4488"
+ inkscape:cy="185.26469"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:window-width="1280"
+ inkscape:window-height="753"
+ inkscape:window-x="0"
+ inkscape:window-y="47"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/publicdomain/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Capa 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-160.08253,-45.555814)">
+ <g
+ id="g3261"
+ inkscape:export-filename="/home/e288288/imagen/svg/palm_z22.png"
+ inkscape:export-xdpi="75"
+ inkscape:export-ydpi="75"
+ transform="translate(89.3787,-74.9628)">
+ <rect
+ ry="22.210958"
+ rx="22.210958"
+ y="120.88235"
+ x="71.067566"
+ height="185.20511"
+ width="122.14287"
+ id="rect2176"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="fill:url(#linearGradient3243);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect2856"
+ width="119.34706"
+ height="182.73219"
+ x="72.215469"
+ y="121.8688"
+ rx="20.444592"
+ ry="20.444592" />
+ <rect
+ ry="18.259377"
+ rx="18.259377"
+ y="124.17456"
+ x="74.340469"
+ height="178.12067"
+ width="115.09706"
+ id="rect3235"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="6.9516835"
+ rx="6.9516835"
+ y="135.9494"
+ x="84.825104"
+ height="125.89838"
+ width="94.6278"
+ id="rect2839"
+ style="fill:#e3e3e3;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#a4a4a4;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect2841"
+ width="81.335205"
+ height="111.10477"
+ x="91.471397"
+ y="142.06659"
+ rx="1.7201494"
+ ry="1.7201494" />
+ <rect
+ ry="0"
+ rx="0"
+ y="143.58203"
+ x="92.920067"
+ height="79.936684"
+ width="78.437866"
+ id="rect2843"
+ style="fill:url(#linearGradient3229);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <g
+ id="g3257">
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a2a2a2;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 73.133883,261.125 L 73.133883,279.3125 L 74.196383,279.3125 C 79.236007,279.3125 83.290129,275.25837 83.290133,270.21875 C 83.290133,265.17913 79.236011,261.125 74.196383,261.125 L 73.133883,261.125 z"
+ id="rect2875" />
+ <rect
+ style="fill:#164532;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.72746599;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect2884"
+ width="1.8988454"
+ height="5.4946771"
+ x="78.096237"
+ y="267.47141" />
+ </g>
+ <g
+ transform="translate(-3.8147e-6,0)"
+ id="g3095">
+ <rect
+ ry="10.619836"
+ rx="10.619836"
+ y="272.72806"
+ x="89.104172"
+ height="21.239672"
+ width="86.069664"
+ id="rect2847"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.10249996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ id="rect2845"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.10249996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 129.26628,274.47992 L 135.01173,274.47992 C 139.92459,274.47992 143.87971,278.43504 143.87971,283.34789 C 143.87971,288.26075 139.92459,292.21587 135.01173,292.21587 L 129.26628,292.21587 C 124.35342,292.21587 120.39831,288.26075 120.39831,283.34789 C 120.39831,278.43504 124.35342,274.47992 129.26628,274.47992 z M 127.49374,268.95493 L 136.78426,268.95493 C 144.72845,268.95493 151.12396,275.37419 151.12396,283.34789 C 151.12396,291.3216 144.72845,297.74086 136.78426,297.74086 L 127.49374,297.74086 C 119.54955,297.74086 113.15404,291.3216 113.15404,283.34789 C 113.15404,275.37419 119.54955,268.95493 127.49374,268.95493 z" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.17324996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path2873"
+ sodipodi:cx="99.667305"
+ sodipodi:cy="282.88821"
+ sodipodi:rx="8.7876797"
+ sodipodi:ry="8.7876797"
+ d="M 108.45498,282.88821 A 8.7876797,8.7876797 0 1 1 90.879625,282.88821 A 8.7876797,8.7876797 0 1 1 108.45498,282.88821 z"
+ transform="matrix(0.939699,0,0,0.939699,5.30354,17.5183)" />
+ <path
+ transform="matrix(0.939699,0,0,0.939699,70.8358,17.5183)"
+ d="M 108.45498,282.88821 A 8.7876797,8.7876797 0 1 1 90.879625,282.88821 A 8.7876797,8.7876797 0 1 1 108.45498,282.88821 z"
+ sodipodi:ry="8.7876797"
+ sodipodi:rx="8.7876797"
+ sodipodi:cy="282.88821"
+ sodipodi:cx="99.667305"
+ id="path2896"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.17324996;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ sodipodi:type="arc" />
+ </g>
+ <g
+ transform="translate(-138.895,0)"
+ id="g3076">
+ <g
+ transform="translate(-8.39025,0)"
+ id="g3042">
+ <path
+ id="path3044"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72750002;stroke-linecap:round;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 251.74434,230.02968 L 247.09281,226.05818 L 242.23893,230.0407 C 243.96351,230.02965 244.22246,229.99149 244.24454,230.64788 L 244.24454,233.6507 C 244.24454,234.04213 244.55966,234.35725 244.95109,234.35725 L 249.19037,234.35725 C 249.5818,234.35725 249.89692,234.04213 249.89692,233.6507 L 249.89692,230.64788"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="opacity:1;fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.72750002;stroke-linecap:round;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect3046"
+ width="1.1260595"
+ height="2.2521191"
+ x="246.4286"
+ y="232.10513" />
+ </g>
+ <g
+ transform="matrix(0.847116,0,0,0.847116,36.3844,36.8906)"
+ id="g3048">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 243.32987,241.79807 L 234.14142,241.79807"
+ id="path3050" />
+ <path
+ id="path3052"
+ d="M 239.3129,244.33722 L 235.75172,244.33722"
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 239.3129,246.43478 L 235.75172,246.43478"
+ id="path3054" />
+ <path
+ id="path3056"
+ d="M 239.48636,248.88562 L 234.09189,248.88562 L 234.09189,243.45405"
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.18048px;stroke-linecap:square;stroke-linejoin:round;stroke-opacity:1"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="opacity:1;fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:0.858796;stroke-linecap:square;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 241.24351,243.98638 L 241.24351,246.04888 L 240.43101,246.04888 L 241.96226,247.58013 L 243.49351,246.04888 L 242.64976,246.04888 L 242.64976,243.98638 L 241.24351,243.98638 z"
+ id="path3058" />
+ </g>
+ <path
+ id="path3060"
+ d="M 245.43681,225.79037 L 245.43681,252.3742"
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 298.33953,225.79037 L 298.33953,252.3742"
+ id="path3062" />
+ <g
+ transform="matrix(0.842444,-0.225732,0.225732,0.842444,-7.44249,107.397)"
+ id="g3064">
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.16912997;stroke-linecap:square;stroke-linejoin:round;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path3066"
+ sodipodi:cx="293.76904"
+ sodipodi:cy="243.16701"
+ sodipodi:rx="2.9365864"
+ sodipodi:ry="2.9365864"
+ d="M 296.70563,243.16701 A 2.9365864,2.9365864 0 1 1 290.83246,243.16701 A 2.9365864,2.9365864 0 1 1 296.70563,243.16701 z"
+ transform="matrix(0.81203,0,0,0.81203,68.3571,45.3769)" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1.14657998px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 304.01429,244.66842 L 300.87837,246.47894"
+ id="path3068" />
+ </g>
+ <path
+ d="M 304.43441,227.375 C 302.53928,227.375 301.00444,228.90984 301.00443,230.80498 C 301.00443,232.67076 302.49414,234.18843 304.34866,234.23495 L 305.6349,231.97689 L 306.17798,232.2913 L 305.77781,230.69064 L 304.14858,231.09081 L 304.72024,231.43381 L 303.54833,233.40604 C 302.71926,232.84537 302.17634,231.87806 302.17634,230.80498 C 302.17635,229.33317 303.23075,228.15568 304.60591,227.83233 L 304.83804,227.41022 C 304.59686,227.39462 304.55861,227.375 304.43441,227.375 z M 305.15315,234.23495 C 307.04829,234.23495 308.58312,232.70011 308.58312,230.80498 C 308.58312,228.93918 307.09342,227.42152 305.23891,227.375 L 303.95265,229.63306 L 303.40958,229.31865 L 303.80975,230.91931 L 305.43898,230.51915 L 304.86732,230.17615 L 306.03923,228.2039 C 306.8683,228.76457 307.41122,229.73189 307.41122,230.80498 C 307.41121,232.27677 306.35681,233.45426 304.98165,233.77762 L 304.74953,234.19973 C 304.99069,234.21533 305.02895,234.23495 305.15315,234.23495 z"
+ style="fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.228;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path3070" />
+ <path
+ id="path3072"
+ d="M 275.27017,248.65837 L 275.27017,252.84071"
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#a1a1a1;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 275.27017,225.34016 L 275.27017,227.98729"
+ id="path3074" />
+ </g>
+ </g>
+ </g>
+</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/resource/adriankierman_cell_phone_tower.svg Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="54.71582" height="243.43661" id="svg5560" sodipodi:version="0.32" inkscape:version="0.45.1" version="1.0" sodipodi:docbase="/root/workspace/svg/clipart" sodipodi:docname="simple_cellular_tower.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs id="defs5562"/>
+ <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" gridtolerance="10000" guidetolerance="10" objecttolerance="10" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.35" inkscape:cx="375" inkscape:cy="520" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="826" inkscape:window-height="622" inkscape:window-x="5" inkscape:window-y="73"/>
+ <metadata id="metadata5565">
+ <rdf:RDF>
+ <cc:Work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-241.214, -213.501)">
+ <g id="g5542" transform="translate(-505.802, 139.945)">
+ <rect y="74.055664" x="769.73621" height="242.43661" width="10.101525" id="rect4253" style="opacity: 0.535519; fill: rgb(102, 102, 102); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;"/>
+ <g transform="matrix(-1, 0, 0, 1, 1549.23, 0)" id="g5232">
+ <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5226" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
+ <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5228" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
+ </g>
+ <g transform="matrix(-1, 0, 0, 1, 1549.25, 32.9924)" id="g5236">
+ <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5238" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
+ <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5240" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
+ </g>
+ <g transform="translate(-0.48229, 0.313456)" id="g5242">
+ <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5244" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
+ <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5246" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
+ </g>
+ <g transform="translate(-0.50263, 33.3059)" id="g5248">
+ <rect style="opacity: 0.535519; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5250" width="16.667517" height="3.0304577" x="752.56366" y="87.187645"/>
+ <rect style="opacity: 0.535519; fill: rgb(230, 230, 230); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" id="rect5252" width="3.0304713" height="26.263954" x="748.01801" y="75.570892"/>
+ </g>
+ <path transform="translate(-3.01015, 3.03046)" d="M 776.80727 152.84756 A 7.0710678 12.12183 0 1 1 762.66514,152.84756 A 7.0710678 12.12183 0 1 1 776.80727 152.84756 z" sodipodi:ry="12.12183" sodipodi:rx="7.0710678" sodipodi:cy="152.84756" sodipodi:cx="769.73621" id="path5254" style="opacity: 1; fill: rgb(128, 128, 128); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" sodipodi:type="arc"/>
+ <path transform="translate(11.1117, -46.467)" d="M 776.80727 152.84756 A 7.0710678 12.12183 0 1 1 762.66514,152.84756 A 7.0710678 12.12183 0 1 1 776.80727 152.84756 z" sodipodi:ry="12.12183" sodipodi:rx="7.0710678" sodipodi:cy="152.84756" sodipodi:cx="769.73621" id="path5256" style="opacity: 1; fill: rgb(128, 128, 128); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" sodipodi:type="arc"/>
+ <path transform="translate(11.132, 3.03045)" d="M 776.80727 152.84756 A 7.0710678 12.12183 0 1 1 762.66514,152.84756 A 7.0710678 12.12183 0 1 1 776.80727 152.84756 z" sodipodi:ry="12.12183" sodipodi:rx="7.0710678" sodipodi:cy="152.84756" sodipodi:cx="769.73621" id="path5258" style="opacity: 1; fill: rgb(128, 128, 128); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-opacity: 1;" sodipodi:type="arc"/>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/resource/bobocal_Yellow_Bus.svg Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0" width="993.7254" height="310.89276" id="svg2160">
+ <defs id="defs2162"/>
+ <g transform="translate(-31.7463, -366.985)" id="layer1">
+ <g id="g2386">
+ <path d="M 32.325515,677.29858 L 1024.8925,677.29858" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 1.15842px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1;" id="path2175"/>
+ <path d="M 268.79664,628.66538 A 35.70126,35.70126 0 1 1 273.83521,598.26515 L 239.54393,608.19934 z" transform="translate(34.5496)" style="opacity: 0; fill: rgb(230, 230, 230); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path2177"/>
+ <path d="M 89.0625,367.875 C 69.163607,367.875 53.15625,383.75548 53.15625,403.46875 L 53.15625,609.15625 C 53.15625,628.86953 69.163611,644.75 89.0625,644.75 L 975.40625,644.75 C 995.30514,644.75 1011.3125,628.86955 1011.3125,609.15625 L 1011.3125,403.46875 C 1011.3125,402.85271 1011.3121,402.23319 1011.2813,401.625 L 1011.2813,552 C 1011.2805,553.76879 1009.8625,555.1875 1008.0938,555.1875 L 990.90625,555.1875 C 989.13747,555.18752 987.6875,553.76879 987.6875,552 L 987.6875,399.5625 C 987.6875,397.79372 989.13746,396.375 990.90625,396.375 L 1008.0938,396.375 C 1009.3388,396.375 1010.3796,397.08915 1010.9063,398.125 C 1008.321,380.9619 993.47184,367.875 975.40625,367.875 L 89.0625,367.875 z M 846,388.46875 L 897.875,388.46875 C 898.5113,388.46875 899.11956,388.53428 899.71875,388.65625 C 900.30819,388.77624 900.8956,388.96112 901.4375,389.1875 C 901.44596,389.19107 901.4603,389.18391 901.46875,389.1875 C 902.01063,389.41591 902.51759,389.70788 903,390.03125 C 903.97724,390.69034 904.84091,391.55401 905.5,392.53125 C 905.82337,393.01366 906.11534,393.52062 906.34375,394.0625 C 906.34734,394.07095 906.34018,394.08529 906.34375,394.09375 C 906.57013,394.63565 906.75501,395.22307 906.875,395.8125 C 906.9024,395.94709 906.9159,396.08303 906.9375,396.21875 C 907.6293,391.82302 911.40379,388.46876 916,388.46875 L 967.875,388.46875 C 972.96536,388.46875 977.06251,392.56592 977.0625,397.65625 L 977.0625,616.53125 C 977.06251,621.62157 972.96535,625.71873 967.875,625.71875 L 916,625.71875 C 911.38062,625.71872 907.57016,622.36596 906.90625,617.9375 C 906.87063,618.14482 906.85874,618.35754 906.8125,618.5625 C 906.69252,619.09427 906.55109,619.63312 906.34375,620.125 C 906.23319,620.38729 906.10226,620.65719 905.96875,620.90625 C 905.96211,620.9185 905.94419,620.92528 905.9375,620.9375 C 905.7964,621.19791 905.66477,621.44319 905.5,621.6875 C 905.00568,622.42043 904.39885,623.06421 903.71875,623.625 C 902.58525,624.55966 901.21674,625.22631 899.71875,625.53125 C 899.11956,625.65323 898.51129,625.71875 897.875,625.71875 L 846,625.71875 C 845.37436,625.71875 844.74612,625.64927 844.15625,625.53125 C 844.14649,625.52926 844.13475,625.53327 844.125,625.53125 C 843.23571,625.35022 842.3994,625.04152 841.625,624.625 C 841.61734,624.62085 841.6014,624.62917 841.59375,624.625 C 841.08026,624.34677 840.60429,623.99242 840.15625,623.625 C 840.15031,623.62011 840.13092,623.62991 840.125,623.625 C 839.66523,623.24588 839.28415,622.83582 838.90625,622.375 C 838.71932,622.1483 838.53977,621.93181 838.375,621.6875 C 838.205,621.43544 838.05102,621.17541 837.90625,620.90625 C 837.76515,620.64585 837.64716,620.39998 837.53125,620.125 C 837.29555,619.56583 837.12204,618.98496 837,618.375 C 836.88198,617.78513 836.8125,617.15689 836.8125,616.53125 L 836.8125,397.65625 C 836.8125,397.01995 836.87803,396.41169 837,395.8125 C 837.06297,395.50315 837.12571,395.20327 837.21875,394.90625 C 837.30505,394.62758 837.41993,394.36021 837.53125,394.09375 C 837.53493,394.08503 837.52755,394.07121 837.53125,394.0625 C 837.64716,393.78752 837.76515,393.54165 837.90625,393.28125 C 838.05132,393.01352 838.20493,392.75069 838.375,392.5 C 838.53977,392.25569 838.71932,392.0392 838.90625,391.8125 C 839.6626,390.89524 840.56851,390.12884 841.625,389.5625 C 841.8854,389.4214 842.13127,389.30341 842.40625,389.1875 C 842.89813,388.98016 843.43698,388.83873 843.96875,388.71875 C 844.61866,388.57397 845.30518,388.46875 846,388.46875 z M 169.15625,389.03125 L 272.09375,389.03125 C 277.1841,389.03125 281.28125,393.12841 281.28125,398.21875 L 281.28125,464.53125 C 281.28124,469.62158 277.18409,473.71875 272.09375,473.71875 L 169.15625,473.71875 C 164.06591,473.71876 159.96875,469.62159 159.96875,464.53125 L 159.96875,398.21875 C 159.96875,393.12839 164.06591,389.03125 169.15625,389.03125 z M 305.3125,389.03125 L 408.28125,389.03125 C 413.37158,389.03125 417.46875,393.12841 417.46875,398.21875 L 417.46875,464.53125 C 417.46876,469.62158 413.37159,473.71875 408.28125,473.71875 L 305.3125,473.71875 C 300.22218,473.71876 296.125,469.62159 296.125,464.53125 L 296.125,398.21875 C 296.125,393.12839 300.22216,389.03125 305.3125,389.03125 z M 441.46875,389.03125 L 544.4375,389.03125 C 549.52786,389.03125 553.625,393.12841 553.625,398.21875 L 553.625,464.53125 C 553.62501,469.62158 549.52784,473.71875 544.4375,473.71875 L 441.46875,473.71875 C 436.37843,473.71876 432.28125,469.62159 432.28125,464.53125 L 432.28125,398.21875 C 432.28125,393.12839 436.37841,389.03125 441.46875,389.03125 z M 577.65625,389.03125 L 680.59375,389.03125 C 685.68408,389.03125 689.78125,393.12841 689.78125,398.21875 L 689.78125,464.53125 C 689.78123,469.62158 685.68409,473.71875 680.59375,473.71875 L 577.65625,473.71875 C 572.56589,473.71876 568.4375,469.62159 568.4375,464.53125 L 568.4375,398.21875 C 568.4375,393.12839 572.56591,389.03125 577.65625,389.03125 z M 713.8125,389.03125 L 816.78125,389.03125 C 821.87158,389.03125 825.96875,393.12841 825.96875,398.21875 L 825.96875,464.53125 C 825.96873,469.62158 821.87159,473.71875 816.78125,473.71875 L 713.8125,473.71875 C 708.72214,473.71876 704.625,469.62159 704.625,464.53125 L 704.625,398.21875 C 704.625,393.12839 708.72216,389.03125 713.8125,389.03125 z " style="fill: rgb(255, 255, 0); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77992; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect3179"/>
+ <path d="M 177.12517,635.35797 A 27.063858,27.063858 0 1 1 229.40853,635.35797" transform="matrix(2.19149, 0, 0, 2.19149, -207.641, -748.676)" style="opacity: 1; fill: rgb(77, 77, 77); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 2.00004; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3167"/>
+ <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(1.80851, 0, 0, 1.80851, -129.794, -508.03)" style="opacity: 1; fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3152"/>
+ <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(0.787234, 0, 0, 0.787234, 77.7979, 133.692)" style="opacity: 1; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3156"/>
+ <path d="M 268.79664,628.66538 A 35.70126,35.70126 0 1 1 273.83521,598.26515 L 239.54393,608.19934 z" transform="translate(560.207)" style="opacity: 0; fill: rgb(230, 230, 230); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3169"/>
+ <path d="M 177.12517,635.35797 A 27.063858,27.063858 0 1 1 229.40853,635.35797" transform="matrix(2.19149, 0, 0, 2.19149, 318.017, -748.676)" style="opacity: 1; fill: rgb(77, 77, 77); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 2.00004; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3171"/>
+ <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(1.80851, 0, 0, 1.80851, 395.864, -508.03)" style="opacity: 1; fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3173"/>
+ <path d="M 230.3307 628.35333 A 27.063858 27.063858 0 1 1 176.20299,628.35333 A 27.063858 27.063858 0 1 1 230.3307 628.35333 z" transform="matrix(0.787234, 0, 0, 0.787234, 603.456, 133.692)" style="opacity: 1; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: 2, 2; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path3175"/>
+ <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="159.95827" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect3181"/>
+ <rect width="23.578625" height="158.81502" rx="3.1927617" ry="3.1927617" x="987.69922" y="396.37573" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.00874; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4170"/>
+ <rect width="40.307938" height="41.459484" rx="4.8945279" ry="5.6405392" x="980.63293" y="608.1994" style="opacity: 1; fill: rgb(40, 11, 11); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4176"/>
+ <rect width="114.01376" height="41.459484" rx="4.8945279" ry="5.6405392" x="47.217747" y="608.1994" style="opacity: 1; fill: rgb(40, 11, 11); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4178"/>
+ <rect width="161.23149" height="78.312439" rx="7.9438462" ry="7.9438462" x="499.61023" y="560.98157" style="opacity: 1; fill: none; fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4184"/>
+ <rect width="161.23149" height="78.312439" rx="7.9438462" ry="7.9438462" x="330.31717" y="560.98157" style="opacity: 1; fill: none; fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect4186"/>
+ <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="296.12302" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2197"/>
+ <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="432.28775" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2199"/>
+ <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="568.45251" y="389.04138" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2201"/>
+ <rect width="121.33695" height="84.691566" rx="9.1883392" ry="9.1883392" x="704.61719" y="388.48038" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2203"/>
+ <g transform="translate(-0.000273234, 0.000265655)" id="g2378">
+ <g id="g2370">
+ <path d="M 915.98701,388.48039 C 910.89667,388.48039 906.79951,392.57753 906.79951,397.66789 L 906.79951,616.54289 C 906.79951,621.63323 910.89665,625.73036 915.98701,625.73039 L 967.86201,625.73039 C 972.95235,625.73039 977.04952,621.63321 977.04951,616.54289 L 977.04951,397.66789 C 977.04951,392.57755 972.95237,388.48039 967.86201,388.48039 L 915.98701,388.48039 z M 924.04951,397.69914 L 960.95576,397.69914 C 966.04613,397.69914 970.14326,401.7963 970.14326,406.88664 L 970.14326,519.79289 C 970.14327,524.8832 966.0461,528.98039 960.95576,528.98039 L 924.04951,528.98039 C 918.95915,528.98041 914.86201,524.88323 914.86201,519.79289 L 914.86201,406.88664 C 914.86201,401.79632 918.95917,397.69914 924.04951,397.69914 z " style="fill: rgb(255, 255, 0); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path2351"/>
+ <rect width="55.279369" height="131.2885" rx="9.1883392" ry="9.1883392" x="914.87238" y="397.70074" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2353"/>
+ </g>
+ <g id="g2374">
+ <path d="M 845.9886,388.48039 C 840.89826,388.48039 836.8011,392.57753 836.8011,397.66789 L 836.8011,616.54289 C 836.8011,621.63323 840.89824,625.73036 845.9886,625.73039 L 897.8636,625.73039 C 902.95394,625.73039 907.05111,621.63321 907.0511,616.54289 L 907.0511,397.66789 C 907.0511,392.57755 902.95396,388.48039 897.8636,388.48039 L 845.9886,388.48039 z M 854.0511,397.69914 L 890.95735,397.69914 C 896.04772,397.69914 900.14485,401.7963 900.14485,406.88664 L 900.14485,519.79289 C 900.14486,524.8832 896.04769,528.98039 890.95735,528.98039 L 854.0511,528.98039 C 848.96074,528.98041 844.8636,524.88323 844.8636,519.79289 L 844.8636,406.88664 C 844.8636,401.79632 848.96076,397.69914 854.0511,397.69914 z " style="fill: rgb(255, 255, 0); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="path2284"/>
+ <rect width="55.279369" height="131.2885" rx="9.1883392" ry="9.1883392" x="844.87396" y="397.70074" style="opacity: 0.6; fill: rgb(204, 204, 204); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(0, 0, 0); stroke-width: 1.77165; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1;" id="rect2286"/>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/resource/thilakarathna_Bus_Halt.svg Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="178.37129" height="264.19806" id="svg6213" sodipodi:version="0.32" inkscape:version="0.45" version="1.0" sodipodi:docbase="/home/fahad/Desktop" sodipodi:docname="thilakarathna_Bus_Halt.svg" inkscape:export-filename="/home/fahad/Desktop/Bus_Halt.png" inkscape:export-xdpi="150" inkscape:export-ydpi="150" inkscape:output_extension="org.inkscape.output.svg.inkscape" sodipodi:modified="TRUE">
+ <defs id="defs6215">
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient5498" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.83731, 0, 0, 0.83731, 122.117, -209.238)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" id="linearGradient5456">
+ <stop style="stop-color: rgb(0, 255, 255); stop-opacity: 1;" offset="0" id="stop5458"/>
+ <stop style="stop-color: rgb(0, 255, 255); stop-opacity: 0;" offset="1" id="stop5460"/>
+ </linearGradient>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient5496" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.508315, 0, 0, 0.508315, 196.577, -737.854)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6269" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6282" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6312" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6314" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6331" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6344" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6373" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient6375" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient1928" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient1941" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient2296" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.135991, 0, 0, 0.135991, 381.515, 500.095)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ <linearGradient inkscape:collect="always" xlink:href="#linearGradient5456" id="linearGradient2312" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0825575, 0, 0, 0.0825575, 393.609, 414.241)" x1="527.5" y1="-1917.553" x2="479.5" y2="-131.72624"/>
+ </defs>
+ <sodipodi:namedview inkscape:document-units="mm" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.86831672" inkscape:cx="303.71381" inkscape:cy="154.70921" inkscape:current-layer="layer1" id="namedview6217" inkscape:window-width="872" inkscape:window-height="622" inkscape:window-x="25" inkscape:window-y="49"/>
+ <metadata id="metadata6219">
+ <rdf:RDF>
+ <cc:Work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ <dc:title>Bus Halt</dc:title>
+ <dc:date>07 th June 2008</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Kenneth Thilakarathna - UCSC - LK</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>bus-stop</rdf:li>
+ <rdf:li>bus-halt</rdf:li>
+ <rdf:li>bus stop</rdf:li>
+ <rdf:li>bus halt</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ </cc:Work>
+ <cc:License rdf:about="http://web.resource.org/cc/PublicDomain">
+ <cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
+ <cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
+ <cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-323.107, -221.199)">
+ <g id="g2314">
+ <rect y="305.73587" x="399.18127" height="80.035286" width="59.441422" id="rect5464" style="fill: url(#linearGradient2312) rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 0.87758; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
+ <g transform="matrix(0.102737, 0, 0, 0.102737, 376.38, 502.333)" id="g5414">
+ <path sodipodi:type="arc" style="fill: rgb(10, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 4.53543; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" id="path5416" sodipodi:cx="600" sodipodi:cy="-992.12592" sodipodi:rx="168" sodipodi:ry="38.267715" d="M 768 -992.12592 A 168 38.267715 0 1 1 432,-992.12592 A 168 38.267715 0 1 1 768 -992.12592 z" transform="translate(-0.5, 5.75398)"/>
+ <path style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 86.0315; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 595.50002,-946.1042 C 595.50002,-742.00971 595.50002,-742.00971 595.50002,-742.00971" id="path5418"/>
+ </g>
+ <g transform="matrix(0.0922068, 0, 0, 0.0922068, 376.384, 471.043)" id="g5420">
+ <path sodipodi:type="arc" style="fill: rgb(10, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 4.53543; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" id="path5422" sodipodi:cx="600" sodipodi:cy="-992.12592" sodipodi:rx="168" sodipodi:ry="38.267715" d="M 768 -992.12592 A 168 38.267715 0 1 1 432,-992.12592 A 168 38.267715 0 1 1 768 -992.12592 z" transform="translate(-0.5, 5.75398)"/>
+ <path style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 86.0315; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 595.50002,-946.1042 C 595.50002,-742.00971 595.50002,-742.00971 595.50002,-742.00971" id="path5424"/>
+ </g>
+ <g transform="matrix(0.141346, 0, 0, 0.141346, 360.279, 565.272)" id="g5394">
+ <path sodipodi:type="arc" style="fill: rgb(10, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 4.53543; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" id="path5390" sodipodi:cx="600" sodipodi:cy="-992.12592" sodipodi:rx="168" sodipodi:ry="38.267715" d="M 768 -992.12592 A 168 38.267715 0 1 1 432,-992.12592 A 168 38.267715 0 1 1 768 -992.12592 z" transform="translate(-0.5, 5.75398)"/>
+ <path style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 86.0315; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 595.50002,-946.1042 C 595.50002,-742.00971 595.50002,-742.00971 595.50002,-742.00971" id="path5392"/>
+ </g>
+ <path sodipodi:end="6.2814937" sodipodi:start="3.1458674" transform="matrix(0.139174, 0, 0, 0.125355, 348.828, 471.175)" d="M -143.99452,-1250.2431 A 600,701.57483 0 0 1 1055.9991,-1248.4308 L 456,-1247.244 z" sodipodi:ry="701.57483" sodipodi:rx="600" sodipodi:cy="-1247.244" sodipodi:cx="456" id="path5398" style="fill: rgb(85, 34, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 86.0315; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" sodipodi:type="arc"/>
+ <path id="path5402" d="M 495.51107,320.20041 C 495.51107,479.43124 495.51107,479.43124 495.51107,479.43124" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 11.9325; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
+ <path id="path5410" d="M 478.53868,320.4603 C 478.53868,448.7526 478.53868,448.7526 478.53868,448.7526" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 10.7107; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
+ <path id="path5412" d="M 462.94693,320.38103 C 462.94693,400.73806 462.94693,400.73806 462.94693,400.73806" style="fill: none; fill-rule: evenodd; stroke: rgb(0, 0, 0); stroke-width: 8.47674; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
+ <rect y="321.36346" x="390.69467" height="131.83618" width="97.913445" id="rect5454" style="fill: url(#linearGradient2296) rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(7, 0, 0); stroke-width: 1.44557; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;"/>
+ <g transform="matrix(0.162414, 0, 0, 0.162414, 396.455, 615.534)" id="g5378">
+ <g id="g5366" transform="translate(-556.499, -494.074)">
+ <g transform="matrix(0.996807, 0.0798454, -0.0798454, 0.996807, -118.094, -58.9951)" id="g5360">
+ <g id="g5341" transform="matrix(0.999743, -0.022669, 0.022669, 0.999743, 34.3179, 14.9971)">
+ <path transform="matrix(0.998587, 0.0531485, -0.0531485, 0.998587, -560.394, 98.4307)" d="M 1248,-1479.685 L 1086.5899,-1467.0142 L 963.49616,-1572.1888 L 950.8254,-1733.5989 L 1056,-1856.6927 L 1217.4101,-1869.3634 L 1340.5038,-1764.1888 L 1353.1746,-1602.7788 L 1248,-1479.685 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="true" sodipodi:arg2="1.4924566" sodipodi:arg1="1.0997575" sodipodi:r2="171.14047" sodipodi:r1="211.54124" sodipodi:cy="-1668.1888" sodipodi:cx="1152" sodipodi:sides="8" id="path4558" style="fill: rgb(255, 0, 0);" sodipodi:type="star"/>
+ <g transform="matrix(0.998587, 0.0531485, -0.0531485, 0.998587, -79.0917, -38.1975)" id="g5338">
+ <path sodipodi:type="star" style="fill: rgb(255, 255, 255);" id="path4566" sodipodi:sides="8" sodipodi:cx="1152" sodipodi:cy="-1668.1888" sodipodi:r1="211.54124" sodipodi:r2="171.14047" sodipodi:arg1="1.0997575" sodipodi:arg2="1.4924566" inkscape:flatsided="true" inkscape:rounded="0" inkscape:randomized="0" d="M 1248,-1479.685 L 1086.5899,-1467.0142 L 963.49616,-1572.1888 L 950.8254,-1733.5989 L 1056,-1856.6927 L 1217.4101,-1869.3634 L 1340.5038,-1764.1888 L 1353.1746,-1602.7788 L 1248,-1479.685 z " transform="matrix(0.928634, 0, 0, 0.928634, -391.436, 43.3049)"/>
+ </g>
+ </g>
+ </g>
+ <path id="text5346" d="M 607.79673,-1572.4732 C 610.28949,-1572.4731 612.17962,-1573.021 613.46715,-1574.1167 C 614.75459,-1575.2124 615.39833,-1576.8286 615.39837,-1578.9654 C 615.39833,-1581.0746 614.75459,-1582.6771 613.46715,-1583.7729 C 612.17962,-1584.896 610.28949,-1585.4575 607.79673,-1585.4576 L 599.04458,-1585.4576 L 599.04458,-1572.4732 L 607.79673,-1572.4732 M 608.3309,-1545.6414 C 611.50849,-1545.6414 613.8917,-1546.3125 615.48055,-1547.6548 C 617.09672,-1548.9971 617.90482,-1551.0242 617.90486,-1553.7361 C 617.90482,-1556.3933 617.11041,-1558.3793 615.52164,-1559.6942 C 613.93279,-1561.0364 611.53588,-1561.7076 608.3309,-1561.7076 L 599.04458,-1561.7076 L 599.04458,-1545.6414 L 608.3309,-1545.6414 M 623.0411,-1567.7067 C 626.43782,-1566.7205 629.06757,-1564.8989 630.93037,-1562.2418 C 632.79306,-1559.5846 633.72443,-1556.3248 633.72449,-1552.4623 C 633.72443,-1546.5454 631.72472,-1542.1351 627.72536,-1539.2314 C 623.72589,-1536.3277 617.64458,-1534.8759 609.48142,-1534.8759 L 583.22495,-1534.8759 L 583.22495,-1596.2231 L 606.97494,-1596.2231 C 615.49421,-1596.2231 621.65769,-1594.9356 625.46541,-1592.3607 C 629.30042,-1589.7857 631.21794,-1585.663 631.218,-1579.9926 C 631.21794,-1577.0067 630.51942,-1574.4591 629.12241,-1572.3499 C 627.7253,-1570.268 625.6982,-1568.7202 623.0411,-1567.7067 M 647.32526,-1596.2231 L 663.14489,-1596.2231 L 663.14489,-1559.4476 C 663.14486,-1554.3799 663.96666,-1550.7503 665.61028,-1548.5588 C 667.28125,-1546.3947 669.99318,-1545.3127 673.74609,-1545.3127 C 677.52633,-1545.3127 680.23826,-1546.3947 681.8819,-1548.5588 C 683.55285,-1550.7503 684.38834,-1554.3799 684.38839,-1559.4476 L 684.38839,-1596.2231 L 700.20801,-1596.2231 L 700.20801,-1559.4476 C 700.20795,-1550.7639 698.03019,-1544.2991 693.67471,-1540.0532 C 689.31913,-1535.8072 682.67626,-1533.6842 673.74609,-1533.6842 C 664.84325,-1533.6842 658.21408,-1535.8072 653.85856,-1540.0532 C 649.50302,-1544.2991 647.32525,-1550.7639 647.32526,-1559.4476 L 647.32526,-1596.2231 M 758.39137,-1594.2919 L 758.39137,-1581.3075 C 755.02194,-1582.8141 751.73475,-1583.9509 748.52978,-1584.718 C 745.32473,-1585.4849 742.29777,-1585.8684 739.4489,-1585.8685 C 735.6686,-1585.8684 732.87449,-1585.3479 731.06656,-1584.3071 C 729.25858,-1583.2661 728.3546,-1581.6499 728.35462,-1579.4584 C 728.3546,-1577.8148 728.95725,-1576.5273 730.16258,-1575.596 C 731.39525,-1574.692 733.61411,-1573.9113 736.81915,-1573.2539 L 743.5579,-1571.8979 C 750.37879,-1570.5282 755.22739,-1568.4463 758.10374,-1565.6522 C 760.97998,-1562.8581 762.41813,-1558.8861 762.41818,-1553.7361 C 762.41813,-1546.97 760.40472,-1541.9296 756.37796,-1538.615 C 752.37849,-1535.3278 746.2561,-1533.6842 738.01076,-1533.6842 C 734.12088,-1533.6842 730.21734,-1534.0541 726.30012,-1534.7937 C 722.38287,-1535.5333 718.46563,-1536.629 714.5484,-1538.0809 L 714.5484,-1551.4351 C 718.46563,-1549.3532 722.2459,-1547.7781 725.88922,-1546.7098 C 729.5599,-1545.6688 733.09363,-1545.1483 736.49043,-1545.1483 C 739.94195,-1545.1483 742.5854,-1545.7236 744.42079,-1546.8741 C 746.2561,-1548.0246 747.17377,-1549.6682 747.17381,-1551.8049 C 747.17377,-1553.7224 746.54373,-1555.2017 745.28368,-1556.2426 C 744.05094,-1557.2835 741.57185,-1558.2149 737.8464,-1559.0367 L 731.72399,-1560.3927 C 725.58788,-1561.7076 721.09538,-1563.8031 718.24649,-1566.6795 C 715.42498,-1569.5557 714.01422,-1573.4319 714.01423,-1578.3079 C 714.01422,-1584.4166 715.98654,-1589.1145 719.93118,-1592.4018 C 723.8758,-1595.6889 729.54621,-1597.3325 736.94242,-1597.3326 C 740.31176,-1597.3325 743.77701,-1597.0723 747.33817,-1596.5519 C 750.89926,-1596.0587 754.58365,-1595.3054 758.39137,-1594.2919 M 596.9079,-1489.1017 L 596.9079,-1476.1172 C 593.53848,-1477.6238 590.25129,-1478.7606 587.04631,-1479.5277 C 583.84126,-1480.2947 580.81431,-1480.6782 577.96544,-1480.6782 C 574.18513,-1480.6782 571.39102,-1480.1577 569.58309,-1479.1168 C 567.77511,-1478.0758 566.87113,-1476.4596 566.87115,-1474.2682 C 566.87113,-1472.6246 567.47378,-1471.3371 568.67911,-1470.4057 C 569.91179,-1469.5017 572.13064,-1468.721 575.33568,-1468.0636 L 582.07443,-1466.7076 C 588.89532,-1465.3379 593.74393,-1463.2561 596.62027,-1460.462 C 599.49651,-1457.6678 600.93466,-1453.6958 600.93471,-1448.5459 C 600.93466,-1441.7797 598.92125,-1436.7394 594.89449,-1433.4248 C 590.89503,-1430.1376 584.77263,-1428.494 576.52729,-1428.494 C 572.63742,-1428.494 568.73387,-1428.8638 564.81666,-1429.6034 C 560.8994,-1430.343 556.98216,-1431.4388 553.06493,-1432.8906 L 553.06493,-1446.2449 C 556.98216,-1444.1629 560.76243,-1442.5878 564.40576,-1441.5195 C 568.07644,-1440.4786 571.61017,-1439.9581 575.00696,-1439.9581 C 578.45848,-1439.9581 581.10193,-1440.5333 582.93732,-1441.6839 C 584.77263,-1442.8344 585.69031,-1444.478 585.69035,-1446.6147 C 585.69031,-1448.5322 585.06026,-1450.0114 583.80021,-1451.0524 C 582.56747,-1452.0933 580.08838,-1453.0247 576.36293,-1453.8465 L 570.24053,-1455.2025 C 564.10441,-1456.5173 559.61192,-1458.6129 556.76303,-1461.4892 C 553.94151,-1464.3655 552.53076,-1468.2416 552.53076,-1473.1177 C 552.53076,-1479.2263 554.50307,-1483.9243 558.44772,-1487.2115 C 562.39233,-1490.4987 568.06274,-1492.1423 575.45895,-1492.1423 C 578.82829,-1492.1423 582.29354,-1491.882 585.85471,-1491.3616 C 589.41579,-1490.8685 593.10019,-1490.1152 596.9079,-1489.1017 M 607.5502,-1491.0329 L 664.08995,-1491.0329 L 664.08995,-1479.0757 L 643.75043,-1479.0757 L 643.75043,-1429.6856 L 627.93081,-1429.6856 L 627.93081,-1479.0757 L 607.5502,-1479.0757 L 607.5502,-1491.0329 M 700.24911,-1480.6782 C 695.42786,-1480.6782 691.68867,-1478.8976 689.03155,-1475.3365 C 686.37438,-1471.7754 685.04581,-1466.7624 685.04583,-1460.2976 C 685.04581,-1453.8602 686.37438,-1448.8609 689.03155,-1445.2998 C 691.68867,-1441.7386 695.42786,-1439.9581 700.24911,-1439.9581 C 705.09768,-1439.9581 708.85056,-1441.7386 711.50775,-1445.2998 C 714.16485,-1448.8609 715.49342,-1453.8602 715.49347,-1460.2976 C 715.49342,-1466.7624 714.16485,-1471.7754 711.50775,-1475.3365 C 708.85056,-1478.8976 705.09768,-1480.6782 700.24911,-1480.6782 M 700.24911,-1492.1423 C 710.11065,-1492.1423 717.83555,-1489.3207 723.42383,-1483.6778 C 729.012,-1478.0347 731.80611,-1470.2413 731.80618,-1460.2976 C 731.80611,-1450.3812 729.012,-1442.6015 723.42383,-1436.9585 C 717.83555,-1431.3155 710.11065,-1428.494 700.24911,-1428.494 C 690.41489,-1428.494 682.68999,-1431.3155 677.07438,-1436.9585 C 671.48614,-1442.6015 668.69203,-1450.3812 668.69203,-1460.2976 C 668.69203,-1470.2413 671.48614,-1478.0347 677.07438,-1483.6778 C 682.68999,-1489.3207 690.41489,-1492.1423 700.24911,-1492.1423 M 743.72226,-1491.0329 L 769.97873,-1491.0329 C 777.78578,-1491.0328 783.7712,-1489.2934 787.93503,-1485.8145 C 792.12615,-1482.3629 794.22174,-1477.4321 794.22179,-1471.0221 C 794.22174,-1464.5846 792.12615,-1459.6264 787.93503,-1456.1475 C 783.7712,-1452.6959 777.78578,-1450.9702 769.97873,-1450.9702 L 759.54188,-1450.9702 L 759.54188,-1429.6856 L 743.72226,-1429.6856 L 743.72226,-1491.0329 M 759.54188,-1479.5688 L 759.54188,-1462.4343 L 768.29404,-1462.4343 C 771.36205,-1462.4343 773.73157,-1463.1739 775.4026,-1464.6531 C 777.07355,-1466.1597 777.90905,-1468.2827 777.90909,-1471.0221 C 777.90905,-1473.7614 777.07355,-1475.8707 775.4026,-1477.3499 C 773.73157,-1478.8291 771.36205,-1479.5687 768.29404,-1479.5688 L 759.54188,-1479.5688" style="font-size: 84.1522px; font-style: normal; font-weight: bold; fill: rgb(255, 0, 0); fill-opacity: 1; stroke: none; stroke-width: 1px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; font-family: Bitstream Vera Sans;"/>
+ </g>
+ <path style="fill: none; fill-opacity: 1; fill-rule: evenodd; stroke: rgb(252, 0, 0); stroke-width: 25.7953; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" d="M 115.5,-1811.5058 C 115.5,-842.05694 115.5,-842.05694 115.5,-842.05694" id="path5376"/>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/visualizer/svgitem.py Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,156 @@
+import gobject
+import rsvg
+#import cairo
+import goocanvas
+import os.path
+
+
+class SvgItem(goocanvas.ItemSimple):
+ # setup our custom properties
+ __gproperties__ = {
+ 'x': (float, # property type
+ 'X', # property nick name
+ 'The x coordinate of a SVG image', # property description
+ -10e6, # property minimum value
+ 10e6, # property maximum value
+ 0, # property default value
+ gobject.PARAM_READWRITE), # property flags
+
+ 'y': (float,
+ 'Y',
+ 'The y coordinate of a SVG image',
+ -10e6,
+ 10e6,
+ 0,
+ gobject.PARAM_READWRITE),
+
+ 'width': (float,
+ 'Width',
+ 'The width of the SVG Image',
+ 0,
+ 10e6,
+ 0,
+ gobject.PARAM_READWRITE),
+
+ 'height': (float,
+ 'Height',
+ 'The width of the SVG Image',
+ 0,
+ 10e6,
+ 0,
+ gobject.PARAM_READWRITE),
+ }
+
+ def __init__(self, x, y, rsvg_handle, **kwargs):
+ super(SvgItem, self).__init__(**kwargs)
+ assert isinstance(rsvg_handle, rsvg.Handle)
+ self.x = x
+ self.y = y
+ self.sx = 1.0
+ self.sy = 1.0
+ self.handle = rsvg_handle
+ self.width = self.handle.props.width
+ self.height = self.handle.props.height
+ self.custom_width = None
+ self.custom_height = None
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'x':
+ self.x = value
+
+ # make sure we update the display
+ self.changed(True)
+
+ elif pspec.name == 'y':
+ self.y = value
+
+ # make sure we update the display
+ self.changed(True)
+
+ elif pspec.name == 'width':
+ self.custom_width = value
+ self._size_changed()
+
+ # make sure we update the display
+ self.changed(True)
+
+ elif pspec.name == 'height':
+ self.custom_height = value
+ self._size_changed()
+
+ # make sure we update the display
+ self.changed(True)
+
+ else:
+ raise AttributeError, 'unknown property %s' % pspec.name
+
+ def _size_changed(self):
+ if self.custom_width is None and self.custom_height is None:
+ self.width = self.handle.props.width
+ self.height = self.handle.props.height
+ self.sx = 1.0
+ self.sy = 1.0
+ elif self.custom_width is not None and self.custom_height is None:
+ self.width = self.custom_width
+ self.sx = self.custom_width / self.handle.props.width
+ self.sy = self.sx
+ self.height = self.handle.props.height*self.sy
+ elif self.custom_width is None and self.custom_height is not None:
+ self.height = self.custom_height
+ self.sy = self.custom_height / self.handle.props.height
+ self.sx = self.sy
+ self.width = self.handle.props.width*self.sx
+ else:
+ self.width = self.custom_width
+ self.height = self.custom_height
+ self.sx = self.custom_width / self.handle.props.width
+ self.sy = self.custom_height / self.handle.props.height
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'x':
+ return self.x
+
+ elif pspec.name == 'y':
+ return self.y
+
+ elif pspec.name == 'width':
+ self.width = self.handle.props.width
+ self.height = self.handle.props.height
+
+ return self.width
+
+ elif pspec.name == 'height':
+ return self.height
+
+ else:
+ raise AttributeError, 'unknown property %s' % pspec.name
+
+ def do_simple_paint(self, cr, bounds):
+ cr.translate(self.x, self.y)
+ cr.scale(self.sx, self.sy)
+ self.handle.render_cairo(cr)
+
+ def do_simple_update(self, cr):
+ self.bounds_x1 = float(self.x)
+ self.bounds_y1 = float(self.y)
+ self.bounds_x2 = float(self.x + self.width)
+ self.bounds_y2 = float(self.y + self.height)
+
+ def do_simple_is_item_at(self, x, y, cr, is_pointer_event):
+ if ((x < self.x) or (x > self.x + self.width)) or ((y < self.y) or (y > self.y + self.height)):
+ return False
+ else:
+ return True
+
+
+_rsvg_cache = dict()
+
+def rsvg_handle_factory(base_file_name):
+ try:
+ return _rsvg_cache[base_file_name]
+ except KeyError:
+ full_path = os.path.join(os.path.dirname(__file__), 'resource', base_file_name)
+ rsvg_handle = rsvg.Handle(full_path)
+ _rsvg_cache[base_file_name] = rsvg_handle
+ return rsvg_handle
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/visualizer/wscript Thu Mar 24 10:54:24 2011 -0700
@@ -0,0 +1,25 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ headers = bld.new_task_gen('ns3header')
+ headers.module = 'visualizer'
+ headers.source = [
+ ]
+
+ module = bld.create_ns3_module('visualizer', ['core'])
+ if not bld.env['ENABLE_PYTHON_BINDINGS']:
+ return
+
+ module.features.append('pyembed')
+ module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
+ module.includes = '.'
+
+ if bld.env['ENABLE_PYTHON_BINDINGS']:
+ module.source = [
+ 'model/pyviz.cc',
+ 'model/visual-simulator-impl.cc',
+ ]
+ headers.source.append('model/pyviz.h')
+ else:
+ module.source = [
+ ]
--- a/src/wscript Thu Mar 24 10:32:51 2011 -0700
+++ b/src/wscript Thu Mar 24 10:54:24 2011 -0700
@@ -56,7 +56,7 @@
'topology-read',
'energy',
'tools',
- 'tools/visualizer',
+ 'visualizer',
)
def set_options(opt):