src/contrib/pyviz.cc
author Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
Thu Jan 29 16:46:39 2009 +0000 (2009-01-29)
changeset 3911 e070ed523ee9
parent 3902 2f13b3d633bf
permissions -rw-r--r--
Visualizer.set_follow_node(node) API (makes camera follow a node)
gjc@3519
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
gjc@3519
     2
/*
gjc@3519
     3
 * Copyright (c) 2008 INESC Porto
gjc@3519
     4
 *
gjc@3519
     5
 * This program is free software; you can redistribute it and/or modify
gjc@3519
     6
 * it under the terms of the GNU General Public License version 2 as
gjc@3519
     7
 * published by the Free Software Foundation;
gjc@3519
     8
 *
gjc@3519
     9
 * This program is distributed in the hope that it will be useful,
gjc@3519
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
gjc@3519
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
gjc@3519
    12
 * GNU General Public License for more details.
gjc@3519
    13
 *
gjc@3519
    14
 * You should have received a copy of the GNU General Public License
gjc@3519
    15
 * along with this program; if not, write to the Free Software
gjc@3519
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
gjc@3519
    17
 *
gjc@3519
    18
 * Author: Gustavo Carneiro  <gjc@inescporto.pt>
gjc@3519
    19
 */
gjc@3519
    20
gjc@3840
    21
#include <stdlib.h>
gjc@3519
    22
#include "pyviz.h"
gjc@3519
    23
#include "ns3/simulator.h"
gjc@3595
    24
#include "ns3/config.h"
gjc@3595
    25
#include "ns3/node-list.h"
gjc@3615
    26
#include "ns3/wifi-net-device.h"
gjc@3702
    27
#include "ns3/ethernet-header.h"
gjc@3702
    28
#include "ns3/log.h"
gjc@3887
    29
#include "ns3/ppp-header.h"
gjc@3615
    30
gjc@3615
    31
#include <sstream>
gjc@3615
    32
gjc@3702
    33
NS_LOG_COMPONENT_DEFINE ("PyViz");
gjc@3760
    34
#define NUM_LAST_PACKETS 10
gjc@3595
    35
gjc@3595
    36
static
gjc@3595
    37
std::vector<std::string>
gjc@3595
    38
PathSplit (std::string str)
gjc@3595
    39
{
gjc@3595
    40
  std::vector<std::string> results;
gjc@3595
    41
  size_t cutAt;
gjc@3595
    42
  while ((cutAt = str.find_first_of('/')) != str.npos)
gjc@3595
    43
    {
gjc@3595
    44
      if(cutAt > 0)
gjc@3595
    45
        {
gjc@3595
    46
          results.push_back(str.substr(0,cutAt));
gjc@3595
    47
        }
gjc@3595
    48
      str = str.substr(cutAt+1);
gjc@3595
    49
    }
gjc@3595
    50
  if (str.length() > 0)
gjc@3595
    51
    {
gjc@3595
    52
      results.push_back(str);
gjc@3595
    53
    }
gjc@3595
    54
  return results;
gjc@3595
    55
}
gjc@3595
    56
gjc@3519
    57
gjc@3530
    58
namespace ns3 {
gjc@3530
    59
gjc@3780
    60
static PyViz* g_visualizer = NULL;
gjc@3780
    61
gjc@3530
    62
PyViz::PyViz ()
gjc@3530
    63
{
gjc@3780
    64
  NS_ASSERT (g_visualizer == NULL);
gjc@3780
    65
  g_visualizer = this;
gjc@3780
    66
gjc@3837
    67
  Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Tx",
gjc@3887
    68
                   MakeCallback (&PyViz::TraceNetDevTxWifi, this));
gjc@3887
    69
gjc@3837
    70
  Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Rx",
gjc@3887
    71
                   MakeCallback (&PyViz::TraceNetDevRxWifi, this));
gjc@3887
    72
gjc@3837
    73
  Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/TxQueue/Dequeue",
gjc@3837
    74
                   MakeCallback (&PyViz::TraceNetDevTxCsma, this));
gjc@3887
    75
gjc@3837
    76
  Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/Rx",
gjc@3837
    77
                   MakeCallback (&PyViz::TraceNetDevRxCsma, this));
gjc@3887
    78
gjc@3837
    79
  Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/PromiscRx",
gjc@3837
    80
                   MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
gjc@3887
    81
gjc@3837
    82
  Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop",
gjc@3837
    83
                   MakeCallback (&PyViz::TraceDrop, this));
gjc@3887
    84
gjc@3837
    85
  Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Drop",
gjc@3837
    86
                   MakeCallback (&PyViz::TraceDrop, this));
gjc@3887
    87
gjc@3837
    88
  Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/TxQueue/Dequeue",
gjc@3887
    89
                   MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
gjc@3887
    90
gjc@3837
    91
  Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/Rx",
gjc@3887
    92
                   MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
gjc@3887
    93
}
gjc@3887
    94
gjc@3887
    95
void
gjc@3887
    96
PyViz::RegisterCsmaLikeDevice (std::string const &deviceTypeName)
gjc@3887
    97
{
gjc@3887
    98
  TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
gjc@3887
    99
gjc@3887
   100
  std::ostringstream sstream;
gjc@3887
   101
  sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
gjc@3887
   102
  Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxCsma, this));
gjc@3887
   103
gjc@3887
   104
  sstream.str ("");
gjc@3887
   105
  sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
gjc@3887
   106
  Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxCsma, this));
gjc@3887
   107
gjc@3887
   108
  sstream.str ("");
gjc@3887
   109
  sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/PromiscRx";
gjc@3887
   110
  Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
gjc@3887
   111
}
gjc@3887
   112
gjc@3887
   113
void
gjc@3887
   114
PyViz::RegisterWifiLikeDevice (std::string const &deviceTypeName)
gjc@3887
   115
{
gjc@3887
   116
  TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
gjc@3887
   117
gjc@3887
   118
  std::ostringstream sstream;
gjc@3887
   119
  sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Tx";
gjc@3887
   120
  Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxWifi, this));
gjc@3887
   121
gjc@3887
   122
  sstream.str ("");
gjc@3887
   123
  sstream <<"/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
gjc@3887
   124
  Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxWifi, this));
gjc@3887
   125
}
gjc@3887
   126
gjc@3887
   127
void
gjc@3887
   128
PyViz::RegisterPointToPointLikeDevice (std::string const &deviceTypeName)
gjc@3887
   129
{
gjc@3887
   130
  TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
gjc@3887
   131
gjc@3887
   132
  std::ostringstream sstream;
gjc@3887
   133
  sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
gjc@3887
   134
  Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
gjc@3887
   135
gjc@3887
   136
  sstream.str ("");
gjc@3887
   137
  sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
gjc@3887
   138
  Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
gjc@3530
   139
}
gjc@3530
   140
gjc@3820
   141
void
gjc@3885
   142
PyViz::SetPacketCaptureOptions (uint32_t nodeId, PacketCaptureOptions options)
gjc@3848
   143
{
gjc@3887
   144
  NS_LOG_DEBUG ("  SetPacketCaptureOptions " << nodeId
gjc@3887
   145
                << " PacketCaptureOptions (headers size = " << options.headers.size ()
gjc@3887
   146
                << " mode = " << options.mode << " numLastPackets = " << options.numLastPackets
gjc@3887
   147
                << ")");
gjc@3885
   148
  m_packetCaptureOptions[nodeId] = options;
gjc@3848
   149
}
gjc@3848
   150
gjc@3848
   151
void
gjc@3820
   152
PyViz::RegisterDropTracePath (std::string const &tracePath)
gjc@3820
   153
{
gjc@3820
   154
  Config::Connect (tracePath, MakeCallback (&PyViz::TraceDrop, this));
gjc@3820
   155
}
gjc@3820
   156
gjc@3530
   157
PyViz::~PyViz ()
gjc@3530
   158
{
gjc@3780
   159
  NS_ASSERT (g_visualizer == this);
gjc@3780
   160
  g_visualizer = NULL;
gjc@3780
   161
}
gjc@3780
   162
