1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3 * Copyright (c) 2008 INESC Porto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Author: Gustavo Carneiro <gjc@inescporto.pt>
23 #include "ns3/simulator.h"
24 #include "ns3/config.h"
25 #include "ns3/node-list.h"
26 #include "ns3/wifi-net-device.h"
27 #include "ns3/ethernet-header.h"
29 #include "ns3/ppp-header.h"
33 NS_LOG_COMPONENT_DEFINE ("PyViz");
34 #define NUM_LAST_PACKETS 10
37 std::vector<std::string>
38 PathSplit (std::string str)
40 std::vector<std::string> results;
42 while ((cutAt = str.find_first_of('/')) != str.npos)
46 results.push_back(str.substr(0,cutAt));
48 str = str.substr(cutAt+1);
52 results.push_back(str);
60 static PyViz* g_visualizer = NULL;
64 NS_ASSERT (g_visualizer == NULL);
67 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Tx",
68 MakeCallback (&PyViz::TraceNetDevTxWifi, this));
70 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Rx",
71 MakeCallback (&PyViz::TraceNetDevRxWifi, this));
73 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/TxQueue/Dequeue",
74 MakeCallback (&PyViz::TraceNetDevTxCsma, this));
76 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/Rx",
77 MakeCallback (&PyViz::TraceNetDevRxCsma, this));
79 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/PromiscRx",
80 MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
82 Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop",
83 MakeCallback (&PyViz::TraceDrop, this));
85 Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Drop",
86 MakeCallback (&PyViz::TraceDrop, this));
88 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/TxQueue/Dequeue",
89 MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
91 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/Rx",
92 MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
96 PyViz::RegisterCsmaLikeDevice (std::string const &deviceTypeName)
98 TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
100 std::ostringstream sstream;
101 sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
102 Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxCsma, this));
105 sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
106 Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxCsma, this));
109 sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/PromiscRx";
110 Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
114 PyViz::RegisterWifiLikeDevice (std::string const &deviceTypeName)
116 TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
118 std::ostringstream sstream;
119 sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Tx";
120 Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxWifi, this));
123 sstream <<"/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
124 Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxWifi, this));
128 PyViz::RegisterPointToPointLikeDevice (std::string const &deviceTypeName)
130 TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
132 std::ostringstream sstream;
133 sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
134 Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
137 sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
138 Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
142 PyViz::SetPacketCaptureOptions (uint32_t nodeId, PacketCaptureOptions options)
144 NS_LOG_DEBUG (" SetPacketCaptureOptions " << nodeId
145 << " PacketCaptureOptions (headers size = " << options.headers.size ()
146 << " mode = " << options.mode << " numLastPackets = " << options.numLastPackets
148 m_packetCaptureOptions[nodeId] = options;
152 PyViz::RegisterDropTracePath (std::string const &tracePath)
154 Config::Connect (tracePath, MakeCallback (&PyViz::TraceDrop, this));
159 NS_ASSERT (g_visualizer == this);
163 void PyViz::DoPause (std::string const &message)
165 m_pauseMessages.push_back (message);
167 NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": Have "
168 << g_visualizer->m_pauseMessages.size () << " pause messages");
171 void PyViz::Pause (std::string const &message)
173 NS_ASSERT (g_visualizer);
174 g_visualizer->DoPause (message);
177 std::vector<std::string>
178 PyViz::GetPauseMessages () const
180 NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": GetPauseMessages: have "
181 << g_visualizer->m_pauseMessages.size () << " pause messages");
182 return m_pauseMessages;
187 PyViz::CallbackStopSimulation ()
189 NS_LOG_FUNCTION_NOARGS ();
194 PyViz::SimulatorRunUntil (Time time)
196 NS_LOG_LOGIC ("SimulatorRunUntil " << time << " (now is " << Simulator::Now () << ")");
198 m_pauseMessages.clear ();
199 m_transmissionSamples.clear ();
200 m_packetDrops.clear ();
202 Time expirationTime = Simulator::Now () - Seconds (10);
204 // Clear very old transmission records
205 for (std::map<TxRecordKey, TxRecordValue>::iterator iter = m_txRecords.begin ();
206 iter != m_txRecords.end ();)
208 if (iter->second.time < expirationTime)
210 m_txRecords.erase (iter++);
218 // Clear very old packets of interest
219 for (std::map<uint32_t, Time>::iterator iter = m_packetsOfInterest.begin ();
220 iter != m_packetsOfInterest.end ();)
222 if (iter->second < expirationTime)
224 m_packetsOfInterest.erase (iter++);
232 if (Simulator::IsFinished () || Simulator::Now () >= time)
236 // Schedule a dummy callback function for the target time, to make
237 // sure we stop at the right time. Otherwise, simulations with few
238 // events just appear to "jump" big chunks of time.
239 NS_LOG_LOGIC ("Schedule dummy callback to be called in " << (time - Simulator::Now ()));
241 Simulator::Cancel (m_stopCallbackEvent);
242 m_stopCallbackEvent = Simulator::Schedule (time - Simulator::Now (), &PyViz::CallbackStopSimulation, this);
244 while (!Simulator::IsFinished ())
250 Simulator::RunOneEvent ();
254 bool PyViz::TransmissionSampleKey::operator < (PyViz::TransmissionSampleKey const &other) const
256 if (this->transmitter < other.transmitter)
260 if (this->transmitter != other.transmitter)
264 if (this->receiver < other.receiver)
267 if (this->receiver != other.receiver)
271 if (this->channel < other.channel)
281 bool PyViz::TransmissionSampleKey::operator == (PyViz::TransmissionSampleKey const &other) const
283 bool retval = (transmitter == other.transmitter) &&
284 (receiver == other.receiver) &&
285 (channel == other.channel);
290 PyViz::NetDeviceStatistics &
291 PyViz::FindNetDeviceStatistics (int node, int interface)
293 std::map<uint32_t, std::vector<NetDeviceStatistics> >::iterator nodeStatsIter = m_nodesStatistics.find (node);
294 std::vector<NetDeviceStatistics> *stats;
295 if (nodeStatsIter == m_nodesStatistics.end ())
297 stats = &m_nodesStatistics[node];
298 stats->resize (NodeList::GetNode (node)->GetNDevices ());
302 stats = &(nodeStatsIter->second);
304 NetDeviceStatistics &devStats = (*stats)[interface];
308 bool PyViz::GetPacketCaptureOptions (uint32_t nodeId, const PacketCaptureOptions **outOptions) const
310 std::map<uint32_t, PacketCaptureOptions>::const_iterator iter = m_packetCaptureOptions.find (nodeId);
311 if (iter == m_packetCaptureOptions.end ())
317 *outOptions = &iter->second;
322 bool PyViz::FilterPacket (Ptr<const Packet> packet, const PacketCaptureOptions &options)
324 switch (options.mode)
326 case PACKET_CAPTURE_DISABLED:
329 case PACKET_CAPTURE_FILTER_HEADERS_OR:
331 PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
332 while (metadataIterator.HasNext ())
334 PacketMetadata::Item item = metadataIterator.Next ();
335 if (options.headers.find (item.tid) != options.headers.end ())
343 case PACKET_CAPTURE_FILTER_HEADERS_AND:
345 std::set<TypeId> missingHeaders (options.headers);
346 PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
347 while (metadataIterator.HasNext ())
349 PacketMetadata::Item item = metadataIterator.Next ();
350 std::set<TypeId>::iterator missingIter = missingHeaders.find (item.tid);
351 if (missingIter != missingHeaders.end ())
353 missingHeaders.erase (missingIter);
356 if (missingHeaders.size () == 0)
367 NS_FATAL_ERROR ("should not be reached");
372 void PyViz::TraceDrop (std::string context, Ptr<const Packet> packet)
374 NS_LOG_FUNCTION (context << packet->GetUid ());
375 std::vector<std::string> splitPath = PathSplit (context);
376 int nodeIndex = atoi (splitPath[1].c_str ());
377 Ptr<Node> node = NodeList::GetNode (nodeIndex);
379 if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
381 // if the transmitting node is not "of interest", we still
382 // record the transmission if it is a packet of interest.
383 if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
385 NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
390 // ---- "last packets"
391 const PacketCaptureOptions *captureOptions;
392 if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
394 LastPacketsSample &last = m_lastPackets[nodeIndex];
395 PacketSample lastPacket;
396 lastPacket.time = Simulator::Now ();
397 lastPacket.packet = packet->Copy ();
398 lastPacket.device = NULL;
399 last.lastDroppedPackets.push_back (lastPacket);
400 while (last.lastDroppedPackets.size () > captureOptions->numLastPackets)
402 last.lastDroppedPackets.erase (last.lastDroppedPackets.begin ());
406 std::map<Ptr<Node>, uint32_t>::iterator iter = m_packetDrops.find (node);
407 if (iter == m_packetDrops.end ())
409 m_packetDrops[node] = packet->GetSize ();
413 iter->second += packet->GetSize ();
418 PyViz::TraceNetDevTxWifi (std::string context, Ptr<const Packet> packet, Mac48Address destinationAddress)
420 NS_LOG_FUNCTION (context << packet->GetUid () << *packet);
422 std::vector<std::string> splitPath = PathSplit (context);
423 int nodeIndex = atoi (splitPath[1].c_str ());
424 int devIndex = atoi (splitPath[3].c_str ());
425 Ptr<Node> node = NodeList::GetNode (nodeIndex);
426 Ptr<NetDevice> device = node->GetDevice (devIndex);
429 NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
430 ++stats.transmittedPackets;
431 stats.transmittedBytes += packet->GetSize ();
433 // ---- "last packets"
434 const PacketCaptureOptions *captureOptions;
435 if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
437 LastPacketsSample &last = m_lastPackets[nodeIndex];
438 TxPacketSample lastPacket;
439 lastPacket.time = Simulator::Now ();
440 lastPacket.packet = packet->Copy ();
441 lastPacket.device = device;
442 lastPacket.to = destinationAddress;
443 last.lastTransmittedPackets.push_back (lastPacket);
444 while (last.lastTransmittedPackets.size () > captureOptions->numLastPackets)
446 last.lastTransmittedPackets.erase (last.lastTransmittedPackets.begin ());
450 // ---- transmissions records
452 if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
454 // if the transmitting node is not "of interest", we still
455 // record the transmission if it is a packet of interest.
456 if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
458 NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
464 // We will follow this packet throughout the network.
465 m_packetsOfInterest[packet->GetUid ()] = Simulator::Now ();
468 TxRecordValue record = { Simulator::Now (), node, false };
469 if (destinationAddress == device->GetBroadcast ())
471 record.isBroadcast = true;
473 m_txRecords[TxRecordKey (device->GetChannel (), packet->GetUid ())] = record;
477 PyViz::TraceNetDevRxCsma (std::string context, Ptr<const Packet> packet)
479 Ptr<Packet> p = packet->Copy ();
480 EthernetHeader ethernetHeader;
481 p->RemoveHeader (ethernetHeader);
482 TraceNetDevRxWifi (context, p, ethernetHeader.GetSource ());
486 PyViz::TraceNetDevRxPointToPoint (std::string context, Ptr<const Packet> packet)
488 Ptr<Packet> p = packet->Copy ();
491 TraceNetDevRxWifi (context, p, Mac48Address ());
495 PyViz::TraceNetDevPromiscRxCsma (std::string context, Ptr<const Packet> packet, NetDevice::PacketType packetType)
497 Ptr<Packet> p = packet->Copy ();
498 EthernetHeader ethernetHeader;
499 p->RemoveHeader (ethernetHeader);
500 // Other packet types are already being received by
501 // TraceNetDevRxCsma; we don't want to receive them twice.
502 if (packetType == NetDevice::PACKET_OTHERHOST)
504 TraceNetDevRxWifi (context, p, ethernetHeader.GetDestination ());
509 PyViz::TraceNetDevTxCsma (std::string context, Ptr<const Packet> packet)
511 EthernetHeader ethernetHeader;
512 Ptr<Packet> p = packet->Copy ();
513 p->RemoveHeader (ethernetHeader);
514 TraceNetDevTxWifi (context, p, ethernetHeader.GetDestination ());
518 PyViz::TraceNetDevTxPointToPoint (std::string context, Ptr<const Packet> packet)
520 Ptr<Packet> p = packet->Copy ();
523 TraceNetDevTxWifi (context, p, Mac48Address ());
527 PyViz::TraceNetDevRxWifi (std::string context, Ptr<const Packet> packet, Mac48Address from)
529 NS_LOG_FUNCTION (context << packet->GetUid ());
530 std::vector<std::string> splitPath = PathSplit (context);
531 int nodeIndex = atoi (splitPath[1].c_str ());
532 int devIndex = atoi (splitPath[3].c_str ());
535 NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
536 ++stats.receivedPackets;
537 stats.receivedBytes += packet->GetSize ();
539 Ptr<Node> node = NodeList::GetNode (nodeIndex);
540 Ptr<NetDevice> device = node->GetDevice (devIndex);
542 // ---- "last packets"
543 const PacketCaptureOptions *captureOptions;
544 if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
546 LastPacketsSample &last = m_lastPackets[nodeIndex];
547 RxPacketSample lastPacket;
548 lastPacket.time = Simulator::Now ();
549 lastPacket.packet = packet->Copy ();
550 lastPacket.device = device;
551 lastPacket.from = from;
552 last.lastReceivedPackets.push_back (lastPacket);
553 while (last.lastReceivedPackets.size () > captureOptions->numLastPackets)
555 last.lastReceivedPackets.erase (last.lastReceivedPackets.begin ());
559 // ---- transmissions
560 if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
562 NS_LOG_DEBUG ("RX Packet " << packet->GetUid () << " is not of interest");
566 Ptr<Channel> channel = device->GetChannel ();
568 std::map<TxRecordKey, TxRecordValue>::iterator recordIter =
569 m_txRecords.find (TxRecordKey (channel, packet->GetUid ()));
571 if (recordIter == m_txRecords.end ())
573 NS_LOG_DEBUG ("RX Packet " << packet->GetUid () << " was not transmitted?!");
577 TxRecordValue &record = recordIter->second;
579 if (record.srcNode == node)
581 NS_LOG_WARN ("Node " << node->GetId () << " receiving back the same packet (UID=" << packet->GetUid ()
582 << ") it had previously transmitted, on the same channel!");
586 TransmissionSampleKey key = { record.srcNode, node, channel };
588 #ifdef NS3_LOG_ENABLE
589 NS_LOG_DEBUG("m_transmissionSamples begin:");
590 if (g_log.IsEnabled (ns3::LOG_DEBUG))
592 for (std::map<TransmissionSampleKey,TransmissionSampleValue>::const_iterator iter
593 = m_transmissionSamples.begin (); iter != m_transmissionSamples.end (); iter++)
595 NS_LOG_DEBUG(iter->first.transmitter<<"/"<<iter->first.transmitter->GetId () << ", "
596 << iter->first.receiver<<"/"<<iter->first.receiver->GetId ()
597 << ", " << iter->first.channel << " => " << iter->second.bytes << " (@ " << &iter->second << ")");
600 NS_LOG_DEBUG("m_transmissionSamples end.");
603 std::map<TransmissionSampleKey,TransmissionSampleValue>::iterator
604 iter = m_transmissionSamples.find (key);
606 if (iter == m_transmissionSamples.end ())
608 TransmissionSampleValue sample = { packet->GetSize () };
609 NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
610 << key.receiver<<"/"<<key.receiver->GetId()
611 << " channel " << channel << ": " << packet->GetSize ()
612 << " bytes more. => new sample with " << packet->GetSize () << " bytes.");
613 m_transmissionSamples[key] = sample;
617 TransmissionSampleValue &sample = iter->second;
618 NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
619 << key.receiver<<"/"<<key.receiver->GetId()
620 << " channel " << channel << ": " << packet->GetSize ()
621 << " bytes more. => sample " << &sample << " with bytes " << sample.bytes);
623 sample.bytes += packet->GetSize ();
627 PyViz::TransmissionSampleList
628 PyViz::GetTransmissionSamples () const
630 NS_LOG_DEBUG ("GetTransmissionSamples BEGIN");
631 TransmissionSampleList list;
632 for (std::map<TransmissionSampleKey, TransmissionSampleValue>::const_iterator
633 iter = m_transmissionSamples.begin ();
634 iter != m_transmissionSamples.end ();
637 TransmissionSample sample;
638 sample.transmitter = iter->first.transmitter;
639 sample.receiver = iter->first.receiver;
640 sample.channel = iter->first.channel;
641 sample.bytes = iter->second.bytes;
642 NS_LOG_DEBUG ("from " << sample.transmitter->GetId() << " to " << sample.receiver->GetId()
643 << ": " << sample.bytes << " bytes.");
644 list.push_back (sample);
646 NS_LOG_DEBUG ("GetTransmissionSamples END");
650 PyViz::PacketDropSampleList
651 PyViz::GetPacketDropSamples () const
653 NS_LOG_DEBUG ("GetPacketDropSamples BEGIN");
654 PacketDropSampleList list;
655 for (std::map<Ptr<Node>, uint32_t>::const_iterator
656 iter = m_packetDrops.begin ();
657 iter != m_packetDrops.end ();
660 PacketDropSample sample;
661 sample.transmitter = iter->first;
662 sample.bytes = iter->second;
663 NS_LOG_DEBUG ("in " << sample.transmitter->GetId()
664 << ": " << sample.bytes << " bytes dropped.");
665 list.push_back (sample);
667 NS_LOG_DEBUG ("GetPacketDropSamples END");
672 PyViz::SetNodesOfInterest (std::set<uint32_t> nodes)
674 m_nodesOfInterest = nodes;
677 std::vector<PyViz::NodeStatistics>
678 PyViz::GetNodesStatistics () const
680 std::vector<PyViz::NodeStatistics> retval;
681 for (std::map<uint32_t, std::vector<NetDeviceStatistics> >::const_iterator iter = m_nodesStatistics.begin ();
682 iter != m_nodesStatistics.end (); iter++)
684 NodeStatistics stats = { iter->first, iter->second };
685 retval.push_back (stats);
691 PyViz::LastPacketsSample
692 PyViz::GetLastPackets (uint32_t nodeId) const
694 NS_LOG_DEBUG ("GetLastPackets: " << nodeId);
696 std::map<uint32_t, LastPacketsSample>::const_iterator
697 iter = m_lastPackets.find(nodeId);
698 if (iter != m_lastPackets.end ())
704 return LastPacketsSample ();
715 // Adapted from http://en.wikipedia.org/w/index.php?title=Line_clipping&oldid=248609574
725 Vector2 m_clipMin, m_clipMax;
735 void ClipStartTop (Line &line)
737 line.start.x += line.dx * (m_clipMin.y - line.start.y) / line.dy;
738 line.start.y = m_clipMin.y;
741 void ClipStartBottom (Line &line)
743 line.start.x += line.dx * (m_clipMax.y - line.start.y) / line.dy;
744 line.start.y = m_clipMax.y;
747 void ClipStartRight (Line &line)
749 line.start.y += line.dy * (m_clipMax.x - line.start.x) / line.dx;
750 line.start.x = m_clipMax.x;
753 void ClipStartLeft (Line &line)
755 line.start.y += line.dy * (m_clipMin.x - line.start.x) / line.dx;
756 line.start.x = m_clipMin.x;
759 void ClipEndTop (Line &line)
761 line.end.x += line.dx * (m_clipMin.y - line.end.y) / line.dy;
762 line.end.y = m_clipMin.y;
765 void ClipEndBottom (Line &line) {
766 line.end.x += line.dx * (m_clipMax.y - line.end.y) / line.dy;
767 line.end.y = m_clipMax.y;
770 void ClipEndRight (Line &line)
772 line.end.y += line.dy * (m_clipMax.x - line.end.x) / line.dx;
773 line.end.x = m_clipMax.x;
776 void ClipEndLeft (Line &line)
778 line.end.y += line.dy * (m_clipMin.x - line.end.x) / line.dx;
779 line.end.x = m_clipMin.x;
783 FastClipping (Vector2 clipMin, Vector2 clipMax)
784 : m_clipMin (clipMin), m_clipMax (clipMax)
789 bool ClipLine (Line &line)
791 uint8_t lineCode = 0;
793 if (line.end.y < m_clipMin.y)
795 else if (line.end.y > m_clipMax.y)
798 if (line.end.x > m_clipMax.x)
800 else if (line.end.x < m_clipMin.x)
803 if (line.start.y < m_clipMin.y)
805 else if (line.start.y > m_clipMax.y)
808 if (line.start.x > m_clipMax.x)
810 else if (line.start.x < m_clipMin.x)
833 ClipEndBottom (line);
838 if (line.end.y > m_clipMax.y)
839 ClipEndBottom (line);
844 if (line.end.y > m_clipMax.y)
845 ClipEndBottom (line);
854 if (line.end.y < m_clipMin.y)
860 if (line.end.y < m_clipMin.y)
866 ClipStartLeft (line);
870 ClipStartLeft (line);
875 ClipStartLeft (line);
876 if (line.start.y > m_clipMax.y)
878 ClipEndBottom (line);
882 ClipStartLeft (line);
883 if (line.start.y > m_clipMax.y)
885 ClipEndBottom (line);
886 if (line.end.x > m_clipMax.x)
891 ClipStartLeft (line);
892 if (line.start.y < m_clipMin.y)
898 ClipStartLeft (line);
899 if (line.start.y < m_clipMin.y)
902 if (line.end.x > m_clipMax.x)
908 ClipStartRight (line);
912 ClipStartRight (line);
917 ClipStartRight (line);
918 if (line.start.y > m_clipMax.y)
920 ClipEndBottom (line);
924 ClipStartRight (line);
925 if (line.start.y > m_clipMax.y)
927 ClipEndBottom (line);
928 if (line.end.x < m_clipMin.x)
933 ClipStartRight (line);
934 if (line.start.y < m_clipMin.y)
940 ClipStartRight (line);
941 if (line.start.y < m_clipMin.y)
944 if (line.end.x < m_clipMin.x)
950 ClipStartBottom (line);
954 ClipStartBottom (line);
955 if (line.start.x < m_clipMin.x)
958 if (line.end.y > m_clipMax.y)
959 ClipEndBottom (line);
963 ClipStartBottom (line);
964 if (line.start.x > m_clipMax.x)
970 ClipStartBottom (line);
975 ClipStartBottom (line);
976 if (line.start.x < m_clipMin.x)
979 if (line.end.y < m_clipMin.y)
984 ClipStartBottom (line);
985 if (line.start.x > m_clipMax.x)
988 if (line.end.y < m_clipMin.y)
994 ClipStartLeft (line);
995 if (line.start.y > m_clipMax.y)
996 ClipStartBottom (line);
1000 ClipEndRight (line);
1001 if (line.end.y > m_clipMax.y)
1003 ClipStartBottom (line);
1004 if (line.start.x < m_clipMin.x)
1005 ClipStartLeft (line);
1010 if (line.end.x < m_clipMin.x)
1012 ClipStartBottom (line);
1013 if (line.start.x < m_clipMin.x)
1014 ClipStartLeft (line);
1018 ClipStartLeft (line);
1019 if (line.start.y < m_clipMin.y)
1021 ClipEndRight (line);
1022 if (line.end.y > m_clipMax.y)
1024 if (line.start.y > m_clipMax.y)
1025 ClipStartBottom (line);
1026 if (line.end.y < m_clipMin.y)
1032 ClipStartRight (line);
1033 if (line.start.y > m_clipMax.y)
1034 ClipStartBottom (line);
1039 if (line.end.y > m_clipMax.y)
1041 ClipStartBottom (line);
1042 if (line.start.x > m_clipMax.x)
1043 ClipStartRight (line);
1048 if (line.end.x > m_clipMax.x)
1050 ClipStartRight (line);
1051 if (line.start.y > m_clipMax.y)
1052 ClipStartBottom (line);
1057 if (line.end.y > m_clipMax.y)
1059 ClipStartRight (line);
1060 if (line.start.y < m_clipMin.y)
1062 if (line.end.y < m_clipMin.y)
1064 if (line.start.y > m_clipMax.y)
1065 ClipStartBottom (line);
1070 ClipStartTop (line);
1074 ClipStartTop (line);
1075 if (line.start.x < m_clipMin.x)
1081 ClipStartTop (line);
1082 if (line.start.x > m_clipMax.x)
1084 ClipEndRight (line);
1088 ClipStartTop (line);
1089 ClipEndBottom (line);
1093 ClipStartTop (line);
1094 if (line.start.x < m_clipMin.x)
1097 if (line.end.y > m_clipMax.y)
1098 ClipEndBottom (line);
1102 ClipStartTop (line);
1103 if (line.start.x > m_clipMax.x)
1105 ClipEndRight (line);
1106 if (line.end.y > m_clipMax.y)
1107 ClipEndBottom (line);
1112 ClipStartLeft (line);
1113 if (line.start.y < m_clipMin.y)
1114 ClipStartTop (line);
1118 ClipEndRight (line);
1119 if (line.end.y < m_clipMin.y)
1121 ClipStartTop (line);
1122 if (line.start.x < m_clipMin.x)
1123 ClipStartLeft (line);
1127 ClipEndBottom (line);
1128 if (line.end.x < m_clipMin.x)
1130 ClipStartLeft (line);
1131 if (line.start.y < m_clipMin.y)
1132 ClipStartTop (line);
1136 ClipStartLeft (line);
1137 if (line.start.y > m_clipMax.y)
1139 ClipEndRight (line);
1140 if (line.end.y < m_clipMin.y)
1142 if (line.start.y < m_clipMin.y)
1143 ClipStartTop (line);
1144 if (line.end.y > m_clipMax.y)
1145 ClipEndBottom (line);
1150 ClipStartRight (line);
1151 if (line.start.y < m_clipMin.y)
1152 ClipStartTop (line);
1157 if (line.end.y < m_clipMin.y)
1159 ClipStartTop (line);
1160 if (line.start.x > m_clipMax.x)
1161 ClipStartRight (line);
1165 ClipEndBottom (line);
1166 if (line.end.x > m_clipMax.x)
1168 ClipStartRight (line);
1169 if (line.start.y < m_clipMin.y)
1170 ClipStartTop (line);
1175 if (line.end.y < m_clipMin.y)
1177 ClipStartRight (line);
1178 if (line.start.y > m_clipMax.y)
1180 if (line.end.y > m_clipMax.y)
1181 ClipEndBottom (line);
1182 if (line.start.y < m_clipMin.y)
1183 ClipStartTop (line);
1193 PyViz::LineClipping (double boundsX1, double boundsY1, double boundsX2, double boundsY2,
1194 double &lineX1, double &lineY1, double &lineX2, double &lineY2)
1196 FastClipping::Vector2 clipMin = {boundsX1, boundsY1}, clipMax = {boundsX2, boundsY2};
1197 FastClipping::Line line = { { lineX1, lineY1 }, { lineX2, lineY2 }, (lineX2-lineX1), (lineY2-lineY1) };
1199 FastClipping clipper (clipMin, clipMax);
1200 clipper.ClipLine (line);
1201 lineX1 = line.start.x;
1202 lineX2 = line.end.x;
1203 lineY1 = line.start.y;
1204 lineY2 = line.end.y;