gjc@3780
   163
void PyViz::DoPause (std::string const &message)
gjc@3780
   164
{
gjc@3780
   165
  m_pauseMessages.push_back (message);
gjc@3780
   166
  m_stop = true;
gjc@3887
   167
  NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": Have "
gjc@3887
   168
                << g_visualizer->m_pauseMessages.size () << " pause messages");
gjc@3780
   169
}
gjc@3780
   170
gjc@3780
   171
void PyViz::Pause (std::string const &message)
gjc@3780
   172
{
gjc@3780
   173
  NS_ASSERT (g_visualizer);
gjc@3780
   174
  g_visualizer->DoPause (message);
gjc@3780
   175
}
gjc@3780
   176
gjc@3780
   177
std::vector<std::string>
gjc@3780
   178
PyViz::GetPauseMessages () const
gjc@3780
   179
{
gjc@3887
   180
  NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": GetPauseMessages: have "
gjc@3887
   181
                << g_visualizer->m_pauseMessages.size () << " pause messages");
gjc@3780
   182
  return m_pauseMessages;
gjc@3530
   183
}
gjc@3519
   184
    
gjc@3772
   185
gjc@3780
   186
void
gjc@3780
   187
PyViz::CallbackStopSimulation ()
gjc@3772
   188
{
gjc@3780
   189
  NS_LOG_FUNCTION_NOARGS ();
gjc@3780
   190
  m_stop = true;
gjc@3772
   191
}
gjc@3772
   192
gjc@3519
   193
void
gjc@3530
   194
PyViz::SimulatorRunUntil (Time time)
gjc@3519
   195
{
gjc@3780
   196
  NS_LOG_LOGIC ("SimulatorRunUntil " << time << " (now is " << Simulator::Now () << ")");
gjc@3780
   197
gjc@3780
   198
  m_pauseMessages.clear ();
gjc@3595
   199
  m_transmissionSamples.clear ();
gjc@3758
   200
  m_packetDrops.clear ();
gjc@3702
   201
gjc@3714
   202
  Time expirationTime = Simulator::Now () - Seconds (10);
gjc@3714
   203
gjc@3714
   204
  // Clear very old transmission records
gjc@3714
   205
  for (std::map<TxRecordKey, TxRecordValue>::iterator iter = m_txRecords.begin ();
gjc@3714
   206
       iter != m_txRecords.end ();)
gjc@3714
   207
    {
gjc@3714
   208
      if (iter->second.time < expirationTime)
gjc@3714
   209
        {
gjc@3714
   210
          m_txRecords.erase (iter++);
gjc@3714
   211
        }
gjc@3714
   212
      else
gjc@3714
   213
        {
gjc@3714
   214
          iter++;
gjc@3714
   215
        }
gjc@3714
   216
    }
gjc@3714
   217
gjc@3714
   218
  // Clear very old packets of interest
gjc@3714
   219
  for (std::map<uint32_t, Time>::iterator iter = m_packetsOfInterest.begin ();
gjc@3714
   220
       iter != m_packetsOfInterest.end ();)
gjc@3714
   221
    {
gjc@3714
   222
      if (iter->second < expirationTime)
gjc@3714
   223
        {
gjc@3714
   224
          m_packetsOfInterest.erase (iter++);
gjc@3714
   225
        }
gjc@3714
   226
      else
gjc@3714
   227
        {
gjc@3714
   228
          iter++;
gjc@3714
   229
        }
gjc@3714
   230
    }
gjc@3772
   231
gjc@3780
   232
  if (Simulator::IsFinished () || Simulator::Now () >= time)
gjc@3780
   233
    {
gjc@3780
   234
      return;
gjc@3780
   235
    }
gjc@3772
   236
  // Schedule a dummy callback function for the target time, to make
gjc@3772
   237
  // sure we stop at the right time.  Otherwise, simulations with few
gjc@3887
   238
  // events just appear to "jump" big chunks of time.
gjc@3780
   239
  NS_LOG_LOGIC ("Schedule dummy callback to be called in " << (time - Simulator::Now ()));
gjc@3780
   240
  m_stop = false;
gjc@3780
   241
  Simulator::Cancel (m_stopCallbackEvent);
gjc@3780
   242
  m_stopCallbackEvent = Simulator::Schedule (time - Simulator::Now (), &PyViz::CallbackStopSimulation, this);
gjc@3772
   243
gjc@3780
   244
  while (!Simulator::IsFinished ())
gjc@3519
   245
    {
gjc@3780
   246
      if (m_stop)
gjc@3780
   247
        {
gjc@3780
   248
          break;
gjc@3780
   249
        }
gjc@3519
   250
      Simulator::RunOneEvent ();
gjc@3519
   251
    }
gjc@3519
   252
}
gjc@3519
   253
gjc@3595
   254
bool PyViz::TransmissionSampleKey::operator < (PyViz::TransmissionSampleKey const &other) const
gjc@3595
   255
{
gjc@3742
   256
  if (this->transmitter < other.transmitter)
gjc@3742
   257
    {
gjc@3742
   258
      return true;
gjc@3742
   259
    }
gjc@3742
   260
  if (this->transmitter != other.transmitter)
gjc@3742
   261
    {
gjc@3742
   262
      return false;
gjc@3742
   263
    }
gjc@3742
   264
  if (this->receiver < other.receiver)
gjc@3742
   265
    {
gjc@3742
   266
      return true;}
gjc@3742
   267
  if (this->receiver != other.receiver)
gjc@3742
   268
    {
gjc@3742
   269
      return false;
gjc@3742
   270
    }
gjc@3742
   271
  if (this->channel < other.channel)
gjc@3742
   272
    {
gjc@3742
   273
      return true;
gjc@3742
   274
    }
gjc@3742
   275
  else
gjc@3742
   276
    {
gjc@3742
   277
      return false;
gjc@3742
   278
    }
gjc@3742
   279
}
gjc@3742
   280
gjc@3742
   281
bool PyViz::TransmissionSampleKey::operator == (PyViz::TransmissionSampleKey const &other) const
gjc@3742
   282
{
gjc@3742
   283
  bool retval = (transmitter == other.transmitter) &&
gjc@3742
   284
    (receiver == other.receiver) &&
gjc@3742
   285
    (channel == other.channel);
gjc@3742
   286
  return retval;
gjc@3530
   287
}
gjc@3519
   288
gjc@3739
   289
gjc@3739
   290
PyViz::NetDeviceStatistics &
gjc@3739
   291
PyViz::FindNetDeviceStatistics (int node, int interface)
gjc@3739
   292
{
gjc@3739
   293
  std::map<uint32_t, std::vector<NetDeviceStatistics> >::iterator nodeStatsIter = m_nodesStatistics.find (node);
gjc@3739
   294
  std::vector<NetDeviceStatistics> *stats;
gjc@3739
   295
  if (nodeStatsIter == m_nodesStatistics.end ())
gjc@3739
   296
    {
gjc@3739
   297
      stats = &m_nodesStatistics[node];
gjc@3739
   298
      stats->resize (NodeList::GetNode (node)->GetNDevices ());
gjc@3739
   299
    }
gjc@3739
   300
  else
gjc@3739
   301
    {
gjc@3739
   302
      stats = &(nodeStatsIter->second);
gjc@3739
   303
    }
gjc@3739
   304
  NetDeviceStatistics &devStats = (*stats)[interface];
gjc@3739
   305
  return devStats;
gjc@3739
   306
}
gjc@3739
   307
gjc@3885
   308
bool PyViz::GetPacketCaptureOptions (uint32_t nodeId, const PacketCaptureOptions **outOptions) const
gjc@3885
   309
{
gjc@3885
   310
  std::map<uint32_t, PacketCaptureOptions>::const_iterator iter = m_packetCaptureOptions.find (nodeId);
gjc@3885
   311
  if (iter == m_packetCaptureOptions.end ())
gjc@3885
   312
    {
gjc@3885
   313
      return false;
gjc@3885
   314
    }
gjc@3885
   315
  else
gjc@3885
   316
    {
gjc@3885
   317
      *outOptions = &iter->second;
gjc@3885
   318
      return true;
gjc@3885
   319
    }
gjc@3885
   320
}
gjc@3885
   321
gjc@3885
   322
bool PyViz::FilterPacket (Ptr<const Packet> packet, const PacketCaptureOptions &options)
gjc@3885
   323
{
gjc@3885
   324
  switch (options.mode)
gjc@3885
   325
    {
gjc@3885
   326
    case PACKET_CAPTURE_DISABLED:
gjc@3885
   327
      return false;
gjc@3885
   328
gjc@3885
   329
    case PACKET_CAPTURE_FILTER_HEADERS_OR:
gjc@3885
   330
      {
gjc@3885
   331
        PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
gjc@3885
   332
        while (metadataIterator.HasNext ())
gjc@3885
   333
          {
gjc@3885
   334
            PacketMetadata::Item item = metadataIterator.Next ();
gjc@3885
   335
            if (options.headers.find (item.tid) != options.headers.end ())
gjc@3885
   336
              {
gjc@3885
   337
                return true;
gjc@3885
   338
              }
gjc@3885
   339
          }
gjc@3885
   340
        return false;
gjc@3885
   341
      }
gjc@3885
   342
gjc@3885
   343
    case PACKET_CAPTURE_FILTER_HEADERS_AND:
gjc@3885
   344
      {
gjc@3885
   345
        std::set<TypeId> missingHeaders (options.headers);
gjc@3885
   346
        PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
gjc@3885
   347
        while (metadataIterator.HasNext ())
gjc@3885
   348
          {
gjc@3885
   349
            PacketMetadata::Item item = metadataIterator.Next ();
gjc@3885
   350
            std::set<TypeId>::iterator missingIter = missingHeaders.find (item.tid);
gjc@3885
   351
            if (missingIter != missingHeaders.end ())
gjc@3885
   352
              {
gjc@3885
   353
                missingHeaders.erase (missingIter);
gjc@3885
   354
              }
gjc@3885
   355
          }
gjc@3885
   356
        if (missingHeaders.size () == 0)
gjc@3885
   357
          {
gjc@3885
   358
            return true;
gjc@3885
   359
          }
gjc@3885
   360
        else
gjc@3885
   361
          {
gjc@3885
   362
            return false;
gjc@3885
   363
          }
gjc@3885
   364
      }
gjc@3885
   365
gjc@3885
   366
    default:
gjc@3885
   367
      NS_FATAL_ERROR ("should not be reached");
gjc@3885
   368
      return false;
gjc@3885
   369
    }
gjc@3885
   370
}
gjc@3739
   371
gjc@3759
   372
void PyViz::TraceDrop (std::string context, Ptr<const Packet> packet)
gjc@3758
   373
{
gjc@3758
   374
  NS_LOG_FUNCTION (context << packet->GetUid ());
gjc@3758
   375
  std::vector<std::string> splitPath = PathSplit (context);
gjc@3758
   376
  int nodeIndex = atoi (splitPath[1].c_str ());
gjc@3758
   377
  Ptr<Node> node = NodeList::GetNode (nodeIndex);
gjc@3758
   378
gjc@3847
   379
  if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
gjc@3847
   380
    {
gjc@3847
   381
      // if the transmitting node is not "of interest", we still
gjc@3847
   382
      // record the transmission if it is a packet of interest.
gjc@3847
   383
      if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
gjc@3847
   384
        {
gjc@3847
   385
          NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
gjc@3847
   386
          return;
gjc@3847
   387
        }
gjc@3847
   388
    }
gjc@3847
   389
gjc@3760
   390
  // ---- "last packets"
gjc@3885
   391
  const PacketCaptureOptions *captureOptions;
gjc@3885
   392
  if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
gjc@3760
   393
    {
gjc@3885
   394
      LastPacketsSample &last = m_lastPackets[nodeIndex];
gjc@3885
   395
      PacketSample lastPacket;
gjc@3885
   396
      lastPacket.time = Simulator::Now ();
gjc@3885
   397
      lastPacket.packet = packet->Copy ();
gjc@3885
   398
      lastPacket.device = NULL;
gjc@3885
   399
      last.lastDroppedPackets.push_back (lastPacket);
gjc@3885
   400
      while (last.lastDroppedPackets.size () > captureOptions->numLastPackets)
gjc@3885
   401
        {
gjc@3885
   402
          last.lastDroppedPackets.erase (last.lastDroppedPackets.begin ());
gjc@3885
   403
        }
gjc@3760
   404
    }
gjc@3760
   405
gjc@3758
   406
  std::map<Ptr<Node>, uint32_t>::iterator iter = m_packetDrops.find (node);
gjc@3758
   407
  if (iter == m_packetDrops.end ())
gjc@3758
   408
    {
gjc@3758
   409
      m_packetDrops[node] = packet->GetSize ();
gjc@3758
   410
    }
gjc@3758
   411
  else
gjc@3758
   412
    {
gjc@3758
   413
      iter->second += packet->GetSize ();
gjc@3758
   414
    }
gjc@3758
   415
}
gjc@3758
   416
gjc@3595
   417
void
gjc@3887
   418
PyViz::TraceNetDevTxWifi (std::string context, Ptr<const Packet> packet, Mac48Address destinationAddress)
gjc@3595
   419
{
gjc@3842
   420
  NS_LOG_FUNCTION (context << packet->GetUid () << *packet);
gjc@3742
   421
gjc@3595
   422
  std::vector<std::string> splitPath = PathSplit (context);
gjc@3595
   423
  int nodeIndex = atoi (splitPath[1].c_str ());
gjc@3739
   424
  int devIndex = atoi (splitPath[3].c_str ());
gjc@3760
   425
  Ptr<Node> node = NodeList::GetNode (nodeIndex);
gjc@3760
   426
  Ptr<NetDevice> device = node->GetDevice (devIndex);
gjc@3739
   427
gjc@3739
   428
  // ---- statistics
gjc@3739
   429
  NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
gjc@3741
   430
  ++stats.transmittedPackets;
gjc@3741
   431
  stats.transmittedBytes += packet->GetSize ();
gjc@3710
   432
gjc@3760
   433
  // ---- "last packets"
gjc@3885
   434
  const PacketCaptureOptions *captureOptions;
gjc@3885
   435
  if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
gjc@3760
   436
    {
gjc@3885
   437
      LastPacketsSample &last = m_lastPackets[nodeIndex];
gjc@3887
   438
      TxPacketSample lastPacket;
gjc@3885
   439
      lastPacket.time = Simulator::Now ();
gjc@3885
   440
      lastPacket.packet = packet->Copy ();
gjc@3885
   441
      lastPacket.device = device;
gjc@3887
   442
      lastPacket.to = destinationAddress;
gjc@3885
   443
      last.lastTransmittedPackets.push_back (lastPacket);
gjc@3885
   444
      while (last.lastTransmittedPackets.size () > captureOptions->numLastPackets)
gjc@3885
   445
        {
gjc@3885
   446
          last.lastTransmittedPackets.erase (last.lastTransmittedPackets.begin ());
gjc@3885
   447
        }
gjc@3760
   448
    }
gjc@3760
   449
gjc@3742
   450
  // ---- transmissions records
gjc@3742
   451
gjc@3710
   452
  if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
gjc@3710
   453
    {
gjc@3710
   454
      // if the transmitting node is not "of interest", we still
gjc@3710
   455
      // record the transmission if it is a packet of interest.
gjc@3710
   456
      if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
gjc@3710
   457
        {
gjc@3742
   458
          NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
gjc@3710
   459
          return;
gjc@3710
   460
        }
gjc@3710
   461
    }
gjc@3710
   462
  else
gjc@3710
   463
    {
gjc@3710
   464
      // We will follow this packet throughout the network.
gjc@3714
   465
      m_packetsOfInterest[packet->GetUid ()] = Simulator::Now ();
gjc@3710
   466
    }
gjc@3710
   467
gjc@3714
   468
  TxRecordValue record = { Simulator::Now (), node, false };
gjc@3702
   469
  if (destinationAddress == device->GetBroadcast ())
gjc@3595
   470
    {
gjc@3702
   471
      record.isBroadcast = true;
gjc@3595
   472
    }
gjc@3714
   473
  m_txRecords[TxRecordKey (device->GetChannel (), packet->GetUid ())] = record;
gjc@3595
   474
}
gjc@3595
   475
gjc@3595
   476
void
gjc@3702
   477
PyViz::TraceNetDevRxCsma (std::string context, Ptr<const Packet> packet)
gjc@3702
   478
{
gjc@3887
   479
  Ptr<Packet> p = packet->Copy ();
gjc@3887
   480
  EthernetHeader ethernetHeader;
gjc@3887
   481
  p->RemoveHeader (ethernetHeader);
gjc@3887
   482
  TraceNetDevRxWifi (context, p, ethernetHeader.GetSource ());
gjc@3887
   483
}
gjc@3887
   484
gjc@3887
   485
void
gjc@3887
   486
PyViz::TraceNetDevRxPointToPoint (std::string context, Ptr<const Packet> packet)
gjc@3887
   487
{
gjc@3887
   488
  Ptr<Packet> p = packet->Copy ();
gjc@3887
   489
  PppHeader h;
gjc@3887
   490
  p->RemoveHeader (h);
gjc@3887
   491
  TraceNetDevRxWifi (context, p, Mac48Address ());
gjc@3702
   492
}
gjc@3702
   493
gjc@3702
   494
void
gjc@3702
   495
PyViz::TraceNetDevPromiscRxCsma (std::string context, Ptr<const Packet> packet, NetDevice::PacketType packetType)
gjc@3702
   496
{
gjc@3887
   497
  Ptr<Packet> p = packet->Copy ();
gjc@3887
   498
  EthernetHeader ethernetHeader;
gjc@3887
   499
  p->RemoveHeader (ethernetHeader);
gjc@3706
   500
  // Other packet types are already being received by
gjc@3742
   501
  // TraceNetDevRxCsma; we don't want to receive them twice.
gjc@3706
   502
  if (packetType == NetDevice::PACKET_OTHERHOST)
gjc@3706
   503
    {
gjc@3887
   504
      TraceNetDevRxWifi (context, p, ethernetHeader.GetDestination ());
gjc@3706
   505
    }
gjc@3702
   506
}
gjc@3702
   507
gjc@3702
   508
void
gjc@3702
   509
PyViz::TraceNetDevTxCsma (std::string context, Ptr<const Packet> packet)
gjc@3702
   510
{
gjc@3887
   511
  EthernetHeader ethernetHeader;
gjc@3887
   512
  Ptr<Packet> p = packet->Copy ();
gjc@3887
   513
  p->RemoveHeader (ethernetHeader);
gjc@3887
   514
  TraceNetDevTxWifi (context, p, ethernetHeader.GetDestination ());
gjc@3702
   515
}
gjc@3702
   516
gjc@3702
   517
void
gjc@3887
   518
PyViz::TraceNetDevTxPointToPoint (std::string context, Ptr<const Packet> packet)
gjc@3887
   519
{
gjc@3887
   520
  Ptr<Packet> p = packet->Copy ();
gjc@3887
   521
  PppHeader h;
gjc@3887
   522
  p->RemoveHeader (h);
gjc@3887
   523
  TraceNetDevTxWifi (context, p, Mac48Address ());
gjc@3887
   524
}
gjc@3887
   525
gjc@3887
   526
void
gjc@3887
   527
PyViz::TraceNetDevRxWifi (std::string context, Ptr<const Packet> packet, Mac48Address from)
gjc@3595
   528
{
gjc@3742
   529
  NS_LOG_FUNCTION (context << packet->GetUid ());
gjc@3739
   530
  std::vector<std::string> splitPath = PathSplit (context);
gjc@3739
   531
  int nodeIndex = atoi (splitPath[1].c_str ());
gjc@3739
   532
  int devIndex = atoi (splitPath[3].c_str ());
gjc@3739
   533
gjc@3739
   534
  // ---- statistics
gjc@3739
   535
  NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
gjc@3739
   536
  ++stats.receivedPackets;
gjc@3739
   537
  stats.receivedBytes += packet->GetSize ();
gjc@3739
   538
gjc@3739
   539
  Ptr<Node> node = NodeList::GetNode (nodeIndex);
gjc@3760
   540
  Ptr<NetDevice> device = node->GetDevice (devIndex);
gjc@3760
   541
gjc@3760
   542
  // ---- "last packets"
gjc@3885
   543
  const PacketCaptureOptions *captureOptions;
gjc@3885
   544
  if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
gjc@3760
   545
    {
gjc@3885
   546
      LastPacketsSample &last = m_lastPackets[nodeIndex];
gjc@3887
   547
      RxPacketSample lastPacket;
gjc@3885
   548
      lastPacket.time = Simulator::Now ();
gjc@3885
   549
      lastPacket.packet = packet->Copy ();
gjc@3885
   550
      lastPacket.device = device;
gjc@3887
   551
      lastPacket.from = from;
gjc@3885
   552
      last.lastReceivedPackets.push_back (lastPacket);
gjc@3885
   553
      while (last.lastReceivedPackets.size () > captureOptions->numLastPackets)
gjc@3885
   554
        {
gjc@3885
   555
          last.lastReceivedPackets.erase (last.lastReceivedPackets.begin ());
gjc@3885
   556
        }
gjc@3760
   557
    }
gjc@3742
   558
gjc@3739
   559
  // ---- transmissions
gjc@3710
   560
  if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
gjc@3710
   561
    {
gjc@3742
   562
      NS_LOG_DEBUG ("RX Packet " << packet->GetUid () << " is not of interest");
gjc@3710
   563
      return;
gjc@3710
   564
    }
gjc@3710
   565
gjc@3595
   566
  Ptr<Channel> channel = device->GetChannel ();
gjc@3595
   567
gjc@3714
   568
  std::map<TxRecordKey, TxRecordValue>::iterator recordIter = 
gjc@3714
   569
    m_txRecords.find (TxRecordKey (channel, packet->GetUid ()));
gjc@3742
   570
gjc@3595
   571
  if (recordIter == m_txRecords.end ())
gjc@3595
   572
    {
gjc@3742
   573
      NS_LOG_DEBUG ("RX Packet " << packet->GetUid () << " was not transmitted?!");
gjc@3595
   574
      return;
gjc@3595
   575
    }
gjc@3595
   576
  
gjc@3714
   577
  TxRecordValue &record = recordIter->second;
gjc@3595
   578
  
gjc@3842
   579
  if (record.srcNode == node)
gjc@3842
   580
    {
gjc@3842
   581
      NS_LOG_WARN ("Node " << node->GetId () << " receiving back the same packet (UID=" << packet->GetUid ()
gjc@3842
   582
                   << ") it had previously transmitted, on the same channel!");
gjc@3842
   583
      return;
gjc@3842
   584
    }
gjc@3714
   585
gjc@3595
   586
  TransmissionSampleKey key = { record.srcNode, node, channel };
gjc@3742
   587
gjc@3742
   588
#ifdef  NS3_LOG_ENABLE
gjc@3742
   589
  NS_LOG_DEBUG("m_transmissionSamples begin:");
gjc@3742
   590
  if (g_log.IsEnabled (ns3::LOG_DEBUG))
gjc@3742
   591
    {
gjc@3742
   592
      for (std::map<TransmissionSampleKey,TransmissionSampleValue>::const_iterator iter
gjc@3742
   593
             = m_transmissionSamples.begin (); iter != m_transmissionSamples.end (); iter++)
gjc@3742
   594
        {
gjc@3742
   595
          NS_LOG_DEBUG(iter->first.transmitter<<"/"<<iter->first.transmitter->GetId () << ", "
gjc@3742
   596
                       << iter->first.receiver<<"/"<<iter->first.receiver->GetId ()
gjc@3742
   597
                       << ", " << iter->first.channel << " => " << iter->second.bytes << " (@ " << &iter->second << ")");
gjc@3742
   598
        }
gjc@3742
   599
    }
gjc@3742
   600
  NS_LOG_DEBUG("m_transmissionSamples end.");
gjc@3742
   601
#endif
gjc@3742
   602
gjc@3742
   603
  std::map<TransmissionSampleKey,TransmissionSampleValue>::iterator
gjc@3742
   604
    iter = m_transmissionSamples.find (key);
gjc@3742
   605
gjc@3742
   606
  if (iter == m_transmissionSamples.end ())
gjc@3742
   607
    {
gjc@3742
   608
      TransmissionSampleValue sample = { packet->GetSize () };
gjc@3742
   609
      NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
gjc@3742
   610
                    << key.receiver<<"/"<<key.receiver->GetId()
gjc@3742
   611
                    << " channel " << channel << ": " << packet->GetSize ()
gjc@3742
   612
                    << " bytes more. => new sample with " << packet->GetSize () << " bytes.");
gjc@3742
   613
      m_transmissionSamples[key] = sample;
gjc@3742
   614
    }
gjc@3742
   615
  else
gjc@3742
   616
    {
gjc@3742
   617
      TransmissionSampleValue &sample = iter->second;
gjc@3742
   618
      NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
gjc@3742
   619
                    << key.receiver<<"/"<<key.receiver->GetId()
gjc@3742
   620
                    << " channel " << channel << ": " << packet->GetSize ()
gjc@3742
   621
                    << " bytes more. => sample " << &sample << " with bytes " << sample.bytes);
gjc@3742
   622
gjc@3742
   623
      sample.bytes += packet->GetSize ();
gjc@3742
   624
    }
gjc@3595
   625
}
gjc@3595
   626
gjc@3595
   627
PyViz::TransmissionSampleList
gjc@3595
   628
PyViz::GetTransmissionSamples () const
gjc@3595
   629
{
gjc@3745
   630
  NS_LOG_DEBUG ("GetTransmissionSamples BEGIN");
gjc@3595
   631
  TransmissionSampleList list;
gjc@3595
   632
  for (std::map<TransmissionSampleKey, TransmissionSampleValue>::const_iterator
gjc@3595
   633
         iter = m_transmissionSamples.begin ();
gjc@3595
   634
       iter !=  m_transmissionSamples.end ();
gjc@3595
   635
       iter++)
gjc@3595
   636
    {
gjc@3595
   637
      TransmissionSample sample;
gjc@3595
   638
      sample.transmitter = iter->first.transmitter;
gjc@3595
   639
      sample.receiver = iter->first.receiver;
gjc@3595
   640
      sample.channel = iter->first.channel;
gjc@3595
   641
      sample.bytes = iter->second.bytes;
gjc@3742
   642
      NS_LOG_DEBUG ("from " << sample.transmitter->GetId() << " to " << sample.receiver->GetId()
gjc@3742
   643
                    << ": " << sample.bytes << " bytes.");
gjc@3595
   644
      list.push_back (sample);
gjc@3595
   645
    }
gjc@3745
   646
  NS_LOG_DEBUG ("GetTransmissionSamples END");
gjc@3595
   647
  return list;
gjc@3595
   648
}
gjc@3595
   649
gjc@3758
   650
PyViz::PacketDropSampleList
gjc@3758
   651
PyViz::GetPacketDropSamples () const
gjc@3758
   652
{
gjc@3758
   653
  NS_LOG_DEBUG ("GetPacketDropSamples BEGIN");
gjc@3758
   654
  PacketDropSampleList list;
gjc@3758
   655
  for (std::map<Ptr<Node>, uint32_t>::const_iterator
gjc@3758
   656
         iter = m_packetDrops.begin ();
gjc@3758
   657
       iter !=  m_packetDrops.end ();
gjc@3758
   658
       iter++)
gjc@3758
   659
    {
gjc@3758
   660
      PacketDropSample sample;
gjc@3758
   661
      sample.transmitter = iter->first;
gjc@3758
   662
      sample.bytes = iter->second;
gjc@3758
   663
      NS_LOG_DEBUG ("in " << sample.transmitter->GetId() 
gjc@3758
   664
                    << ": " << sample.bytes << " bytes dropped.");
gjc@3758
   665
      list.push_back (sample);
gjc@3758
   666
    }
gjc@3758
   667
  NS_LOG_DEBUG ("GetPacketDropSamples END");
gjc@3758
   668
  return list;
gjc@3758
   669
}
gjc@3758
   670
gjc@3710
   671
void
gjc@3710
   672
PyViz::SetNodesOfInterest (std::set<uint32_t> nodes)
gjc@3710
   673
{
gjc@3710
   674
  m_nodesOfInterest = nodes;
gjc@3595
   675
}
gjc@3595
   676
gjc@3739
   677
std::vector<PyViz::NodeStatistics>
gjc@3739
   678
PyViz::GetNodesStatistics () const
gjc@3739
   679
{
gjc@3739
   680
  std::vector<PyViz::NodeStatistics> retval;
gjc@3739
   681
  for (std::map<uint32_t, std::vector<NetDeviceStatistics> >::const_iterator iter = m_nodesStatistics.begin ();
gjc@3739
   682
       iter != m_nodesStatistics.end (); iter++)
gjc@3739
   683
    {
gjc@3739
   684
      NodeStatistics stats = { iter->first, iter->second };
gjc@3739
   685
      retval.push_back (stats);
gjc@3739
   686
    }
gjc@3739
   687
  return retval;
gjc@3710
   688
}
gjc@3710
   689
gjc@3760
   690
gjc@3766
   691
PyViz::LastPacketsSample
gjc@3766
   692
PyViz::GetLastPackets (uint32_t nodeId) const
gjc@3760
   693
{
gjc@3766
   694
  NS_LOG_DEBUG ("GetLastPackets: " << nodeId);
gjc@3766
   695
  
gjc@3766
   696
  std::map<uint32_t, LastPacketsSample>::const_iterator
gjc@3766
   697
    iter = m_lastPackets.find(nodeId);
gjc@3766
   698
  if (iter != m_lastPackets.end ())
gjc@3760
   699
    {
gjc@3766
   700
      return iter->second;
gjc@3760
   701
    }
gjc@3766
   702
  else
gjc@3766
   703
    {
gjc@3766
   704
      return LastPacketsSample ();
gjc@3766
   705
    }
gjc@3739
   706
}
gjc@3739
   707
gjc@3902
   708
gjc@3903
   709
gjc@3903
   710
gjc@3903
   711
gjc@3903
   712
gjc@3903
   713
namespace
gjc@3903
   714
{
gjc@3903
   715
  // Adapted from http://en.wikipedia.org/w/index.php?title=Line_clipping&oldid=248609574
gjc@3903
   716
  class FastClipping
gjc@3903
   717
  {
gjc@3903
   718
  public:
gjc@3903
   719
    struct Vector2 
gjc@3903
   720
    {
gjc@3903
   721
      double x;
gjc@3903
   722
      double y;
gjc@3903
   723
    };
gjc@3903
   724
      
gjc@3903
   725
    Vector2 m_clipMin, m_clipMax;
gjc@3903
   726
gjc@3903
   727
    struct Line
gjc@3903
   728
    {
gjc@3903
   729
      Vector2 start, end;
gjc@3903
   730
      double dx, dy;
gjc@3903
   731
    };
gjc@3903
   732
gjc@3903
   733
  private:
gjc@3903
   734
gjc@3903
   735
    void ClipStartTop (Line &line)
gjc@3903
   736
    {
gjc@3903
   737
      line.start.x += line.dx * (m_clipMin.y - line.start.y) / line.dy;
gjc@3903
   738
      line.start.y = m_clipMin.y;
gjc@3903
   739
    }
gjc@3903
   740
 
gjc@3903
   741
    void ClipStartBottom (Line &line)
gjc@3903
   742
    {
gjc@3903
   743
      line.start.x += line.dx * (m_clipMax.y - line.start.y) / line.dy;
gjc@3903
   744
      line.start.y = m_clipMax.y;
gjc@3903
   745
    }
gjc@3903
   746
 
gjc@3903
   747
    void ClipStartRight (Line &line)
gjc@3903
   748
    {
gjc@3903
   749
      line.start.y += line.dy * (m_clipMax.x - line.start.x) / line.dx;
gjc@3903
   750
      line.start.x = m_clipMax.x;
gjc@3903
   751
    }
gjc@3903
   752
 
gjc@3903
   753
    void ClipStartLeft (Line &line)
gjc@3903
   754
    {
gjc@3903
   755
      line.start.y += line.dy * (m_clipMin.x - line.start.x) / line.dx;
gjc@3903
   756
      line.start.x = m_clipMin.x;
gjc@3903
   757
    }
gjc@3903
   758
 
gjc@3903
   759
    void ClipEndTop (Line &line)
gjc@3903
   760
    {
gjc@3903
   761
      line.end.x += line.dx * (m_clipMin.y - line.end.y) / line.dy;
gjc@3903
   762
      line.end.y = m_clipMin.y;
gjc@3903
   763
    }
gjc@3903
   764
    
gjc@3903
   765
    void ClipEndBottom (Line &line) {
gjc@3903
   766
      line.end.x += line.dx * (m_clipMax.y - line.end.y) / line.dy;
gjc@3903
   767
      line.end.y = m_clipMax.y;
gjc@3903
   768
    }
gjc@3903
   769
 
gjc@3903
   770
    void ClipEndRight (Line &line)
gjc@3903
   771
    {
gjc@3903
   772
      line.end.y += line.dy * (m_clipMax.x - line.end.x) / line.dx;
gjc@3903
   773
      line.end.x = m_clipMax.x;
gjc@3903
   774
    }
gjc@3903
   775
 
gjc@3903
   776
    void ClipEndLeft (Line &line)
gjc@3903
   777
    {
gjc@3903
   778
      line.end.y += line.dy * (m_clipMin.x - line.end.x) / line.dx;
gjc@3903
   779
      line.end.x = m_clipMin.x;
gjc@3903
   780
    }
gjc@3903
   781
gjc@3903
   782
  public:
gjc@3903
   783
    FastClipping (Vector2 clipMin, Vector2 clipMax)
gjc@3903
   784
      : m_clipMin (clipMin), m_clipMax (clipMax)
gjc@3903
   785
    {
gjc@3903
   786
    }
gjc@3903
   787
    
gjc@3903
   788
 
gjc@3903
   789
    bool ClipLine (Line &line)
gjc@3903
   790
    {
gjc@3903
   791
      uint8_t lineCode = 0;
gjc@3903
   792
 
gjc@3903
   793
      if (line.end.y < m_clipMin.y)
gjc@3903
   794
        lineCode |= 8;
gjc@3903
   795
      else if (line.end.y > m_clipMax.y)
gjc@3903
   796
        lineCode |= 4;
gjc@3903
   797
 
gjc@3903
   798
      if (line.end.x > m_clipMax.x)
gjc@3903
   799
        lineCode |= 2;
gjc@3903
   800
      else if (line.end.x < m_clipMin.x)
gjc@3903
   801
        lineCode |= 1;
gjc@3903
   802
 
gjc@3903
   803
      if (line.start.y < m_clipMin.y)
gjc@3903
   804
        lineCode |= 128;
gjc@3903
   805
      else if (line.start.y > m_clipMax.y)
gjc@3903
   806
        lineCode |= 64;
gjc@3903
   807
 
gjc@3903
   808
      if (line.start.x > m_clipMax.x)
gjc@3903
   809
        lineCode |= 32;
gjc@3903
   810
      else if (line.start.x < m_clipMin.x)
gjc@3903
   811
        lineCode |= 16;
gjc@3903
   812
 
gjc@3903
   813
      // 9 - 8 - A
gjc@3903
   814
      // |   |   |
gjc@3903
   815
      // 1 - 0 - 2
gjc@3903
   816
      // |   |   |
gjc@3903
   817
      // 5 - 4 - 6
gjc@3903
   818
      switch (lineCode)
gjc@3903
   819
        {
gjc@3903
   820
          // center
gjc@3903
   821
        case 0x00:
gjc@3903
   822
          return true;
gjc@3903
   823
 
gjc@3903
   824
        case 0x01:
gjc@3903
   825
          ClipEndLeft (line);
gjc@3903
   826
          return true;
gjc@3903
   827
 
gjc@3903
   828
        case 0x02:
gjc@3903
   829
          ClipEndRight (line);
gjc@3903
   830
          return true;
gjc@3903
   831
 
gjc@3903
   832
        case 0x04:
gjc@3903
   833
          ClipEndBottom (line);
gjc@3903
   834
          return true;
gjc@3903
   835
 
gjc@3903
   836
        case 0x05:
gjc@3903
   837
          ClipEndLeft (line);
gjc@3903
   838
          if (line.end.y > m_clipMax.y)
gjc@3903
   839
            ClipEndBottom (line);
gjc@3903
   840
          return true;
gjc@3903
   841
 
gjc@3903
   842
        case 0x06:
gjc@3903
   843
          ClipEndRight (line);
gjc@3903
   844
          if (line.end.y > m_clipMax.y)
gjc@3903
   845
            ClipEndBottom (line);
gjc@3903
   846
          return true;
gjc@3903
   847
 
gjc@3903
   848
        case 0x08:
gjc@3903
   849
          ClipEndTop (line);
gjc@3903
   850
          return true;
gjc@3903
   851
 
gjc@3903
   852
        case 0x09:
gjc@3903
   853
          ClipEndLeft (line);
gjc@3903
   854
          if (line.end.y < m_clipMin.y)
gjc@3903
   855
            ClipEndTop (line);
gjc@3903
   856
          return true;
gjc@3903
   857
 
gjc@3903
   858
        case 0x0A:
gjc@3903
   859
          ClipEndRight (line);
gjc@3903
   860
          if (line.end.y < m_clipMin.y)
gjc@3903
   861
            ClipEndTop (line);
gjc@3903
   862
          return true;
gjc@3903
   863
 
gjc@3903
   864
          // left
gjc@3903
   865
        case 0x10:
gjc@3903
   866
          ClipStartLeft (line);
gjc@3903
   867
          return true;
gjc@3903
   868
 
gjc@3903
   869
        case 0x12:
gjc@3903
   870
          ClipStartLeft (line);
gjc@3903
   871
          ClipEndRight (line);
gjc@3903
   872
          return true;
gjc@3903
   873
 
gjc@3903
   874
        case 0x14:
gjc@3903
   875
          ClipStartLeft (line);
gjc@3903
   876
          if (line.start.y > m_clipMax.y)
gjc@3903
   877
            return false;
gjc@3903
   878
          ClipEndBottom (line);
gjc@3903
   879
          return true;
gjc@3903
   880
 
gjc@3903
   881
        case 0x16:
gjc@3903
   882
          ClipStartLeft (line);
gjc@3903
   883
          if (line.start.y > m_clipMax.y)
gjc@3903
   884
            return false;
gjc@3903
   885
          ClipEndBottom (line);
gjc@3903
   886
          if (line.end.x > m_clipMax.x)
gjc@3903
   887
            ClipEndRight (line);
gjc@3903
   888
          return true;
gjc@3903
   889
 
gjc@3903
   890
        case 0x18:
gjc@3903
   891
          ClipStartLeft (line);
gjc@3903
   892
          if (line.start.y < m_clipMin.y)
gjc@3903
   893
            return false;
gjc@3903
   894
          ClipEndTop (line);
gjc@3903
   895
          return true;
gjc@3903
   896
 
gjc@3903
   897
        case 0x1A:
gjc@3903
   898
          ClipStartLeft (line);
gjc@3903
   899
          if (line.start.y < m_clipMin.y)
gjc@3903
   900
            return false;
gjc@3903
   901
          ClipEndTop (line);
gjc@3903
   902
          if (line.end.x > m_clipMax.x)
gjc@3903
   903
            ClipEndRight (line);
gjc@3903
   904
          return true;
gjc@3903
   905
 
gjc@3903
   906
          // right
gjc@3903
   907
        case 0x20:
gjc@3903
   908
          ClipStartRight (line);
gjc@3903
   909
          return true;
gjc@3903
   910
 
gjc@3903
   911
        case 0x21:
gjc@3903
   912
          ClipStartRight (line);
gjc@3903
   913
          ClipEndLeft (line);
gjc@3903
   914
          return true;
gjc@3903
   915
 
gjc@3903
   916
        case 0x24:
gjc@3903
   917
          ClipStartRight (line);
gjc@3903
   918
          if (line.start.y > m_clipMax.y)
gjc@3903
   919
            return false;
gjc@3903
   920
          ClipEndBottom (line);
gjc@3903
   921
          return true;
gjc@3903
   922
 
gjc@3903
   923
        case 0x25:
gjc@3903
   924
          ClipStartRight (line);
gjc@3903
   925
          if (line.start.y > m_clipMax.y)
gjc@3903
   926
            return false;
gjc@3903
   927
          ClipEndBottom (line);
gjc@3903
   928
          if (line.end.x < m_clipMin.x)
gjc@3903
   929
            ClipEndLeft (line);
gjc@3903
   930
          return true;
gjc@3903
   931
 
gjc@3903
   932
        case 0x28:
gjc@3903
   933
          ClipStartRight (line);
gjc@3903
   934
          if (line.start.y < m_clipMin.y)
gjc@3903
   935
            return false;
gjc@3903
   936
          ClipEndTop (line);
gjc@3903
   937
          return true;
gjc@3903
   938
 
gjc@3903
   939
        case 0x29:
gjc@3903
   940
          ClipStartRight (line);
gjc@3903
   941
          if (line.start.y < m_clipMin.y)
gjc@3903
   942
            return false;
gjc@3903
   943
          ClipEndTop (line);
gjc@3903
   944
          if (line.end.x < m_clipMin.x)
gjc@3903
   945
            ClipEndLeft (line);
gjc@3903
   946
          return true;
gjc@3903
   947
 
gjc@3903
   948
          // bottom
gjc@3903
   949
        case 0x40:
gjc@3903
   950
          ClipStartBottom (line);
gjc@3903
   951
          return true;
gjc@3903
   952
 
gjc@3903
   953
        case 0x41:
gjc@3903
   954
          ClipStartBottom (line);
gjc@3903
   955
          if (line.start.x < m_clipMin.x)
gjc@3903
   956
            return false;
gjc@3903
   957
          ClipEndLeft (line);
gjc@3903
   958
          if (line.end.y > m_clipMax.y)
gjc@3903
   959
            ClipEndBottom (line);
gjc@3903
   960
          return true;
gjc@3903
   961
 
gjc@3903
   962
        case 0x42:
gjc@3903
   963
          ClipStartBottom (line);
gjc@3903
   964
          if (line.start.x > m_clipMax.x)
gjc@3903
   965
            return false;
gjc@3903
   966
          ClipEndRight (line);
gjc@3903
   967
          return true;
gjc@3903
   968
 
gjc@3903
   969
        case 0x48:
gjc@3903
   970
          ClipStartBottom (line);
gjc@3903
   971
          ClipEndTop (line);
gjc@3903
   972
          return true;
gjc@3903
   973
 
gjc@3903
   974
        case 0x49:
gjc@3903
   975
          ClipStartBottom (line);
gjc@3903
   976
          if (line.start.x < m_clipMin.x)
gjc@3903
   977
            return false;
gjc@3903
   978
          ClipEndLeft (line);
gjc@3903
   979
          if (line.end.y < m_clipMin.y)
gjc@3903
   980
            ClipEndTop (line);
gjc@3903
   981
          return true;
gjc@3903
   982
 
gjc@3903
   983
        case 0x4A:
gjc@3903
   984
          ClipStartBottom (line);
gjc@3903
   985
          if (line.start.x > m_clipMax.x)
gjc@3903
   986
            return false;
gjc@3903
   987
          ClipEndRight (line);
gjc@3903
   988
          if (line.end.y < m_clipMin.y)
gjc@3903
   989
            ClipEndTop (line);
gjc@3903
   990
          return true;
gjc@3903
   991
 
gjc@3903
   992
          // bottom-left
gjc@3903
   993
        case 0x50:
gjc@3903
   994
          ClipStartLeft (line);
gjc@3903
   995
          if (line.start.y > m_clipMax.y)
gjc@3903
   996
            ClipStartBottom (line);
gjc@3903
   997
          return true;
gjc@3903
   998
 
gjc@3903
   999
        case 0x52:
gjc@3903
  1000
          ClipEndRight (line);
gjc@3903
  1001
          if (line.end.y > m_clipMax.y)
gjc@3903
  1002
            return false;
gjc@3903
  1003
          ClipStartBottom (line);
gjc@3903
  1004
          if (line.start.x < m_clipMin.x)
gjc@3903
  1005
            ClipStartLeft (line);
gjc@3903
  1006
          return true;
gjc@3903
  1007
 
gjc@3903
  1008
        case 0x58:
gjc@3903
  1009
          ClipEndTop (line);
gjc@3903
  1010
          if (line.end.x < m_clipMin.x)
gjc@3903
  1011
            return false;
gjc@3903
  1012
          ClipStartBottom (line);
gjc@3903
  1013
          if (line.start.x < m_clipMin.x)
gjc@3903
  1014
            ClipStartLeft (line);
gjc@3903
  1015
          return true;
gjc@3903
  1016
 
gjc@3903
  1017
        case 0x5A:
gjc@3903
  1018
          ClipStartLeft (line);
gjc@3903
  1019
          if (line.start.y < m_clipMin.y)
gjc@3903
  1020
            return false;
gjc@3903
  1021
          ClipEndRight (line);
gjc@3903
  1022
          if (line.end.y > m_clipMax.y)
gjc@3903
  1023
            return false;
gjc@3903
  1024
          if (line.start.y > m_clipMax.y)
gjc@3903
  1025
            ClipStartBottom (line);
gjc@3903
  1026
          if (line.end.y < m_clipMin.y)
gjc@3903
  1027
            ClipEndTop (line);
gjc@3903
  1028
          return true;
gjc@3903
  1029
 
gjc@3903
  1030
          // bottom-right
gjc@3903
  1031
        case 0x60:
gjc@3903
  1032
          ClipStartRight (line);
gjc@3903
  1033
          if (line.start.y > m_clipMax.y)
gjc@3903
  1034
            ClipStartBottom (line);
gjc@3903
  1035
          return true;
gjc@3903
  1036
 
gjc@3903
  1037
        case 0x61:
gjc@3903
  1038
          ClipEndLeft (line);
gjc@3903
  1039
          if (line.end.y > m_clipMax.y)
gjc@3903
  1040
            return false;
gjc@3903
  1041
          ClipStartBottom (line);
gjc@3903
  1042
          if (line.start.x > m_clipMax.x)
gjc@3903
  1043
            ClipStartRight (line);
gjc@3903
  1044
          return true;
gjc@3903
  1045
 
gjc@3903
  1046
        case 0x68:
gjc@3903
  1047
          ClipEndTop (line);
gjc@3903
  1048
          if (line.end.x > m_clipMax.x)
gjc@3903
  1049
            return false;
gjc@3903
  1050
          ClipStartRight (line);
gjc@3903
  1051
          if (line.start.y > m_clipMax.y)
gjc@3903
  1052
            ClipStartBottom (line);
gjc@3903
  1053
          return true;
gjc@3903
  1054
 
gjc@3903
  1055
        case 0x69:
gjc@3903
  1056
          ClipEndLeft (line);
gjc@3903
  1057
          if (line.end.y > m_clipMax.y)
gjc@3903
  1058
            return false;
gjc@3903
  1059
          ClipStartRight (line);
gjc@3903
  1060
          if (line.start.y < m_clipMin.y)
gjc@3903
  1061
            return false;
gjc@3903
  1062
          if (line.end.y < m_clipMin.y)
gjc@3903
  1063
            ClipEndTop (line);
gjc@3903
  1064
          if (line.start.y > m_clipMax.y)
gjc@3903
  1065
            ClipStartBottom (line);
gjc@3903
  1066
          return true;
gjc@3903
  1067
 
gjc@3903
  1068
          // top
gjc@3903
  1069
        case 0x80:
gjc@3903
  1070
          ClipStartTop (line);
gjc@3903
  1071
          return true;
gjc@3903
  1072
 
gjc@3903
  1073
        case 0x81:
gjc@3903
  1074
          ClipStartTop (line);
gjc@3903
  1075
          if (line.start.x < m_clipMin.x)
gjc@3903
  1076
            return false;
gjc@3903
  1077
          ClipEndLeft (line);
gjc@3903
  1078
          return true;
gjc@3903
  1079
 
gjc@3903
  1080
        case 0x82:
gjc@3903
  1081
          ClipStartTop (line);
gjc@3903
  1082
          if (line.start.x > m_clipMax.x)
gjc@3903
  1083
            return false;
gjc@3903
  1084
          ClipEndRight (line);
gjc@3903
  1085
          return true;
gjc@3903
  1086
 
gjc@3903
  1087
        case 0x84:
gjc@3903
  1088
          ClipStartTop (line);
gjc@3903
  1089
          ClipEndBottom (line);
gjc@3903
  1090
          return true;
gjc@3903
  1091
 
gjc@3903
  1092
        case 0x85:
gjc@3903
  1093
          ClipStartTop (line);
gjc@3903
  1094
          if (line.start.x < m_clipMin.x)
gjc@3903
  1095
            return false;
gjc@3903
  1096
          ClipEndLeft (line);
gjc@3903
  1097
          if (line.end.y > m_clipMax.y)
gjc@3903
  1098
            ClipEndBottom (line);
gjc@3903
  1099
          return true;
gjc@3903
  1100
 
gjc@3903
  1101
        case 0x86:
gjc@3903
  1102
          ClipStartTop (line);
gjc@3903
  1103
          if (line.start.x > m_clipMax.x)
gjc@3903
  1104
            return false;
gjc@3903
  1105
          ClipEndRight (line);
gjc@3903
  1106
          if (line.end.y > m_clipMax.y)
gjc@3903
  1107
            ClipEndBottom (line);
gjc@3903
  1108
          return true;
gjc@3903
  1109
 
gjc@3903
  1110
          // top-left
gjc@3903
  1111
        case 0x90:
gjc@3903
  1112
          ClipStartLeft (line);
gjc@3903
  1113
          if (line.start.y < m_clipMin.y)
gjc@3903
  1114
            ClipStartTop (line);
gjc@3903
  1115
          return true;
gjc@3903
  1116
 
gjc@3903
  1117
        case 0x92:
gjc@3903
  1118
          ClipEndRight (line);
gjc@3903
  1119
          if (line.end.y < m_clipMin.y)
gjc@3903
  1120
            return false;
gjc@3903
  1121
          ClipStartTop (line);
gjc@3903
  1122
          if (line.start.x < m_clipMin.x)
gjc@3903
  1123
            ClipStartLeft (line);
gjc@3903
  1124
          return true;
gjc@3903
  1125
 
gjc@3903
  1126
        case 0x94:
gjc@3903
  1127
          ClipEndBottom (line);
gjc@3903
  1128
          if (line.end.x < m_clipMin.x)
gjc@3903
  1129
            return false;
gjc@3903
  1130
          ClipStartLeft (line);
gjc@3903
  1131
          if (line.start.y < m_clipMin.y)
gjc@3903
  1132
            ClipStartTop (line);
gjc@3903
  1133
          return true;
gjc@3903
  1134
 
gjc@3903
  1135
        case 0x96:
gjc@3903
  1136
          ClipStartLeft (line);
gjc@3903
  1137
          if (line.start.y > m_clipMax.y)
gjc@3903
  1138
            return false;
gjc@3903
  1139
          ClipEndRight (line);
gjc@3903
  1140
          if (line.end.y < m_clipMin.y)
gjc@3903
  1141
            return false;
gjc@3903
  1142
          if (line.start.y < m_clipMin.y)
gjc@3903
  1143
            ClipStartTop (line);
gjc@3903
  1144
          if (line.end.y > m_clipMax.y)
gjc@3903
  1145
            ClipEndBottom (line);
gjc@3903
  1146
          return true;
gjc@3903
  1147
 
gjc@3903
  1148
          // top-right
gjc@3903
  1149
        case 0xA0:
gjc@3903
  1150
          ClipStartRight (line);
gjc@3903
  1151
          if (line.start.y < m_clipMin.y)
gjc@3903
  1152
            ClipStartTop (line);
gjc@3903
  1153
          return true;
gjc@3903
  1154
 
gjc@3903
  1155
        case 0xA1:
gjc@3903
  1156
          ClipEndLeft (line);
gjc@3903
  1157
          if (line.end.y < m_clipMin.y)
gjc@3903
  1158
            return false;
gjc@3903
  1159
          ClipStartTop (line);
gjc@3903
  1160
          if (line.start.x > m_clipMax.x)
gjc@3903
  1161
            ClipStartRight (line);
gjc@3903
  1162
          return true;
gjc@3903
  1163
 
gjc@3903
  1164
        case 0xA4:
gjc@3903
  1165
          ClipEndBottom (line);
gjc@3903
  1166
          if (line.end.x > m_clipMax.x)
gjc@3903
  1167
            return false;
gjc@3903
  1168
          ClipStartRight (line);
gjc@3903
  1169
          if (line.start.y < m_clipMin.y)
gjc@3903
  1170
            ClipStartTop (line);
gjc@3903
  1171
          return true;
gjc@3903
  1172
 
gjc@3903
  1173
        case 0xA5:
gjc@3903
  1174
          ClipEndLeft (line);
gjc@3903
  1175
          if (line.end.y < m_clipMin.y)
gjc@3903
  1176
            return false;
gjc@3903
  1177
          ClipStartRight (line);
gjc@3903
  1178
          if (line.start.y > m_clipMax.y)
gjc@3903
  1179
            return false;
gjc@3903
  1180
          if (line.end.y > m_clipMax.y)
gjc@3903
  1181
            ClipEndBottom (line);
gjc@3903
  1182
          if (line.start.y < m_clipMin.y)
gjc@3903
  1183
            ClipStartTop (line);
gjc@3903
  1184
          return true;
gjc@3903
  1185
        }
gjc@3903
  1186
 
gjc@3903
  1187
      return false;
gjc@3903
  1188
    }
gjc@3903
  1189
  };
gjc@3903
  1190
}
gjc@3903
  1191
gjc@3902
  1192
void
gjc@3902
  1193
PyViz::LineClipping (double boundsX1, double boundsY1, double boundsX2, double boundsY2,
gjc@3902
  1194
                     double &lineX1, double &lineY1, double &lineX2, double &lineY2)
gjc@3902
  1195
{
gjc@3903
  1196
  FastClipping::Vector2 clipMin = {boundsX1, boundsY1}, clipMax = {boundsX2, boundsY2};
gjc@3903
  1197
  FastClipping::Line line = { { lineX1, lineY1 }, { lineX2, lineY2 }, (lineX2-lineX1), (lineY2-lineY1) };
gjc@3903
  1198
gjc@3903
  1199
  FastClipping clipper (clipMin, clipMax);
gjc@3903
  1200
  clipper.ClipLine (line);
gjc@3903
  1201
  lineX1 = line.start.x;
gjc@3903
  1202
  lineX2 = line.end.x;
gjc@3903
  1203
  lineY1 = line.start.y;
gjc@3903
  1204
  lineY2 = line.end.y;
gjc@3903
  1205
}
gjc@3903
  1206
gjc@3902
  1207
gjc@3760
  1208
}
gjc@3760
  1209