diff --git a/HISTORY.txt b/HISTORY.txt new file mode 100644 index 000000000..0e90d4166 --- /dev/null +++ b/HISTORY.txt @@ -0,0 +1,205 @@ +HISTORY + +This document describes the main changes between each release version. + + +Version 1.6.0 (Oct 2015) + - Migrated code to github: https://github.com/akeranen/the-one + - New interface module: DistanceCapacityInterface for modeling + interfaces where transfer capacity depends on the distance between + nodes (see also example_settings/wifi-interface.txt) + - New report module: BufferOccupancyReport + - New movement modules: RandomDirection and ModifiedRandomDirection + - moved all example settings except default_settings.txt to example_settings + - Lots of small bug fixes + + +Version 1.5.0 (Dec 2011 - Nov 2013) + - New movement models + - GridLocation for static grid formations + - LinearMovement for nodes moving on a line + - Path-based external movement model and reader (ExternalPathMovement) + - New router modules + - WaveRouter for forwarding messages in waves + - LifeRouter for "Conway's game of life"-kind of routing + - ProphetV2Router with updated PRoPHET algorithm (by Samo Grasic) + - New Report modules: MessageCopyCountReport & MessageAvailabilityReport + (and analyzing/plotting scripts for them) + - Generic energy awareness feature for all routing modules + - Message Transfer Accept Policy for defining which messages and from who + the nodes should accept for transfers (with any routing module) + - Configuration settings improvements + - Ability to define ranges as setting values + - Ability to define arithmetic expressions as setting values + - Default-getters for various settings types + - Optimization option to simulate connections only once (see World class) + - Sub-namespace support + - Group-specific network interface related settings (e.g., activePeriods + and scanInterval) are now in "net" sub-namespace + - GUI fixes & updates + - Offset to playfield view and dynamic scaling of distance reference bar + - Option to disable (by default) the node name string + - Autorefresh-feature and keeping the expanded-state to routing info window + - Showing of radio coverages, connections and message count is configurable + - New GUI features + - Focus nodes by clicking on the playfield (see "Playfield options" menu) + - GUI node filters feature and one message based filter (see "Tools" menu) + - Bugfixes + - Scan intervals work also without MessageCommunicationBus; + thanks to Matthew Orlinski + - Connections are properly cleared when ActivenessHandler is used + - MaxProp doesn't send messages to hosts that have already received the + message even if they have then deleted it + - Fix to scanning intervals (works with only the 1st interface though) + - Fixed cellSizeMultiplier in ConnectivityGrid class + - Message blacklisting for messages that have been rejected by application + - Typo fix to initialEnergy setting (need to update config files using this) + - Refactoring (may break some third party code) + - Moved utility classes to util and routing.util packages + - Renamed getOldestMessage method to getNextMessageToRemove in ActiveRouter + + +Version 1.4.1 (31 Jan 2011) + - Bugfixes + - External connectivity traces now properly clear connections; thanks to CS + - InterferenceLimitedInterface speeds are updated; thanks to Jad Makhlouta + - CarMovement reads speed properly from settings + - Warmup time fix to connectivity reports + - Fixed initial location (was off by one stop) in MapRoute movement model + - dieselnetConverter.pl supports now also exponent format in the input data + - GUI fixes + - Fixed window resize issue and using spinner instead of dropdown for zoom + levels; thanks to PJ + - Set of javadoc, style, and other small fixes + + +Version 1.4.0 (18 Mar 2010) + - Added the possibility for each node having multiple interfaces + * Requires changes to the configuration files, see default_settings.txt + - New/improved routing algorithms + * added parametrization for MaxProp (default alpha=1) + * added Prophet and Maxprop routing algorithm versions that + take timescale as a parameter, and estimate the needed routing algorithm + parameters based on that + * see Karvo and Ott, Time Scales and Delay-Tolerant Routing Protocols, + CHANTS 2008, for more information. + * added new (unrealistic) EpidemicOracleRouter that transfers messages + immediately and deletes all replicas from buffers when the message is + delivered + * added maximum meeting probability set size support for MaxProp to improve + its performance in scenarios with many nodes + - Added MessageReport class for reporting message deliveries, + CreatedMessagesReport for message creations and EventLogReport for + reporting everything (in a StandardEventsReader-compatible format) + - Added application layer + * applications can be created by extending the Application class + * multiple applications can run in the nodes + * report modules can register for application events + * see PingApplication and PingAppReporter for an example + - Added ClusterMovement for creating clusters of nodes and LinearFormation + for lines of nodes + - ExternalMovementReader supports comment lines (starting with "#") + - "Delete all" message event and support for this in StandardEventsReader + - Possibility to choose first route stop for MapRouteMovement + - Added new message event generators: OneFromEachMessageGenerator and + OneToEachMessageGenerator + - Added time range setting to MessageEventGenerator + - GUI improvements + * highlighting of pause-events to EventLogPanel + * GUI starts paused by default + * hh:mm:ss display for simulation time (right-click the simulation time) + - Improved and new analysis scripts + * added "log", "total", and "index" options for the ccdfPlotter.pl + * added getStatsAverages.pl + - Bugfixes + * host range checking in MessageEventGenerator + * command line option -b doesn't require range anymore + + + +Version 1.3.0 (19 Jan 2009) +- New Features + - ModuleCommunicationBus for sharing information between different + (types of) modules + - EnergyAwareRouter demonstrating energy awareness possibilities and use of + the ModuleCommunicationBus + - EnergyLevelReport for reporting the energy levels + - ConnectivityONEReport class for generating connectivity traces + that can be read using the StandardEventsReader +- Enhancements + - Any number of input config files supported + - Batch mode supports run index ranges (can start from any index) + - small change in the command line syntax; see README for details + - MessageEventGenerator supports message creation time and destination + host ranges + - NetworkLayer has configurable scanning intervals + - ExternalEventsQueue can be configured like all the other event + generators (though the old way is still supported too) + - ccdfPlotter script has better help and can now also create CDFs +- New toolkit scripts + - messageLocationAnimator for creating GIF animations out of + MessageLocation reports + - dieselNetConverter for converting DieselNet traces into ONE + mobility traces + - getAverages for counting averages out of different time-stamped reports + - splotEnergy for creating 3D plots from EnergyLevel reports +- Fixed bugs in + - handling of incoming messages with expired TTL + - report directory creation; thanks to STARpio + - BusTravellerMovement incState; thanks to Mehedi Bakht + - MaxProp calcTreshold; thanks to Vasco Soares and STARpio + + +Version 1.2.0 (25 Aug 2008) +- New movement model (framework): Working Day Movement + - see WDM_conf_help.txt for configuration help + - sample configuration files can be found from the wdm_settings folder + - for information about the model, see our paper at + http://www.netlab.tkk.fi/tutkimus/distance/papers/ + 2008-mobmod-working-day-model.pdf +- A "stationary movement model" StationaryMovement. + - useful for running simulations with only connectivity trace input + - createCircles.pl script for easily creating suitable configuration + files for this movement model + + +Version 1.1.0 (6 May 2008) +- External Events Interface which allows event generator classes that + can generate external events (such as creating new messages or + setting up and tearing down connections). See EventQueueHandler + class for details. + - due to the EEI, some API changes (in e.g., + createNewMessage method) + - external events file feature is now part of the new interface + - MessageEventGenerator class for generating uniformly + distributed message creation patterns + - new event: ConnectionEvent (supported by StandardEventsReader) +- Configurable message queue modes (random and FIFO) +- Option to automatically delete messages that are already delivered + to the final recipient +- Small change in the ordering of checks whether transfer has + already succeeded when the connection has gone down +- Connection class has now getTransferDoneTime method +- Settings class can validate range settings (assertValidRange) +- Classes that need to reset static fields between batch runs can + register to the "resetting service" at DTNSim class + (registerForReset) +- Experimental "update scheduling" functionality that can be used to + dynamically insert "update points" between time steps for higher + precision simulations +- DTN2 connectivity (requires JDK 6 or higher) +- Generic property adding feature for Message class (addProperty, + getProperty and updateProperty) + - SprayAndWait router uses this now for the copy count +- New tests + + +Version 1.0.1 (24 February 2008) +- New warm up feature for the report modules that allows ignoring + events and messages that were created during a configurable warm + up time. +- New routing module: First Contact + + +Version 1.0.0 (27 November 2007) +- First official public release diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..b03cc8a8b --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,628 @@ +This program (the ONE) is released under the GPLv3 (see details below). +The included vector map data of the downtown Helsinki area is not GPL'ed +and it should be used only with the ONE simulator +(Copyright: Maanmittauslaitos, 2007). + +------------------------------------------------------------------------ + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/README.txt b/README.txt new file mode 100644 index 000000000..900dd4354 --- /dev/null +++ b/README.txt @@ -0,0 +1,723 @@ +The ONE v1.6.0 - Readme +======================= + +The ONE is a Opportunistic Network Environment simulator which provides a +powerful tool for generating mobility traces, running DTN messaging +simulations with different routing protocols, and visualizing both +simulations interactively in real-time and results after their completion. + + +Quick start +=========== + +Compiling +--------- + +You can compile ONE from the source code using the included compile.bat +script. That should work both in Windows and Unix/Linux environment with +Java 6 JDK or later. + +If you want to use Eclipse for compiling the ONE, since version 1.1.0 you need +to include some jar libraries in the project's build path. The libraries are +located in the lib folder. To include them in Eclipse, assuming that you have +an Eclipse Java project whose root folder is the folder where you extracted +the ONE, do the following: + +select from menus: Project -> Properties -> Java Build Path +Go to "Libraries" tab +Click "Add JARs..." +Select "DTNConsoleConnection.jar" under the "lib" folder +Add the "ECLA.jar" the same way +Press "OK". + +Now Eclipse should be able to compile the ONE without warnings. + + +Running +------- + +ONE can be started using the included one.bat (for Windows) or one.sh (for +Linux/Unix) script. Following examples assume you're using the Linux/Unix +script (just replace "./one.sh" with "one.bat" for Windows). + +Synopsis: +./one.sh [-b runcount] [conf-files] + +Options: + -b Run simulation in batch mode. Doesn't start GUI but prints +information about the progress to terminal. The option must be followed +by the number of runs to perform in the batch mode or by a range of runs +to perform, delimited with a colon (e.g, value 2:4 would perform runs 2, +3 and 4). See section "Run indexing" for more information. + +Parameters: + conf-files: The configuration file names where simulation parameters +are read from. Any number of configuration files can be defined and they are +read in the order given in the command line. Values in the later config files +override values in earlier config files. + + +Configuring +=========== + +All simulation parameters are given using configuration files. These files +are normal text files that contain key-value pairs. Syntax for most of the +variables is: +Namespace.key = value + +I.e., the key is (usually) prefixed by a namespace, followed by a dot, and +then key name. Key and value are separated by equals-sign. Namespaces +start with capital letter and both namespace and keys are written in +CamelCase (and are case sensitive). Namespace defines (loosely) the part +of the simulation environment where the setting has effect on. Many, but +not all, namespaces are equal to the class name where they are read. +Especially movement models, report modules and routing modules follow this +convention. In some cases the namespace is defined by the user: e.g., with +network interfaces user can pick up any idenfitier, define interface specific +settings in that namespace, and give the name of the namespace when +configuring which interface each group should use. + +Numeric values use '.' as the decimal separator and can be suffixed with +kilo (k) mega (M) or giga (G) suffix. Boolean settings accept "true", +"false", "0", and "1" as values. + +Many settings define paths to external data files. The paths can be relative +or absolute but the directory separator must be '/' in both Unix and Windows +environment. + +Some variables contain comma-separated values, and for them the syntax is: +Namespace.key = value1, value2, value3, etc. + +For run-indexed values the syntax is: +Namespace.key = [run1value; run2value; run3value; etc] +I.e., all values are given in brackets and values for different run are +separated by semicolon. Each value can also be a comma-separated value. +For more information about run indexing, go to section "Run indexing". + +Setting files can contain comments too. A comment line must start with "#" +character. Rest of the line is skipped when the settings are read. This can +be also useful for disabling settings easily. + +Some values (scenario and report names at the moment) support "value +filling". With this feature, you can construct e.g., scenario name +dynamically from the setting values. This is especially useful when using +run indexing. Just put setting key names in the value part prefixed and +suffixed by two percent (%) signs. These placeholders are replaces by the +current setting value from the configuration file. See the included +snw_comparison_settings.txt for an example. + +File "default_settings.txt", if exists, is always read and the other +configuration files given as parameter can define more settings or override +some (or even all) settings in the previous files. The idea is that +you can define in the earlier files all the settings that are common for +all the simulations and run different, specific, simulations using +different configuration files. + + +Run indexing +------------ + +Run indexing is a feature that allows you to run large amounts of +different configurations using only single configuration file. The idea is +that you provide an array of settings (using the syntax described above) +for the variables that should be changed between runs. For example, if you +want to run the simulation using five different random number generator +seeds for movement models, you can define in the settings file the +following: + +MovementModel.rngSeed = [1; 2; 3; 4; 5] + +Now, if you run the simulation using command: + +./one.sh -b 5 my_config.txt + +you would run first using seed 1 (run index 0), then another run using +seed 2, etc. Note that you have to run it using batch mode (-b option) if +you want to use different values. Without the batch mode flag the first +parameter (if numeric) is the run index to use when running in GUI mode. + +Run indexes wrap around: used value is the value at index (runIndex % +arrayLength). Because of wrapping, you can easily run large amount of +permutations easily. For example, if you define two key-value pairs: + +key1 = [1; 2] +key2 = [a; b; c] + +and run simulation using run-index count 6, you would get all permutations +of the two values (1,a; 2,b; 1,c; 2,a; 1,b; 2,c). This naturally works +with any amount of arrays. Just make sure that the smallest common +nominator of all array sizes is 1 (e.g., use arrays whose sizes are primes) +-- unless you don't want all permutations but some values should be +paired. + + +Movement models +--------------- + +Movement models govern the way nodes move in the simulation. They provide +coordinates, speeds and pause times for the nodes. The basic installation +contains, e.g., random waypoint, map based movement, shortest path map based +movement, map route movement, and external movement. All these models, except +external movement, have configurable speed and pause time distributions. A +minimum and maximum values can be given and the movement model draws +uniformly distributed random values that are within the given range. Same +applies for pause times. In external movement model the speeds and pause +times are interpreted from the given data. + +When a node uses the random waypoint movement model (RandomWaypoint), it is +given a random coordinate in the simulation area. Node moves directly to the +given destination at constant speed, pauses for a while, and then gets a new +destination. This continues throughout the simulations and nodes move along +these zig-zag paths. + +Map-based movement models constrain the node movement to predefined paths. +Different types of paths can be defined and one can define valid paths for +all node groups. This way e.g., cars can be prevented from driving indoors or +on pedestrian paths. + +The basic map-based movement model (MapBasedMovement) initially distributes +the nodes between any two adjacent (i.e., connected by a path) map nodes and +then nodes start moving from adjacent map node to another. When node reaches +the next map node, it randomly selects the next adjacent map node but chooses +the map node where it came from only if that is the only option (i.e., avoids +going back to where it came from). Once node has moved trough 10-100 map +nodes, it pauses for a while and then starts moving again. + +The more sophisticated version of the map-based movement model +(ShortestPathMapBasedMovement) uses Dijkstra's shortest path algorithm to +find its way trough the map area. Once a node reaches its destination, and +has waited for the pause time, a new random map node is chosen and node moves +there using the shortest path that can be taken using only valid map nodes. + +For the shortest path based movement models, map data can also contain Points +Of Interest (POIs). Instead of selecting any random map node for the next +destination, the movement model can be configured to give a POI belonging to +a certain POI group with a configurable probability. There can be unlimited +amount of POI groups and all groups can contain any amount of POIs. All node +groups can have different probabilities for all POI groups. POIs can be used +to model e.g., shops, restaurants and tourist attractions. + +Route based movement model (MapRouteMovement) can be used to model nodes that +follow certain routes, e.g. bus or tram lines. Only the stops on the route +have to be defined and then the nodes using that route move from stop to stop +using shortest paths and stop on the stops for the configured time. + +All movement models can also decide when the node is active (moves and can be +connected to) and when not. For all models, except for the external movement, +multiple simulation time intervals can be given and the nodes in that group +will be active only during those times. + +All map-based models get their input data using files formatted with a subset +of the Well Known Text (WKT) format. LINESTRING and MULTILINESTRING +directives of WKT files are supported by the parser for map path data. For +point data (e.g. for POIs), also the POINT directive is supported. Adjacent +nodes in a (MULTI)LINESTRING are considered to form a path and if some lines +contain some vertex(es) with exactly the same coordinates, the paths are +joined from those places (this is how you create intersections). WKT files +can be edited and generated from real world map data using any suitable +Geographic Information System (GIS) program. The map data included in the +simulator distribution was converted and edited using the free, Java based +OpenJUMP GIS program. + +Different map types are defined by storing the paths belonging to different +types to different files. Points Of Interest are simply defined with WKT +POINT directive and POI groups are defined by storing all POIs belonging to a +certain group in the same file. All POIs must also be part of the map data so +they are accessible using the paths. Stops for the routes are defined with +LINESTRING and the stops are traversed in the same order they appear in the +LINESTRING. One WKT file can contain multiple routes and they are given to +nodes in the same order as they appear in the file. + +The experimental movement model that uses external movement data +(ExternalMovement) reads timestamped node locations from a file and moves the +nodes in the simulation accordingly. See javadocs of ExternalMovementReader +class from input package for details of the format. A suitable, experimental +converter script (transimsParser.pl) for TRANSIMS data is included in the +toolkit folder. + +The movement model to use is defined per node group with the "movementModel" +setting. Value of the setting must be a valid movement model class name from +the movement package. Settings that are common for all movement models are +read in the MovementModel class and movement model specific settings are read +in the respective classes. See the javadoc documentation and example +configuration files for details. + +Routing modules and message creation +------------------------------------ + +Routing modules define how the messages are handled in the simulation. Six +basic active routing modules (First Contact, Epidemic, Spray and Wait, Direct +delivery, PRoPHET and MaxProp) and also a passive router for external routing +simulation are included in the package. The active routing modules are +implementations of the well known routing algorithms for DTN routing. There +are also variants of these models and couple of different models included in +the latest versions. See the classes in the routing package for details. + +Passive router is made especially for interacting with other (DTN) routing +simulators or running simulations that don't need any routing functionality. +The router doesn't do anything unless commanded by external events. These +external events are provided to the simulator by a class that implements the +EventQueue interface. + +There are two basic classes that can be used as a source of message events: +ExternalEventsQueue and MessageEventGenerator. The former can read events +from a file that can be created by hand, with a suitable script (e.g., +createCreates.pl script in the toolkit folder), or by converting e.g., +dtnsim2's output to suitable form. See StandardEventsReader class from input +package for details of the format. MessageEventGenerator is a simple message +generator class that creates uniformly distributed message creation patterns +with configurable message creation interval, message size and +source/destination host ranges. More specific messaging scenarios can be +created with MessageBurstGenerator, and One{From,To}EachMessageGenerator +classes. See javadocs for details. + +The toolkit folder contains an experimental parser script (dtnsim2parser.pl) +for dtnsim2's output (there used to be a more capable Java-based parser but +it was discarded in favor of this more easily extendable script). The script +requires a few patches to dtnsim2's code and those can be found from the +toolkit/dtnsim2patches folder. + +The routing module to use is defined per node group with the setting +"router". All routers can't interact properly (e.g., PRoPHET router can only +work with other PRoPHET routers) so usually it makes sense to use the same +(or compatible) router for all groups. + +Reports +------- + +Reports can be used to create summary data of simulation runs, detailed data +of connections and messages, files suitable for post-processing using e.g., +Graphviz (to create graphs) and also to interface with other programs. See +javadocs of report-package classes for details. + +There can be any number of reports for any simulation run and the number of +reports to load is defined with "Report.nrofReports" setting. Report class +names are defined with "Report.reportN" setting, where N is an integer value +starting from 1. The values of the settings must be valid report class names +from the report package. The output directory of all reports (which can be +overridden per report class with the "output" setting) must be defined with +Report.reportDir -setting. If no "output" setting is given for a report +class, the resulting report file name is "ReportClassName_ScenarioName.txt". + +All reports have many configurable settings which can be defined using +ReportClassName.settingKey -syntax. See javadocs of Report class and specific +report classes for details (look for "setting id" definitions). + +Host groups +----------- + +A host group is group of hosts (nodes) that shares movement and routing +module settings. Different groups can have different values for the settings +and this way they can represent different types of nodes. Base settings can +be defined in the "Group" namespace and different node groups can override +these settings or define new settings in their specific namespaces (Group1, +Group2, etc.). + +The settings +------------ + +There are plenty of settings to configure; more than is meaningful to +present here. See javadocs of especially report, routing and movement +model classes for details. See also included settings files for examples. +Perhaps the most important settings are the following. + + +Scenario settings: +--- + +Scenario.name +Name of the scenario. All report files are by default prefixed with this. + +Scenario.simulateConnections +Should connections be simulated. If you're only interested in movement +modeling, you can disable this to get faster simulation. Usually you want +this to be on. + +Scenario.updateInterval +How many seconds are stepped on every update. Increase this to get faster +simulation, but then you'll lose some precision. Values from 0.1 to 2 are good +for simulations. + +Scenario.endTime +How many simulated seconds to simulate. + +Scenario.nrofHostGroups +How many hosts group are present in the simulation. + + +Interface settings (used to define the possible interfaces the nodes can have) +--- + +type +What class (from the interfaces-directory) is used for this interface + +The remaining settings are class-specific. Can be for example: + +transmitRange +Range (meters) of the interface. + +transmitSpeed +Transmit speed of the interface (bytes per second). + + +Host group settings (used in Group or GroupN namespace): +--- + +groupID +Group's identifier (a string or a character). Used as the prefix of host +names that are shown in the GUI and reports. Host's full name is +groupID+networkAddress. + +nrofHosts +Number of hosts in this group. + +nrofInterfaces +Number of interfaces this the nodes of this group use + +interfaceX +The interface that should be used as the interface number X + +movementModel +The movement model all hosts in the group use. Must be a valid class (one +that is a subclass of MovementModel class) name from the movement package. + +waitTime +Minimum and maximum (two comma-separated decimal values) of the wait time +interval (seconds). Defines how long nodes should stay in the same place +after reaching the destination of the current path. A new random value within +the interval is used on every stop. Default value is 0,0. + +speed +Minimum and maximum (two comma-separated decimal values) of the speed +interval (m/s). Defines how fast nodes move. A new random value is used on +every new path. Default value is 1,1. + +bufferSize +Size of the nodes' message buffer (bytes). When the buffer is full, node can't +accept any more messages unless it drops some old messages from the buffer. + +router +Router module which is used to route messages. Must be a valid class +(subclass of MessageRouter class) name from routing package. + +activeTimes +Time intervals (comma-separated simulated time value tuples: start1, end1, +start2, end2, ...) when the nodes in the group should be active. If no +intervals are defined, nodes are active all the time. + +msgTtl +Time To Live (simulated minutes) of the messages created by this host group. +Nodes (with active routing module) check every one minute whether some of +their messages' TTLs have expired and drop such messages. If no TTL is +defined, infinite TTL is used. + + +Group and movement model specific settings (only meaningful for certain +movement models): + +pois +Points Of Interest indexes and probabilities (comma-separated +index-probability tuples: poiIndex1, poiProb1, poiIndex2, poiProb2, ... ). +Indexes are integers and probabilities are decimal values in the range of +0.0-1.0. Setting defines the POI groups where the nodes in this host group +can choose destinations from and the probabilities for choosing a certain POI +group. For example, a (random) POI from the group defined in the POI file1 +(defined with PointsOfInterest.poiFile1 setting) is chosen with the +probability poiProb1. If the sum of all probabilities is less than 1.0, a +probability of choosing any random map node for the next destination is (1.0 +- theSumOfProbabilities). Setting can be used only with +ShortestPathMapBasedMovement -based movement models. + +okMaps +Which map node types (refers to map file indexes) are OK for the group +(comma-separated list of integers). Nodes will not travel trough map nodes +that are not OK for them. As default, all map nodes are OK. Setting can be +used with any MapBasedMovent -based movement model. + +routeFile +If MapRouteMovement movement model is used, this setting defines the route +file (path) where the route is read from. Route file should contain +LINESTRING WKT directives. Each vertex in a LINESTRING represents one stop +on the route. + +routeType +If MapRouteMovement movement model is used, this setting defines the routes +type. Type can be either circular (value 1) or ping-pong (value 2). See +movement.map.MapRoute class for details. + + +Movement model settings: +--- + +MovementModel.rngSeed +The seed for all movement models' random number generator. If the seed and +all the movement model related settings are kept the same, all nodes should +move the same way in different simulations (same destinations and speed & +wait time values are used). + +MovementModel.worldSize +Size of the simulation world in meters (two comma separated values: +width, height). + +PointsOfInterest.poiFileN +For ShortestPathMapBasedMovement -based movement models, this setting defines +the WKT files where the POI coordinates are read from. POI coordinates are +defined using the POINT WKT directive. The "N" in the end of the setting must +be a positive integer (i.e., poiFile1, poiFile2, ...). + +MapBasedMovement.nrofMapFiles +How many map file settings to look for in the settings file. + +MapBasedMovement.mapFileN +Path to the Nth map file ("N" must be a positive integer). There must be at +least nrofMapFiles separate files defined in the configuration files(s). All +map files must be WKT files with LINESTRING and/or MULTILINESTRING WKT +directives. Map files can contain POINT directives too, but those are +skipped. This way the same file(s) can be used for both POI and map data. By +default the map coordinates are translated so that the upper left corner of +the map is at coordinate point (0,0). Y-coordinates are mirrored before +translation so that the map's north points up in the playfield view. Also all +POI and route files are translated to match to the map data transformation. + + +Report settings: +--- + +Report.nrofReports +How many report modules to load. Module names are defined with settings +"Report.report1", "Report.report2", etc. Following report settings can be +defined for all reports (using Report name space) or just for certain reports +(using ReportN name spaces). + +Report.reportDir +Where to store the report output files. Can be absolute path or relative to +the path where the simulation was started. If the directory doesn't exists, +it is created. + +Report.warmup +Length of the warm up period (simulated seconds from the start). During the +warm up the report modules should discard the new events. The behavior is +report module specific so check the (java)documentation of different report +modules for details. + + +Event generator settings: +--- + +Events.nrof +How many event generators are loaded for the simulation. Event generator +specific settings (see below) are defined in EventsN namespaces (so +Events1.settingName configures a setting for the 1st event generator etc.). + +EventsN.class +Name of the generator class to load (e.g., ExternalEventsQueue or +MessageEventGenerator). The class must be found from the input package. + +For the ExternalEventsQueue you must at least define the path to the external +events file (using setting "filePath"). See input.StandardEventsReader class' +javadocs for information about different external events. + + +Other settings: +--- + +Optimization.randomizeUpdateOrder +Should the order in which the nodes' update method is called be randomized. +Call to update causes the nodes to check their connections and also update +their routing module. If set to false, node update order is the same as their +network address order. With randomizing, the order is different on every time +step. + +Optimization.cellSizeMult +Adjust the trade-off between memory consumption and simulation speed. +Especially useful for large maps. See ConnectivityOptimizer class for details. + + +GUI +=== + +The GUI's main window is divided into three parts. The main part contains +the playfield view (where node movement is displayed) and simulation and +GUI control and information. The right part is used to select nodes and +the lower part is for logging and breakpoints. + +The main part's topmost section is for simulation and GUI controls. The +first field shows the current simulation time. Next field shows the +simulation speed (simulated seconds per second). The following four +buttons are used to pause, step, fast forward, and fast forward simulation +to given time. Pressing step-button multiple times runs simulation +step-by-step. Fast forward (FFW) can be used to skip uninteresting parts +of simulation. In FFW, the GUI update speed is set to a large value. Next +drop-down is used to control GUI update speed. Speed 1 means that GUI is +updated on every simulated second. Speed 10 means that GUI is updated only +on every 10th second etc. Negative values slow down the simulation. The +following drop-down controls the zoom factor. The last button saves the +current view as a png-image. + +Middle section, i.e., the playfield view, shows the node placement, map +paths, node identifiers, connections among nodes etc. All nodes are +displayed as small rectangles and their radio range is shown as a green +circle around the node. Node's group identifier and network address (a +number) are shown next to each node. If a node is carrying messages, each +message is represented by a green or blue filled rectangle. If node +carries more than 10 messages, another column of rectangles is drawn for +each 10 messages but every other rectangle is now red. You can center the +view to any place by clicking with mouse button on the play field. Zoom +factor can also be changed using mouse wheel on top of the playfield view. + +The right part of main window is for choosing a node for closer inspection. +Simply clicking a button shows the node info in main parts lower section. +From there more information can be displayed by selecting one of the +messages the node is carrying (if any) from the drop-down menu. Pressing +the "routing info" button opens a new window where information about the +routing module is displayed. When a node is chosen, the playfield view is +also centered on that node and the current path the node is traveling is +shown in red. + +Logging (the lowest part) if divided to two sections, control and log. From +the control part you can select what kind of messages are shown in the +log. You can also define if simulation should be paused on certain type of +event (using the check boxes in the "pause" column). Log part displays time +stamped events. All nodes and message names in the log messages are +buttons and you can get more information about them by clicking the +buttons. + + +DTN2 Reference Implementation Connectivity +========================================== + +DTN2 connectivity allows bundles to be passed between the ONE and any +number of DTN2 routers. This is done through DTN2's External Convergence +Layer Interface. + +When DTN2 connectivity is enabled ONE will connect to dtnd routers as +an external convergence layer adapter. ONE will also automatically configure +dtnd through a console connection with a link and route for bundles to reach +the simulator. + +When a bundle is received from dtnd, ONE attempts to match the destination EID +against the regular expressions configured in the configuration file (see DTN2 +Connectivity Configuration File below). For each matching node a copy of a +message is created and routed inside ONE. When the bundle reaches its destination +inside ONE it is delivered to the dtnd router instance attached to the node. +Copies of the bundle payload are stored within 'bundles' directory. + +To enable this functionality the following steps must be taken: + +1) DTN2 must be compiled and configured with ECL support enabled. +2) DTN2Events event generator must be configured to be loaded into ONE + as an events class. +3) DTN2Reporter must be configured and loaded into one as a report class. +4) DTN2 connectivity configuration file must be configured as DTN2.configFile + +To start the simulation: +1) Start all the dtnd router instances. +2) Start ONE. + +Example Configuration (2-4 above) +--------------------------------- + +Events.nrof = 1 +Events1.class = DTN2Events +Report.nrofReports = 1 +Report.report1 = DTN2Reporter +DTN2.configFile = cla.conf + +DTN2 Connectivity Configuration File +------------------------------------ + +The DTN2 connectivity configuration file defines which nodes inside ONE +should connect to which DTN2 router instances. It also defines the EID's +that the nodes match. + +The configuration file is composed of comment lines starting with # and +configuration lines with the following format: + + + +The fields have the following meaning: + +nodeID: The ID of a node inside ONE (integer >= 0) +EID regexp: Incoming bundles whose destination EID matches this regexp + will be forwarded to the node inside ONE. + (see java.util.regex.Pattern) +dtnd host: Hostname/IP of the dtnd router to connect to this node. +ECL port: dtnd router's port listening to ECLAs +console port: dtnd router's console port + +Example: +# +1 dtn://local-1.dtn/(.*) localhost 8801 5051 +2 dtn://local-2.dtn/(.*) localhost 8802 5052 + +Known Issues +------------ + +For DTN2 connectivity related issues, you can contact teemuk@netlab.tkk.fi + +-Quitting dtnd router instances connected to ONE will cause ONE to quit. + + +Toolkit +======= + +The simulation package includes a folder called "toolkit" that contains +scripts for generating input and processing the output of the simulator. All +(currently included) scripts are written with Perl (http://www.perl.com/) so +you need to have it installed before running the scripts. Some post processing +scripts use gnuplot (http://www.gnuplot.info/) for creating graphics. Both of +the programs are freely available for most of the Unix/Linux and Windows +environments. For Windows environment, you may need to change the path to the +executables for some of the scripts. + +getStats.pl +This script can be used to create bar-plots of various statistics gathered by +the MessageStatsReport -report module. The only mandatory option is "-stat" +which is used to define the name of the statistics value that should be parsed +from the report files (e.g., "delivery_prob" for message delivery +probabilities). Rest of the parameters should be MessageStatsReport output +filenames (or paths). Script creates three output files: one with values from +all the files, one with the gnuplot commands used to create the graphics and +finally an image file containing the graphics. One bar is created to the plot +for each input file. The title for each bar is parsed from the report filename +using the regular expression defined with "-label" option. Run getStats.pl +with "-help" option for more help. + +ccdfPlotter.pl +Script for creating Complementary(/Inverse) Cumulative Distribution Function +plots (using gluplot) from reports that contain time-hitcount-tuples. Output +filename must be defined with the "-out" option and rest of the parameters +should be (suitable) report filenames. "-label" option can be used for +defining label extracting regular expression (similar to one for the getStats +script) for the legend. + +createCreates.pl +Message creation pattern for the simulation can be defined with external events +file. Such a file can be simply created with any text editor but this script +makes it easier to create a large amount of messages. Mandatory options are +the number of messages ("-nrof"), time range ("-time"), host address range +("-hosts") and message size range ("-sizes"). The number of messages is simply +an integer but the ranges are given with two integers with a colon (:) between +them. If hosts should reply to the messages that they receive, size range of +the reply messages can be defined with "-rsizes" option. If a certain random +number generator seed should be used, that can be defined with "-seed" option. +All random values are drawn from a uniform distribution with inclusive minimum +value and exclusive maximum value. Script outputs commands that are suitable +for external events file's contents. You probably want to redirect the output +to some file. + +dtnsim2parser.pl and transimsParser.pl +These two (quite experimental) parsers convert data from other programs to a +form that is suitable for ONE. Both take two parameters: input and output +file. If these parameters are omitted, stdin and stdout are used for input and +output. With "-h" option a short help is printed. +dtnsim2parser converts dtnsim2's (http://watwire.uwaterloo.ca/DTN/sim/) output +(with verbose mode 8) to an external events file that can be fed to ONE. The +main idea of this parser is that you can first create a connectivity pattern +file using ONE and ConnectivityDtnsim2Report, feed that to dtnsim2 and then +observe the results visually in ONE (using the output converted with +dtnsim2parser as the external events file). +transimsParser can convert TRANSIM's (http://transims-opensource.net/) vehicle +snapshot files to external movement files that can be used as an input for +node movement. See ExternalMovement and ExternalMovementReader classes for +more information. \ No newline at end of file diff --git a/applications/PingApplication.java b/applications/PingApplication.java new file mode 100644 index 000000000..b2787db20 --- /dev/null +++ b/applications/PingApplication.java @@ -0,0 +1,305 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package applications; + +import java.util.Random; + +import report.PingAppReporter; +import core.Application; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimClock; +import core.SimScenario; +import core.World; + +/** + * Simple ping application to demonstrate the application support. The + * application can be configured to send pings with a fixed interval or to only + * answer to pings it receives. When the application receives a ping it sends + * a pong message in response. + * + * The corresponding PingAppReporter class can be used to record + * information about the application behavior. + * + * @see PingAppReporter + * @author teemuk + */ +public class PingApplication extends Application { + /** Run in passive mode - don't generate pings but respond */ + public static final String PING_PASSIVE = "passive"; + /** Ping generation interval */ + public static final String PING_INTERVAL = "interval"; + /** Ping interval offset - avoids synchronization of ping sending */ + public static final String PING_OFFSET = "offset"; + /** Destination address range - inclusive lower, exclusive upper */ + public static final String PING_DEST_RANGE = "destinationRange"; + /** Seed for the app's random number generator */ + public static final String PING_SEED = "seed"; + /** Size of the ping message */ + public static final String PING_PING_SIZE = "pingSize"; + /** Size of the pong message */ + public static final String PING_PONG_SIZE = "pongSize"; + + /** Application ID */ + public static final String APP_ID = "fi.tkk.netlab.PingApplication"; + + // Private vars + private double lastPing = 0; + private double interval = 500; + private boolean passive = false; + private int seed = 0; + private int destMin=0; + private int destMax=1; + private int pingSize=1; + private int pongSize=1; + private Random rng; + + /** + * Creates a new ping application with the given settings. + * + * @param s Settings to use for initializing the application. + */ + public PingApplication(Settings s) { + if (s.contains(PING_PASSIVE)){ + this.passive = s.getBoolean(PING_PASSIVE); + } + if (s.contains(PING_INTERVAL)){ + this.interval = s.getDouble(PING_INTERVAL); + } + if (s.contains(PING_OFFSET)){ + this.lastPing = s.getDouble(PING_OFFSET); + } + if (s.contains(PING_SEED)){ + this.seed = s.getInt(PING_SEED); + } + if (s.contains(PING_PING_SIZE)) { + this.pingSize = s.getInt(PING_PING_SIZE); + } + if (s.contains(PING_PONG_SIZE)) { + this.pongSize = s.getInt(PING_PONG_SIZE); + } + if (s.contains(PING_DEST_RANGE)){ + int[] destination = s.getCsvInts(PING_DEST_RANGE,2); + this.destMin = destination[0]; + this.destMax = destination[1]; + } + + rng = new Random(this.seed); + super.setAppID(APP_ID); + } + + /** + * Copy-constructor + * + * @param a + */ + public PingApplication(PingApplication a) { + super(a); + this.lastPing = a.getLastPing(); + this.interval = a.getInterval(); + this.passive = a.isPassive(); + this.destMax = a.getDestMax(); + this.destMin = a.getDestMin(); + this.seed = a.getSeed(); + this.pongSize = a.getPongSize(); + this.pingSize = a.getPingSize(); + this.rng = new Random(this.seed); + } + + /** + * Handles an incoming message. If the message is a ping message replies + * with a pong message. Generates events for ping and pong messages. + * + * @param msg message received by the router + * @param host host to which the application instance is attached + */ + @Override + public Message handle(Message msg, DTNHost host) { + String type = (String)msg.getProperty("type"); + if (type==null) return msg; // Not a ping/pong message + + // Respond with pong if we're the recipient + if (msg.getTo()==host && type.equalsIgnoreCase("ping")) { + String id = "pong" + SimClock.getIntTime() + "-" + + host.getAddress(); + Message m = new Message(host, msg.getFrom(), id, getPongSize()); + m.addProperty("type", "pong"); + m.setAppID(APP_ID); + host.createNewMessage(m); + + // Send event to listeners + super.sendEventToListeners("GotPing", null, host); + super.sendEventToListeners("SentPong", null, host); + } + + // Received a pong reply + if (msg.getTo()==host && type.equalsIgnoreCase("pong")) { + // Send event to listeners + super.sendEventToListeners("GotPong", null, host); + } + + return msg; + } + + /** + * Draws a random host from the destination range + * + * @return host + */ + private DTNHost randomHost() { + int destaddr = 0; + if (destMax == destMin) { + destaddr = destMin; + } + destaddr = destMin + rng.nextInt(destMax - destMin); + World w = SimScenario.getInstance().getWorld(); + return w.getNodeByAddress(destaddr); + } + + @Override + public Application replicate() { + return new PingApplication(this); + } + + /** + * Sends a ping packet if this is an active application instance. + * + * @param host to which the application instance is attached + */ + @Override + public void update(DTNHost host) { + if (this.passive) return; + double curTime = SimClock.getTime(); + if (curTime - this.lastPing >= this.interval) { + // Time to send a new ping + Message m = new Message(host, randomHost(), "ping" + + SimClock.getIntTime() + "-" + host.getAddress(), + getPingSize()); + m.addProperty("type", "ping"); + m.setAppID(APP_ID); + host.createNewMessage(m); + + // Call listeners + super.sendEventToListeners("SentPing", null, host); + + this.lastPing = curTime; + } + } + + /** + * @return the lastPing + */ + public double getLastPing() { + return lastPing; + } + + /** + * @param lastPing the lastPing to set + */ + public void setLastPing(double lastPing) { + this.lastPing = lastPing; + } + + /** + * @return the interval + */ + public double getInterval() { + return interval; + } + + /** + * @param interval the interval to set + */ + public void setInterval(double interval) { + this.interval = interval; + } + + /** + * @return the passive + */ + public boolean isPassive() { + return passive; + } + + /** + * @param passive the passive to set + */ + public void setPassive(boolean passive) { + this.passive = passive; + } + + /** + * @return the destMin + */ + public int getDestMin() { + return destMin; + } + + /** + * @param destMin the destMin to set + */ + public void setDestMin(int destMin) { + this.destMin = destMin; + } + + /** + * @return the destMax + */ + public int getDestMax() { + return destMax; + } + + /** + * @param destMax the destMax to set + */ + public void setDestMax(int destMax) { + this.destMax = destMax; + } + + /** + * @return the seed + */ + public int getSeed() { + return seed; + } + + /** + * @param seed the seed to set + */ + public void setSeed(int seed) { + this.seed = seed; + } + + /** + * @return the pongSize + */ + public int getPongSize() { + return pongSize; + } + + /** + * @param pongSize the pongSize to set + */ + public void setPongSize(int pongSize) { + this.pongSize = pongSize; + } + + /** + * @return the pingSize + */ + public int getPingSize() { + return pingSize; + } + + /** + * @param pingSize the pingSize to set + */ + public void setPingSize(int pingSize) { + this.pingSize = pingSize; + } + +} diff --git a/compile.bat b/compile.bat new file mode 100755 index 000000000..496c1e7c2 --- /dev/null +++ b/compile.bat @@ -0,0 +1,8 @@ +javac -extdirs lib/ core/*.java +javac -extdirs lib/ movement/*.java +javac -extdirs lib/ report/*.java +javac -extdirs lib/ routing/*.java +javac -extdirs lib/ gui/*.java +javac -extdirs lib/ input/*.java +javac -extdirs lib/ applications/*.java +javac -extdirs lib/ interfaces/*.java \ No newline at end of file diff --git a/core/Application.java b/core/Application.java new file mode 100644 index 000000000..d2aabaeec --- /dev/null +++ b/core/Application.java @@ -0,0 +1,125 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import java.util.List; + +/** + *

+ * Base class for applications. Nodes that have an application running will + * forward all incoming messages to the application handle() + * method before they are processed further. The application can change the + * properties of the message before returning it or return null to signal + * to the router that it wants the message to be dropped. + *

+ * + *

+ * In addition, the application's update() method is called every + * simulation cycle. + *

+ * + *

+ * Configuration of application is done by picking a unique application instance + * name (e.g., mySimpleApp) and setting its type property to the + * concrete application class: mySimpleApp.type = SimpleApplication + * . These application instances can be assigned to node groups using the + * Group.application setting: Group1.application = + * mySimpleApp. + *

+ * + * @author mjpitka + * @author teemuk + */ +public abstract class Application { + + private List aListeners = null; + + public String appID = null; + + public Application(){ + } + + /** + * Copy constructor. + * + * @param app + */ + public Application(Application app){ + this.aListeners = app.getAppListeners(); + this.appID = app.appID; + } + + /** + * This method handles application functionality related to + * processing of the bundle. Application handles a messages, + * which arrives to the node hosting this application. After + * performing application specific handling, this method returns + * a list of messages. If node wishes to continue forwarding the + * incoming + * + * @param msg The incoming message. + * @param host The host this application instance is attached to. + * @return the (possibly modified) message to forward or null + * if the application wants the router to stop forwarding the + * message. + */ + public abstract Message handle(Message msg, DTNHost host); + + + /** + * Called every simulation cycle. + * + * @param host The host this application instance is attached to. + */ + public abstract void update(DTNHost host); + + /** + *

+ * Returns an unique application ID. The application will only receive + * messages with this application ID. If the AppID is set to + * null the application will receive all messages. + *

+ * + * @return Application ID. + */ + public String getAppID() { + return this.appID; + } + + /** + * Sets the application ID. Should only set once when the application is + * created. Changing the value during simulation runtime is not recommended + * unless you really know what you're doing. + * + * @param appID + */ + public void setAppID(String appID) { + this.appID = appID; + } + + public abstract Application replicate(); + + public void setAppListeners (List aListeners){ + this.aListeners = aListeners; + } + + public List getAppListeners(){ + return this.aListeners; + } + + /** + * Sends an event to all listeners. + * + * @param event The event to send. + * @param params Any additional parameters to send. + * @param host The host which where the app is running. + */ + public void sendEventToListeners(String event, Object params, + DTNHost host) { + for (ApplicationListener al : this.aListeners) { + al.gotEvent(event, params, this, host); + } + } +} diff --git a/core/ApplicationListener.java b/core/ApplicationListener.java new file mode 100644 index 000000000..2d22c397c --- /dev/null +++ b/core/ApplicationListener.java @@ -0,0 +1,35 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + *

+ * Interface for classes that want to be informed about messages + * between hosts. + *

+ * + *

+ * Report classes wishing to receive application events should implement this + * interface. Note that the application event names are defined by the + * applications so any class wishing to interpret them must know the + * application. + *

+ * + * @author teemuk + * @author mjpitka + */ +public interface ApplicationListener { + + /** + * Application has generated an event. + * + * @param event Event name. + * @param params Additional parameters for the event + * @param app Application instance that generated the event. + * @param host The host this application instance is running on. + */ + public void gotEvent(String event, Object params, Application app, + DTNHost host); +} diff --git a/core/ArithmeticCondition.java b/core/ArithmeticCondition.java new file mode 100644 index 000000000..448acf046 --- /dev/null +++ b/core/ArithmeticCondition.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * This class presents a simple arithmetic condition: is value smaller than, + * bigger than, or equal to another value. The condition is given in text + * form, e.g., "< 42", and then different values can be matched against that + * condition. + * @author Ari + */ +public class ArithmeticCondition { + + private static final String VALID_OPERATORS = "><="; + private char operator; + private double number; + + /** + * Creates a new condition based on the given string. + * @param cond The condition string. Must consist of one operator + * ("<", ">", or "=") and one double-precision floating point number. + * @throws SettingsError if the given string is not a valid condition + */ + public ArithmeticCondition(String cond) { + String value; + int multiplier = 1; + + if (cond.length() < 2) { + throw new SettingsError("Invalid condition \"" + cond + "\""); + } + + operator = cond.charAt(0); + value = cond.substring(1); + + /* handle kilo and Mega suffixes for the value */ + if (value.endsWith("k")) { + multiplier = 1000; + } else if (value.endsWith("M")) { + multiplier = 1000000; + } + if (multiplier > 1) { /* remove suffix */ + value = value.substring(0, value.length() - 1); + } + + if (VALID_OPERATORS.indexOf(operator) == -1) { + throw new SettingsError("Invalid operator in condition \"" + cond + + "\" valid operators: " + VALID_OPERATORS); + } + + try { + number = Double.parseDouble(value); + } catch (NumberFormatException e) { + throw new SettingsError("Invalid numeric value in condition \"" + + cond + "\""); + } + + number *= multiplier; + + } + + /** + * Returns true if the given value satisfies "V X N" where V is the given + * value, X is the operator (from the settings), and N is the numeric value + * given after the operator in the settings. + * @param value The value to check + * @return true if the condition holds for the given value, false otherwise + */ + public boolean isTrueFor(double value) { + switch (operator) { + case '<': return value < this.number; + case '>': return value > this.number; + case '=': return value == this.number; // XXX: == for doubles... + default: throw new SettingsError("Invalid operator"); + } + } + + @Override + public String toString() { + return "Condition \"" + operator + " " + number + "\""; + } +} diff --git a/core/CBRConnection.java b/core/CBRConnection.java new file mode 100644 index 000000000..0db8634bd --- /dev/null +++ b/core/CBRConnection.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import routing.MessageRouter; + +/** + * A constant bit-rate connection between two DTN nodes. + */ +public class CBRConnection extends Connection { + private int speed; + private double transferDoneTime; + + /** + * Creates a new connection between nodes and sets the connection + * state to "up". + * @param fromNode The node that initiated the connection + * @param fromInterface The interface that initiated the connection + * @param toNode The node in the other side of the connection + * @param toInterface The interface in the other side of the connection + * @param connectionSpeed Transfer speed of the connection (Bps) when + * the connection is initiated + */ + public CBRConnection(DTNHost fromNode, NetworkInterface fromInterface, + DTNHost toNode, NetworkInterface toInterface, int connectionSpeed) { + super(fromNode, fromInterface, toNode, toInterface); + this.speed = connectionSpeed; + this.transferDoneTime = 0; + + } + + /** + * Sets a message that this connection is currently transferring. If message + * passing is controlled by external events, this method is not needed + * (but then e.g. {@link #finalizeTransfer()} and + * {@link #isMessageTransferred()} will not work either). Only a one message + * at a time can be transferred using one connection. + * @param from The host sending the message + * @param m The message + * @return The value returned by + * {@link MessageRouter#receiveMessage(Message, DTNHost)} + */ + public int startTransfer(DTNHost from, Message m) { + assert this.msgOnFly == null : "Already transferring " + + this.msgOnFly + " from " + this.msgFromNode + " to " + + this.getOtherNode(this.msgFromNode) + ". Can't " + + "start transfer of " + m + " from " + from; + + this.msgFromNode = from; + Message newMessage = m.replicate(); + int retVal = getOtherNode(from).receiveMessage(newMessage, from); + + if (retVal == MessageRouter.RCV_OK) { + this.msgOnFly = newMessage; + this.transferDoneTime = SimClock.getTime() + + (1.0*m.getSize()) / this.speed; + } + + return retVal; + } + + /** + * Aborts the transfer of the currently transferred message. + */ + public void abortTransfer() { + assert msgOnFly != null : "No message to abort at " + msgFromNode; + getOtherNode(msgFromNode).messageAborted(this.msgOnFly.getId(), + msgFromNode,getRemainingByteCount()); + clearMsgOnFly(); + this.transferDoneTime = 0; + } + + /** + * Gets the transferdonetime + */ + public double getTransferDoneTime() { + return transferDoneTime; + } + + /** + * Returns true if the current message transfer is done. + * @return True if the transfer is done, false if not + */ + public boolean isMessageTransferred() { + return getRemainingByteCount() == 0; + } + + /** + * returns the current speed of the connection + */ + public double getSpeed() { + return this.speed; + } + + /** + * Returns the amount of bytes to be transferred before ongoing transfer + * is ready or 0 if there's no ongoing transfer or it has finished + * already + * @return the amount of bytes to be transferred + */ + public int getRemainingByteCount() { + int remaining; + + if (msgOnFly == null) { + return 0; + } + + remaining = (int)((this.transferDoneTime - SimClock.getTime()) + * this.speed); + + return (remaining > 0 ? remaining : 0); + } + + /** + * Returns a String presentation of the connection. + */ + public String toString() { + return super.toString() + (isTransferring() ? + " until " + String.format("%.2f", this.transferDoneTime) : ""); + } + +} diff --git a/core/Connection.java b/core/Connection.java new file mode 100644 index 000000000..d6e24d43f --- /dev/null +++ b/core/Connection.java @@ -0,0 +1,230 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import routing.MessageRouter; + +/** + * A connection between two DTN nodes. + */ +public abstract class Connection { + protected DTNHost toNode; + protected NetworkInterface toInterface; + protected DTNHost fromNode; + protected NetworkInterface fromInterface; + protected DTNHost msgFromNode; + + private boolean isUp; + protected Message msgOnFly; + /** how many bytes this connection has transferred */ + protected int bytesTransferred; + + /** + * Creates a new connection between nodes and sets the connection + * state to "up". + * @param fromNode The node that initiated the connection + * @param fromInterface The interface that initiated the connection + * @param toNode The node in the other side of the connection + * @param toInterface The interface in the other side of the connection + */ + public Connection(DTNHost fromNode, NetworkInterface fromInterface, + DTNHost toNode, NetworkInterface toInterface) { + this.fromNode = fromNode; + this.fromInterface = fromInterface; + this.toNode = toNode; + this.toInterface = toInterface; + this.isUp = true; + this.bytesTransferred = 0; + } + + + /** + * Returns true if the connection is up + * @return state of the connection + */ + public boolean isUp() { + return this.isUp; + } + + /** + * Returns true if the connections is transferring a message + * @return true if the connections is transferring a message + */ + public boolean isTransferring() { + return this.msgOnFly != null; + } + + + /** + * Returns true if the given node is the initiator of the connection, false + * otherwise + * @param node The node to check + * @return true if the given node is the initiator of the connection + */ + public boolean isInitiator(DTNHost node) { + return node == this.fromNode; + } + + /** + * Sets the state of the connection. + * @param state True if the connection is up, false if not + */ + public void setUpState(boolean state) { + this.isUp = state; + } + + /** + * Sets a message that this connection is currently transferring. If message + * passing is controlled by external events, this method is not needed + * (but then e.g. {@link #finalizeTransfer()} and + * {@link #isMessageTransferred()} will not work either). Only a one message + * at a time can be transferred using one connection. + * @param m The message + * @return The value returned by + * {@link MessageRouter#receiveMessage(Message, DTNHost)} + */ + public abstract int startTransfer(DTNHost from, Message m); + + /** + * Calculate the current transmission speed from the information + * given by the interfaces, and calculate the missing data amount. + */ + public void update() {}; + + /** + * Aborts the transfer of the currently transferred message. + */ + public void abortTransfer() { + assert msgOnFly != null : "No message to abort at " + msgFromNode; + int bytesRemaining = getRemainingByteCount(); + + this.bytesTransferred += msgOnFly.getSize() - bytesRemaining; + + getOtherNode(msgFromNode).messageAborted(this.msgOnFly.getId(), + msgFromNode, bytesRemaining); + clearMsgOnFly(); + } + + /** + * Returns the amount of bytes to be transferred before ongoing transfer + * is ready or 0 if there's no ongoing transfer or it has finished + * already + * @return the amount of bytes to be transferred + */ + public abstract int getRemainingByteCount(); + + /** + * Clears the message that is currently being transferred. + * Calls to {@link #getMessage()} will return null after this. + */ + protected void clearMsgOnFly() { + this.msgOnFly = null; + this.msgFromNode = null; + } + + /** + * Finalizes the transfer of the currently transferred message. + * The message that was being transferred can not be + * retrieved from this connections after calling this method (using + * {@link #getMessage()}). + */ + public void finalizeTransfer() { + assert this.msgOnFly != null : "Nothing to finalize in " + this; + assert msgFromNode != null : "msgFromNode is not set"; + + this.bytesTransferred += msgOnFly.getSize(); + + getOtherNode(msgFromNode).messageTransferred(this.msgOnFly.getId(), + msgFromNode); + clearMsgOnFly(); + } + + /** + * Returns true if the current message transfer is done + * @return True if the transfer is done, false if not + */ + public abstract boolean isMessageTransferred(); + + /** + * Returns true if the connection is ready to transfer a message (connection + * is up and there is no message being transferred). + * @return true if the connection is ready to transfer a message + */ + public boolean isReadyForTransfer() { + return this.isUp && this.msgOnFly == null; + } + + /** + * Gets the message that this connection is currently transferring. + * @return The message or null if no message is being transferred + */ + public Message getMessage() { + return this.msgOnFly; + } + + /** + * Gets the current connection speed + */ + public abstract double getSpeed(); + + /** + * Returns the total amount of bytes this connection has transferred so far + * (including all transfers). + */ + public int getTotalBytesTransferred() { + if (this.msgOnFly == null) { + return this.bytesTransferred; + } + else { + if (isMessageTransferred()) { + return this.bytesTransferred + this.msgOnFly.getSize(); + } + else { + return this.bytesTransferred + + (msgOnFly.getSize() - getRemainingByteCount()); + } + } + } + + /** + * Returns the node in the other end of the connection + * @param node The node in this end of the connection + * @return The requested node + */ + public DTNHost getOtherNode(DTNHost node) { + if (node == this.fromNode) { + return this.toNode; + } + else { + return this.fromNode; + } + } + + /** + * Returns the interface in the other end of the connection + * @param i The interface in this end of the connection + * @return The requested interface + */ + public NetworkInterface getOtherInterface(NetworkInterface i) { + if (i == this.fromInterface) { + return this.toInterface; + } + else { + return this.fromInterface; + } + } + + /** + * Returns a String presentation of the connection. + */ + public String toString() { + return fromNode + "<->" + toNode + " (" + getSpeed()/1000 + " kBps) is " + + (isUp() ? "up":"down") + + (isTransferring() ? " transferring " + this.msgOnFly + + " from " + this.msgFromNode : ""); + } + +} + diff --git a/core/ConnectionListener.java b/core/ConnectionListener.java new file mode 100644 index 000000000..210978f2e --- /dev/null +++ b/core/ConnectionListener.java @@ -0,0 +1,27 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * Interface for classes that want to be informed about connections + * between hosts. + */ +public interface ConnectionListener { + + /** + * Method is called when two hosts are connected. + * @param host1 Host that initiated the connection + * @param host2 Host that was connected to + */ + public void hostsConnected(DTNHost host1, DTNHost host2); + + /** + * Method is called when connection between hosts is disconnected. + * @param host1 Host that initiated the disconnection + * @param host2 Host at the other end of the connection + */ + public void hostsDisconnected(DTNHost host1, DTNHost host2); + +} diff --git a/core/Coord.java b/core/Coord.java new file mode 100644 index 000000000..002801c57 --- /dev/null +++ b/core/Coord.java @@ -0,0 +1,156 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * Class to hold 2D coordinates and perform simple arithmetics and + * transformations + */ +public class Coord implements Cloneable, Comparable { + private double x; + private double y; + + /** + * Constructor. + * @param x Initial X-coordinate + * @param y Initial Y-coordinate + */ + public Coord(double x, double y) { + setLocation(x,y); + } + + /** + * Sets the location of this coordinate object + * @param x The x coordinate to set + * @param y The y coordinate to set + */ + public void setLocation(double x, double y) { + this.x = x; + this.y = y; + } + + /** + * Sets this coordinate's location to be equal to other + * coordinates location + * @param c The other coordinate + */ + public void setLocation(Coord c) { + this.x = c.x; + this.y = c.y; + } + + /** + * Moves the point by dx and dy + * @param dx How much to move the point in X-direction + * @param dy How much to move the point in Y-direction + */ + public void translate(double dx, double dy) { + this.x += dx; + this.y += dy; + } + + /** + * Returns the distance to another coordinate + * @param other The other coordinate + * @return The distance between this and another coordinate + */ + public double distance(Coord other) { + double dx = this.x - other.x; + double dy = this.y - other.y; + + return Math.sqrt(dx*dx + dy*dy); + } + + /** + * Returns the x coordinate + * @return x coordinate + */ + public double getX() { + return this.x; + } + + /** + * Returns the y coordinate + * @return y coordinate + */ + public double getY() { + return this.y; + } + + /** + * Returns a text representation of the coordinate (rounded to 2 decimals) + * @return a text representation of the coordinate + */ + public String toString() { + return String.format("(%.2f,%.2f)",x,y); + } + + /** + * Returns a clone of this coordinate + */ + public Coord clone() { + Coord clone = null; + try { + clone = (Coord) super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + System.exit(-1); + } + return clone; + } + + /** + * Checks if this coordinate's location is equal to other coordinate's + * @param c The other coordinate + * @return True if locations are the same + */ + public boolean equals(Coord c) { + if (c == this) { + return true; + } + else { + return (x == c.x && y == c.y); // XXX: == for doubles... + } + } + + @Override + public boolean equals(Object o) { + if (o == null) return false; + return equals((Coord) o); + } + + /** + * Returns a hash code for this coordinate + * (actually a hash of the String made of the coordinates) + */ + public int hashCode() { + return (x+","+y).hashCode(); + } + + /** + * Compares this coordinate to other coordinate. Coordinate whose y + * value is smaller comes first and if y values are equal, the one with + * smaller x value comes first. + * @return -1, 0 or 1 if this node is before, in the same place or + * after the other coordinate + */ + public int compareTo(Coord other) { + if (this.y < other.y) { + return -1; + } + else if (this.y > other.y) { + return 1; + } + else if (this.x < other.x) { + return -1; + } + else if (this.x > other.x) { + return 1; + } + else { + return 0; + } + } +} diff --git a/core/DTN2Manager.java b/core/DTN2Manager.java new file mode 100644 index 000000000..9e1592ecd --- /dev/null +++ b/core/DTN2Manager.java @@ -0,0 +1,222 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package core; + +import input.DTN2Events; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import report.DTN2Reporter; +import fi.tkk.netlab.dtn.ecla.Bundle; +import fi.tkk.netlab.dtn.ecla.CLAParser; + +/** + * Manages the external convergence layer connections to dtnd. + * Parses the configuration file and sets up the CLAParsers + * and EID->host mappings. + * @author teemuk + */ +public class DTN2Manager { + private static Map CLAs = null; + /** Mapping from EID to DTNHost */ + private static Collection EID_to_host = null; + /** Set of all bundles in the simulator */ + private static Map bundles = null; + /** Reporter object that passes messages from ONE to dtnd */ + private static DTN2Reporter reporter = null; + /** Events object that passes messages from dtnd to ONE */ + private static DTN2Events events = null; + + /** + * EID to DTNHost mapping elements. + */ + public static class EIDHost { + public String EID; + public int host_id; + public DTNHost host; + public EIDHost(String eid, int host_id, DTNHost host) { + this.EID = eid; + this.host = host; + this.host_id = host_id; + } + } + + /** + * Sets up the dtnd connections by parsing the configuration file + * defined in the DTN2.configFile setting. + * @param world reference to the world that contains the nodes + */ + public static void setup(World world) { + FileInputStream f_in; + InputStreamReader isr; + BufferedReader in; + File f; + String s; + String[] attrs; + int nodeID, dtnd_port, console_port; + String nodeEID, dtnd_host; + + DTN2Manager.CLAs = new HashMap(); + DTN2Manager.EID_to_host = new LinkedList(); + DTN2Manager.bundles = new HashMap(); + + // Check if DTN2Reporter and DTN2Events have been loaded. + // If not, we do nothing here. + if (DTN2Manager.reporter==null || DTN2Manager.events==null) + return; + + // Get input stream from the settings file. + Settings conf = new Settings("DTN2"); + String fname; + try { + fname = conf.getSetting("configFile"); + } catch (SettingsError se) { + return; + } + f = new File(fname); + if (!f.exists()) return; + try { + f_in = new FileInputStream(f); + isr = new InputStreamReader(f_in); + in = new BufferedReader(isr); + } catch (Exception e) { + Debug.p("Could not load requested DTN2 configuration file '" + +fname+"'"); + return; + } + + // Create a directory to hold copies of the bundles + f = new File("bundles"); + if (!f.exists()) + f.mkdir(); + + // Parse config file + try { + s = in.readLine(); + } catch (Exception e) { + return; + } + while (s!=null) { + attrs = s.split(" "); + if (attrs.length==5 && !s.startsWith("#")) { + nodeID = Integer.parseInt(attrs[0]); + nodeEID = attrs[1]; + dtnd_host = attrs[2]; + dtnd_port = Integer.parseInt(attrs[3]); + console_port = Integer.parseInt(attrs[4]); + + // Find the host + DTNHost h = world.getNodeByAddress(nodeID); + + // Add to the EID -> Host mapping + DTN2Manager.EIDHost e = new DTN2Manager.EIDHost(nodeEID, + nodeID, h); + DTN2Manager.EID_to_host.add(e); + + // Configure and start the CLA + CLAParser p; + p = new CLAParser(dtnd_host, dtnd_port, "ONE"); + DTN2Events.ParserHandler ph = + DTN2Manager.events.getParserHandler(nodeID, dtnd_host, + console_port); + p.setListener(ph); + Thread t = new Thread(p); + t.start(); + // Save reference to the CLA + DTN2Manager.CLAs.put(h,p); + } + try { + s = in.readLine(); + } catch (Exception e) { + return; + } + } + } + + + /** + * Sets the DTN2Reporter object used to pass messages from ONE + * to dtnd. + * This should be used by the dynamically loaded DTN2Reporter object to + * allow other objects get reference to it. + * @param reporter the reporter object to save reference to + */ + public static void setReporter(DTN2Reporter reporter) { + DTN2Manager.reporter = reporter; + } + + /** + * Returns reference to the DTN2Reporter object. + * @return reference to the active DTN2Reporter object + */ + public static DTN2Reporter getReporter() { + return DTN2Manager.reporter; + } + + /** + * Sets the DTN2Events object. + * @param events the active events object to use + */ + public static void setEvents(DTN2Events events) { + DTN2Manager.events = events; + } + + /** + * Returns the DTN2Events object. + * @return the currently active events object. + */ + public static DTN2Events getEvents() { + return DTN2Manager.events; + } + + /** + * Returns the ECL parser associated with the host. + * @param host the host who's parser to return + * @return the host's parser. + */ + public static CLAParser getParser(DTNHost host) { + return DTN2Manager.CLAs.get(host); + } + + /** + * Returns a Collection of DTNHost + * objects corresponding to the given EID. + * @param EID EID of the host + * @return the host corresponding to the EID + */ + public static Collection getHosts(String EID) { + Collection c = new LinkedList(); + for (EIDHost e : DTN2Manager.EID_to_host) { + if (EID.matches(e.EID)) c.add(e); + } + return c; + } + + /** + * Stores a reference to a bundle corresponding to the given message. + * @param id the id of the message + * @param bundle the bundle associated with the message + */ + public static void addBundle(String id, Bundle bundle) { + DTN2Manager.bundles.put(id, bundle); + } + + /** + * Returns the bundle associated with the given message id. + * @param id the message id + * @return the bundle associated with the message + */ + public static Bundle getBundle(String id) { + return DTN2Manager.bundles.remove(id); + } +} diff --git a/core/DTNHost.java b/core/DTNHost.java new file mode 100644 index 000000000..6a8c6c934 --- /dev/null +++ b/core/DTNHost.java @@ -0,0 +1,536 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import movement.MovementModel; +import movement.Path; +import routing.MessageRouter; +import routing.util.RoutingInfo; + +/** + * A DTN capable host. + */ +public class DTNHost implements Comparable { + private static int nextAddress = 0; + private int address; + + private Coord location; // where is the host + private Coord destination; // where is it going + + private MessageRouter router; + private MovementModel movement; + private Path path; + private double speed; + private double nextTimeToMove; + private String name; + private List msgListeners; + private List movListeners; + private List net; + private ModuleCommunicationBus comBus; + + static { + DTNSim.registerForReset(DTNHost.class.getCanonicalName()); + reset(); + } + /** + * Creates a new DTNHost. + * @param msgLs Message listeners + * @param movLs Movement listeners + * @param groupId GroupID of this host + * @param interf List of NetworkInterfaces for the class + * @param comBus Module communication bus object + * @param mmProto Prototype of the movement model of this host + * @param mRouterProto Prototype of the message router of this host + */ + public DTNHost(List msgLs, + List movLs, + String groupId, List interf, + ModuleCommunicationBus comBus, + MovementModel mmProto, MessageRouter mRouterProto) { + this.comBus = comBus; + this.location = new Coord(0,0); + this.address = getNextAddress(); + this.name = groupId+address; + this.net = new ArrayList(); + + for (NetworkInterface i : interf) { + NetworkInterface ni = i.replicate(); + ni.setHost(this); + net.add(ni); + } + + // TODO - think about the names of the interfaces and the nodes + //this.name = groupId + ((NetworkInterface)net.get(1)).getAddress(); + + this.msgListeners = msgLs; + this.movListeners = movLs; + + // create instances by replicating the prototypes + this.movement = mmProto.replicate(); + this.movement.setComBus(comBus); + this.movement.setHost(this); + setRouter(mRouterProto.replicate()); + + this.location = movement.getInitialLocation(); + + this.nextTimeToMove = movement.nextPathAvailable(); + this.path = null; + + if (movLs != null) { // inform movement listeners about the location + for (MovementListener l : movLs) { + l.initialLocation(this, this.location); + } + } + } + + /** + * Returns a new network interface address and increments the address for + * subsequent calls. + * @return The next address. + */ + private synchronized static int getNextAddress() { + return nextAddress++; + } + + /** + * Reset the host and its interfaces + */ + public static void reset() { + nextAddress = 0; + } + + /** + * Returns true if this node is actively moving (false if not) + * @return true if this node is actively moving (false if not) + */ + public boolean isMovementActive() { + return this.movement.isActive(); + } + + /** + * Returns true if this node's radio is active (false if not) + * @return true if this node's radio is active (false if not) + */ + public boolean isRadioActive() { + /* TODO: make this work for multiple interfaces */ + return this.getInterface(1).isActive(); + } + + /** + * Set a router for this host + * @param router The router to set + */ + private void setRouter(MessageRouter router) { + router.init(this, msgListeners); + this.router = router; + } + + /** + * Returns the router of this host + * @return the router of this host + */ + public MessageRouter getRouter() { + return this.router; + } + + /** + * Returns the network-layer address of this host. + */ + public int getAddress() { + return this.address; + } + + /** + * Returns this hosts's ModuleCommunicationBus + * @return this hosts's ModuleCommunicationBus + */ + public ModuleCommunicationBus getComBus() { + return this.comBus; + } + + /** + * Informs the router of this host about state change in a connection + * object. + * @param con The connection object whose state changed + */ + public void connectionUp(Connection con) { + this.router.changedConnection(con); + } + + public void connectionDown(Connection con) { + this.router.changedConnection(con); + } + + /** + * Returns a copy of the list of connections this host has with other hosts + * @return a copy of the list of connections this host has with other hosts + */ + public List getConnections() { + List lc = new ArrayList(); + + for (NetworkInterface i : net) { + lc.addAll(i.getConnections()); + } + + return lc; + } + + /** + * Returns the current location of this host. + * @return The location + */ + public Coord getLocation() { + return this.location; + } + + /** + * Returns the Path this node is currently traveling or null if no + * path is in use at the moment. + * @return The path this node is traveling + */ + public Path getPath() { + return this.path; + } + + + /** + * Sets the Node's location overriding any location set by movement model + * @param location The location to set + */ + public void setLocation(Coord location) { + this.location = location.clone(); + } + + /** + * Sets the Node's name overriding the default name (groupId + netAddress) + * @param name The name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the messages in a collection. + * @return Messages in a collection + */ + public Collection getMessageCollection() { + return this.router.getMessageCollection(); + } + + /** + * Returns the number of messages this node is carrying. + * @return How many messages the node is carrying currently. + */ + public int getNrofMessages() { + return this.router.getNrofMessages(); + } + + /** + * Returns the buffer occupancy percentage. Occupancy is 0 for empty + * buffer but can be over 100 if a created message is bigger than buffer + * space that could be freed. + * @return Buffer occupancy percentage + */ + public double getBufferOccupancy() { + double bSize = router.getBufferSize(); + double freeBuffer = router.getFreeBufferSize(); + return 100*((bSize-freeBuffer)/bSize); + } + + /** + * Returns routing info of this host's router. + * @return The routing info. + */ + public RoutingInfo getRoutingInfo() { + return this.router.getRoutingInfo(); + } + + /** + * Returns the interface objects of the node + */ + public List getInterfaces() { + return net; + } + + /** + * Find the network interface based on the index + */ + public NetworkInterface getInterface(int interfaceNo) { + NetworkInterface ni = null; + try { + ni = net.get(interfaceNo-1); + } catch (IndexOutOfBoundsException ex) { + throw new SimError("No such interface: "+interfaceNo + + " at " + this); + } + return ni; + } + + /** + * Find the network interface based on the interfacetype + */ + protected NetworkInterface getInterface(String interfacetype) { + for (NetworkInterface ni : net) { + if (ni.getInterfaceType().equals(interfacetype)) { + return ni; + } + } + return null; + } + + /** + * Force a connection event + */ + public void forceConnection(DTNHost anotherHost, String interfaceId, + boolean up) { + NetworkInterface ni; + NetworkInterface no; + + if (interfaceId != null) { + ni = getInterface(interfaceId); + no = anotherHost.getInterface(interfaceId); + + assert (ni != null) : "Tried to use a nonexisting interfacetype "+interfaceId; + assert (no != null) : "Tried to use a nonexisting interfacetype "+interfaceId; + } else { + ni = getInterface(1); + no = anotherHost.getInterface(1); + + assert (ni.getInterfaceType().equals(no.getInterfaceType())) : + "Interface types do not match. Please specify interface type explicitly"; + } + + if (up) { + ni.createConnection(no); + } else { + ni.destroyConnection(no); + } + } + + /** + * for tests only --- do not use!!! + */ + public void connect(DTNHost h) { + Debug.p("WARNING: using deprecated DTNHost.connect(DTNHost)" + + "Use DTNHost.forceConnection(DTNHost,null,true) instead"); + forceConnection(h,null,true); + } + + /** + * Updates node's network layer and router. + * @param simulateConnections Should network layer be updated too + */ + public void update(boolean simulateConnections) { + if (!isRadioActive()) { + // Make sure inactive nodes don't have connections + tearDownAllConnections(); + return; + } + + if (simulateConnections) { + for (NetworkInterface i : net) { + i.update(); + } + } + this.router.update(); + } + + /** + * Tears down all connections for this host. + */ + private void tearDownAllConnections() { + for (NetworkInterface i : net) { + // Get all connections for the interface + List conns = i.getConnections(); + if (conns.size() == 0) continue; + + // Destroy all connections + List removeList = + new ArrayList(conns.size()); + for (Connection con : conns) { + removeList.add(con.getOtherInterface(i)); + } + for (NetworkInterface inf : removeList) { + i.destroyConnection(inf); + } + } + } + + /** + * Moves the node towards the next waypoint or waits if it is + * not time to move yet + * @param timeIncrement How long time the node moves + */ + public void move(double timeIncrement) { + double possibleMovement; + double distance; + double dx, dy; + + if (!isMovementActive() || SimClock.getTime() < this.nextTimeToMove) { + return; + } + if (this.destination == null) { + if (!setNextWaypoint()) { + return; + } + } + + possibleMovement = timeIncrement * speed; + distance = this.location.distance(this.destination); + + while (possibleMovement >= distance) { + // node can move past its next destination + this.location.setLocation(this.destination); // snap to destination + possibleMovement -= distance; + if (!setNextWaypoint()) { // get a new waypoint + return; // no more waypoints left + } + distance = this.location.distance(this.destination); + } + + // move towards the point for possibleMovement amount + dx = (possibleMovement/distance) * (this.destination.getX() - + this.location.getX()); + dy = (possibleMovement/distance) * (this.destination.getY() - + this.location.getY()); + this.location.translate(dx, dy); + } + + /** + * Sets the next destination and speed to correspond the next waypoint + * on the path. + * @return True if there was a next waypoint to set, false if node still + * should wait + */ + private boolean setNextWaypoint() { + if (path == null) { + path = movement.getPath(); + } + + if (path == null || !path.hasNext()) { + this.nextTimeToMove = movement.nextPathAvailable(); + this.path = null; + return false; + } + + this.destination = path.getNextWaypoint(); + this.speed = path.getSpeed(); + + if (this.movListeners != null) { + for (MovementListener l : this.movListeners) { + l.newDestination(this, this.destination, this.speed); + } + } + + return true; + } + + /** + * Sends a message from this host to another host + * @param id Identifier of the message + * @param to Host the message should be sent to + */ + public void sendMessage(String id, DTNHost to) { + this.router.sendMessage(id, to); + } + + /** + * Start receiving a message from another host + * @param m The message + * @param from Who the message is from + * @return The value returned by + * {@link MessageRouter#receiveMessage(Message, DTNHost)} + */ + public int receiveMessage(Message m, DTNHost from) { + int retVal = this.router.receiveMessage(m, from); + + if (retVal == MessageRouter.RCV_OK) { + m.addNodeOnPath(this); // add this node on the messages path + } + + return retVal; + } + + /** + * Requests for deliverable message from this host to be sent trough a + * connection. + * @param con The connection to send the messages trough + * @return True if this host started a transfer, false if not + */ + public boolean requestDeliverableMessages(Connection con) { + return this.router.requestDeliverableMessages(con); + } + + /** + * Informs the host that a message was successfully transferred. + * @param id Identifier of the message + * @param from From who the message was from + */ + public void messageTransferred(String id, DTNHost from) { + this.router.messageTransferred(id, from); + } + + /** + * Informs the host that a message transfer was aborted. + * @param id Identifier of the message + * @param from From who the message was from + * @param bytesRemaining Nrof bytes that were left before the transfer + * would have been ready; or -1 if the number of bytes is not known + */ + public void messageAborted(String id, DTNHost from, int bytesRemaining) { + this.router.messageAborted(id, from, bytesRemaining); + } + + /** + * Creates a new message to this host's router + * @param m The message to create + */ + public void createNewMessage(Message m) { + this.router.createNewMessage(m); + } + + /** + * Deletes a message from this host + * @param id Identifier of the message + * @param drop True if the message is deleted because of "dropping" + * (e.g. buffer is full) or false if it was deleted for some other reason + * (e.g. the message got delivered to final destination). This effects the + * way the removing is reported to the message listeners. + */ + public void deleteMessage(String id, boolean drop) { + this.router.deleteMessage(id, drop); + } + + /** + * Returns a string presentation of the host. + * @return Host's name + */ + public String toString() { + return name; + } + + /** + * Checks if a host is the same as this host by comparing the object + * reference + * @param otherHost The other host + * @return True if the hosts objects are the same object + */ + public boolean equals(DTNHost otherHost) { + return this == otherHost; + } + + /** + * Compares two DTNHosts by their addresses. + * @see Comparable#compareTo(Object) + */ + public int compareTo(DTNHost h) { + return this.getAddress() - h.getAddress(); + } + +} diff --git a/core/DTNSim.java b/core/DTNSim.java new file mode 100644 index 000000000..bfa3307e7 --- /dev/null +++ b/core/DTNSim.java @@ -0,0 +1,226 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; +import gui.DTNSimGUI; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import ui.DTNSimTextUI; + +/** + * Simulator's main class + */ +public class DTNSim { + /** If this option ({@value}) is given to program, batch mode and + * Text UI are used*/ + public static final String BATCH_MODE_FLAG = "-b"; + /** Delimiter for batch mode index range values (colon) */ + public static final String RANGE_DELIMETER = ":"; + + /** Name of the static method that all resettable classes must have + * @see #registerForReset(String) */ + public static final String RESET_METHOD_NAME = "reset"; + /** List of class names that should be reset between batch runs */ + private static List> resetList = new ArrayList>(); + + /** + * Starts the user interface with given arguments. + * If first argument is {@link #BATCH_MODE_FLAG}, the batch mode and text UI + * is started. The batch mode option must be followed by the number of runs, + * or a with a combination of starting run and the number of runs, + * delimited with a {@value #RANGE_DELIMETER}. Different settings from run + * arrays are used for different runs (see + * {@link Settings#setRunIndex(int)}). Following arguments are the settings + * files for the simulation run (if any). For GUI mode, the number before + * settings files (if given) is the run index to use for that run. + * @param args Command line arguments + */ + public static void main(String[] args) { + boolean batchMode = false; + int nrofRuns[] = {0,1}; + String confFiles[]; + int firstConfIndex = 0; + int guiIndex = 0; + + /* set US locale to parse decimals in consistent way */ + java.util.Locale.setDefault(java.util.Locale.US); + + if (args.length > 0) { + if (args[0].equals(BATCH_MODE_FLAG)) { + batchMode = true; + if (args.length == 1) { + firstConfIndex = 1; + } + else { + nrofRuns = parseNrofRuns(args[1]); + firstConfIndex = 2; + } + } + else { /* GUI mode */ + try { /* is there a run index for the GUI mode ? */ + guiIndex = Integer.parseInt(args[0]); + firstConfIndex = 1; + } catch (NumberFormatException e) { + firstConfIndex = 0; + } + } + confFiles = args; + } + else { + confFiles = new String[] {null}; + } + + initSettings(confFiles, firstConfIndex); + + if (batchMode) { + long startTime = System.currentTimeMillis(); + for (int i=nrofRuns[0]; i= confFiles.length) { + return; + } + + try { + Settings.init(confFiles[i]); + for (i=firstIndex+1; icore.SimClock + */ + public static void registerForReset(String className) { + Class c = null; + try { + c = Class.forName(className); + c.getMethod(RESET_METHOD_NAME); + } catch (ClassNotFoundException e) { + System.err.println("Can't register class " + className + + " for resetting; class not found"); + System.exit(-1); + + } + catch (NoSuchMethodException e) { + System.err.println("Can't register class " + className + + " for resetting; class doesn't contain resetting method"); + System.exit(-1); + } + resetList.add(c); + } + + /** + * Resets all registered classes. + */ + private static void resetForNextRun() { + for (Class c : resetList) { + try { + Method m = c.getMethod(RESET_METHOD_NAME); + m.invoke(null); + } catch (Exception e) { + System.err.println("Failed to reset class " + c.getName()); + e.printStackTrace(); + System.exit(-1); + } + } + } + + /** + * Parses the number of runs, and an optional starting run index, from a + * command line argument + * @param arg The argument to parse + * @return The first and (last_run_index - 1) in an array + */ + private static int[] parseNrofRuns(String arg) { + int val[] = {0,1}; + try { + if (arg.contains(RANGE_DELIMETER)) { + val[0] = Integer.parseInt(arg.substring(0, + arg.indexOf(RANGE_DELIMETER))) - 1; + val[1] = Integer.parseInt(arg.substring(arg. + indexOf(RANGE_DELIMETER) + 1, arg.length())); + } + else { + val[0] = 0; + val[1] = Integer.parseInt(arg); + } + } catch (NumberFormatException e) { + System.err.println("Invalid argument '" + arg + "' for" + + " number of runs"); + System.err.println("The argument must be either a single value, " + + "or a range of values (e.g., '2:5'). Note that this " + + "option has changed in version 1.3."); + System.exit(-1); + } + + if (val[0] < 0) { + System.err.println("Starting run value can't be smaller than 1"); + System.exit(-1); + } + if (val[0] >= val[1]) { + System.err.println("Starting run value can't be bigger than the " + + "last run value"); + System.exit(-1); + } + + return val; + } + + /** + * Prints text to stdout + * @param txt Text to print + */ + private static void print(String txt) { + System.out.println(txt); + } +} diff --git a/core/Debug.java b/core/Debug.java new file mode 100644 index 000000000..722b79fde --- /dev/null +++ b/core/Debug.java @@ -0,0 +1,115 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import java.io.PrintStream; + +/** + * Debugging info printer with time stamping. This class is not to be actively + * used but convenient for temporary debugging. + */ +public class Debug { + private static PrintStream out = System.out; + private static int debugLevel = 0; + private static long timingStart = -1; + private static String timingCause; + + /** + * Sets the current debug level (smaller level -> more messages) + * @param level The level to set + */ + public void setDebugLevel(int level) { + debugLevel = level; + } + + /** + * Sets print stream of debug output. + * @param outStrm The stream + */ + public void setPrintStream(PrintStream outStrm) { + out = outStrm; + } + + /** + * Prints text to output with level 0 + * @param txt text to print + */ + public static void p(String txt) { + p(txt, 0, false); + } + + /** + * Prints text to output given with level + * @param level The debug level + * @param txt text to print + */ + public static void p(String txt, int level) { + p(txt,level, false); + } + + + /** + * Debug print with a timestamp + * @param txt Text to print + * @param level Debug level + */ + public static void pt(String txt, int level) { + p(txt,level,true); + } + + /** + * Debug print with a timestamp and 0 level + * @param txt Text to print + */ + public static void pt(String txt) { + p(txt,0,true); + } + + /** + * Print text to debug output. + * @param txt The text to print + * @param level The debug level (only messages with level >= debugLevel + * are printed) + * @param timestamp If true, text is (sim)timestamped + */ + public static void p(String txt, int level, boolean timestamp) { + String time = ""; + int simTime = SimClock.getIntTime(); + if (level < debugLevel) { + return; + } + + if (timestamp) { + time = "[@"+simTime+"]"; + } + out.println("D" + time + ": " + txt); + } + + /** + * Start timing an action. + * @see #doneTiming() + */ + public static void startTiming(String cause) { + if (timingStart != -1) { + doneTiming(); + } + timingCause = cause; + timingStart = System.currentTimeMillis(); + } + + /** + * End timing an action. Information how long the action took is + * printed to debug stream. + * @see #startTiming(String) + */ + public static void doneTiming() { + long end = System.currentTimeMillis(); + long diff = end-timingStart; + if (end-timingStart > 0) + pt(timingCause + " took "+ diff/1000.0 + "s" ); + + timingStart = -1; + } +} diff --git a/core/Message.java b/core/Message.java new file mode 100644 index 000000000..60b48b75e --- /dev/null +++ b/core/Message.java @@ -0,0 +1,363 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * A message that is created at a node or passed between nodes. + */ +public class Message implements Comparable { + /** Value for infinite TTL of message */ + public static final int INFINITE_TTL = -1; + private DTNHost from; + private DTNHost to; + /** Identifier of the message */ + private String id; + /** Size of the message (bytes) */ + private int size; + /** List of nodes this message has passed */ + private List path; + /** Next unique identifier to be given */ + private static int nextUniqueId; + /** Unique ID of this message */ + private int uniqueId; + /** The time this message was received */ + private double timeReceived; + /** The time when this message was created */ + private double timeCreated; + /** Initial TTL of the message */ + private int initTtl; + + /** if a response to this message is required, this is the size of the + * response message (or 0 if no response is requested) */ + private int responseSize; + /** if this message is a response message, this is set to the request msg*/ + private Message requestMsg; + + /** Container for generic message properties. Note that all values + * stored in the properties should be immutable because only a shallow + * copy of the properties is made when replicating messages */ + private Map properties; + + /** Application ID of the application that created the message */ + private String appID; + + static { + reset(); + DTNSim.registerForReset(Message.class.getCanonicalName()); + } + + /** + * Creates a new Message. + * @param from Who the message is (originally) from + * @param to Who the message is (originally) to + * @param id Message identifier (must be unique for message but + * will be the same for all replicates of the message) + * @param size Size of the message (in bytes) + */ + public Message(DTNHost from, DTNHost to, String id, int size) { + this.from = from; + this.to = to; + this.id = id; + this.size = size; + this.path = new ArrayList(); + this.uniqueId = nextUniqueId; + + this.timeCreated = SimClock.getTime(); + this.timeReceived = this.timeCreated; + this.initTtl = INFINITE_TTL; + this.responseSize = 0; + this.requestMsg = null; + this.properties = null; + this.appID = null; + + Message.nextUniqueId++; + addNodeOnPath(from); + } + + /** + * Returns the node this message is originally from + * @return the node this message is originally from + */ + public DTNHost getFrom() { + return this.from; + } + + /** + * Returns the node this message is originally to + * @return the node this message is originally to + */ + public DTNHost getTo() { + return this.to; + } + + /** + * Returns the ID of the message + * @return The message id + */ + public String getId() { + return this.id; + } + + /** + * Returns an ID that is unique per message instance + * (different for replicates too) + * @return The unique id + */ + public int getUniqueId() { + return this.uniqueId; + } + + /** + * Returns the size of the message (in bytes) + * @return the size of the message + */ + public int getSize() { + return this.size; + } + + /** + * Adds a new node on the list of nodes this message has passed + * @param node The node to add + */ + public void addNodeOnPath(DTNHost node) { + this.path.add(node); + } + + /** + * Returns a list of nodes this message has passed so far + * @return The list as vector + */ + public List getHops() { + return this.path; + } + + /** + * Returns the amount of hops this message has passed + * @return the amount of hops this message has passed + */ + public int getHopCount() { + return this.path.size() -1; + } + + /** + * Returns the time to live (minutes) of the message or Integer.MAX_VALUE + * if the TTL is infinite. Returned value can be negative if the TTL has + * passed already. + * @return The TTL (minutes) + */ + public int getTtl() { + if (this.initTtl == INFINITE_TTL) { + return Integer.MAX_VALUE; + } + else { + return (int)( ((this.initTtl * 60) - + (SimClock.getTime()-this.timeCreated)) /60.0 ); + } + } + + + /** + * Sets the initial TTL (time-to-live) for this message. The initial + * TTL is the TTL when the original message was created. The current TTL + * is calculated based on the time of + * @param ttl The time-to-live to set + */ + public void setTtl(int ttl) { + this.initTtl = ttl; + } + + /** + * Sets the time when this message was received. + * @param time The time to set + */ + public void setReceiveTime(double time) { + this.timeReceived = time; + } + + /** + * Returns the time when this message was received + * @return The time + */ + public double getReceiveTime() { + return this.timeReceived; + } + + /** + * Returns the time when this message was created + * @return the time when this message was created + */ + public double getCreationTime() { + return this.timeCreated; + } + + /** + * If this message is a response to a request, sets the request message + * @param request The request message + */ + public void setRequest(Message request) { + this.requestMsg = request; + } + + /** + * Returns the message this message is response to or null if this is not + * a response message + * @return the message this message is response to + */ + public Message getRequest() { + return this.requestMsg; + } + + /** + * Returns true if this message is a response message + * @return true if this message is a response message + */ + public boolean isResponse() { + return this.requestMsg != null; + } + + /** + * Sets the requested response message's size. If size == 0, no response + * is requested (default) + * @param size Size of the response message + */ + public void setResponseSize(int size) { + this.responseSize = size; + } + + /** + * Returns the size of the requested response message or 0 if no response + * is requested. + * @return the size of the requested response message + */ + public int getResponseSize() { + return responseSize; + } + + /** + * Returns a string representation of the message + * @return a string representation of the message + */ + public String toString () { + return id; + } + + /** + * Deep copies message data from other message. If new fields are + * introduced to this class, most likely they should be copied here too + * (unless done in constructor). + * @param m The message where the data is copied + */ + protected void copyFrom(Message m) { + this.path = new ArrayList(m.path); + this.timeCreated = m.timeCreated; + this.responseSize = m.responseSize; + this.requestMsg = m.requestMsg; + this.initTtl = m.initTtl; + this.appID = m.appID; + + if (m.properties != null) { + Set keys = m.properties.keySet(); + for (String key : keys) { + updateProperty(key, m.getProperty(key)); + } + } + } + + /** + * Adds a generic property for this message. The key can be any string but + * it should be such that no other class accidently uses the same value. + * The value can be any object but it's good idea to store only immutable + * objects because when message is replicated, only a shallow copy of the + * properties is made. + * @param key The key which is used to lookup the value + * @param value The value to store + * @throws SimError if the message already has a value for the given key + */ + public void addProperty(String key, Object value) throws SimError { + if (this.properties != null && this.properties.containsKey(key)) { + /* check to prevent accidental name space collisions */ + throw new SimError("Message " + this + " already contains value " + + "for a key " + key); + } + + this.updateProperty(key, value); + } + + /** + * Returns an object that was stored to this message using the given + * key. If such object is not found, null is returned. + * @param key The key used to lookup the object + * @return The stored object or null if it isn't found + */ + public Object getProperty(String key) { + if (this.properties == null) { + return null; + } + return this.properties.get(key); + } + + /** + * Updates a value for an existing property. For storing the value first + * time, {@link #addProperty(String, Object)} should be used which + * checks for name space clashes. + * @param key The key which is used to lookup the value + * @param value The new value to store + */ + public void updateProperty(String key, Object value) throws SimError { + if (this.properties == null) { + /* lazy creation to prevent performance overhead for classes + that don't use the property feature */ + this.properties = new HashMap(); + } + + this.properties.put(key, value); + } + + /** + * Returns a replicate of this message (identical except for the unique id) + * @return A replicate of the message + */ + public Message replicate() { + Message m = new Message(from, to, id, size); + m.copyFrom(this); + return m; + } + + /** + * Compares two messages by their ID (alphabetically). + * @see String#compareTo(String) + */ + public int compareTo(Message m) { + return toString().compareTo(m.toString()); + } + + /** + * Resets all static fields to default values + */ + public static void reset() { + nextUniqueId = 0; + } + + /** + * @return the appID + */ + public String getAppID() { + return appID; + } + + /** + * @param appID the appID to set + */ + public void setAppID(String appID) { + this.appID = appID; + } + +} diff --git a/core/MessageListener.java b/core/MessageListener.java new file mode 100644 index 000000000..f4ee2048d --- /dev/null +++ b/core/MessageListener.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * Interface for classes that want to be informed about messages + * between hosts + * + */ +public interface MessageListener { + + /** + * Method is called when a new message is created + * @param m Message that was created + */ + public void newMessage(Message m); + + /** + * Method is called when a message's transfer is started + * @param m The message that is going to be transferred + * @param from Node where the message is transferred from + * @param to Node where the message is transferred to + */ + public void messageTransferStarted(Message m, DTNHost from, DTNHost to); + + /** + * Method is called when a message is deleted + * @param m The message that was deleted + * @param where The host where the message was deleted + * @param dropped True if the message was dropped, false if removed + */ + public void messageDeleted(Message m, DTNHost where, boolean dropped); + + /** + * Method is called when a message's transfer was aborted before + * it finished + * @param m The message that was being transferred + * @param from Node where the message was being transferred from + * @param to Node where the message was being transferred to + */ + public void messageTransferAborted(Message m, DTNHost from, DTNHost to); + + /** + * Method is called when a message is successfully transferred from + * a node to another. + * @param m The message that was transferred + * @param from Node where the message was transferred from + * @param to Node where the message was transferred to + * @param firstDelivery Was the target node final destination of the message + * and received this message for the first time. + */ + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery); +} diff --git a/core/ModuleCommunicationBus.java b/core/ModuleCommunicationBus.java new file mode 100644 index 000000000..d15177e17 --- /dev/null +++ b/core/ModuleCommunicationBus.java @@ -0,0 +1,229 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Intermodule communication bus. Works as a blackboard where modules can + * post data, subscribe to data changes and also poll for data values. + * This is fairly similar to Message class' property interface, but these + * values are shared for a node instead of message. + */ +public class ModuleCommunicationBus { + /** Initial capacity for the listener lists (instead of 10) */ + private static int INIT_CAPACITY = 3; + /** The values in the blackboard (or null if none)*/ + private HashMap values; + /** Subscribed listeners (or null if none)*/ + private HashMap> listeners; + + /** + * Constructor. + */ + public ModuleCommunicationBus() { + this.values = null; /* use lazy creation */ + this.listeners = null; + } + + /** + * Adds a new property for this node. The key can be any string but + * it should be such that no other class accidently uses the same value. + * Note that, unless the value is immutable, it can be changed by any + * object that can call {@link #getProperty}. + * @param key The key which is used to lookup the value + * @param value The value to store + * @throws SimError if there is already a value for the given key + */ + public void addProperty(String key, Object value) throws SimError { + if (this.values != null && this.values.containsKey(key)) { + /* check to prevent accidental name space collisions */ + throw new SimError("A value for the key " + key + + " already exists"); + } + + this.updateProperty(key, value); + } + + /** + * Returns an object that was stored using the given key. If such object + * is not found, null is returned. + * @param key The key used to lookup the object + * @return The stored object or null if it isn't found + */ + public Object getProperty(String key) { + if (this.values == null) { + return null; + } + return this.values.get(key); + } + + /** + * Returns true if the bus contains a value for the given key + * @param key The key for which a value's existence is checked + * @return true if the value exists, false if not + */ + public boolean containsProperty(String key) { + if (this.values == null) { + return false; + } + return this.values.containsKey(key); + } + + /** + * Updates a value for an existing property. For storing the value first + * time, {@link #addProperty(String, Object)} should be used which + * checks for name space clashes. + * @param key The key which is used to lookup the value + * @param value The new value to store + */ + public void updateProperty(String key, Object value) throws SimError { + if (this.values == null) { + /* lazy creation to prevent performance overhead for classes + that don't use the property feature */ + this.values = new HashMap(); + } + + this.values.put(key, value); + notifyListeners(key, value); + } + + /** + * Changes the Double value with given key with the value delta + * @param key The key of variable to update + * @param delta Value added to the old value + * @return The new value + * @throws SimError if the value with the given key was not a Double + */ + public double updateDouble(String key, double delta) throws SimError { + double current; + try { + current = (Double)getProperty(key); + updateProperty(key, current + delta); + } + catch (ClassCastException cce) { + throw new SimError("No Double value for key " + key); + } + catch (NullPointerException npe) { + throw new SimError("No value for key " + key); + } + + return current + delta; + } + + /** + * Returns a double value from the communication bus. + * @param key The key of the variable + * @param naValue The value to return if there is no value for the key + * @return The value of the key, or the naValue if they key was not found + * @throws SimError if the value with the given key was not a Double + */ + public double getDouble(String key, double naValue) throws SimError { + Object value = this.getProperty(key); + if (value == null) { + return naValue; + } + try { + return (Double)value; + } + catch (ClassCastException cce) { + throw new SimError("No Double value for key " + key); + } + } + + /** + * Returns an integer value from the communication bus. + * @param key The key of the variable + * @param naValue The value to return if there is no value for the key + * @return The value of the key, or the naValue if they key was not found + * @throws SimError if the value with the given key was not an Integer + */ + public int getInt(String key, int naValue) throws SimError { + Object value = this.getProperty(key); + if (value == null) { + return naValue; + } + try { + return (Integer)value; + } + catch (ClassCastException cce) { + throw new SimError("No Integer value for key " + key); + } + } + + /** + * Subscribes a module to changes of a certain value. + * @param key The key of the value whose changes the module is interested of + * @param module The module to subscribe. + */ + public void subscribe(String key, ModuleCommunicationListener module) { + if (this.listeners == null) { + /* first listener for the whole node */ + this.listeners = + new HashMap>(); + } + + List list = this.listeners.get(key); + if (list == null) { + /* first listener for this key */ + list = new ArrayList(INIT_CAPACITY); + this.listeners.put(key, list); + } + + list.add(module); + } + + /** + * Removes a notification subscription + * @param key The key for which the subscription should be removed + * @param module The module to whose subscription is removed + */ + public void unsubscribe(String key, ModuleCommunicationListener module) { + List list; + + if (this.listeners == null) { + return; /* no subscriptions */ + } + + list = this.listeners.get(key); + if (list == null) { + return; /* no subscriptions for the key */ + } + + list.remove(module); + } + + + /** + * Notifies all listeners that have subscribed to the given key + * @param key The key which got new value + * @param newValue The new value for the key + */ + private void notifyListeners(String key, Object newValue) { + List list; + + if (this.listeners == null) { + return; + } + list = this.listeners.get(key); + + if (list == null) { + return; + } + + for (ModuleCommunicationListener mcl : list) { + mcl.moduleValueChanged(key, newValue); + } + } + + + @Override + public String toString() { + return "ComBus with mapping: " + (this.values != null ? + this.values.toString() : "n/a"); + } +} diff --git a/core/ModuleCommunicationListener.java b/core/ModuleCommunicationListener.java new file mode 100644 index 000000000..2df2c14b9 --- /dev/null +++ b/core/ModuleCommunicationListener.java @@ -0,0 +1,21 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * This interface should be implemented by classes that want to be notified + * of variable value changes in ModuleCommunicationBuses. + */ +public interface ModuleCommunicationListener { + + /** + * This method is called whenever a variable, whose changes the module has + * registered to, changes. + * @param key The name of the variable + * @param newValue New value for the variable + */ + public void moduleValueChanged(String key, Object newValue); + +} diff --git a/core/MovementListener.java b/core/MovementListener.java new file mode 100644 index 000000000..8b1bbd45c --- /dev/null +++ b/core/MovementListener.java @@ -0,0 +1,29 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * Interface for classes that want to be informed about node movement. + */ +public interface MovementListener { + + /** + * Method is called every time a host receives a new destination from its + * movement model. + * @param host The host that got a new destination + * @param destination Coordinates of the destination + * @param speed Speed towards that destination + */ + public void newDestination(DTNHost host, Coord destination, double speed); + + /** + * Method is called when a host receives its initial location from + * movement model. + * @param host The host that got the location + * @param location Coordinates of the location + */ + public void initialLocation(DTNHost host, Coord location); + +} diff --git a/core/NetworkInterface.java b/core/NetworkInterface.java new file mode 100644 index 000000000..24433d7e9 --- /dev/null +++ b/core/NetworkInterface.java @@ -0,0 +1,517 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import interfaces.ConnectivityGrid; +import interfaces.ConnectivityOptimizer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import routing.util.EnergyModel; + +import util.ActivenessHandler; + +/** + * Network interface of a DTNHost. Takes care of connectivity among hosts. + */ +abstract public class NetworkInterface implements ModuleCommunicationListener { + /** transmit range -setting id ({@value})*/ + public static final String TRANSMIT_RANGE_S = "transmitRange"; + /** transmit speed -setting id ({@value})*/ + public static final String TRANSMIT_SPEED_S = "transmitSpeed"; + /** scanning interval -setting id ({@value})*/ + public static final String SCAN_INTERVAL_S = "scanInterval"; + + /** + * Sub-namespace for the network related settings in the Group namespace + * ({@value}) + */ + public static final String NET_SUB_NS = "net"; + + /** Activeness offset jitter -setting id ({@value}) + * The maximum amount of random offset for the offset */ + public static final String ACT_JITTER_S = "activenessOffsetJitter"; + + /** {@link ModuleCommunicationBus} identifier for the "scanning interval" + variable. */ + public static final String SCAN_INTERVAL_ID = "Network.scanInterval"; + /** {@link ModuleCommunicationBus} identifier for the "radio range" + variable. Value type: double */ + public static final String RANGE_ID = "Network.radioRange"; + /** {@link ModuleCommunicationBus} identifier for the "transmission speed" + variable. Value type: integer */ + public static final String SPEED_ID = "Network.speed"; + + private static final int CON_UP = 1; + private static final int CON_DOWN = 2; + + private static Random rng; + protected DTNHost host = null; + + protected String interfacetype; + protected List connections; // connected hosts + private List cListeners = null; // list of listeners + private int address; // network interface address + protected double transmitRange; + protected double oldTransmitRange; + protected int transmitSpeed; + protected ConnectivityOptimizer optimizer = null; + /** scanning interval, or 0.0 if n/a */ + private double scanInterval; + private double lastScanTime; + + /** activeness handler for the node group */ + private ActivenessHandler ah; + /** maximum activeness jitter value for the node group */ + private int activenessJitterMax; + /** this interface's activeness jitter value */ + private int activenessJitterValue; + + static { + DTNSim.registerForReset(NetworkInterface.class.getCanonicalName()); + reset(); + } + + /** + * Resets the static fields of the class + */ + public static void reset() { + rng = new Random(0); + } + + /** + * For creating an empty class of a specific type + */ + public NetworkInterface(Settings s) { + this.interfacetype = s.getNameSpace(); + this.connections = new ArrayList(); + + this.transmitRange = s.getDouble(TRANSMIT_RANGE_S); + this.transmitSpeed = s.getInt(TRANSMIT_SPEED_S); + ensurePositiveValue(transmitRange, TRANSMIT_RANGE_S); + ensurePositiveValue(transmitSpeed, TRANSMIT_SPEED_S); + } + + /** + * For creating an empty class of a specific type + */ + public NetworkInterface() { + this.interfacetype = "Default"; + this.connections = new ArrayList(); + } + + /** + * copy constructor + */ + public NetworkInterface(NetworkInterface ni) { + this.connections = new ArrayList(); + this.host = ni.host; + this.cListeners = ni.cListeners; + this.interfacetype = ni.interfacetype; + this.transmitRange = ni.transmitRange; + this.transmitSpeed = ni.transmitSpeed; + this.scanInterval = ni.scanInterval; + this.ah = ni.ah; + + if (ni.activenessJitterMax > 0) { + this.activenessJitterValue = rng.nextInt(ni.activenessJitterMax); + } else { + this.activenessJitterValue = 0; + } + + this.scanInterval = ni.scanInterval; + /* draw lastScanTime of [0 -- scanInterval] */ + this.lastScanTime = rng.nextDouble() * this.scanInterval; + } + + /** + * Replication function + */ + abstract public NetworkInterface replicate(); + + /** + * For setting the host - needed when a prototype is copied for several + * hosts + * @param host The host where the network interface is + */ + public void setHost(DTNHost host) { + this.host = host; + ModuleCommunicationBus comBus = host.getComBus(); + + if (!comBus.containsProperty(SCAN_INTERVAL_ID) && + !comBus.containsProperty(RANGE_ID)) { + /* add properties and subscriptions only for the 1st interface */ + /* TODO: support for multiple interfaces */ + comBus.addProperty(SCAN_INTERVAL_ID, this.scanInterval); + comBus.addProperty(RANGE_ID, this.transmitRange); + comBus.addProperty(SPEED_ID, this.transmitSpeed); + comBus.subscribe(SCAN_INTERVAL_ID, this); + comBus.subscribe(RANGE_ID, this); + comBus.subscribe(SPEED_ID, this); + } + + if (transmitRange > 0) { + optimizer = ConnectivityGrid.ConnectivityGridFactory( + this.interfacetype.hashCode(), transmitRange); + optimizer.addInterface(this); + } else { + optimizer = null; + } + } + + /** + * Sets group-based settings for the network interface + * @param s The settings object using the right group namespace + */ + public void setGroupSettings(Settings s) { + s.setSubNameSpace(NET_SUB_NS); + ah = new ActivenessHandler(s); + + if (s.contains(SCAN_INTERVAL_S)) { + this.scanInterval = s.getDouble(SCAN_INTERVAL_S); + } else { + this.scanInterval = 0; + } + if (s.contains(ACT_JITTER_S)) { + this.activenessJitterMax = s.getInt(ACT_JITTER_S); + } + + s.restoreSubNameSpace(); + } + + /** + * For checking what interface type this interface is + */ + public String getInterfaceType() { + return interfacetype; + } + + /** + * For setting the connectionListeners + * @param cListeners List of connection listeners + */ + public void setClisteners(List cListeners) { + this.cListeners = cListeners; + } + + /** + * Returns the transmit range of this network layer + * @return the transmit range + */ + public double getTransmitRange() { + return this.transmitRange; + } + + /** + * Returns the transmit speed of this network layer with respect to the + * another network interface + * @param ni The other network interface + * @return the transmit speed + */ + public int getTransmitSpeed(NetworkInterface ni) { + return this.transmitSpeed; + } + + /** + * Returns a list of currently connected connections + * @return a list of currently connected connections + */ + public List getConnections() { + return this.connections; + } + + /** + * Returns true if the interface is on at the moment (false if not) + * @return true if the interface is on at the moment (false if not) + */ + public boolean isActive() { + boolean active; + + if (ah == null) { + return true; /* no handler: always active */ + } + + active = ah.isActive(this.activenessJitterValue); + + if (active && host.getComBus().getDouble(EnergyModel.ENERGY_VALUE_ID, + 1) <= 0) { + /* TODO: better way to check battery level */ + /* no battery -> inactive */ + active = false; + } + + if (active == false && this.transmitRange > 0) { + /* not active -> make range 0 */ + this.oldTransmitRange = this.transmitRange; + host.getComBus().updateProperty(RANGE_ID, 0.0); + } else if (active == true && this.transmitRange == 0.0) { + /* active, but range == 0 -> restore range */ + host.getComBus().updateProperty(RANGE_ID, + this.oldTransmitRange); + } + return active; + } + + /** + * Checks if this interface is currently in the scanning mode + * @return True if the interface is scanning; false if not + */ + public boolean isScanning() { + double simTime = SimClock.getTime(); + + if (!isActive()) { + return false; + } + + if (scanInterval > 0.0) { + if (simTime < lastScanTime) { + return false; /* not time for the first scan */ + } + else if (simTime > lastScanTime + scanInterval) { + lastScanTime = simTime; /* time to start the next scan round */ + return true; + } + else if (simTime != lastScanTime ){ + return false; /* not in the scan round */ + } + } + /* interval == 0 or still in the same scan round as when + last time asked */ + return true; + } + + /** + * Returns true if one of the connections of this interface is transferring + * data + * @return true if the interface transferring + */ + public boolean isTransferring() { + for (Connection c : this.connections) { + if (c.isTransferring()) { + return true; + } + } + return false; + } + + /** + * Connects the interface to another interface. + * + * Overload this in a derived class. Check the requirements for + * the connection to work in the derived class, then call + * connect(Connection, NetworkInterface) for the actual connection. + * @param anotherInterface The interface to connect to + */ + public abstract void connect(NetworkInterface anotherInterface); + + /** + * Connects this host to another host. The derived class should check + * that all pre-requisites for making a connection are satisfied before + * actually connecting. + * @param con The new connection object + * @param anotherInterface The interface to connect to + */ + protected void connect(Connection con, NetworkInterface anotherInterface) { + this.connections.add(con); + notifyConnectionListeners(CON_UP, anotherInterface.getHost()); + + // set up bidirectional connection + anotherInterface.getConnections().add(con); + + // inform routers about the connection + this.host.connectionUp(con); + anotherInterface.getHost().connectionUp(con); + } + + /** + * Disconnects this host from another host. The derived class should + * make the decision whether to disconnect or not + * @param con The connection to tear down + */ + protected void disconnect(Connection con, + NetworkInterface anotherInterface) { + con.setUpState(false); + notifyConnectionListeners(CON_DOWN, anotherInterface.getHost()); + + // tear down bidirectional connection + if (!anotherInterface.getConnections().remove(con)) { + throw new SimError("No connection " + con + " found in " + + anotherInterface); + } + + this.host.connectionDown(con); + anotherInterface.getHost().connectionDown(con); + } + + /** + * Returns true if another interface is within radio range of this interface + * and this interface is also within radio range of the another interface. + * @param anotherInterface The another interface + * @return True if the interface is within range, false if not + */ + protected boolean isWithinRange(NetworkInterface anotherInterface) { + double smallerRange = anotherInterface.getTransmitRange(); + double myRange = getTransmitRange(); + if (myRange < smallerRange) { + smallerRange = myRange; + } + + return this.host.getLocation().distance( + anotherInterface.getHost().getLocation()) <= smallerRange; + } + + /** + * Returns true if the given NetworkInterface is connected to this host. + * @param netinterface The other NetworkInterface to check + * @return True if the two hosts are connected + */ + protected boolean isConnected(NetworkInterface netinterface) { + for (int i = 0; i < this.connections.size(); i++) { + if (this.connections.get(i).getOtherInterface(this) == + netinterface) { + return true; + } + } + return false; + } + + /** + * Makes sure that a value is positive + * @param value Value to check + * @param settingName Name of the setting (for error's message) + * @throws SettingsError if the value was not positive + */ + protected void ensurePositiveValue(double value, String settingName) { + if (value < 0) { + throw new SettingsError("Negative value (" + value + + ") not accepted for setting " + settingName); + } + } + + /** + * Updates the state of current connections (ie tears down connections + * that are out of range, recalculates transmission speeds etc.). + */ + abstract public void update(); + + /** + * Notifies all the connection listeners about a change in connections. + * @param type Type of the change (e.g. {@link #CON_DOWN} ) + * @param otherHost The other host on the other end of the connection. + */ + private void notifyConnectionListeners(int type, DTNHost otherHost) { + if (this.cListeners == null) { + return; + } + for (ConnectionListener cl : this.cListeners) { + switch (type) { + case CON_UP: + cl.hostsConnected(this.host, otherHost); + break; + case CON_DOWN: + cl.hostsDisconnected(this.host, otherHost); + break; + default: + assert false : type; // invalid type code + } + } + } + + /** + * This method is called by the {@link ModuleCommunicationBus} when/if + * someone changes the scanning interval, transmit speed, or range + * @param key Identifier of the changed value + * @param newValue New value for the variable + */ + public void moduleValueChanged(String key, Object newValue) { + if (key.equals(SCAN_INTERVAL_ID)) { + this.scanInterval = (Double)newValue; + } + else if (key.equals(SPEED_ID)) { + this.transmitSpeed = (Integer)newValue; + } + else if (key.equals(RANGE_ID)) { + this.transmitRange = (Double)newValue; + } + else { + throw new SimError("Unexpected combus ID " + key); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * (cf. {@link #connect(NetworkInterface)}). + * @param anotherInterface The interface to create the connection to + */ + public abstract void createConnection(NetworkInterface anotherInterface); + + /** + * Disconnect a connection between this and another host. + * @param anotherInterface The other host's network interface to disconnect + * from this host + */ + public void destroyConnection(NetworkInterface anotherInterface) { + DTNHost anotherHost = anotherInterface.getHost(); + for (int i=0; i < this.connections.size(); i++) { + if (this.connections.get(i).getOtherNode(this.host) == anotherHost){ + removeConnectionByIndex(i, anotherInterface); + } + } + // the connection didn't exist, do nothing + } + + /** + * Removes a connection by its position (index) in the connections array + * of the interface + * @param index The array index of the connection to be removed + * @param anotherInterface The interface of the other host + */ + private void removeConnectionByIndex(int index, + NetworkInterface anotherInterface) { + Connection con = this.connections.get(index); + DTNHost anotherNode = anotherInterface.getHost(); + con.setUpState(false); + notifyConnectionListeners(CON_DOWN, anotherNode); + + // tear down bidirectional connection + if (!anotherInterface.getConnections().remove(con)) { + throw new SimError("No connection " + con + " found in " + + anotherNode); + } + + this.host.connectionDown(con); + anotherNode.connectionDown(con); + + connections.remove(index); + } + + /** + * Returns the DTNHost of this interface + */ + public DTNHost getHost() { + return host; + } + + /** + * Returns the current location of the host of this interface. + * @return The location + */ + public Coord getLocation() { + return host.getLocation(); + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return this.address + " of " + this.host + + ". Connections: " + this.connections; + } + +} diff --git a/core/Settings.java b/core/Settings.java new file mode 100644 index 000000000..f39794f52 --- /dev/null +++ b/core/Settings.java @@ -0,0 +1,885 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Properties; +import java.util.Scanner; +import java.util.Set; +import java.util.Stack; + +import util.Range; + +/** + * Interface for simulation settings stored in setting file(s). Settings + * class should be initialized before using (with {@link #init(String)}). If + * Settings isn't initialized, only settings in {@link #DEF_SETTINGS_FILE} + * are read. Normally, after initialization, settings in the given file can + * override any settings defined in the default settings file and/or define + * new settings. + *

All settings are key-value pairs. For parsing details see + * {@link java.util.Properties#getProperty(String)}. Value can be a single + * value or comma separated list of values. With CSV values, CSV methods + * must be used (e.g. {@link #getCsvInts(String, int)}). Setting value should + * not start and end with a bracket since those are reserved for run-specific + * values (see {@link #setRunIndex(int)}). In file paths directory separator + * should always be forward slash ("/"). + *

+ */ +public class Settings { + /** properties object where the setting files are read into */ + protected static Properties props; + /** file name of the default settings file ({@value}) */ + public static final String DEF_SETTINGS_FILE ="default_settings.txt"; + + /** + * Setting to define the file name where all read settings are written + * ({@value}. If set to an empty string, standard output is used. + * By default setting are not written anywhere. + */ + public static final String SETTING_OUTPUT_S = "Settings.output"; + + /** delimiter for requested values in strings ({@value}) + * @see #valueFillString(String) */ + public static final String FILL_DELIMITER = "%%"; + + /** Stream where all read settings are written to */ + private static PrintStream out = null; + private static Set writtenSettings = new HashSet(); + + /** run index for run-specific settings */ + private static int runIndex = 0; + private String namespace = null; // namespace to look the settings from + private String secondaryNamespace = null; + private Stack oldNamespaces; + private Stack secondaryNamespaces; + + /** + * Creates a setting object with a namespace. Namespace is the prefix + * of the all subsequent setting requests. + * @param namespace Namespace to use + */ + public Settings(String namespace) { + this.oldNamespaces = new Stack(); + this.secondaryNamespaces = new Stack(); + setNameSpace(namespace); + } + + /** + * Create a setting object without namespace. All setting requests must + * be prefixed with a valid namespace (e.g. "Report.nrofReports"). + */ + public Settings() { + this(null); + } + + /** + * Sets the run index for the settings (only has effect on settings with + * run array). A run array can be defined with syntax
+ * [settingFor1stRun ; settingFor2ndRun ; SettingFor3rdRun] + *
I.e. settings are put in brackets and delimited with semicolon. + * First run's setting is returned when index is 0, second when index is + * 1 etc. If run index is bigger than run array's length, indexing wraps + * around in run array (i.e. return value is the value at index + * runIndex % arrayLength). + * To disable whole run-index-thing, set index to value smaller than + * zero (e.g. -1). When disabled, run-arrays are returned as normal values, + * including the brackets. + * @param index The run index to use for subsequent settings calls, or + * -1 to disable run indexing + */ + public static void setRunIndex(int index) { + runIndex = index; + writtenSettings.clear(); + } + + /** + * Checks that the given integer array contains a valid range. I.e., + * the length of the array must be two and + * first_value <= second_value. + * @param range The range array + * @param sname Name of the setting (for error messages) + * @throws SettingsError If the given array didn't qualify as a range + */ + public void assertValidRange(int range[], String sname) + throws SettingsError { + if (range.length != 2) { + throw new SettingsError("Range setting " + + getFullPropertyName(sname) + + " should contain only two comma separated integer values"); + } + if (range[0] > range[1]) { + throw new SettingsError("Range setting's " + + getFullPropertyName(sname) + + " first value should be smaller or equal to second value"); + } + } + + /** + * Makes sure that the given settings value is positive + * @param value Value to check + * @param settingName Name of the setting (for error's message) + * @throws SettingsError if the value was not positive + */ + public void ensurePositiveValue(double value, String settingName) { + if (value < 0) { + throw new SettingsError("Negative value (" + value + + ") not accepted for setting " + settingName); + } + } + + /** + * Sets the namespace to something else than the current namespace. + * This change can be reverted using {@link #restoreNameSpace()} + * @param namespace The new namespace + */ + public void setNameSpace(String namespace) { + this.oldNamespaces.push(this.namespace); + this.namespace = namespace; + } + + /** + * Appends the given namespace to the the current namespace, + * for both the primary and secondary namespace . + * This change can be reverted using {@link #restoreNameSpace()} and + * {@link #restoreSecondaryNamespace()}. + * @param namespace The new namespace to append + */ + public void setSubNameSpace(String namespace) { + this.oldNamespaces.push(this.namespace); + this.namespace = this.namespace + "." + namespace; + this.secondaryNamespaces.push(this.secondaryNamespace); + this.secondaryNamespace = this.secondaryNamespace + "." + namespace; + } + + /** + * Returns full (namespace prefixed) property name for a setting. + * @param setting The name of the setting + * @return The setting name prefixed with fully qualified name of the + * namespace where the requested setting would be retrieved from or null + * if that setting is not found from any of the current namespace(s) + */ + public String getFullPropertyName(String setting) { + if (!contains(setting)) { + return null; + } + + if (props.getProperty(getFullPropertyName(setting, false)) != null) { + return getFullPropertyName(setting, false); + } + + // not found from primary, but Settings contains -> must be from 2ndary + else return getFullPropertyName(setting, true); + } + + /** + * Returns the namespace of the settings object + * @return the namespace of the settings object + */ + public String getNameSpace() { + return this.namespace; + } + + /** + * Returns the secondary namespace of the settings object + * @return the secondary namespace of the settings object + */ + public String getSecondaryNameSpace() { + return this.secondaryNamespace; + } + + /** + * Sets a secondary namespace where a setting is searched from if it + * isn't found from the primary namespace. Secondary namespace can + * be used e.g. as a "default" space where the settings are looked from + * if no specific setting is set. + * This change can be reverted using {@link #restoreSecondaryNamespace()} + * @param namespace The new secondary namespace or null if secondary + * namespace is not used (default behavior) + */ + public void setSecondaryNamespace(String namespace) { + this.secondaryNamespaces.push(this.secondaryNamespace); + this.secondaryNamespace = namespace; + } + + /** + * Restores the namespace that was in use before a call to setNameSpace + * @see #setNameSpace(String) + */ + public void restoreNameSpace() { + this.namespace = this.oldNamespaces.pop(); + } + + /** + * Restores the secondary namespace that was in use before a call to + * setSecondaryNameSpace + * @see #setSecondaryNamespace(String) + */ + public void restoreSecondaryNamespace() { + this.secondaryNamespace = this.secondaryNamespaces.pop(); + } + + /** + * Reverts the change made with {@link #setSubNameSpace(String)}, i.e., + * restores both the primary and secondary namespace. + */ + public void restoreSubNameSpace() { + restoreNameSpace(); + restoreSecondaryNamespace(); + } + + /** + * Initializes the settings all Settings objects will use. This should be + * called before any setting requests. Subsequent calls replace all + * old settings and then Settings contains only the new settings. + * The file {@link #DEF_SETTINGS_FILE}, if exists, is always read. + * @param propFile Path to the property file where additional settings + * are read from or null if no additional settings files are needed. + * @throws SettingsError If loading the settings file(s) didn't succeed + */ + public static void init(String propFile) throws SettingsError { + String outFile; + try { + if (new File(DEF_SETTINGS_FILE).exists()) { + Properties defProperties = new Properties(); + defProperties.load(new FileInputStream(DEF_SETTINGS_FILE)); + props = new Properties(defProperties); + } + else { + props = new Properties(); + } + if (propFile != null) { + props.load(new FileInputStream(propFile)); + } + } catch (IOException e) { + throw new SettingsError(e); + } + + outFile = props.getProperty(SETTING_OUTPUT_S); + if (outFile != null) { + if (outFile.trim().length() == 0) { + out = System.out; + } else { + try { + out = new PrintStream(new File(outFile)); + } catch (FileNotFoundException e) { + throw new SettingsError("Can't open Settings output file:" + + e); + } + } + } + } + + /** + * Reads another settings file and adds the key-value pairs to the current + * settings overriding any values that already existed with the same keys. + * @param propFile Path to the property file + * @throws SettingsError If loading the settings file didn't succeed + * @see #init(String) + */ + public static void addSettings(String propFile) throws SettingsError { + try { + props.load(new FileInputStream(propFile)); + } catch (IOException e) { + throw new SettingsError(e); + } + } + + /** + * Writes the given setting string to the settings output (if any) + * @param setting The string to write + */ + private static void outputSetting(String setting) { + if (out != null && !writtenSettings.contains(setting)) { + if (writtenSettings.size() == 0) { + out.println("# Settings for run " + (runIndex + 1)); + } + out.println(setting); + writtenSettings.add(setting); + } + } + + /** + * Returns true if a setting with defined name (in the current namespace + * or secondary namespace if such is set) exists and has some value + * (not just white space) + * @param name Name of the setting to check + * @return True if the setting exists, false if not + */ + public boolean contains(String name) { + try { + String value = getSetting(name); + if (value == null) { + return false; + } + + else return value.trim().length() > 0; + } + catch (SettingsError e) { + return false; // didn't find the setting + } + } + + /** + * Returns full (namespace prefixed) property name for setting. + * @param name Name of the settings + * @param secondary If true, the secondary namespace is used. + * @return full (prefixed with current namespace) property name for setting + */ + private String getFullPropertyName(String name, boolean secondary) { + String usedNamespace = (secondary ? secondaryNamespace : namespace); + + if (usedNamespace != null) { + return usedNamespace + "." + name; + } + else { + return name; + } + } + + /** + * Returns a String-valued setting. Setting is first looked from the + * namespace that is set (if any) and then from the secondary namespace + * (if any). All other getters use this method as their first step too + * (so all getters may throw SettingsError and look from both namespaces). + * @param name Name of the setting to get + * @return The contents of the setting in a String + * @throws SettingsError if the setting is not found from either one of + * the namespaces + */ + public String getSetting(String name) { + String fullPropName; + if (props == null) { + init(null); + } + fullPropName = getFullPropertyName(name, false); + String value = props.getProperty(fullPropName); + + if (value != null) { // found value, check if run setting can be parsed + value = parseRunSetting(value.trim()); + } + + if ((value == null || value.length() == 0) && + this.secondaryNamespace != null) { + // try secondary namespace if the value wasn't found from primary + fullPropName = getFullPropertyName(name, true); + value = props.getProperty(fullPropName); + + if (value != null) { + value = parseRunSetting(value.trim()); + } + } + + if (value == null || value.length() == 0) { + throw new SettingsError("Can't find setting " + + getPropertyNamesString(name)); + } + + outputSetting(fullPropName + " = " + value); + return value; + } + + /** + * Returns the given setting if it exists, or defaultValue if the setting + * does not exist + * @param name The name of the setting + * @param defaultValue The value to return if the given setting didn't exist + * @return The setting value or the default value if the setting didn't + * exist + */ + public String getSetting(String name, String defaultValue) { + if (!contains(name)) { + return defaultValue; + } else { + return getSetting(name); + } + } + + /** + * Parses run-specific settings from a String value + * @param value The String to parse + * @return The runIndex % arrayLength'th value of the run array + */ + private static String parseRunSetting(String value) { + final String RUN_ARRAY_START = "["; + final String RUN_ARRAY_END = "]"; + final String RUN_ARRAY_DELIM = ";"; + final int MIN_LENGTH = 3; // minimum run is one value. e.g. "[v]" + + if (!value.startsWith(RUN_ARRAY_START) || + !value.endsWith(RUN_ARRAY_END) || + runIndex < 0 || + value.length() < MIN_LENGTH) { + return value; // standard format setting -> return + } + + value = value.substring(1,value.length()-1); // remove brackets + String[] valueArr = value.split(RUN_ARRAY_DELIM); + int arrIndex = runIndex % valueArr.length; + value = valueArr[arrIndex].trim(); + + return value; + } + + /** + * Returns the setting name appended to namespace name(s) on a String + * (for error messages) + * @param name Name of the setting + * @return the setting name appended to namespace name(s) on a String + */ + private String getPropertyNamesString(String name) { + if (this.secondaryNamespace != null) { + return "'"+ this.secondaryNamespace + "." + name + "' nor '" + + this.namespace + "." + name + "'"; + } + else if (this.namespace != null){ + return "'" + this.namespace + "." + name + "'"; + } + else { + return "'" + name + "'"; + } + } + + /** + * Returns a double-valued setting + * @param name Name of the setting to get + * @return Value of the setting as a double + */ + public double getDouble(String name) { + return parseDouble(getSetting(name), name); + } + + /** + * Returns a double-valued setting, or the default value if the given + * setting does not exist + * @param name Name of the setting to get + * @param defaultValue The value to return if the setting doesn't exist + * @return Value of the setting as a double (or the default value) + */ + public double getDouble(String name, double defaultValue) { + return parseDouble(getSetting(name, ""+defaultValue), name); + } + + /** + * Parses a double value from a String valued setting. Supports + * kilo (k), mega (M) and giga (G) suffixes. + * @param value String value to parse + * @param setting The setting where this value was from (for error msgs) + * @return The value as a double + * @throws SettingsError if the value wasn't a numeric value + * (or the suffix wasn't recognized) + */ + private double parseDouble(String value, String setting) { + double number; + int multiplier = 1; + + if (value.endsWith("k")) { + multiplier = 1000; + } + else if (value.endsWith("M")) { + multiplier = 1000000; + } + else if (value.endsWith("G")) { + multiplier = 1000000000; + } + + if (multiplier > 1) { // take the suffix away before parsing + value = value.substring(0,value.length()-1); + } + + try { + number = Double.parseDouble(value) * multiplier; + } catch (NumberFormatException e) { + throw new SettingsError("Invalid numeric setting '" + value + + "' for '" + setting +"'\n" + e.getMessage()); + } + return number; + } + + /** + * Returns a CSV setting. Value part of the setting must be a list of + * comma separated values. Whitespace between values is trimmed away. + * @param name Name of the setting + * @return Array of values that were comma-separated + * @throws SettingsError if something went wrong with reading + */ + public String[] getCsvSetting(String name) { + ArrayList values = new ArrayList(); + String csv = getSetting(name); + Scanner s = new Scanner(csv); + s.useDelimiter(","); + + while (s.hasNext()) { + values.add(s.next().trim()); + } + + return values.toArray(new String[0]); + } + + /** + * Returns a CSV setting containing expected amount of values. + * Value part of the setting must be a list of + * comma separated values. Whitespace between values is trimmed away. + * @param name Name of the setting + * @param expectedCount how many values are expected + * @return Array of values that were comma-separated + * @throws SettingsError if something went wrong with reading or didn't + * read the expected amount of values. + */ + public String[] getCsvSetting(String name, int expectedCount) { + String[] values = getCsvSetting(name); + + if (values.length != expectedCount) { + throw new SettingsError("Read unexpected amount (" + values.length + + ") of comma separated values for setting '" + + name + "' (expected " + expectedCount + ")"); + } + + return values; + } + + /** + * Returns an array of CSV setting double values containing expected + * amount of values. + * @param name Name of the setting + * @param expectedCount how many values are expected + * @return Array of values that were comma-separated + * @see #getCsvSetting(String, int) + */ + public double[] getCsvDoubles(String name, int expectedCount) { + return parseDoubles(getCsvSetting(name, expectedCount),name); + } + + /** + * Returns an array of CSV setting double values. + * @param name Name of the setting + * @return Array of values that were comma-separated + * @see #getCsvSetting(String) + */ + public double[] getCsvDoubles(String name) { + return parseDoubles(getCsvSetting(name), name); + } + + /** + * Parses a double array out of a String array + * @param strings The array of strings containing double values + * @param name Name of the setting + * @return Array of double values parsed from the string values + */ + private double[] parseDoubles(String[] strings, String name) { + double[] values = new double[strings.length]; + for (int i=0; i[] argsClass = {Settings.class}; + Object[] args = {this}; + + return loadObject(className, argsClass, args); + } + + /** + * Creates (and dynamically loads the class of) an object using the + * constructor without any parameters. + * @param className Name of the class of the object + * @return Initialized object + * @throws SettingsError if object couldn't be created + */ + public Object createObject(String className) { + return loadObject(className, null, null); + } + + /** + * Dynamically loads and creates an object. + * @param className Name of the class of the object + * @param argsClass Class(es) of the argument(s) or null if no-argument + * constructor should be called + * @param args Argument(s) + * @return The new object + * @throws SettingsError if object couldn't be created + */ + private Object loadObject(String className, Class[] argsClass, + Object[] args) { + Object o = null; + Class objClass = getClass(className); + Constructor constructor; + + try { + if (argsClass != null) { // use a specific constructor + constructor = objClass.getConstructor((Class[])argsClass); + o = constructor.newInstance(args); + } + else { // call empty constructor + o = objClass.newInstance(); + } + } catch (SecurityException e) { + e.printStackTrace(); + throw new SettingsError("Fatal exception " + e, e); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + throw new SettingsError("Fatal exception " + e, e); + } catch (NoSuchMethodException e) { + throw new SettingsError("Class '" + className + + "' doesn't have a suitable constructor", e); + } catch (InstantiationException e) { + throw new SettingsError("Can't create an instance of '" + + className + "'", e); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new SettingsError("Fatal exception " + e, e); + } catch (InvocationTargetException e) { + // this exception occurs if initialization of the object fails + if (e.getCause() instanceof SettingsError) { + throw (SettingsError)e.getCause(); + } + else { + e.printStackTrace(); + throw new SimError("Couldn't create settings-accepting object"+ + " for '" + className + "'\n" + "cause: " + e.getCause(), e); + } + } + + return o; + } + + /** + * Returns a Class object for the name of class of throws SettingsError + * if such class wasn't found. + * @param name Full name of the class (including package name) + * @return A Class object of that class + * @throws SettingsError if such class wasn't found or couldn't be loaded + */ + private Class getClass(String name) { + String className = name; + Class c; + + try { + c = Class.forName(className); + } catch (ClassNotFoundException e) { + throw new SettingsError("Couldn't find class '" + className + "'"+ + "\n" + e.getMessage(),e); + } + + return c; + } + + /** + * Fills a String formatted in a special way with values from Settings. + * String can contain (fully qualified) setting names surrounded by + * delimiters (see {@link #FILL_DELIMITER}). Values for those settings + * are retrieved and filled in the place of place holders. + * @param input The input string that may contain value requests + * @return A string filled with requested values (or the original string + * if no requests were found) + * @throws SettingsError if such settings were not found + */ + public String valueFillString(String input) { + if (!input.contains(FILL_DELIMITER)) { + return input; // nothing to fill + } + + Settings s = new Settings(); // don't use any namespace + String result = ""; + Scanner scan = new Scanner(input); + scan.useDelimiter(FILL_DELIMITER); + + if (input.startsWith(FILL_DELIMITER)) { + result += s.getSetting(scan.next()); + } + + while(scan.hasNext()) { + result += scan.next(); + if (!scan.hasNext()) { + break; + } + result += s.getSetting(scan.next()); + } + + return result; + } + + /** + * Returns a String representation of the stored settings + * @return a String representation of the stored settings + */ + public String toString() { + return props.toString(); + } + +} \ No newline at end of file diff --git a/core/SettingsError.java b/core/SettingsError.java new file mode 100644 index 000000000..5f4e42a18 --- /dev/null +++ b/core/SettingsError.java @@ -0,0 +1,25 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * Settings related error + * + */ +public class SettingsError extends SimError { + + public SettingsError(String cause) { + super(cause); + } + + public SettingsError(String cause, Exception e) { + super(cause,e); + } + + public SettingsError(Exception e) { + super(e); + } + +} diff --git a/core/SimClock.java b/core/SimClock.java new file mode 100644 index 000000000..d67c5fde2 --- /dev/null +++ b/core/SimClock.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * Wall clock for checking the simulation time. + */ +public class SimClock { + private static double clockTime = 0.0; + private static SimClock clock = null; + + private SimClock() {} + + static { + DTNSim.registerForReset(SimClock.class.getCanonicalName()); + reset(); + } + + /** + * Get the instance of the class that can also change the time. + * @return The instance of this clock + */ + public static SimClock getInstance() { + if (clock == null) { + clock = new SimClock(); + } + return clock; + } + + /** + * Returns the current time (seconds since start) + * @return Time as a double + */ + public static double getTime() { + return clockTime; + } + + /** + * Returns the current time rounded to the nearest integer + * @return Time as integer + */ + public static int getIntTime() { + return (int)Math.round(clockTime); + } + + /** + * Returns a string presentation of the sim time shown with the given amount + * of decimals + * @param decimals The number of decimals to show + * @return The sim time + */ + public static String getFormattedTime(int decimals) { + return String.format("%." + decimals + "f", clockTime); + } + + /** + * Advances the time by n seconds + * @param time Nrof seconds to increase the time + */ + public void advance(double time) { + clockTime += time; + } + + /** + * Sets the time of the clock. + * @param time the time to set + */ + public void setTime(double time) { + clockTime = time; + } + + /** + * Returns the current simulation time in a string + * @return the current simulation time in a string + */ + public String toString() { + return "SimTime: " + clockTime; + } + + /** + * Resets the static fields of the class + */ + public static void reset() { + clockTime = 0; + } +} diff --git a/core/SimError.java b/core/SimError.java new file mode 100644 index 000000000..fdccc0500 --- /dev/null +++ b/core/SimError.java @@ -0,0 +1,32 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +/** + * Error in the simulation + * + */ +public class SimError extends AssertionError { + private Exception e; + + public SimError(String cause) { + super(cause); + e = null; + } + + public SimError(String cause, Exception e) { + super(cause); + this.e = e; + } + + public SimError(Exception e) { + this(e.getMessage(),e); + } + + public Exception getException() { + return e; + } + +} diff --git a/core/SimScenario.java b/core/SimScenario.java new file mode 100644 index 000000000..b2fcf5767 --- /dev/null +++ b/core/SimScenario.java @@ -0,0 +1,415 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import input.EventQueue; +import input.EventQueueHandler; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import movement.MapBasedMovement; +import movement.MovementModel; +import movement.map.SimMap; +import routing.MessageRouter; + +/** + * A simulation scenario used for getting and storing the settings of a + * simulation run. + */ +public class SimScenario implements Serializable { + + /** a way to get a hold of this... */ + private static SimScenario myinstance=null; + + /** namespace of scenario settings ({@value})*/ + public static final String SCENARIO_NS = "Scenario"; + /** number of host groups -setting id ({@value})*/ + public static final String NROF_GROUPS_S = "nrofHostGroups"; + /** number of interface types -setting id ({@value})*/ + public static final String NROF_INTTYPES_S = "nrofInterfaceTypes"; + /** scenario name -setting id ({@value})*/ + public static final String NAME_S = "name"; + /** end time -setting id ({@value})*/ + public static final String END_TIME_S = "endTime"; + /** update interval -setting id ({@value})*/ + public static final String UP_INT_S = "updateInterval"; + /** simulate connections -setting id ({@value})*/ + public static final String SIM_CON_S = "simulateConnections"; + + /** namespace for interface type settings ({@value}) */ + public static final String INTTYPE_NS = "Interface"; + /** interface type -setting id ({@value}) */ + public static final String INTTYPE_S = "type"; + /** interface name -setting id ({@value}) */ + public static final String INTNAME_S = "name"; + + /** namespace for application type settings ({@value}) */ + public static final String APPTYPE_NS = "Application"; + /** application type -setting id ({@value}) */ + public static final String APPTYPE_S = "type"; + /** setting name for the number of applications */ + public static final String APPCOUNT_S = "nrofApplications"; + + /** namespace for host group settings ({@value})*/ + public static final String GROUP_NS = "Group"; + /** group id -setting id ({@value})*/ + public static final String GROUP_ID_S = "groupID"; + /** number of hosts in the group -setting id ({@value})*/ + public static final String NROF_HOSTS_S = "nrofHosts"; + /** movement model class -setting id ({@value})*/ + public static final String MOVEMENT_MODEL_S = "movementModel"; + /** router class -setting id ({@value})*/ + public static final String ROUTER_S = "router"; + /** number of interfaces in the group -setting id ({@value})*/ + public static final String NROF_INTERF_S = "nrofInterfaces"; + /** interface name in the group -setting id ({@value})*/ + public static final String INTERFACENAME_S = "interface"; + /** application name in the group -setting id ({@value})*/ + public static final String GAPPNAME_S = "application"; + + /** package where to look for movement models */ + private static final String MM_PACKAGE = "movement."; + /** package where to look for router classes */ + private static final String ROUTING_PACKAGE = "routing."; + + /** package where to look for interface classes */ + private static final String INTTYPE_PACKAGE = "interfaces."; + + /** package where to look for application classes */ + private static final String APP_PACKAGE = "applications."; + + /** The world instance */ + private World world; + /** List of hosts in this simulation */ + protected List hosts; + /** Name of the simulation */ + private String name; + /** number of host groups */ + int nrofGroups; + /** Width of the world */ + private int worldSizeX; + /** Height of the world */ + private int worldSizeY; + /** Largest host's radio range */ + private double maxHostRange; + /** Simulation end time */ + private double endTime; + /** Update interval of sim time */ + private double updateInterval; + /** External events queue */ + private EventQueueHandler eqHandler; + /** Should connections between hosts be simulated */ + private boolean simulateConnections; + /** Map used for host movement (if any) */ + private SimMap simMap; + + /** Global connection event listeners */ + private List connectionListeners; + /** Global message event listeners */ + private List messageListeners; + /** Global movement event listeners */ + private List movementListeners; + /** Global update event listeners */ + private List updateListeners; + /** Global application event listeners */ + private List appListeners; + + static { + DTNSim.registerForReset(SimScenario.class.getCanonicalName()); + reset(); + } + + public static void reset() { + myinstance = null; + } + + /** + * Creates a scenario based on Settings object. + */ + protected SimScenario() { + Settings s = new Settings(SCENARIO_NS); + nrofGroups = s.getInt(NROF_GROUPS_S); + + this.name = s.valueFillString(s.getSetting(NAME_S)); + this.endTime = s.getDouble(END_TIME_S); + this.updateInterval = s.getDouble(UP_INT_S); + this.simulateConnections = s.getBoolean(SIM_CON_S); + + s.ensurePositiveValue(nrofGroups, NROF_GROUPS_S); + s.ensurePositiveValue(endTime, END_TIME_S); + s.ensurePositiveValue(updateInterval, UP_INT_S); + + this.simMap = null; + this.maxHostRange = 1; + + this.connectionListeners = new ArrayList(); + this.messageListeners = new ArrayList(); + this.movementListeners = new ArrayList(); + this.updateListeners = new ArrayList(); + this.appListeners = new ArrayList(); + this.eqHandler = new EventQueueHandler(); + + /* TODO: check size from movement models */ + s.setNameSpace(MovementModel.MOVEMENT_MODEL_NS); + int [] worldSize = s.getCsvInts(MovementModel.WORLD_SIZE, 2); + this.worldSizeX = worldSize[0]; + this.worldSizeY = worldSize[1]; + + createHosts(); + + this.world = new World(hosts, worldSizeX, worldSizeY, updateInterval, + updateListeners, simulateConnections, + eqHandler.getEventQueues()); + } + + /** + * Returns the SimScenario instance and creates one if it doesn't exist yet + */ + public static SimScenario getInstance() { + if (myinstance == null) { + myinstance = new SimScenario(); + } + return myinstance; + } + + + + /** + * Returns the name of the simulation run + * @return the name of the simulation run + */ + public String getName() { + return this.name; + } + + /** + * Returns true if connections should be simulated + * @return true if connections should be simulated (false if not) + */ + public boolean simulateConnections() { + return this.simulateConnections; + } + + /** + * Returns the width of the world + * @return the width of the world + */ + public int getWorldSizeX() { + return this.worldSizeX; + } + + /** + * Returns the height of the world + * @return the height of the world + */ + public int getWorldSizeY() { + return worldSizeY; + } + + /** + * Returns simulation's end time + * @return simulation's end time + */ + public double getEndTime() { + return endTime; + } + + /** + * Returns update interval (simulated seconds) of the simulation + * @return update interval (simulated seconds) of the simulation + */ + public double getUpdateInterval() { + return updateInterval; + } + + /** + * Returns how long range the hosts' radios have + * @return Range in meters + */ + public double getMaxHostRange() { + return maxHostRange; + } + + /** + * Returns the (external) event queue(s) of this scenario or null if there + * aren't any + * @return External event queues in a list or null + */ + public List getExternalEvents() { + return this.eqHandler.getEventQueues(); + } + + /** + * Returns the SimMap this scenario uses, or null if scenario doesn't + * use any map + * @return SimMap or null if no map is used + */ + public SimMap getMap() { + return this.simMap; + } + + /** + * Adds a new connection listener for all nodes + * @param cl The listener + */ + public void addConnectionListener(ConnectionListener cl){ + this.connectionListeners.add(cl); + } + + /** + * Adds a new message listener for all nodes + * @param ml The listener + */ + public void addMessageListener(MessageListener ml){ + this.messageListeners.add(ml); + } + + /** + * Adds a new movement listener for all nodes + * @param ml The listener + */ + public void addMovementListener(MovementListener ml){ + this.movementListeners.add(ml); + } + + /** + * Adds a new update listener for the world + * @param ul The listener + */ + public void addUpdateListener(UpdateListener ul) { + this.updateListeners.add(ul); + } + + /** + * Returns the list of registered update listeners + * @return the list of registered update listeners + */ + public List getUpdateListeners() { + return this.updateListeners; + } + + /** + * Adds a new application event listener for all nodes. + * @param al The listener + */ + public void addApplicationListener(ApplicationListener al) { + this.appListeners.add(al); + } + + /** + * Returns the list of registered application event listeners + * @return the list of registered application event listeners + */ + public List getApplicationListeners() { + return this.appListeners; + } + + /** + * Creates hosts for the scenario + */ + protected void createHosts() { + this.hosts = new ArrayList(); + + for (int i=1; i<=nrofGroups; i++) { + List interfaces = + new ArrayList(); + Settings s = new Settings(GROUP_NS+i); + s.setSecondaryNamespace(GROUP_NS); + String gid = s.getSetting(GROUP_ID_S); + int nrofHosts = s.getInt(NROF_HOSTS_S); + int nrofInterfaces = s.getInt(NROF_INTERF_S); + int appCount; + + // creates prototypes of MessageRouter and MovementModel + MovementModel mmProto = + (MovementModel)s.createIntializedObject(MM_PACKAGE + + s.getSetting(MOVEMENT_MODEL_S)); + MessageRouter mRouterProto = + (MessageRouter)s.createIntializedObject(ROUTING_PACKAGE + + s.getSetting(ROUTER_S)); + + /* checks that these values are positive (throws Error if not) */ + s.ensurePositiveValue(nrofHosts, NROF_HOSTS_S); + s.ensurePositiveValue(nrofInterfaces, NROF_INTERF_S); + + // setup interfaces + for (int j=1;j<=nrofInterfaces;j++) { + String intName = s.getSetting(INTERFACENAME_S + j); + Settings intSettings = new Settings(intName); + NetworkInterface iface = + (NetworkInterface)intSettings.createIntializedObject( + INTTYPE_PACKAGE +intSettings.getSetting(INTTYPE_S)); + iface.setClisteners(connectionListeners); + iface.setGroupSettings(s); + interfaces.add(iface); + } + + // setup applications + if (s.contains(APPCOUNT_S)) { + appCount = s.getInt(APPCOUNT_S); + } else { + appCount = 0; + } + for (int j=1; j<=appCount; j++) { + String appname = null; + Application protoApp = null; + try { + // Get name of the application for this group + appname = s.getSetting(GAPPNAME_S+j); + // Get settings for the given application + Settings t = new Settings(appname); + // Load an instance of the application + protoApp = (Application)t.createIntializedObject( + APP_PACKAGE + t.getSetting(APPTYPE_S)); + // Set application listeners + protoApp.setAppListeners(this.appListeners); + // Set the proto application in proto router + //mRouterProto.setApplication(protoApp); + mRouterProto.addApplication(protoApp); + } catch (SettingsError se) { + // Failed to create an application for this group + System.err.println("Failed to setup an application: " + se); + System.err.println("Caught at " + se.getStackTrace()[0]); + System.exit(-1); + } + } + + if (mmProto instanceof MapBasedMovement) { + this.simMap = ((MapBasedMovement)mmProto).getMap(); + } + + // creates hosts of ith group + for (int j=0; j getHosts() { + return this.hosts; + } + + /** + * Returns the World object of this scenario + * @return the World object + */ + public World getWorld() { + return this.world; + } + +} \ No newline at end of file diff --git a/core/UpdateListener.java b/core/UpdateListener.java new file mode 100644 index 000000000..276d7cae6 --- /dev/null +++ b/core/UpdateListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import java.util.List; + +/** + * Interface for classes that want to be informed about every single update + * call to the World object.
+ * NOTE: if update interval is large (if, e.g., no movement or + * connection simulation is needed), update listeners may not get called at all + * during the simulation. + */ +public interface UpdateListener { + + /** + * Method is called on every update cycle. + * @param hosts A list of all hosts in the world + */ + public void updated(List hosts); + +} diff --git a/core/VBRConnection.java b/core/VBRConnection.java new file mode 100644 index 000000000..6750e2130 --- /dev/null +++ b/core/VBRConnection.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import routing.MessageRouter; + +/** + * A connection between two DTN nodes. The transmission speed + * is updated every round from the end point transmission speeds + */ +public class VBRConnection extends Connection { + private int msgsize; + private int msgsent; + private int currentspeed = 0; + private double lastUpdate = 0; + + + /** + * Creates a new connection between nodes and sets the connection + * state to "up". + * @param fromNode The node that initiated the connection + * @param fromInterface The interface that initiated the connection + * @param toNode The node in the other side of the connection + * @param toInterface The interface in the other side of the connection + */ + public VBRConnection(DTNHost fromNode, NetworkInterface fromInterface, + DTNHost toNode, NetworkInterface toInterface) { + super(fromNode, fromInterface, toNode, toInterface); + this.msgsent = 0; + } + + /** + * Sets a message that this connection is currently transferring. If message + * passing is controlled by external events, this method is not needed + * (but then e.g. {@link #finalizeTransfer()} and + * {@link #isMessageTransferred()} will not work either). Only a one message + * at a time can be transferred using one connection. + * @param from The host sending the message + * @param m The message + * @return The value returned by + * {@link MessageRouter#receiveMessage(Message, DTNHost)} + */ + public int startTransfer(DTNHost from, Message m) { + assert this.msgOnFly == null : "Already transferring " + + this.msgOnFly + " from " + this.msgFromNode + " to " + + this.getOtherNode(this.msgFromNode) + ". Can't "+ + "start transfer of " + m + " from " + from; + + this.msgFromNode = from; + Message newMessage = m.replicate(); + int retVal = getOtherNode(from).receiveMessage(newMessage, from); + + if (retVal == MessageRouter.RCV_OK) { + this.msgOnFly = newMessage; + this.msgsize = m.getSize(); + this.msgsent = 0; + } + + return retVal; + } + + /** + * Calculate the current transmission speed from the information + * given by the interfaces, and calculate the missing data amount. + * + */ + public void update() { + currentspeed = this.fromInterface.getTransmitSpeed(toInterface); + int othspeed = this.toInterface.getTransmitSpeed(fromInterface); + double now = core.SimClock.getTime(); + + if (othspeed < currentspeed) { + currentspeed = othspeed; + } + + + msgsent += currentspeed * (now - this.lastUpdate); + this.lastUpdate = now; + } + + /** + * returns the current speed of the connection + */ + public double getSpeed() { + return this.currentspeed; + } + + /** + * Returns the amount of bytes to be transferred before ongoing transfer + * is ready or 0 if there's no ongoing transfer or it has finished + * already + * @return the amount of bytes to be transferred + */ + public int getRemainingByteCount() { + int bytesLeft = msgsize - msgsent; + return (bytesLeft > 0 ? bytesLeft : 0); + } + + /** + * Returns true if the current message transfer is done. + * @return True if the transfer is done, false if not + */ + public boolean isMessageTransferred() { + if (msgsent >= msgsize) { + return true; + } else { + return false; + } + } + +} diff --git a/core/World.java b/core/World.java new file mode 100644 index 000000000..ebdcdc381 --- /dev/null +++ b/core/World.java @@ -0,0 +1,275 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package core; + +import input.EventQueue; +import input.ExternalEvent; +import input.ScheduledUpdatesQueue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +/** + * World contains all the nodes and is responsible for updating their + * location and connections. + */ +public class World { + /** name space of optimization settings ({@value})*/ + public static final String OPTIMIZATION_SETTINGS_NS = "Optimization"; + + /** + * Should the order of node updates be different (random) within every + * update step -setting id ({@value}). Boolean (true/false) variable. + * Default is @link {@link #DEF_RANDOMIZE_UPDATES}. + */ + public static final String RANDOMIZE_UPDATES_S = "randomizeUpdateOrder"; + /** should the update order of nodes be randomized -setting's default value + * ({@value}) */ + public static final boolean DEF_RANDOMIZE_UPDATES = true; + + /** + * Should the connectivity simulation be stopped after one round + * -setting id ({@value}). Boolean (true/false) variable. + */ + public static final String SIMULATE_CON_ONCE_S = "simulateConnectionsOnce"; + + private int sizeX; + private int sizeY; + private List eventQueues; + private double updateInterval; + private SimClock simClock; + private double nextQueueEventTime; + private EventQueue nextEventQueue; + /** list of nodes; nodes are indexed by their network address */ + private List hosts; + private boolean simulateConnections; + /** nodes in the order they should be updated (if the order should be + * randomized; null value means that the order should not be randomized) */ + private ArrayList updateOrder; + /** is cancellation of simulation requested from UI */ + private boolean isCancelled; + private List updateListeners; + /** Queue of scheduled update requests */ + private ScheduledUpdatesQueue scheduledUpdates; + private boolean simulateConOnce; + + /** + * Constructor. + */ + public World(List hosts, int sizeX, int sizeY, + double updateInterval, List updateListeners, + boolean simulateConnections, List eventQueues) { + this.hosts = hosts; + this.sizeX = sizeX; + this.sizeY = sizeY; + this.updateInterval = updateInterval; + this.updateListeners = updateListeners; + this.simulateConnections = simulateConnections; + this.eventQueues = eventQueues; + + this.simClock = SimClock.getInstance(); + this.scheduledUpdates = new ScheduledUpdatesQueue(); + this.isCancelled = false; + + setNextEventQueue(); + initSettings(); + } + + /** + * Initializes settings fields that can be configured using Settings class + */ + private void initSettings() { + Settings s = new Settings(OPTIMIZATION_SETTINGS_NS); + boolean randomizeUpdates = DEF_RANDOMIZE_UPDATES; + + if (s.contains(RANDOMIZE_UPDATES_S)) { + randomizeUpdates = s.getBoolean(RANDOMIZE_UPDATES_S); + } + simulateConOnce = s.getBoolean(SIMULATE_CON_ONCE_S, false); + + if(randomizeUpdates) { + // creates the update order array that can be shuffled + this.updateOrder = new ArrayList(this.hosts); + } + else { // null pointer means "don't randomize" + this.updateOrder = null; + } + } + + /** + * Moves hosts in the world for the time given time initialize host + * positions properly. SimClock must be set to -time before + * calling this method. + * @param time The total time (seconds) to move + */ + public void warmupMovementModel(double time) { + if (time <= 0) { + return; + } + + while(SimClock.getTime() < -updateInterval) { + moveHosts(updateInterval); + simClock.advance(updateInterval); + } + + double finalStep = -SimClock.getTime(); + + moveHosts(finalStep); + simClock.setTime(0); + } + + /** + * Goes through all event Queues and sets the + * event queue that has the next event. + */ + public void setNextEventQueue() { + EventQueue nextQueue = scheduledUpdates; + double earliest = nextQueue.nextEventsTime(); + + /* find the queue that has the next event */ + for (EventQueue eq : eventQueues) { + if (eq.nextEventsTime() < earliest){ + nextQueue = eq; + earliest = eq.nextEventsTime(); + } + } + + this.nextEventQueue = nextQueue; + this.nextQueueEventTime = earliest; + } + + /** + * Update (move, connect, disconnect etc.) all hosts in the world. + * Runs all external events that are due between the time when + * this method is called and after one update interval. + */ + public void update () { + double runUntil = SimClock.getTime() + this.updateInterval; + + setNextEventQueue(); + + /* process all events that are due until next interval update */ + while (this.nextQueueEventTime <= runUntil) { + simClock.setTime(this.nextQueueEventTime); + ExternalEvent ee = this.nextEventQueue.nextEvent(); + ee.processEvent(this); + updateHosts(); // update all hosts after every event + setNextEventQueue(); + } + + moveHosts(this.updateInterval); + simClock.setTime(runUntil); + + updateHosts(); + + /* inform all update listeners */ + for (UpdateListener ul : this.updateListeners) { + ul.updated(this.hosts); + } + } + + /** + * Updates all hosts (calls update for every one of them). If update + * order randomizing is on (updateOrder array is defined), the calls + * are made in random order. + */ + private void updateHosts() { + if (this.updateOrder == null) { // randomizing is off + for (int i=0, n = hosts.size();i < n; i++) { + if (this.isCancelled) { + break; + } + hosts.get(i).update(simulateConnections); + } + } + else { // update order randomizing is on + assert this.updateOrder.size() == this.hosts.size() : + "Nrof hosts has changed unexpectedly"; + Random rng = new Random(SimClock.getIntTime()); + Collections.shuffle(this.updateOrder, rng); + for (int i=0, n = hosts.size();i < n; i++) { + if (this.isCancelled) { + break; + } + this.updateOrder.get(i).update(simulateConnections); + } + } + + if (simulateConOnce && simulateConnections) { + simulateConnections = false; + } + } + + /** + * Moves all hosts in the world for a given amount of time + * @param timeIncrement The time how long all nodes should move + */ + private void moveHosts(double timeIncrement) { + for (int i=0,n = hosts.size(); i getHosts() { + return this.hosts; + } + + /** + * Returns the x-size (width) of the world + * @return the x-size (width) of the world + */ + public int getSizeX() { + return this.sizeX; + } + + /** + * Returns the y-size (height) of the world + * @return the y-size (height) of the world + */ + public int getSizeY() { + return this.sizeY; + } + + /** + * Returns a node from the world by its address + * @param address The address of the node + * @return The requested node or null if it wasn't found + */ + public DTNHost getNodeByAddress(int address) { + if (address < 0 || address >= hosts.size()) { + throw new SimError("No host for address " + address + ". Address " + + "range of 0-" + (hosts.size()-1) + " is valid"); + } + + DTNHost node = this.hosts.get(address); + assert node.getAddress() == address : "Node indexing failed. " + + "Node " + node + " in index " + address; + + return node; + } + + /** + * Schedules an update request to all nodes to happen at the specified + * simulation time. + * @param simTime The time of the update + */ + public void scheduleUpdate(double simTime) { + scheduledUpdates.addUpdate(simTime); + } +} diff --git a/core/package.html b/core/package.html new file mode 100644 index 000000000..81ea38f32 --- /dev/null +++ b/core/package.html @@ -0,0 +1,14 @@ + + + + +Contains core classes and interfaces of the simulator. + +Almost all of these classes are needed for every run of the simulator. +DTNSim is the main class of the program. It starts up a proper user interface +which in turn starts the simulation. + +@see ui.DTNSimUI + + + \ No newline at end of file diff --git a/data/CentralPOIs.wkt b/data/CentralPOIs.wkt new file mode 100644 index 000000000..5167d943e --- /dev/null +++ b/data/CentralPOIs.wkt @@ -0,0 +1,7 @@ +POINT (2552448.388211649 6673384.4020657055) + +POINT (2552275.9398973365 6673509.820852942) + +POINT (2552361.289603607 6673630.088457832) + +POINT (2552782.3212060533 6673285.5993876355) \ No newline at end of file diff --git a/data/HelsinkiMedium/A_bus.wkt b/data/HelsinkiMedium/A_bus.wkt new file mode 100644 index 000000000..ff8a92e55 --- /dev/null +++ b/data/HelsinkiMedium/A_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2553558.1158829676 6674022.108437747, 2553256.4880741183 6674002.824011413, 2552932.8422519267 6673978.828503751, 2552757.3251099777 6673680.650063182, 2552363.5334775783 6673567.544102095, 2552275.651163554 6673509.600802434, 2551892.3364427104 6673318.977048773, 2552122.746001586 6673002.154328803, 2552264.671030261 6672803.6187591525, 2552483.811722061 6672500.92928317, + 2552253.088680792 6672172.793966631) \ No newline at end of file diff --git a/data/HelsinkiMedium/A_homes.wkt b/data/HelsinkiMedium/A_homes.wkt new file mode 100644 index 000000000..e1789ca07 --- /dev/null +++ b/data/HelsinkiMedium/A_homes.wkt @@ -0,0 +1,283 @@ +POINT (2550611.983604681 6672531.376271633) + +POINT (2551127.200167159 6672617.045935297) + +POINT (2551121.9534618445 6672693.903576347) + +POINT (2551871.4321168177 6673231.22690758) + +POINT (2551825.407951799 6673124.782475507) + +POINT (2551655.096267482 6673173.833734188) + +POINT (2551725.456565643 6672934.608825157) + +POINT (2551671.7025847756 6672805.259135666) + +POINT (2551290.1450152406 6673526.754739758) + +POINT (2551173.7605520603 6673670.577751296) + +POINT (2551326.8967010546 6673752.106464491) + +POINT (2551331.69793139 6673952.922557588) + +POINT (2551201.2315091337 6673936.978898058) + +POINT (2551497.6291117417 6674081.552081781) + +POINT (2551679.712884871 6673895.7394324085) + +POINT (2551645.3123170044 6673652.453591277) + +POINT (2551952.4673154154 6673511.141155989) + +POINT (2551892.3364427104 6673318.977048773) + +POINT (2552146.09219033 6673240.589056464) + +POINT (2552122.746001586 6673002.154328803) + +POINT (2551983.931048231 6672903.211618591) + +POINT (2551814.8402953395 6672778.893083896) + +POINT (2551898.243110958 6672671.248376324) + +POINT (2552135.4420385035 6672451.177863781) + +POINT (2552222.5653951555 6672317.377152652) + +POINT (2552277.0370857124 6672028.170771429) + +POINT (2552192.6443256945 6671895.100227893) + +POINT (2552487.458017264 6672030.541315537) + +POINT (2552411.215799465 6671838.257180772) + +POINT (2552348.7420583493 6672011.997059095) + +POINT (2552261.4207128175 6672125.6131372675) + +POINT (2552270.379709629 6672251.59205307) + +POINT (2552630.0925060916 6672212.543090205) + +POINT (2552707.5061580963 6671918.555611582) + +POINT (2552898.4829317434 6671882.237275475) + +POINT (2552932.009048724 6672051.656162005) + +POINT (2553078.108342949 6672215.473762878) + +POINT (2552883.7245106613 6672239.799346303) + +POINT (2552708.001130296 6672220.484913082) + +POINT (2552505.9039812325 6672310.61560068) + +POINT (2552498.9166236827 6672416.219839904) + +POINT (2552630.043008872 6672569.124936043) + +POINT (2552437.820555189 6672563.973753698) + +POINT (2552264.671030261 6672803.6187591525) + +POINT (2552471.2311786567 6672787.425042226) + +POINT (2552393.388550746 6672896.21001152) + +POINT (2552330.7745675067 6672982.3197762) + +POINT (2552459.211603745 6673074.480929848) + +POINT (2552521.487355981 6672986.790802429) + +POINT (2552706.5574613805 6672882.976974156) + +POINT (2552849.2414474282 6672948.622041596) + +POINT (2553070.947745129 6672902.731508393) + +POINT (2552994.8622685266 6673053.926211947) + +POINT (2552796.015436907 6673098.0563410865) + +POINT (2552692.5414985977 6673061.627979725) + +POINT (2552568.979938525 6673125.642672947) + +POINT (2552468.145851946 6673251.841639256) + +POINT (2552292.5049669473 6673307.024305273) + +POINT (2552147.7668462717 6673412.808585823) + +POINT (2552271.1386670014 6673506.220026447) + +POINT (2552480.8583879373 6673392.573941387) + +POINT (2552669.1210640236 6673406.247079767) + +POINT (2552773.2384661925 6673412.668553681) + +POINT (2552879.3357571587 6673419.2100551445) + +POINT (2552971.7305677356 6673425.081402789) + +POINT (2553031.4242149973 6673429.042311932) + +POINT (2553241.3996715695 6673442.8554824535) + +POINT (2553039.1292822366 6673301.743093083) + +POINT (2552782.3212060533 6673285.5993876355) + +POINT (2552677.906820565 6673285.539373861) + +POINT (2552616.431273385 6673583.687807542) + +POINT (2552757.3251099777 6673680.650063182) + +POINT (2552833.5590782403 6673841.386956944) + +POINT (2552938.220949828 6673883.426606258) + +POINT (2553092.8007677374 6673789.244988856) + +POINT (2552956.9143998967 6673618.665836011) + +POINT (2553098.567193862 6673709.276633807) + +POINT (2553275.9652301692 6673721.07934287) + +POINT (2553485.148731222 6673735.572669507) + +POINT (2553368.6157763824 6673912.273227392) + +POINT (2553263.7229177677 6673904.271390739) + +POINT (2553362.238884545 6674010.265719501) + +POINT (2553442.6636174303 6674102.896981052) + +POINT (2552622.8329138323 6673749.445853804) + +POINT (2553415.7866269965 6673260.363595292) + +POINT (2553557.5136667914 6673231.256914468) + +POINT (2553670.9777939944 6673151.3385708975) + +POINT (2553805.0740123806 6673063.04830573) + +POINT (2553766.004206765 6673008.675825675) + +POINT (2553634.0281193005 6673094.815597242) + +POINT (2553943.575483342 6672977.868754562) + +POINT (2554121.295251579 6673000.804018868) + +POINT (2554266.635588431 6673100.146820912) + +POINT (2554115.636069431 6673175.21405101) + +POINT (2554289.3300637784 6673267.365202363) + +POINT (2554422.9148108917 6673280.538225953) + +POINT (2553785.2338767163 6673218.283936794) + +POINT (2553780.1521621346 6673315.01613963) + +POINT (2553933.329558812 6673324.638348205) + +POINT (2553941.0511251246 6673227.276000733) + +POINT (2553635.9420118053 6673348.1437433725) + +POINT (2553224.11689227 6672386.7130672475) + +POINT (2553149.5493304124 6672557.952371617) + +POINT (2552820.5495589296 6672756.447932084) + +POINT (2552716.8776317406 6672731.242146628) + +POINT (2551619.8624964124 6672639.221025121) + +POINT (2551560.8783093034 6672723.220305383) + +POINT (2551675.596366078 6672560.723007558) + +POINT (2551785.174961515 6672603.022716563) + +POINT (2551931.958967282 6672378.671221412) + +POINT (2551839.7703951215 6672466.191309801) + +POINT (2552001.873790464 6672212.112991484) + +POINT (2552089.277631362 6672241.849816945) + +POINT (2552056.98894488 6672339.2921827845) + +POINT (2552039.310187821 6672058.027624439) + +POINT (2552129.923098479 6672065.879426655) + +POINT (2551890.472047426 6673874.094464263) + +POINT (2551686.840484544 6673785.184056754) + +POINT (2551749.36372288 6673705.585786651) + +POINT (2551913.018031114 6673659.905301659) + +POINT (2551465.6374085797 6673661.9857791895) + +POINT (2551439.808109301 6673769.050353603) + +POINT (2551136.8603745867 6673805.238659865) + +POINT (2551230.7978485185 6673825.183237722) + +POINT (2551075.632313506 6674031.200524644) + +POINT (2551344.7569479207 6674104.177274917) + +POINT (2550674.9523179964 6674116.500103362) + +POINT (2550818.6674961266 6673809.159559825) + +POINT (2550919.047858189 6673708.456445551) + +POINT (2552389.9319948857 6672339.512233292) + +POINT (2552343.1571220313 6672403.776983909) + +POINT (2552299.6078180103 6672464.140839159) + +POINT (2552249.4588846625 6672531.896391016) + +POINT (2552203.3439747407 6672596.1711439295) + +POINT (2552125.790080613 6672703.615805584) + +POINT (2552837.8075896194 6672534.056886912) + +POINT (2552733.0467235916 6672525.654958427) + +POINT (2552739.555608015 6672439.63521441) + +POINT (2552747.310172474 6672343.373119477) + +POINT (2552850.64386866 6672373.590055137) + +POINT (2552608.387975143 6671893.399837605) + +POINT (2553619.970908834 6672194.188877382) \ No newline at end of file diff --git a/data/HelsinkiMedium/A_meetingspots.wkt b/data/HelsinkiMedium/A_meetingspots.wkt new file mode 100644 index 000000000..a49b45d41 --- /dev/null +++ b/data/HelsinkiMedium/A_meetingspots.wkt @@ -0,0 +1,7 @@ +POINT (2551832.205570006 6673236.458108292) + +POINT (2552398.0412894213 6673352.814815518) + +POINT (2552271.1386670014 6673506.220026447) + +POINT (2552747.310172474 6672343.373119477) \ No newline at end of file diff --git a/data/HelsinkiMedium/A_offices.wkt b/data/HelsinkiMedium/A_offices.wkt new file mode 100644 index 000000000..0a8d77521 --- /dev/null +++ b/data/HelsinkiMedium/A_offices.wkt @@ -0,0 +1,59 @@ +POINT (2551110.0823785923 6671906.722895632) + +POINT (2550779.399701631 6671848.84961204) + +POINT (2550210.569400409 6672635.2201067945) + +POINT (2550317.9948667777 6672508.10092927) + +POINT (2550408.599527899 6672561.513188927) + +POINT (2550330.047439836 6672702.395525495) + +POINT (2550574.0522351246 6672733.982775682) + +POINT (2550698.306756277 6672645.982577093) + +POINT (2550848.6793104904 6672658.8755364) + +POINT (2551005.1565218316 6672769.690971744) + +POINT (2550839.241840553 6672755.957819589) + +POINT (2551217.6480870843 6672787.2850100845) + +POINT (2551115.9395496203 6672778.863077007) + +POINT (2551671.7025847756 6672805.259135666) + +POINT (2552032.2815825874 6672414.099353191) + +POINT (2552521.487355981 6672986.790802429) + +POINT (2552971.7305677356 6673425.081402789) + +POINT (2551613.0318800593 6673913.813580948) + +POINT (2551136.8603745867 6673805.238659865) + +POINT (2553785.2338767163 6673218.283936794) + +POINT (2553381.666543376 6673728.240986674) + +POINT (2552270.379709629 6672251.59205307) + +POINT (2552299.6078180103 6672464.140839159) + +POINT (2552065.320976905 6672790.54575852) + +POINT (2552147.7668462717 6673412.808585823) + +POINT (2552873.2723477148 6674175.9337451) + +POINT (2553277.4088990847 6674161.500432238) + +POINT (2552250.077599912 6673094.855606426) + +POINT (2552478.6805102592 6673256.062608091) + +POINT (2552844.266976823 6672450.797776541) \ No newline at end of file diff --git a/data/HelsinkiMedium/B_bus.wkt b/data/HelsinkiMedium/B_bus.wkt new file mode 100644 index 000000000..d4b4091a4 --- /dev/null +++ b/data/HelsinkiMedium/B_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2549711.7116691247 6672521.834081425, 2549326.1448247735 6672446.546800818, 2548919.9211406293 6672451.737992347, 2548857.076170364 6672141.0166728245, 2549038.92070693 6671689.052934085, 2549125.4665960157 6671310.466037451, 2548826.6848773137 6671777.543245168, 2548721.940510359 6672165.17221722, 2548776.5689421124 6672470.202230424, 2548598.576939166 6672504.560116551, + 2548409.3490672903 6672539.118048595, 2548204.9172993526 6672577.186786471, 2547920.50627351 6672635.070072358, 2547945.8323510517 6672417.580152135, 2548008.8175634407 6672181.105874455, 2547895.0977006014 6671978.22930842) \ No newline at end of file diff --git a/data/HelsinkiMedium/B_homes.wkt b/data/HelsinkiMedium/B_homes.wkt new file mode 100644 index 000000000..8ef6dc479 --- /dev/null +++ b/data/HelsinkiMedium/B_homes.wkt @@ -0,0 +1,241 @@ +POINT (2549309.6705000666 6670983.260934425) + +POINT (2549499.7315751445 6670975.109063334) + +POINT (2549456.223518807 6671020.389456493) + +POINT (2549206.1635636105 6670959.665518594) + +POINT (2549174.402847475 6671097.657191671) + +POINT (2549270.600694451 6671125.503583223) + +POINT (2549421.1959861545 6671189.488269557) + +POINT (2549497.231965537 6671140.727077454) + +POINT (2549493.272187941 6671418.080738135) + +POINT (2549726.395844377 6671483.115665531) + +POINT (2549597.0266104965 6671528.065982928) + +POINT (2549395.812161856 6671681.411180082) + +POINT (2549323.9009508025 6671664.947401169) + +POINT (2549342.239670795 6671574.806711275) + +POINT (2549385.1372614196 6671366.5889192745) + +POINT (2549216.590977947 6671328.23011482) + +POINT (2549125.4665960157 6671310.466037451) + +POINT (2548945.4699556613 6671269.13655114) + +POINT (2548899.0168147366 6671469.6525753625) + +POINT (2549038.92070693 6671689.052934085) + +POINT (2549078.518482892 6671515.843177441) + +POINT (2549148.062076924 6671625.868431415) + +POINT (2549129.1046416825 6671709.017516534) + +POINT (2549147.600102871 6671811.280988956) + +POINT (2549092.765432701 6671971.107673799) + +POINT (2549124.59214513 6672070.870572267) + +POINT (2549000.560361468 6672094.435981209) + +POINT (2548812.1409441847 6672129.604053299) + +POINT (2548788.6215151707 6672008.0761591345) + +POINT (2548977.4369102134 6671973.518227091) + +POINT (2548775.7192398366 6671876.385932422) + +POINT (2548826.6848773137 6671777.543245168) + +POINT (2549023.337332182 6671822.0034500705) + +POINT (2548856.308963455 6671647.263342166) + +POINT (2549354.2509961696 6672050.675937015) + +POINT (2549333.726148963 6671842.288105985) + +POINT (2549496.7534924108 6671701.165714318) + +POINT (2549442.8097722 6672281.278867052) + +POINT (2549545.178272597 6672487.866284834) + +POINT (2549328.726929748 6672406.747665767) + +POINT (2549044.2334085386 6672322.608353363) + +POINT (2549025.952435303 6672226.416274501) + +POINT (2548896.2449704194 6672351.384958426) + +POINT (2548914.6744353147 6672439.865267213) + +POINT (2548935.2405302045 6672531.896391016) + +POINT (2549151.9146105433 6672527.495380857) + +POINT (2549377.060965031 6672608.403951712) + +POINT (2549296.5207386324 6672713.648108288) + +POINT (2549563.904720812 6672711.237554996) + +POINT (2549460.1997954766 6672780.91354765) + +POINT (2549732.6407436277 6672352.875300502) + +POINT (2549714.590757419 6672194.158870495) + +POINT (2549601.2751218756 6672288.420506264) + +POINT (2548653.172372773 6672422.691325298) + +POINT (2548487.9176544272 6672268.936034014) + +POINT (2548473.464466201 6672415.589695268) + +POINT (2548616.8661619383 6672245.690698538) + +POINT (2548669.62194887 6672165.182219516) + +POINT (2548659.037793337 6672031.391510681) + +POINT (2548499.7227413855 6671940.530655489) + +POINT (2548536.7961591296 6671858.001712712) + +POINT (2548349.498678832 6671792.986789908) + +POINT (2548274.774375778 6671697.8249475155) + +POINT (2548138.4177843477 6671814.501728209) + +POINT (2548168.124365855 6671897.640811031) + +POINT (2548337.0088803307 6671880.666915031) + +POINT (2548323.8426198238 6671981.420040785) + +POINT (2548200.495547704 6671992.0024697585) + +POINT (2548058.941748178 6672108.509211423) + +POINT (2548008.8175634407 6672181.105874455) + +POINT (2547919.3513383777 6672037.772975412) + +POINT (2547987.030537125 6671903.372126534) + +POINT (2547874.358365441 6671779.45368367) + +POINT (2547866.3563148826 6671640.20172132) + +POINT (2547868.8724235636 6671587.159546608) + +POINT (2547844.4702941272 6671521.584495239) + +POINT (2547805.7964662714 6671466.201783306) + +POINT (2547791.739255805 6671569.015381997) + +POINT (2547589.7988479384 6671804.979542592) + +POINT (2547765.695468574 6671861.002401457) + +POINT (2547688.4220586927 6671938.630219284) + +POINT (2547861.076611421 6671954.783927027) + +POINT (2548987.8560750135 6671081.663520661) + +POINT (2549001.8637882597 6670970.698050879) + +POINT (2548861.6299145995 6670760.719854815) + +POINT (2548953.2740173405 6670834.056687738) + +POINT (2547827.9547217367 6672273.6971268235) + +POINT (2547791.3185294354 6672384.562573647) + +POINT (2547588.4294248535 6672461.920329488) + +POINT (2547927.510130133 6672506.360529798) + +POINT (2548125.5815053065 6672450.737762765) + +POINT (2548094.447753957 6672319.50764166) + +POINT (2547945.8323510517 6672417.580152135) + +POINT (2547971.0181864705 6672303.113878818) + +POINT (2547890.1892262893 6672621.67699826) + +POINT (2547665.834827321 6672719.939552356) + +POINT (2547280.828951463 6672518.693360539) + +POINT (2547304.3566300133 6672649.373355375) + +POINT (2547400.950454749 6672752.236965545) + +POINT (2547782.706013164 6673175.964223197) + +POINT (2547780.17340541 6673331.900014968) + +POINT (2547813.278796021 6673514.251869988) + +POINT (2547937.1620880235 6673384.182015197) + +POINT (2547873.038439576 6673239.588826882) + +POINT (2547927.3038917165 6672968.396580424) + +POINT (2547830.4048341243 6672948.171938284) + +POINT (2547693.1655422715 6672917.094805184) + +POINT (2548203.4818799742 6672795.32685592) + +POINT (2548344.44171286 6672753.367224973) + +POINT (2548393.798690689 6672633.859794564) + +POINT (2548147.4097793056 6672620.4867250575) + +POINT (2547974.3839974273 6672712.217779986) + +POINT (2548241.652486094 6672848.799129353) + +POINT (2548584.362987503 6672703.2157137515) + +POINT (2548809.996064653 6672643.512010026) + +POINT (2548979.8127767714 6672862.812345791) + +POINT (2549047.6404671785 6672675.379324496) + +POINT (2549169.931598606 6672778.703040275) + +POINT (2548841.591790056 6671231.327872955) + +POINT (2548324.791316539 6672456.579103522) + +POINT (2548615.777223099 6672593.840609004) \ No newline at end of file diff --git a/data/HelsinkiMedium/B_meetingspots.wkt b/data/HelsinkiMedium/B_meetingspots.wkt new file mode 100644 index 000000000..c5fe0ca7b --- /dev/null +++ b/data/HelsinkiMedium/B_meetingspots.wkt @@ -0,0 +1 @@ +POINT (2548669.62194887 6672165.182219516) \ No newline at end of file diff --git a/data/HelsinkiMedium/B_offices.wkt b/data/HelsinkiMedium/B_offices.wkt new file mode 100644 index 000000000..1c6e61331 --- /dev/null +++ b/data/HelsinkiMedium/B_offices.wkt @@ -0,0 +1,19 @@ +POINT (2547765.695468574 6671861.002401457) + +POINT (2547876.3630028493 6671967.746902404) + +POINT (2548337.0088803307 6671880.666915031) + +POINT (2548821.3804252422 6671791.406427169) + +POINT (2549000.560361468 6672094.435981209) + +POINT (2549328.726929748 6672406.747665767) + +POINT (2548973.5431289105 6672751.016685456) + +POINT (2549125.4665960157 6671310.466037451) + +POINT (2548899.0168147366 6671469.6525753625) + +POINT (2549038.92070693 6671689.052934085) \ No newline at end of file diff --git a/data/HelsinkiMedium/C_bus.wkt b/data/HelsinkiMedium/C_bus.wkt new file mode 100644 index 000000000..c6102e8c2 --- /dev/null +++ b/data/HelsinkiMedium/C_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2551844.6623703605 6674216.3330179015, 2551557.9002265697 6674544.118254086, 2551245.6800126503 6674810.619423806, 2551126.16072554 6675032.970459795, 2551042.675414555 6675236.6272049025, 2550817.5785572873 6675557.160776621, 2550277.86912047 6675871.0628262125, 2549830.537995156 6676063.476990825, 2549305.5374822007 6676406.915819961, 2548940.256248493 6676559.490840337, + 2548569.3983280044 6677113.988113486) \ No newline at end of file diff --git a/data/HelsinkiMedium/C_homes.wkt b/data/HelsinkiMedium/C_homes.wkt new file mode 100644 index 000000000..0ceca8213 --- /dev/null +++ b/data/HelsinkiMedium/C_homes.wkt @@ -0,0 +1,189 @@ +POINT (2550480.403494976 6674769.309942086) + +POINT (2550699.494689556 6674935.358054927) + +POINT (2549334.089128576 6674507.3298100745) + +POINT (2549255.6937817093 6675409.146803136) + +POINT (2547626.294798116 6674630.097988919) + +POINT (2547822.9555025217 6675118.270038513) + +POINT (2548681.3692890718 6675476.232201174) + +POINT (2548762.0250089834 6676100.105398103) + +POINT (2548542.612082474 6676286.008068138) + +POINT (2548147.929500115 6676753.445358505) + +POINT (2548387.5455419016 6677245.3982759155) + +POINT (2551520.8268088256 6676869.451985378) + +POINT (2551564.483356823 6676702.513668209) + +POINT (2551598.925172373 6676549.378519267) + +POINT (2551651.7139574517 6676399.724169269) + +POINT (2551726.999228998 6676599.710071813) + +POINT (2551430.832613417 6677164.879794598) + +POINT (2551214.2657770542 6677298.630494248) + +POINT (2551198.616406013 6677595.068535346) + +POINT (2550946.510565725 6677618.803983317) + +POINT (2551097.724572678 6677066.147132598) + +POINT (2551441.26827729 6676467.169649956) + +POINT (2551342.133595263 6676740.562401493) + +POINT (2551446.9357089745 6675949.9809402) + +POINT (2551000.2975447397 6675718.547819612) + +POINT (2551550.7066306034 6676302.861936587) + +POINT (2550543.784685124 6676559.450831154) + +POINT (2550205.858914977 6676548.138234586) + +POINT (2550234.880784942 6676700.8732916955) + +POINT (2550033.204362248 6676900.989224086) + +POINT (2550248.4430232085 6676902.809641924) + +POINT (2550170.7983841775 6677132.052259729) + +POINT (2549851.2525817053 6677259.631542862) + +POINT (2549848.8849646845 6677579.775025043) + +POINT (2549641.13688301 6677689.6502445815) + +POINT (2549450.3086010227 6677780.991209973) + +POINT (2548962.216515078 6677555.539462281) + +POINT (2548944.339769139 6677829.712392892) + +POINT (2548761.0020664376 6677528.1531763375) + +POINT (2548854.2465792904 6677147.775868752) + +POINT (2549044.6953825913 6677254.21029853) + +POINT (2549155.041184937 6676773.579979982) + +POINT (2549236.2578733414 6676538.766083406) + +POINT (2549067.1588709126 6676512.280004086) + +POINT (2549024.7315038773 6676405.455484771) + +POINT (2548894.9580427003 6676442.353954037) + +POINT (2548695.286257415 6676526.673307765) + +POINT (2548642.7614575094 6676395.353165997) + +POINT (2548758.914933663 6676332.778803373) + +POINT (2548863.6180529343 6676294.670056314) + +POINT (2548959.6261605676 6676296.040370841) + +POINT (2548909.716463783 6676167.730920114) + +POINT (2548995.0001737596 6676208.860360509) + +POINT (2548526.2779998896 6676474.191261618) + +POINT (2548455.4557276755 6676472.760933317) + +POINT (2548381.4326352375 6676426.870400113) + +POINT (2548275.4590873206 6676549.548558296) + +POINT (2548318.8434006083 6676596.559348631) + +POINT (2548357.2614928274 6676661.654289802) + +POINT (2547233.8808383388 6677177.9227883415) + +POINT (2546874.984746005 6677366.115984119) + +POINT (2546745.0545436316 6677547.607641699) + +POINT (2547440.4327371973 6677617.333645832) + +POINT (2547493.01528386 6677618.133829498) + +POINT (2547785.263369528 6677662.604036695) + +POINT (2548092.880341992 6677652.181644455) + +POINT (2548494.0470601646 6677711.075162219) + +POINT (2548604.4588588034 6676848.5471871225) + +POINT (2548654.855278251 6677031.539189075) + +POINT (2548822.997334427 6676901.8294169335) + +POINT (2549005.14710385 6676746.133680263) + +POINT (2549032.9232937796 6676911.541646171) + +POINT (2549356.519618751 6676887.556140805) + +POINT (2549380.228787108 6676628.726731976) + +POINT (2549259.4803190352 6677171.941415444) + +POINT (2549658.44441092 6675896.308620852) + +POINT (2549836.40341572 6676274.085331525) + +POINT (2549668.5583428633 6676466.379468586) + +POINT (2549851.7393043684 6676412.307057406) + +POINT (2549612.2717542415 6676275.79572411) + +POINT (2550480.032265826 6675730.450551632) + +POINT (2550490.0389537932 6675983.398610522) + +POINT (2550294.6239294237 6676116.669199973) + +POINT (2550808.454569743 6675266.964168113) + +POINT (2551082.545425226 6675357.174874077) + +POINT (2551166.9711833904 6674761.498149053) + +POINT (2551347.5947885313 6674889.117441369) + +POINT (2551482.2107277266 6674984.909428399) + +POINT (2551182.323571112 6675106.617363887) + +POINT (2551406.347988614 6674187.896490896) + +POINT (2551101.9400859103 6674253.821622619) + +POINT (2551479.6698704357 6674688.431378118) + +POINT (2551657.6371247726 6675606.672140909) + +POINT (2550018.5036879224 6675800.976739431) + +POINT (2549939.365882756 6675948.670639449) \ No newline at end of file diff --git a/data/HelsinkiMedium/C_meetingspots.wkt b/data/HelsinkiMedium/C_meetingspots.wkt new file mode 100644 index 000000000..3c3cec952 --- /dev/null +++ b/data/HelsinkiMedium/C_meetingspots.wkt @@ -0,0 +1,3 @@ +POINT (2551019.4859670075 6675223.744247892) + +POINT (2551776.083972117 6676132.332795221) \ No newline at end of file diff --git a/data/HelsinkiMedium/C_offices.wkt b/data/HelsinkiMedium/C_offices.wkt new file mode 100644 index 000000000..5c42fe405 --- /dev/null +++ b/data/HelsinkiMedium/C_offices.wkt @@ -0,0 +1,39 @@ +POINT (2551376.426919153 6674304.123168278) + +POINT (2550967.0766606154 6675000.773069562) + +POINT (2550697.3498100247 6675261.432898526) + +POINT (2550544.1476647374 6675483.043764625) + +POINT (2551431.6740661557 6675050.304438443) + +POINT (2551206.618456572 6675407.336387593) + +POINT (2551000.2975447397 6675718.547819612) + +POINT (2550689.6034951024 6675859.940273265) + +POINT (2550394.3855762365 6676057.865702871) + +POINT (2550193.3443678655 6676346.541962416) + +POINT (2550170.1466707815 6676695.852139196) + +POINT (2549568.351221071 6676074.7895873925) + +POINT (2548866.5796365947 6676319.20568795) + +POINT (2548591.7710714224 6676574.744341456) + +POINT (2548387.5455419016 6677245.3982759155) + +POINT (2549190.6544346926 6676779.691382726) + +POINT (2550699.494689556 6674935.358054927) + +POINT (2550826.0508314357 6675180.984433278) + +POINT (2550853.835270902 6674980.93851696) + +POINT (2550585.040617954 6675171.722307353) \ No newline at end of file diff --git a/data/HelsinkiMedium/D_bus.wkt b/data/HelsinkiMedium/D_bus.wkt new file mode 100644 index 000000000..91da8b1ae --- /dev/null +++ b/data/HelsinkiMedium/D_bus.wkt @@ -0,0 +1 @@ +LINESTRING (2553320.273491563 6674457.528379207, 2553719.84804916 6675104.546888653, 2553670.9035481643 6675714.12680486, 2553683.145860566 6676146.346011659, 2553528.33505563 6676650.701775882, 2553727.5943640824 6677300.7809878485) \ No newline at end of file diff --git a/data/HelsinkiMedium/D_homes.wkt b/data/HelsinkiMedium/D_homes.wkt new file mode 100644 index 000000000..29285b3d7 --- /dev/null +++ b/data/HelsinkiMedium/D_homes.wkt @@ -0,0 +1,245 @@ +POINT (2553301.3325553946 6674456.0780463135) + +POINT (2553403.107089152 6674705.765356767) + +POINT (2552978.453940112 6674694.902863511) + +POINT (2553075.270502338 6674767.719577051) + +POINT (2553150.877505814 6674825.012727485) + +POINT (2554142.290322375 6674448.276255577) + +POINT (2554244.320591769 6674631.058209318) + +POINT (2554392.5235178415 6674574.94532979) + +POINT (2554503.1993016535 6675004.303879986) + +POINT (2554459.1302768234 6675014.6662584515) + +POINT (2554366.9252055897 6675022.638088216) + +POINT (2554645.842040018 6675276.456346842) + +POINT (2554673.997708634 6675411.237282962) + +POINT (2555013.4413935267 6675337.160280149) + +POINT (2554656.4179460146 6675619.875171387) + +POINT (2554808.597148756 6675683.019664873) + +POINT (2554739.6557708997 6675836.414873506) + +POINT (2554687.0897233114 6676142.005015275) + +POINT (2554582.9888202157 6676112.848322972) + +POINT (2554612.423167014 6675880.555004942) + +POINT (2554621.7368939016 6675740.422840561) + +POINT (2554510.19490874 6676193.726886939) + +POINT (2553874.35362124 6676889.326547164) + +POINT (2554058.054303554 6677147.885894006) + +POINT (2554288.274123086 6677394.042394036) + +POINT (2554430.0754087116 6677849.676975341) + +POINT (2554236.805263873 6677810.818056095) + +POINT (2554055.67018746 6677619.424125657) + +POINT (2553995.3083277284 6677545.697203198) + +POINT (2553820.1294167824 6677524.132253419) + +POINT (2553932.7438417096 6677359.32442526) + +POINT (2553836.9502220294 6677263.742486442) + +POINT (2553857.3925738693 6676805.917402355) + +POINT (2554406.572478771 6676113.638504341) + +POINT (2554468.641992591 6675824.642171331) + +POINT (2554425.736152429 6675609.322749301) + +POINT (2554193.1817140225 6675672.157171616) + +POINT (2554288.6783503825 6675625.7565213265) + +POINT (2554326.5684722555 6675869.682509391) + +POINT (2554170.553234968 6676018.396643582) + +POINT (2554077.547958678 6675727.719924875) + +POINT (2553890.89394224 6675364.116467373) + +POINT (2553788.31095389 6675212.56168117) + +POINT (2553939.2444765964 6674917.794023474) + +POINT (2554037.1829758077 6675028.579451931) + +POINT (2554212.931104783 6675112.068615107) + +POINT (2553719.84804916 6675104.546888653) + +POINT (2553532.7980549624 6674875.254259368) + +POINT (2553372.3363174153 6675000.002892785) + +POINT (2553151.1827386706 6674957.58315623) + +POINT (2553236.9036740907 6674889.257473511) + +POINT (2553211.3631085954 6675027.989316478) + +POINT (2553170.527902135 6675122.29096143) + +POINT (2553006.1971318955 6674929.916806002) + +POINT (2552942.890187577 6674846.207592319) + +POINT (2552897.8477174207 6674454.86776852) + +POINT (2552778.4934210437 6674690.971961255) + +POINT (2552589.166554728 6674742.313745678) + +POINT (2552496.0292858523 6674925.59581421) + +POINT (2552559.377477854 6675010.015190897) + +POINT (2552698.3739210153 6674904.100880502) + +POINT (2552760.872410741 6674986.329754405) + +POINT (2552515.5064419033 6675173.012603514) + +POINT (2552658.1574298046 6675140.395116857) + +POINT (2552715.260722555 6675284.768254665) + +POINT (2552543.8683489356 6675273.965775183) + +POINT (2552518.4927741736 6675379.730051141) + +POINT (2552705.7820049347 6675432.572179938) + +POINT (2552883.279035682 6675339.250759974) + +POINT (2552795.2482299977 6675564.042356142) + +POINT (2552742.599687042 6675712.626460488) + +POINT (2553052.246045524 6675578.855756246) + +POINT (2552998.36007207 6675727.009761872) + +POINT (2553209.2099795276 6675696.742814733) + +POINT (2553193.997833929 6675415.13817833) + +POINT (2553241.9111428424 6675316.725589797) + +POINT (2553221.9472641284 6675203.719651668) + +POINT (2553397.5139032975 6675244.609036964) + +POINT (2553450.8719064053 6675500.657807557) + +POINT (2553470.3408129197 6675572.594319065) + +POINT (2553507.9339514733 6675335.729951847) + +POINT (2553477.4766621296 6675206.120202664) + +POINT (2553523.0058549484 6675833.664242157) + +POINT (2553403.569063205 6676127.341649609) + +POINT (2553174.5866741715 6676358.924804635) + +POINT (2553109.8113123276 6676658.843644677) + +POINT (2553314.507065438 6676848.127090698) + +POINT (2553125.0647056093 6676868.411746613) + +POINT (2553195.0702736946 6677226.874024065) + +POINT (2553277.0046717883 6677667.925258069) + +POINT (2552899.2336395797 6677765.667692782) + +POINT (2552710.9049671995 6677653.501947503) + +POINT (2552561.2501226757 6677966.763850162) + +POINT (2552610.153375988 6677178.372891653) + +POINT (2551754.164953215 6677609.0417426005) + +POINT (2551912.597304744 6677299.730746788) + +POINT (2551973.231399185 6677208.489804355) + +POINT (2551590.774630154 6677326.5469018705) + +POINT (2551666.3816336305 6677622.074734049) + +POINT (2551445.7807738422 6677291.28880912) + +POINT (2552148.039080981 6676544.507401205) + +POINT (2552260.175032782 6676640.179360684) + +POINT (2552003.3009603056 6676087.112415837) + +POINT (2552295.2520626546 6676099.89534989) + +POINT (2552411.248797612 6675882.315409006) + +POINT (2552110.0169665217 6675223.784257075) + +POINT (2552141.422952581 6674921.104783389) + +POINT (2552319.9016781906 6675755.536309538) + +POINT (2552585.817242845 6675882.675491655) + +POINT (2552558.552524188 6676065.787521157) + +POINT (2553030.3187770853 6675902.430025891) + +POINT (2553950.4143492323 6676520.931989967) + +POINT (2553868.826431678 6676435.22231712) + +POINT (2553779.318958932 6676056.795457219) + +POINT (2553773.280298098 6675939.628564031) + +POINT (2552428.7213162547 6676613.913331872) + +POINT (2552545.7822414404 6676691.581158883) + +POINT (2552478.927996359 6676850.72768761) + +POINT (2552382.3754193066 6676805.027198027) + +POINT (2552308.9297944345 6677147.625834315) + +POINT (2552211.8574965727 6677157.938201302) + +POINT (2552070.9719095165 6676855.328743686) + +POINT (2551526.3952460703 6675568.953483388) \ No newline at end of file diff --git a/data/HelsinkiMedium/D_meetingspots.wkt b/data/HelsinkiMedium/D_meetingspots.wkt new file mode 100644 index 000000000..8c2c40054 --- /dev/null +++ b/data/HelsinkiMedium/D_meetingspots.wkt @@ -0,0 +1,3 @@ +POINT (2553423.037969719 6674726.15003564) + +POINT (2551506.1838812567 6676962.873428298) \ No newline at end of file diff --git a/data/HelsinkiMedium/D_offices.wkt b/data/HelsinkiMedium/D_offices.wkt new file mode 100644 index 000000000..17e0dc2d1 --- /dev/null +++ b/data/HelsinkiMedium/D_offices.wkt @@ -0,0 +1,39 @@ +POINT (2553394.2553363172 6675336.7501860205) + +POINT (2553062.029996001 6675431.351899847) + +POINT (2553052.246045524 6675578.855756246) + +POINT (2553218.944432785 6676004.253397298) + +POINT (2553362.2306350083 6676160.339223506) + +POINT (2553258.8721902124 6676270.974617526) + +POINT (2553108.3923920225 6676400.944449359) + +POINT (2553363.6083076303 6676465.00915406) + +POINT (2553496.8795723505 6676603.560955702) + +POINT (2553370.8101531332 6676594.448864214) + +POINT (2553458.708966231 6676375.618636353) + +POINT (2553520.0360217514 6676177.143080477) + +POINT (2553447.770080622 6676247.48922695) + +POINT (2553113.0533802346 6676122.790605012) + +POINT (2553020.4605807783 6676178.553404187) + +POINT (2552477.071850611 6676504.3081743205) + +POINT (2552841.833363509 6675831.963851868) + +POINT (2553890.89394224 6675364.116467373) + +POINT (2554326.5684722555 6675869.682509391) + +POINT (2553932.7438417096 6677359.32442526) \ No newline at end of file diff --git a/data/HelsinkiMedium/E_bus.wkt b/data/HelsinkiMedium/E_bus.wkt new file mode 100644 index 000000000..fcc880ca1 --- /dev/null +++ b/data/HelsinkiMedium/E_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2548008.8175634407 6672181.105874455, 2547920.7125119264 6672681.830805297, 2548383.8002522583 6672630.819096636, 2549125.219109916 6672924.776568371, 2550869.4433942605 6673004.914962448, 2551317.2612422374 6672889.818544494, 2551612.3884162 6672988.061093998, 2551699.751009415 6673299.7926453985, 2551893.5491245994 6673447.066448992, 2552153.657015446 6673654.484057328, + 2552256.454491749 6673534.296470803, 2552719.2287496882 6673650.273090789, 2553233.3316247175 6673542.7184038805) \ No newline at end of file diff --git a/data/HelsinkiMedium/E_homes.wkt b/data/HelsinkiMedium/E_homes.wkt new file mode 100644 index 000000000..e9c327f85 --- /dev/null +++ b/data/HelsinkiMedium/E_homes.wkt @@ -0,0 +1,183 @@ +POINT (2549499.286100165 6671007.186426016) + +POINT (2549472.846335174 6671138.376537938) + +POINT (2549309.6705000666 6670983.260934425) + +POINT (2549260.956986097 6671135.005764248) + +POINT (2549174.402847475 6671097.657191671) + +POINT (2549206.1635636105 6670959.665518594) + +POINT (2549125.4665960157 6671310.466037451) + +POINT (2548948.6130291284 6671255.803490818) + +POINT (2549216.590977947 6671328.23011482) + +POINT (2549493.272187941 6671418.080738135) + +POINT (2549493.272187941 6671418.080738135) + +POINT (2549446.34057389 6671492.427802935) + +POINT (2549323.9009508025 6671664.947401169) + +POINT (2549129.1046416825 6671709.017516534) + +POINT (2549129.1046416825 6671709.017516534) + +POINT (2549342.239670795 6671574.806711275) + +POINT (2549078.518482892 6671515.843177441) + +POINT (2548899.0168147366 6671469.6525753625) + +POINT (2548880.521353548 6671546.580232482) + +POINT (2548856.308963455 6671647.263342166) + +POINT (2549038.92070693 6671689.052934085) + +POINT (2548826.6848773137 6671777.543245168) + +POINT (2548775.7192398366 6671876.385932422) + +POINT (2548470.478133931 6671825.244193915) + +POINT (2548295.7446979643 6671789.025880765) + +POINT (2548081.801214259 6671838.827311633) + +POINT (2547874.358365441 6671779.45368367) + +POINT (2547895.0977006014 6671978.22930842) + +POINT (2548047.9203672023 6671965.126300901) + +POINT (2548200.495547704 6671992.0024697585) + +POINT (2548383.8002522583 6671995.793339873) + +POINT (2548615.0925115566 6672144.657508502) + +POINT (2548706.348886074 6672025.30011253) + +POINT (2548788.6215151707 6672008.0761591345) + +POINT (2548977.4369102134 6671973.518227091) + +POINT (2549110.600930957 6671998.894051576) + +POINT (2549230.4501995337 6672337.281721325) + +POINT (2549318.1510237516 6672494.647841398) + +POINT (2549085.4563432215 6672590.609867455) + +POINT (2548793.9754644623 6672558.962603494) + +POINT (2548896.2449704194 6672351.384958426) + +POINT (2549050.767041572 6672511.47170296) + +POINT (2548776.5689421124 6672470.202230424) + +POINT (2548589.1642178386 6672506.290513727) + +POINT (2548482.0522338627 6672525.845002048) + +POINT (2548261.4018768542 6672575.436384703) + +POINT (2548002.440671603 6672518.123229678) + +POINT (2547809.995480431 6672685.101556029) + +POINT (2547939.174974968 6672759.738687407) + +POINT (2547830.4048341243 6672948.171938284) + +POINT (2547685.3779796655 6672758.648437164) + +POINT (2547742.1430414137 6672483.21521728) + +POINT (2547791.3185294354 6672384.562573647) + +POINT (2547827.9547217367 6672273.6971268235) + +POINT (2548040.3060448663 6672264.735069772) + +POINT (2548124.368823418 6672366.038321796) + +POINT (2548112.4894906296 6672473.472981155) + +POINT (2548510.232651089 6672320.717919454) + +POINT (2548487.9176544272 6672268.936034014) + +POINT (2548621.246665904 6672251.612057662) + +POINT (2548639.8246224592 6672424.961846448) + +POINT (2548815.8862338276 6672149.328580648) + +POINT (2548733.1928783613 6672244.160347278) + +POINT (2549248.9704093323 6672253.142408921) + +POINT (2549370.4613357037 6672094.926093705) + +POINT (2549314.974952138 6671750.76709927) + +POINT (2549147.600102871 6671811.280988956) + +POINT (2549496.7534924108 6671701.165714318) + +POINT (2549517.5423247907 6671512.252353243) + +POINT (2549395.812161856 6671681.411180082) + +POINT (2549362.112804605 6671831.315587475) + +POINT (2549425.9147211234 6672289.940855228) + +POINT (2549601.2751218756 6672288.420506264) + +POINT (2549673.697804202 6672341.062589143) + +POINT (2549743.3486422105 6672210.512624154) + +POINT (2549467.888363642 6672609.60422721) + +POINT (2549410.9500616244 6672715.178459547) + +POINT (2549207.2030052296 6672804.628991029) + +POINT (2549109.421247215 6672784.324330524) + +POINT (2548894.5703144777 6672807.949753241) + +POINT (2548738.0518554533 6672768.48069395) + +POINT (2548260.279939869 6672778.793060937) + +POINT (2547867.255514378 6673234.787724891) + +POINT (2547780.17340541 6673331.900014968) + +POINT (2553670.9777939944 6673151.3385708975) + +POINT (2552599.255738062 6672877.725768852) + +POINT (2553270.223552655 6673799.537351251) + +POINT (2551573.186617998 6673194.328438315) + +POINT (2551733.574109715 6672719.2894031275) + +POINT (2552089.277631362 6672241.849816945) + +POINT (2552615.251589643 6672065.289291202) + +POINT (2552879.3357571587 6673419.2100551445) \ No newline at end of file diff --git a/data/HelsinkiMedium/E_meetingspots.wkt b/data/HelsinkiMedium/E_meetingspots.wkt new file mode 100644 index 000000000..82d0bf105 --- /dev/null +++ b/data/HelsinkiMedium/E_meetingspots.wkt @@ -0,0 +1,3 @@ +POINT (2552080.145394281 6673330.999808344) + +POINT (2552531.1145652616 6673268.445450311) \ No newline at end of file diff --git a/data/HelsinkiMedium/E_offices.wkt b/data/HelsinkiMedium/E_offices.wkt new file mode 100644 index 000000000..85ac6c45d --- /dev/null +++ b/data/HelsinkiMedium/E_offices.wkt @@ -0,0 +1,43 @@ +POINT (2553785.2338767163 6673218.283936794) + +POINT (2552971.7305677356 6673425.081402789) + +POINT (2552065.320976905 6672790.54575852) + +POINT (2551613.0318800593 6673913.813580948) + +POINT (2551164.661313126 6671899.611263307) + +POINT (2551217.6480870843 6672787.2850100845) + +POINT (2553277.4088990847 6674161.500432238) + +POINT (2552270.379709629 6672251.59205307) + +POINT (2550839.241840553 6672755.957819589) + +POINT (2552844.266976823 6672450.797776541) + +POINT (2548291.694175465 6671876.545969155) + +POINT (2548973.5431289105 6672751.016685456) + +POINT (2548291.694175465 6671876.545969155) + +POINT (2548973.5431289105 6672751.016685456) + +POINT (2547971.0181864705 6672303.113878818) + +POINT (2552924.1307412153 6672763.979660833) + +POINT (2552892.741254229 6673220.99455896) + +POINT (2552952.212164001 6673697.553943111) + +POINT (2553376.452836208 6673806.188877968) + +POINT (2551923.44544545 6672987.520970024) + +POINT (2551768.7088863445 6672875.395233927) + +POINT (2552330.7745675067 6672982.3197762) \ No newline at end of file diff --git a/data/HelsinkiMedium/F_bus.wkt b/data/HelsinkiMedium/F_bus.wkt new file mode 100644 index 000000000..b4d5e6796 --- /dev/null +++ b/data/HelsinkiMedium/F_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2552951.6016982887 6671978.96947831, 2552883.7245106613 6672239.799346303, 2552821.9107324784 6672739.764102663, 2552599.255738062 6672877.725768852, 2552478.6805102592 6673256.062608091, 2552288.5451893513 6673519.573091362, 2552063.959803357 6673790.795344708, 2551861.5739205102 6674198.388899207, 2551681.816516719 6674680.479552944, 2551335.641209913 6675218.222980602, + 2551083.634364065 6675615.144085466, 2550671.0337880836 6675975.426780757, 2550010.88111605 6676239.047289281, 2549500.1028042943 6676330.738335026, 2548940.256248493 6676559.490840337) \ No newline at end of file diff --git a/data/HelsinkiMedium/F_homes.wkt b/data/HelsinkiMedium/F_homes.wkt new file mode 100644 index 000000000..2711e7c96 --- /dev/null +++ b/data/HelsinkiMedium/F_homes.wkt @@ -0,0 +1,181 @@ +POINT (2553960.9655066184 6673004.774930307) + +POINT (2553785.2338767163 6673218.283936794) + +POINT (2552890.6046242346 6671963.876013924) + +POINT (2552125.790080613 6672703.615805584) + +POINT (2552459.211603745 6673074.480929848) + +POINT (2552963.6212732 6673523.774055605) + +POINT (2551671.7025847756 6672805.259135666) + +POINT (2551828.163297043 6673385.082221821) + +POINT (2551963.950670444 6673689.02198478) + +POINT (2551577.2866377174 6673756.917568779) + +POINT (2551219.034009243 6673822.6826637685) + +POINT (2551500.805183355 6673995.512333172) + +POINT (2551774.252574979 6674172.703003552) + +POINT (2551633.1360008963 6674446.5158515135) + +POINT (2551307.7165283235 6674304.733308323) + +POINT (2551479.6698704357 6674688.431378118) + +POINT (2551482.2107277266 6674984.909428399) + +POINT (2551666.0681512374 6675261.562928372) + +POINT (2551519.176901494 6675706.635085294) + +POINT (2551183.536253001 6675259.012342939) + +POINT (2550929.1040433757 6674996.93218797) + +POINT (2550972.4306099066 6675484.664136547) + +POINT (2551078.63514485 6675623.606027726) + +POINT (2550624.6383939153 6675563.242172477) + +POINT (2550508.6251598853 6675902.209975383) + +POINT (2550394.3855762365 6676057.865702871) + +POINT (2550066.944967182 6676406.875810778) + +POINT (2549951.401956741 6676210.480732432) + +POINT (2549851.805300662 6675947.4303547675) + +POINT (2549151.5103832474 6676045.732918046) + +POINT (2548909.716463783 6676167.730920114) + +POINT (2548623.878268098 6676319.195685655) + +POINT (2548455.4557276755 6676472.760933317) + +POINT (2548977.016183844 6676651.702005465) + +POINT (2549115.1381761194 6676925.464841947) + +POINT (2549061.2027054452 6677165.359904797) + +POINT (2548913.601995549 6677313.193836956) + +POINT (2548687.754430446 6677257.911147982) + +POINT (2548569.3983280044 6677113.988113486) + +POINT (2548227.554027944 6677086.711852795) + +POINT (2547839.223588812 6677132.572379112) + +POINT (2547608.5335456906 6677220.122474389) + +POINT (2549848.6127299746 6677171.911408556) + +POINT (2550055.882338523 6676982.537941873) + +POINT (2549931.718562274 6676739.702204053) + +POINT (2550174.3951821607 6676564.371960695) + +POINT (2550329.32148061 6676544.68744253) + +POINT (2550386.4577715076 6676872.182612135) + +POINT (2550396.0602321783 6677002.332485292) + +POINT (2550311.5932263304 6677127.911309262) + +POINT (2550100.479333699 6677351.662666664) + +POINT (2549642.6547977556 6677502.937388585) + +POINT (2550604.0145522687 6676889.226524206) + +POINT (2550671.0337880836 6675975.426780757) + +POINT (2550892.3276089514 6675946.170065495) + +POINT (2549985.497291751 6675712.356398501) + +POINT (2549999.9999771975 6675316.555550768) + +POINT (2549401.991064813 6675544.987982613) + +POINT (2548659.9204937597 6675512.400502845) + +POINT (2550842.021934407 6674568.053747973) + +POINT (2550888.227589232 6674330.749279739) + +POINT (2550952.3512376794 6673762.378822294) + +POINT (2550609.1292649973 6673933.918195537) + +POINT (2551154.9681075523 6674083.052426154) + +POINT (2551166.9711833904 6674761.498149053) + +POINT (2551138.5267809913 6675037.811570969) + +POINT (2550960.6832697047 6675199.428666763) + +POINT (2550817.223827211 6675252.830924124) + +POINT (2550736.634103593 6675116.409611491) + +POINT (2550397.7678862666 6675625.326422607) + +POINT (2550277.4483941 6675759.607243936) + +POINT (2550510.1348250937 6675681.119228668) + +POINT (2549465.1247688616 6675918.343678535) + +POINT (2549568.351221071 6676074.7895873925) + +POINT (2549612.2717542415 6676275.79572411) + +POINT (2549749.923522928 6676376.828914146) + +POINT (2549013.116156262 6676354.843867943) + +POINT (2548894.9580427003 6676442.353954037) + +POINT (2548656.3484443864 6676539.556264776) + +POINT (2550752.2834746344 6675483.593890894) + +POINT (2551206.618456572 6675407.336387593) + +POINT (2551416.2309335307 6675277.816659073) + +POINT (2549442.5787851736 6675782.422480692) + +POINT (2548756.0853425893 6675861.6306612585) + +POINT (2549385.879719719 6676658.773628606) + +POINT (2548840.502851217 6676797.405448616) + +POINT (2548615.364746266 6676844.806328488) + +POINT (2548410.7927362053 6676628.9067733) + +POINT (2548140.6864069286 6676740.502387718) + +POINT (2548118.3136635106 6677359.964572192) + +POINT (2548761.0020664376 6677528.1531763375) \ No newline at end of file diff --git a/data/HelsinkiMedium/F_meetingspots.wkt b/data/HelsinkiMedium/F_meetingspots.wkt new file mode 100644 index 000000000..9d271a7dd --- /dev/null +++ b/data/HelsinkiMedium/F_meetingspots.wkt @@ -0,0 +1,7 @@ +POINT (2551753.9422157253 6673510.250951662) + +POINT (2552669.1210640236 6673406.247079767) + +POINT (2550808.454569743 6675266.964168113) + +POINT (2550105.5033015246 6676255.961171506) \ No newline at end of file diff --git a/data/HelsinkiMedium/F_offices.wkt b/data/HelsinkiMedium/F_offices.wkt new file mode 100644 index 000000000..ecf8ffb4f --- /dev/null +++ b/data/HelsinkiMedium/F_offices.wkt @@ -0,0 +1,59 @@ +POINT (2552341.7794494093 6672696.104081427) + +POINT (2552203.5997103774 6672890.538709792) + +POINT (2552122.746001586 6673002.154328803) + +POINT (2550574.0522351246 6672733.982775682) + +POINT (2551115.9395496203 6672778.863077007) + +POINT (2550839.241840553 6672755.957819589) + +POINT (2552459.211603745 6673074.480929848) + +POINT (2552971.7305677356 6673425.081402789) + +POINT (2553195.4827505276 6673439.704759272) + +POINT (2552669.1210640236 6673406.247079767) + +POINT (2552708.001130296 6672220.484913082) + +POINT (2552299.6078180103 6672464.140839159) + +POINT (2551826.9588646907 6672789.355485318) + +POINT (2551878.6422118573 6673047.834813794) + +POINT (2551743.440555559 6673647.422436481) + +POINT (2551828.163297043 6673385.082221821) + +POINT (2551326.8967010546 6673752.106464491) + +POINT (2551708.858497886 6674048.154416052) + +POINT (2551166.9711833904 6674761.498149053) + +POINT (2551518.9211658575 6674539.787259997) + +POINT (2550776.0256411377 6675619.855166795) + +POINT (2550075.6564778937 6676303.832159282) + +POINT (2548894.9580427003 6676442.353954037) + +POINT (2552318.9612310114 6673271.776214818) + +POINT (2552056.98894488 6672339.2921827845) + +POINT (2552841.9571065586 6673043.233757719) + +POINT (2553092.8007677374 6673789.244988856) + +POINT (2553381.666543376 6673728.240986674) + +POINT (2553263.7229177677 6673904.271390739) + +POINT (2553841.6277093147 6673119.391238062) \ No newline at end of file diff --git a/data/HelsinkiMedium/G_bus.wkt b/data/HelsinkiMedium/G_bus.wkt new file mode 100644 index 000000000..8a66b5fe7 --- /dev/null +++ b/data/HelsinkiMedium/G_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2551217.6480870843 6672787.2850100845, 2551825.407951799 6673124.782475507, 2552378.5476342966 6673187.666909302, 2552978.882916019 6673298.132264293, 2552956.9143998967 6673618.665836011, 2552928.601990084 6674017.417361009, 2552890.282892305 6674615.774701311, 2553233.0593900075 6674893.908541065, 2553448.322799578 6675165.300833439, 2553667.3479978647 6675699.133363432, + 2553672.2564721764 6676175.662740696, 2553528.33505563 6676650.701775882, 2553570.820169422 6677006.193371478, 2553044.7884643846 6677290.308584129, 2552610.153375988 6677178.372891653, 2552800.0082126497 6676643.68016422, 2552847.575041023 6676242.638113479) \ No newline at end of file diff --git a/data/HelsinkiMedium/G_homes.wkt b/data/HelsinkiMedium/G_homes.wkt new file mode 100644 index 000000000..cc4f87e1d --- /dev/null +++ b/data/HelsinkiMedium/G_homes.wkt @@ -0,0 +1,265 @@ +POINT (2551097.724572678 6677066.147132598) + +POINT (2551324.520834497 6677004.983093684) + +POINT (2551157.9956875057 6677442.863599914) + +POINT (2551450.2025254914 6676362.16554848) + +POINT (2551433.290975341 6676202.248842975) + +POINT (2552192.578329401 6675949.250772606) + +POINT (2551753.7442268454 6676516.801041795) + +POINT (2551691.509722293 6676652.712237342) + +POINT (2551613.040129596 6676809.068125537) + +POINT (2551637.326765519 6677060.915931887) + +POINT (2552054.934810252 6676918.343207326) + +POINT (2551934.4338282794 6677088.602286705) + +POINT (2551924.130156993 6677482.70274415) + +POINT (2552285.4433635673 6676872.1926144315) + +POINT (2552428.7213162547 6676613.913331872) + +POINT (2552148.039080981 6676544.507401205) + +POINT (2552238.9902226427 6676326.42734553) + +POINT (2552389.684508786 6676201.32863176) + +POINT (2552558.552524188 6676065.787521157) + +POINT (2552675.0277322712 6675969.9955341285) + +POINT (2553020.4605807783 6676178.553404187) + +POINT (2553157.9886064143 6676267.573836949) + +POINT (2552992.040926989 6676445.14459457) + +POINT (2552800.2474492127 6676481.492937565) + +POINT (2552894.7211430273 6676764.197826507) + +POINT (2552859.495621495 6677146.545586367) + +POINT (2553295.112404754 6677200.097878166) + +POINT (2553047.461314262 6677319.92538204) + +POINT (2552868.842346529 6677328.447338075) + +POINT (2553017.7712318273 6677599.049449081) + +POINT (2553498.512980609 6677339.8299507145) + +POINT (2553932.7438417096 6677359.32442526) + +POINT (2554104.1774630123 6677538.065451491) + +POINT (2554055.67018746 6677619.424125657) + +POINT (2553684.4162892113 6676981.82777887) + +POINT (2553715.475794731 6676674.007125134) + +POINT (2553616.250367801 6676649.051397073) + +POINT (2553336.2528440706 6676782.191956679) + +POINT (2553317.5263958555 6676505.718498031) + +POINT (2553417.0405565687 6676416.538028535) + +POINT (2553577.8075269717 6676239.867477538) + +POINT (2553622.610760565 6676152.527430474) + +POINT (2553491.401880009 6676038.891347708) + +POINT (2553319.63827724 6676115.9590369705) + +POINT (2553372.7487942483 6676171.031677733) + +POINT (2553345.1045969054 6676349.882729218) + +POINT (2553579.878160673 6676443.8843052965) + +POINT (2553868.826431678 6676435.22231712) + +POINT (2553800.4542718516 6676199.43819785) + +POINT (2553960.9407580085 6675785.733240607) + +POINT (2553640.1080278177 6675591.688701778) + +POINT (2553221.831770615 6675582.566607993) + +POINT (2553052.246045524 6675578.855756246) + +POINT (2553180.1221132693 6675310.7242123075) + +POINT (2553289.4367235326 6675126.671966998) + +POINT (2552861.3352681696 6675041.022307926) + +POINT (2552621.125259744 6675091.723945417) + +POINT (2552373.597912302 6675153.17805091) + +POINT (2552685.7521299277 6675175.6432073135) + +POINT (2552942.890187577 6674846.207592319) + +POINT (2553164.942965817 6674647.952086951) + +POINT (2553403.107089152 6674705.765356767) + +POINT (2553151.1827386706 6674957.58315623) + +POINT (2553778.3455136064 6675172.792553006) + +POINT (2553923.867340265 6675169.641829823) + +POINT (2554176.6496425583 6675114.949276302) + +POINT (2554257.7920851326 6675124.461459623) + +POINT (2554366.9252055897 6675022.638088216) + +POINT (2554355.705835734 6675308.943803652) + +POINT (2554656.3272011112 6675864.1412375085) + +POINT (2554582.9888202157 6676112.848322972) + +POINT (2554395.4933510385 6675847.697463186) + +POINT (2554200.2515669386 6675562.872087532) + +POINT (2553890.89394224 6675364.116467373) + +POINT (2552973.6609593136 6675416.438476786) + +POINT (2552559.1299917544 6675350.793409347) + +POINT (2552841.239396869 6675808.408445221) + +POINT (2552803.943241636 6675439.963876545) + +POINT (2552795.2482299977 6675564.042356142) + +POINT (2553206.4793828935 6675916.143173455) + +POINT (2553597.4826719025 6675694.122213229) + +POINT (2553795.603544296 6675666.425856114) + +POINT (2553030.3187770853 6675902.430025891) + +POINT (2552552.216880034 6675219.863357116) + +POINT (2552150.274705416 6675237.957510246) + +POINT (2552030.169701203 6675410.377085522) + +POINT (2551956.270351815 6675854.0589233255) + +POINT (2551887.5682105217 6675183.465002641) + +POINT (2551722.791965302 6675434.742678129) + +POINT (2551467.757539501 6675888.4568186365) + +POINT (2551525.3310558414 6675682.409524828) + +POINT (2552923.602770869 6674449.906629795) + +POINT (2553020.485329388 6674618.795394648) + +POINT (2552784.3010948515 6674675.568425699) + +POINT (2553093.7824626 6674467.150587782) + +POINT (2553073.3731089067 6674056.326291733) + +POINT (2553270.223552655 6673799.537351251) + +POINT (2553457.3477926827 6673918.384630135) + +POINT (2553277.4088990847 6674161.500432238) + +POINT (2552873.2723477148 6674175.9337451) + +POINT (2552780.927034358 6673737.673151629) + +POINT (2553233.3316247175 6673542.7184038805) + +POINT (2552971.7305677356 6673425.081402789) + +POINT (2552677.906820565 6673285.539373861) + +POINT (2552837.8075896194 6672534.056886912) + +POINT (2552135.4420385035 6672451.177863781) + +POINT (2551826.9588646907 6672789.355485318) + +POINT (2552264.671030261 6672803.6187591525) + +POINT (2553953.829657409 6673110.059096065) + +POINT (2553780.1521621346 6673315.01613963) + +POINT (2552147.7668462717 6673412.808585823) + +POINT (2553372.3363174153 6675000.002892785) + +POINT (2553603.3563420037 6674962.294237559) + +POINT (2553584.547398422 6675077.290632555) + +POINT (2553414.920425647 6675381.700503417) + +POINT (2553335.7413727976 6675585.597303625) + +POINT (2553376.1723519615 6675692.741896406) + +POINT (2553255.448632499 6675777.9514544625) + +POINT (2552891.322333924 6676098.715078983) + +POINT (2552762.827550929 6676310.513692887) + +POINT (2552525.5543775535 6676433.6319520855) + +POINT (2553463.3369562966 6676927.245250602) + +POINT (2553326.1636607368 6676944.679252209) + +POINT (2553220.5695915064 6676858.439457684) + +POINT (2554435.9490788123 6675418.588970386) + +POINT (2554633.59147808 6675465.359705622) + +POINT (2554244.320591769 6674631.058209318) + +POINT (2552596.244657181 6675853.968902663) + +POINT (2552426.8404218964 6675906.450948809) + +POINT (2551618.6828126702 6676472.390848372) + +POINT (2551551.655327319 6676622.915398106) + +POINT (2551366.758462189 6676642.349858876) + +POINT (2552220.610254967 6677124.070427668) \ No newline at end of file diff --git a/data/HelsinkiMedium/G_meetingspots.wkt b/data/HelsinkiMedium/G_meetingspots.wkt new file mode 100644 index 000000000..49ca52af1 --- /dev/null +++ b/data/HelsinkiMedium/G_meetingspots.wkt @@ -0,0 +1,7 @@ +POINT (2552399.5592041663 6675863.2110239975) + +POINT (2552122.746001586 6673002.154328803) + +POINT (2552677.906820565 6673285.539373861) + +POINT (2552459.211603745 6673074.480929848) \ No newline at end of file diff --git a/data/HelsinkiMedium/G_offices.wkt b/data/HelsinkiMedium/G_offices.wkt new file mode 100644 index 000000000..b86aa7afe --- /dev/null +++ b/data/HelsinkiMedium/G_offices.wkt @@ -0,0 +1,59 @@ +POINT (2551121.9534618445 6672693.903576347) + +POINT (2550605.8789475537 6672642.231716162) + +POINT (2552264.671030261 6672803.6187591525) + +POINT (2552487.458017264 6672030.541315537) + +POINT (2552637.005617812 6672559.452715989) + +POINT (2553241.3996715695 6673442.8554824535) + +POINT (2553085.706166211 6673889.8780870605) + +POINT (2551818.5030896156 6673548.549742341) + +POINT (2552788.4341127174 6673214.002954185) + +POINT (2551458.9717829595 6675914.192725771) + +POINT (2551097.724572678 6677066.147132598) + +POINT (2554229.141444317 6673170.67300871) + +POINT (2552949.8940442 6675112.718764335) + +POINT (2553295.4341366836 6676235.586494929) + +POINT (2552321.658829499 6676728.859715389) + +POINT (2552330.7745675067 6672982.3197762) + +POINT (2552144.277292265 6672259.273816257) + +POINT (2551931.958967282 6672378.671221412) + +POINT (2552299.6078180103 6672464.140839159) + +POINT (2552153.3187844427 6672560.252899654) + +POINT (2551671.7025847756 6672805.259135666) + +POINT (2550839.241840553 6672755.957819589) + +POINT (2551217.6480870843 6672787.2850100845) + +POINT (2552924.1307412153 6672763.979660833) + +POINT (2552883.7245106613 6672239.799346303) + +POINT (2553388.9756328557 6672231.9875532705) + +POINT (2552039.310187821 6672058.027624439) + +POINT (2551364.993061344 6672039.063271573) + +POINT (2550978.2795313974 6672002.13479542) + +POINT (2551001.279239602 6672187.047238169) \ No newline at end of file diff --git a/data/HelsinkiMedium/H_bus.wkt b/data/HelsinkiMedium/H_bus.wkt new file mode 100644 index 000000000..8f99f4b07 --- /dev/null +++ b/data/HelsinkiMedium/H_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2547673.3171570706 6672763.109461098, 2548776.5689421124 6672470.202230424, 2549545.178272597 6672487.866284834, 2550330.047439836 6672702.395525495, 2551005.1565218316 6672769.690971744, 2551733.574109715 6672719.2894031275, 2552249.4588846625 6672531.896391016, 2552747.310172474 6672343.373119477, 2552892.741254229 6673220.99455896, 2553296.217842666 6673446.466311243, + 2552889.0537113426 6673977.008085913, 2552889.218702076 6674644.061193879, 2553352.5456789713 6675010.225239109, 2553526.313919149 6675457.6179286605, 2553675.4737914735 6675736.161862543, 2552982.6364551983 6676025.478269019, 2552089.5251174616 6676457.277379394, 2551257.212864899 6675722.818799925, 2550332.8522822997 6676228.294821279, 2549305.5374822007 6676406.915819961) \ No newline at end of file diff --git a/data/HelsinkiMedium/roads.wkt b/data/HelsinkiMedium/roads.wkt new file mode 100644 index 000000000..445026b37 --- /dev/null +++ b/data/HelsinkiMedium/roads.wkt @@ -0,0 +1,5887 @@ +LINESTRING (2553179.3384072864 6674191.97742759, 2553177.2842726586 6674217.663323245, 2553204.730481122 6674219.923842099) + +LINESTRING (2550219.7346356367 6676905.580277865, 2550227.579944999 6677007.843750287, 2550223.611917866 6677037.070458662, 2550214.6364219817 6677066.947316264, 2550198.4920787406 6677098.874644508, 2550184.7236020574 6677117.4989193175) + +LINESTRING (2552342.0186859723 6675795.485479027, 2552309.350520804 6675833.524210015, 2552312.856573884 6675890.1672112215) + +LINESTRING (2553166.5351263923 6671840.257639934, 2553133.875210761 6671847.919398529, 2553100.52233405 6671879.85672907, 2553073.7360885195 6671972.968100821, 2553033.420602869 6672024.900020697) + +LINESTRING (2550033.204362248 6676900.989224086, 2550075.136757084 6676897.898514678) + +LINESTRING (2549600.30167655 6676266.513593592, 2549596.680129957 6676263.692946172) + +LINESTRING (2547866.3563148826 6671640.20172132, 2547872.23823452 6671602.253010994, 2547868.8724235636 6671587.159546608, 2547859.484450846 6671575.806940856) + +LINESTRING (2551369.464310213 6674242.12893881, 2551363.8216271386 6674239.708383223) + +LINESTRING (2551755.715866107 6673348.653860459, 2551695.9644720885 6673304.323685403, 2551680.042866337 6673285.9894771725, 2551676.5285637206 6673275.937169877) + +LINESTRING (2553423.037969719 6674726.15003564, 2553432.013465604 6674720.138655854) + +LINESTRING (2549712.602619084 6677411.716450743, 2549641.392618647 6677444.533983315) + +LINESTRING (2551295.399970092 6677111.777606111, 2551251.033961942 6677100.314975105, 2551230.294626782 6677103.4156868085) + +LINESTRING (2553161.263672468 6674509.460299083, 2553216.8325514 6674555.170790962, 2553231.4012331394 6674563.35266894) + +LINESTRING (2549254.316109087 6675511.960401828, 2549254.77808314 6675452.666792232) + +LINESTRING (2554077.547958678 6675727.719924875, 2554193.1817140225 6675672.157171616) + +LINESTRING (2547852.6125868093 6672839.406973582, 2547830.4048341243 6672948.171938284) + +LINESTRING (2549241.5128281927 6676430.541242678, 2549233.6675188304 6676433.521926831) + +LINESTRING (2549004.0911631575 6677387.730945377, 2548931.025016972 6677383.429958176) + +LINESTRING (2550689.6034951024 6675859.940273265, 2550661.1508431667 6675942.269170127, 2550661.36533112 6675953.651782765, 2550668.0144576663 6675971.205811922) + +LINESTRING (2549574.2083920985 6677584.546120147, 2549549.014307143 6677586.3265288025, 2549512.122379206 6677578.2046646, 2549489.089672855 6677575.774106717) + +LINESTRING (2551159.1588721746 6672286.410044805, 2551001.279239602 6672187.047238169, 2550905.988841658 6672124.8129536025) + +LINESTRING (2551671.7025847756 6672805.259135666, 2551630.2239144556 6672865.68300469) + +LINESTRING (2551010.510471123 6674129.593108585, 2550944.2006954607 6674110.598748831, 2550826.075580046 6674079.33157211, 2550804.717529637 6674077.471145088, 2550763.8328259564 6674081.84214836, 2550737.2775674523 6674091.744421218, 2550705.054877264 6674109.718546798, 2550685.833456849 6674116.240043671, 2550674.9523179964 6674116.500103362) + +LINESTRING (2552747.194678961 6676689.470674465, 2552743.078160168 6676683.519308455) + +LINESTRING (2553066.311505527 6674620.17571147, 2553139.113666539 6674623.78654026) + +LINESTRING (2551039.1363633284 6673648.872769374, 2551034.7063621427 6673639.970726099) + +LINESTRING (2553138.2804633365 6676243.708359132, 2553157.9886064143 6676267.573836949, 2553126.3186351815 6676295.190175696) + +LINESTRING (2551880.2013742854 6673268.035356183, 2551892.3364427104 6673318.977048773) + +LINESTRING (2553482.0469054384 6674652.503131547, 2553489.306497698 6674471.071487742) + +LINESTRING (2550574.2914716876 6675776.061020553, 2550507.0907460665 6675833.574221495, 2550495.236161888 6675852.968673082, 2550494.980426252 6675865.161471682) + +LINESTRING (2553476.9651908567 6676499.447058554, 2553430.7842846415 6676540.6965264985) + +LINESTRING (2552720.0207052073 6675222.293914999, 2552813.149724547 6675228.055237388) + +LINESTRING (2548542.612082474 6676286.008068138, 2548573.811830117 6676310.843768649) + +LINESTRING (2551832.4695551787 6673402.116131595, 2551753.9422157253 6673510.250951662) + +LINESTRING (2552849.2414474282 6672948.622041596, 2552808.521734481 6672946.281504375) + +LINESTRING (2548084.0945854504 6676770.6693119, 2548102.3838082226 6676803.586867429) + +LINESTRING (2553121.4349094797 6676223.603744541, 2553138.2804633365 6676243.708359132) + +LINESTRING (2549155.041184937 6676773.579979982, 2549115.1381761194 6676925.464841947, 2549127.4134866674 6676931.256171225) + +LINESTRING (2549145.2159867766 6672828.484466551, 2549109.421247215 6672784.324330524, 2549099.505304151 6672735.313081025, 2549098.9855833417 6672730.962082345, 2549101.971915612 6672730.211910159) + +LINESTRING (2547799.0070976014 6677546.967494767, 2547779.4886938673 6677543.786764697, 2547768.5828064047 6677536.495091047, 2547760.8199924086 6677521.191578449, 2547759.2113327603 6677485.943487993) + +LINESTRING (2551422.6490730513 6674549.74954663, 2551406.422234444 6674551.429932327) + +LINESTRING (2550684.191799054 6675388.912158701, 2550661.109595483 6675351.45356087) + +LINESTRING (2553313.451124746 6676788.76346503, 2553296.5230755224 6676777.180806476, 2553210.9423822258 6676786.052842864) + +LINESTRING (2551618.6828126702 6676472.390848372, 2551598.925172373 6676549.378519267) + +LINESTRING (2549311.691636548 6674650.87275733, 2549310.7841875153 6674632.1784664495, 2549322.729516597 6674567.503621703) + +LINESTRING (2551463.3192887786 6672655.414742047, 2551445.2198053496 6672682.380931567) + +LINESTRING (2552897.8477174207 6674454.86776852, 2552891.80080705 6674590.969007688, 2552890.282892305 6674615.774701311) + +LINESTRING (2552507.9168681772 6672319.74769676, 2552498.9166236827 6672416.219839904) + +LINESTRING (2548323.8426198238 6671981.420040785, 2548260.0242042323 6671980.549841049, 2548200.495547704 6671992.0024697585) + +LINESTRING (2554115.636069431 6673175.21405101, 2554201.9262228804 6673221.8547564) + +LINESTRING (2552552.216880034 6675219.863357116, 2552543.8683489356 6675273.965775183) + +LINESTRING (2549251.7175050396 6674640.600399526, 2549232.4795855517 6674650.932771104, 2549201.2880874453 6674653.873446074, 2549196.123877497 6674658.424490671, 2549142.980362342 6674666.496343394, 2549129.0798930726 6674682.20995012, 2549119.551678232 6674680.439543761, 2549082.8494896377 6674680.219493253) + +LINESTRING (2553131.986066866 6675319.296179822, 2553103.599411224 6675283.527969984, 2553103.8716459335 6675268.684562993) + +LINESTRING (2552525.5543775535 6676433.6319520855, 2552472.782091548 6676427.5305516375, 2552403.6427248125 6676435.452369924) + +LINESTRING (2553544.215413698 6676566.452438225, 2553534.563455807 6676611.812849751) + +LINESTRING (2549456.223518807 6671020.389456493, 2549421.1959861545 6671189.488269557) + +LINESTRING (2548270.1051380294 6675336.150048272, 2548270.0886389557 6675320.836533377, 2548256.2789145894 6675283.718013604, 2548224.485200307 6675250.1503088465, 2548140.265680559 6675164.140567125, 2548112.2172559197 6675145.726340528, 2547872.848700233 6675061.517012053) + +LINESTRING (2551419.852480124 6674939.328966365, 2551347.5947885313 6674889.117441369) + +LINESTRING (2551941.041707143 6676640.42941808, 2551954.768936143 6676640.379406601, 2551980.5404886645 6676644.800421352, 2552038.6089772047 6676658.383539069) + +LINESTRING (2552808.4227400413 6675372.088297138, 2552796.3371688365 6675371.648196123, 2552744.8600600865 6675368.017362741, 2552710.8142222962 6675361.675907194) + +LINESTRING (2553144.0138913146 6676147.986388173, 2553156.487190742 6676159.188959487) + +LINESTRING (2547988.259718087 6672227.376494899, 2547998.5468903002 6672231.24738338, 2548040.3060448663 6672264.735069772, 2548094.447753957 6672319.50764166, 2548124.368823418 6672366.038321796, 2548133.5258091087 6672398.905865847, 2548132.453369343 6672426.1721242415, 2548125.5815053065 6672450.737762765, 2548112.4894906296 6672473.472981155, 2548083.162387808 6672500.249127055, + 2548058.529271345 6672511.001595057, 2548002.440671603 6672518.123229678, 2547927.510130133 6672506.360529798) + +LINESTRING (2552817.3899863893 6675825.142286122, 2552672.198141197 6675830.973624582) + +LINESTRING (2553184.535615382 6674084.792825625, 2553183.7354103257 6674109.328457262) + +LINESTRING (2547982.2870535464 6673722.389643622, 2547953.149690068 6673715.458052621, 2547931.931881782 6673717.788587547, 2547914.0633853795 6673728.040940758, 2547898.240774068 6673753.836861667) + +LINESTRING (2552599.255738062 6672877.725768852, 2552471.2311786567 6672787.425042226) + +LINESTRING (2552299.6078180103 6672464.140839159, 2552249.4588846625 6672531.896391016) + +LINESTRING (2553296.729313939 6675472.141262185, 2553225.5193135017 6675458.598153651) + +LINESTRING (2554582.9888202157 6676112.848322972, 2554687.0897233114 6676142.005015275) + +LINESTRING (2553086.96834532 6675006.344348332, 2553117.0709045874 6675047.643827756) + +LINESTRING (2551996.445595342 6675190.92671532, 2551999.085447073 6675223.374162947) + +LINESTRING (2553006.271377725 6676006.523918448, 2552994.7880226965 6676015.726030599, 2552982.6364551983 6676025.478269019) + +LINESTRING (2548931.025016972 6677383.429958176, 2548926.9744944726 6677402.224272015, 2548914.014472382 6677432.431205379, 2548906.053669506 6677434.96178622, 2548767.4367050314 6677435.021799995, 2548760.7710794113 6677439.552839999) + +LINESTRING (2552800.0082126497 6676643.68016422, 2552796.3784165196 6676639.20913799) + +LINESTRING (2552390.534211062 6675006.754442461, 2552454.3361275797 6675092.164046433) + +LINESTRING (2551335.641209913 6675218.222980602, 2551330.3532569148 6675214.352092121) + +LINESTRING (2552662.2162018404 6673501.088848694, 2552654.6513767247 6673568.414301831, 2552644.8674262473 6673602.582144339) + +LINESTRING (2552186.1766889542 6672165.952396294, 2552116.3031134554 6672159.020805294) + +LINESTRING (2551630.2239144556 6672865.68300469, 2551518.434443195 6672784.574387918, 2551458.0890825368 6672869.863964342) + +LINESTRING (2553044.136750988 6675713.786726803, 2553042.544590413 6675720.218203013) + +LINESTRING (2552470.90119719 6675959.90321765, 2552416.008780264 6676004.983564893) + +LINESTRING (2551497.6291117417 6674081.552081781, 2551435.5678474586 6674092.2645406) + +LINESTRING (2553227.655943496 6676231.925654661, 2553263.0299566886 6676267.053717567) + +LINESTRING (2553434.3233358683 6674261.343349073, 2553409.995452262 6674269.305176542, 2553343.2319520838 6674273.286090277, 2553328.6632703445 6674268.35495844, 2553305.457323724 6674260.503156224, 2553285.9141713795 6674257.772529467) + +LINESTRING (2552022.74511821 6672148.888479631, 2552011.946474724 6672145.087607222) + +LINESTRING (2551307.84852091 6675247.109610918, 2551194.4091423173 6675230.625827413) + +LINESTRING (2553050.1506632124 6676074.869605758, 2552970.3528951136 6676142.775192053) + +LINESTRING (2554035.524818939 6675640.069806639, 2554151.0265816967 6675585.9073747955, 2554193.1817140225 6675672.157171616) + +LINESTRING (2549106.962885291 6676998.751663391, 2549102.912362791 6676997.70142233) + +LINESTRING (2552450.1371134203 6671958.454769592, 2552394.4774895846 6671930.768414773, 2552322.7560178745 6671906.8729300685, 2552302.775640087 6671904.872470906, 2552263.8130784486 6671910.0536601385, 2552225.469232059 6671927.747721436) + +LINESTRING (2549130.2678263513 6672089.474842485, 2549133.3531530616 6672100.897464307, 2549128.4941759696 6672109.2793882005, 2549122.686502162 6672112.010014959, 2549007.9024490938 6672133.264893567) + +LINESTRING (2553224.11689227 6672386.7130672475, 2553180.9635660085 6672364.467961353) + +LINESTRING (2550254.9189094855 6673758.087837389, 2550235.6892395345 6673737.38308505, 2550212.96176604 6673702.565093315, 2550195.4232511036 6673691.96265975, 2550177.942482924 6673691.572570213) + +LINESTRING (2549842.4503260907 6677349.362138627, 2549751.8044172856 6677393.642302204) + +LINESTRING (2548478.719421053 6676250.2398582995, 2548407.5506682987 6676384.380647487, 2548381.4326352375 6676426.870400113) + +LINESTRING (2548097.5248311306 6677385.360401268, 2548084.0533377673 6677379.259000821, 2548069.756890738 6677379.058954905, 2547974.804723797 6677400.693920755) + +LINESTRING (2551619.8624964124 6672639.221025121, 2551565.234064659 6672717.038886569, 2551560.8783093034 6672723.220305383) + +LINESTRING (2549206.1635636105 6670959.665518594, 2549174.402847475 6671097.657191671) + +LINESTRING (2552820.5495589296 6672756.447932084, 2552817.4477331457 6672794.546676847) + +LINESTRING (2553690.9416727084 6673181.575511149, 2553824.567667505 6673093.225232207) + +LINESTRING (2551725.456565643 6672934.608825157, 2551630.2239144556 6672865.68300469) + +LINESTRING (2553746.3785590543 6676467.58974638, 2553726.6786655136 6676547.067988934, 2553725.5237303814 6676562.6115566315) + +LINESTRING (2553358.3863509255 6674072.089909939, 2553357.000428767 6674095.115194907) + +LINESTRING (2552345.054515463 6673566.843941389, 2552348.164590783 6673563.0530712735) + +LINESTRING (2551730.653773738 6675398.674399417, 2551722.791965302 6675434.742678129, 2551716.885297055 6675468.630456354, 2551709.5019617453 6675528.684240432, 2551710.1701742145 6675561.971880908, 2551720.820326041 6675610.763079898) + +LINESTRING (2552906.715969329 6674283.478429713, 2552905.7342744665 6674299.052004299) + +LINESTRING (2552869.494059925 6674900.820127474, 2552760.872410741 6674986.329754405) + +LINESTRING (2552760.3609394683 6674691.592103596, 2552736.759015088 6674712.566917922, 2552701.6324879956 6674731.48125931, 2552686.7503238632 6674736.8424898675, 2552629.432543159 6674742.873874244) + +LINESTRING (2551598.925172373 6676549.378519267, 2551584.0760063874 6676600.200184308, 2551551.655327319 6676622.915398106) + +LINESTRING (2548394.7721360144 6672592.170225603, 2548364.578831844 6672586.748981271, 2548372.935612479 6672570.825326332, 2548401.3222681214 6672567.384536571) + +LINESTRING (2551894.4565736316 6675131.533082765, 2551894.0440967986 6675129.70266263, 2551879.533161816 6675072.8796201) + +LINESTRING (2552784.3010948515 6674675.568425699, 2552769.039452033 6674685.7007513605, 2552760.3609394683 6674691.592103596) + +LINESTRING (2549124.59214513 6672070.870572267, 2549000.560361468 6672094.435981209) + +LINESTRING (2551019.4859670075 6675223.744247892, 2551000.7017720356 6675211.741492913, 2550993.1864441396 6675199.478678242) + +LINESTRING (2550999.72832671 6675440.514002815, 2550915.244821789 6675393.543221664) + +LINESTRING (2553522.444886456 6676778.801178398, 2553522.774867922 6676791.444080309) + +LINESTRING (2552665.84599797 6672078.382296425, 2552630.0925060916 6672212.543090205) + +LINESTRING (2552495.9550400223 6671994.583062079, 2552450.1371134203 6671958.454769592) + +LINESTRING (2552385.361751577 6671970.1474534, 2552384.074823858 6671979.859682638, 2552397.7195574916 6672026.420369661, 2552394.4032437545 6672059.577980291) + +LINESTRING (2553523.0058549484 6675833.664242157, 2553462.404758654 6675946.380113707) + +LINESTRING (2553553.6941313185 6676530.764246753, 2553547.036755235 6676556.150073535) + +LINESTRING (2549851.7393043684 6676412.307057406, 2549778.0874410802 6676396.783494299, 2549749.923522928 6676376.828914146) + +LINESTRING (2549495.722300329 6671447.877577371, 2549525.115399443 6671424.8923015855, 2549548.3295956007 6671421.881610545, 2549638.7692659893 6671457.529792833) + +LINESTRING (2551445.1950567393 6673509.880866717, 2551290.1450152406 6673526.754739758) + +LINESTRING (2548787.3180883788 6676110.747840851, 2548815.193272748 6676123.740823115, 2548851.441736826 6676140.604693861, 2548909.716463783 6676167.730920114) + +LINESTRING (2553505.937563602 6677026.928130704, 2553513.782872964 6677018.266142528, 2553515.969000179 6677009.334092364, 2553513.626131768 6676989.269486957, 2553510.895535134 6676969.885037665, 2553512.0257216557 6676942.078655297, 2553514.7893164367 6676936.40735357, 2553530.3231939645 6676923.54440115, 2553543.2667169822 6676917.793081056, 2553584.448403982 6676899.478877417, + 2553587.4264867157 6676880.294474042) + +LINESTRING (2552859.4626233485 6674782.643002409, 2552835.0769929853 6674799.846951212, 2552698.3739210153 6674904.100880502) + +LINESTRING (2553038.9560419666 6676066.327645131, 2553050.1506632124 6676074.869605758) + +LINESTRING (2551471.230594434 6675882.435436555, 2551467.757539501 6675888.4568186365) + +LINESTRING (2552487.458017264 6672030.541315537, 2552445.847354358 6672020.799079413) + +LINESTRING (2553907.5497567537 6675674.807780008, 2553960.9407580085 6675785.733240607) + +LINESTRING (2552773.2384661925 6673412.668553681, 2552720.809051393 6673409.434952837, 2552669.1210640236 6673406.247079767) + +LINESTRING (2553357.8171328963 6675007.504614647, 2553372.3363174153 6675000.002892785, 2553495.114171506 6674905.331162887) + +LINESTRING (2553508.379426453 6674894.768738505, 2553627.972959393 6675041.482413534) + +LINESTRING (2552803.943241636 6675439.963876545, 2552795.2482299977 6675564.042356142) + +LINESTRING (2548033.566173416 6672145.257646251, 2548008.8175634407 6672181.105874455) + +LINESTRING (2552146.09219033 6673240.589056464, 2552080.145394281 6673330.999808344) + +LINESTRING (2550779.399701631 6671848.84961204, 2550578.80396824 6671730.592468609) + +LINESTRING (2551383.092544773 6674405.416418006, 2551385.080683108 6674421.690153298) + +LINESTRING (2549484.469932326 6671130.134646186, 2549489.015427025 6671112.480594071, 2549499.286100165 6671007.186426016, 2549499.7315751445 6670975.109063334) + +LINESTRING (2553689.1515232534 6675997.631877468, 2553683.9790637684 6675997.65188206) + +LINESTRING (2554459.1302768234 6675014.6662584515, 2554316.421542166 6675094.534590541, 2554257.7920851326 6675124.461459623) + +LINESTRING (2550968.429584627 6672463.97080013, 2550922.859144125 6672528.195541564, 2550794.1663722503 6672436.714544032, 2550841.0979863014 6672371.139492662) + +LINESTRING (2549233.6675188304 6676433.521926831, 2549180.0125324028 6676455.486968443) + +LINESTRING (2553063.374670476 6675121.190708891, 2552981.4980191393 6675115.589423234) + +LINESTRING (2552242.166294256 6676709.885360226, 2552243.8079520515 6676703.5339023825) + +LINESTRING (2550919.047858189 6673708.456445551, 2550802.3251640056 6673777.652328005) + +LINESTRING (2551727.032227145 6676349.022531778, 2551660.623457043 6676332.648773527) + +LINESTRING (2549867.1164407 6672570.705298782, 2549786.7412050352 6672548.030094167, 2549711.7116691247 6672521.834081425) + +LINESTRING (2551892.3364427104 6673318.977048773, 2551837.3615304176 6673395.314570441, 2551832.4695551787 6673402.116131595) + +LINESTRING (2551403.881377153 6673861.881661071, 2551398.9151560846 6673860.871429194) + +LINESTRING (2552675.0277322712 6675969.9955341285, 2552558.552524188 6676065.787521157) + +LINESTRING (2548714.095200997 6676795.715060622, 2548721.0660594734 6676847.026838158, 2548716.553562921 6676858.089377331, 2548632.598028346 6676920.783767506, 2548595.772096702 6676966.19419051, 2548601.3652825565 6676977.806855951, 2548654.855278251 6677031.539189075) + +LINESTRING (2552426.8404218964 6675906.450948809, 2552366.965284828 6675955.152127137) + +LINESTRING (2553450.8719064053 6675500.657807557, 2553470.3408129197 6675572.594319065) + +LINESTRING (2553243.536301564 6676573.534063662, 2553114.3320584167 6676665.175097928) + +LINESTRING (2553236.9036740907 6674889.257473511, 2553233.0593900075 6674893.908541065) + +LINESTRING (2551219.034009243 6673822.6826637685, 2551179.254743475 6673814.2407261, 2551136.8603745867 6673805.238659865) + +LINESTRING (2552181.4084567656 6673476.683246903, 2552212.113232209 6673461.839839912) + +LINESTRING (2553466.348037177 6673655.7443466, 2553386.5337700048 6673649.462904828) + +LINESTRING (2549805.7481374964 6676012.335252318, 2549795.757948603 6676017.0063244635) + +LINESTRING (2553271.7909646197 6672331.730447147, 2553277.6316365744 6672344.343342171, 2553285.59243945 6672351.434969905, 2553382.573992409 6672376.150642866) + +LINESTRING (2552416.008780264 6676004.983564893, 2552502.199939273 6676110.617811005) + +LINESTRING (2551949.7779664644 6673099.606696938, 2551878.6422118573 6673047.834813794) + +LINESTRING (2553098.567193862 6673709.276633807, 2553092.8007677374 6673789.244988856) + +LINESTRING (2552651.4093088177 6676573.384029225, 2552726.5708373142 6676659.703842117, 2552743.078160168 6676683.519308455) + +LINESTRING (2549858.734911455 6676968.274668039, 2549907.8031555004 6676812.688956622) + +LINESTRING (2554510.19490874 6676193.726886939, 2554542.6815841016 6676160.80933141, 2554582.9888202157 6676112.848322972) + +LINESTRING (2553014.2899273573 6676578.445190908, 2552964.231738913 6676515.460734155) + +LINESTRING (2553463.3369562966 6676927.245250602, 2553470.134574503 6676965.363999957, 2553330.849397559 6676983.47815768) + +LINESTRING (2551431.6740661557 6675050.304438443, 2551419.3987556077 6675041.802487, 2551348.1227588775 6675039.96206457) + +LINESTRING (2552017.9191392646 6673946.871168619, 2551981.9676585067 6673998.423001255, 2551977.1334300246 6673995.322289552) + +LINESTRING (2553442.6636174303 6674102.896981052, 2553357.000428767 6674095.115194907) + +LINESTRING (2548977.016183844 6676651.702005465, 2548817.0659175697 6676739.162080079) + +LINESTRING (2551126.16072554 6675032.970459795, 2551117.853442125 6675055.035524365) + +LINESTRING (2553105.1255755057 6676116.769222932, 2553113.0533802346 6676122.790605012) + +LINESTRING (2550583.3164647925 6672862.86235727, 2550579.9589033723 6672898.080440838, 2550582.7142486162 6672922.015934725) + +LINESTRING (2553039.1292822366 6673301.743093083, 2552978.882916019 6673298.132264293) + +LINESTRING (2548997.772018077 6676011.285011257, 2548979.070318472 6676023.307770828, 2548909.716463783 6676167.730920114) + +LINESTRING (2549378.3726413595 6675899.999468008, 2549278.6687413035 6675887.736653338) + +LINESTRING (2552210.496323024 6677039.921112969, 2552137.7189106215 6677020.596677452) + +LINESTRING (2548515.0998777174 6676498.586861114, 2548488.321881723 6676548.3982942775, 2548442.6524467813 6676602.390687092) + +LINESTRING (2549197.047825603 6676615.883784148, 2549097.2944283267 6676589.747785181, 2549090.0018379204 6676584.716630385) + +LINESTRING (2551433.653954954 6677147.515809061, 2551445.5745354258 6677098.624587113, 2551456.5051714983 6677086.841882641, 2551487.490431188 6677068.067573395) + +LINESTRING (2553014.4384190175 6676475.401539412, 2553009.851676635 6676469.220120599) + +LINESTRING (2554361.727997495 6673132.004133086, 2554427.1468231976 6673177.164498694) + +LINESTRING (2550929.1040433757 6674996.93218797, 2550853.835270902 6674980.93851696) + +LINESTRING (2551896.26322216 6673640.000732986, 2551869.00675304 6673620.5562699195) + +LINESTRING (2552341.7794494093 6672696.104081427, 2552203.3439747407 6672596.1711439295) + +LINESTRING (2552833.7735661934 6674460.779125347, 2552832.0246644216 6674477.432947881, 2552726.925567391 6674469.901219131) + +LINESTRING (2553378.6637120326 6675701.753964936, 2553209.2099795276 6675696.742814733) + +LINESTRING (2552037.3715467057 6676663.8147856975, 2551994.737941254 6676829.342779156, 2551964.618882913 6676958.282374519) + +LINESTRING (2550232.8843970704 6677124.780590671, 2550227.2499635327 6677200.497969998, 2550223.5376720363 6677212.140642328, 2550189.03810973 6677249.839295258) + +LINESTRING (2552483.811722061 6672500.92928317, 2552437.820555189 6672563.973753698) + +LINESTRING (2549360.0751690506 6672276.497769652, 2549248.9704093323 6672253.142408921, 2549144.795260407 6672231.24738338, 2549077.2728028563 6672217.054125617, 2549025.952435303 6672226.416274501) + +LINESTRING (2549170.682306442 6672890.508702905, 2549184.987003008 6672841.267400604) + +LINESTRING (2553560.4587513786 6676211.180893138, 2553577.8075269717 6676239.867477538, 2553463.5596937863 6676350.862954208, 2553462.6109970706 6676365.146232633) + +LINESTRING (2553480.3310018135 6676496.446369809, 2553511.6544925063 6676532.834721988, 2553544.9578719973 6676563.851841313) + +LINESTRING (2552016.7147069126 6673148.767980873, 2551969.535606762 6673214.333029946) + +LINESTRING (2549770.6876066974 6676212.531203073, 2549737.2604841567 6676245.558783858) + +LINESTRING (2549024.7315038773 6676405.455484771, 2548894.9580427003 6676442.353954037) + +LINESTRING (2549456.7679882264 6675900.989695294, 2549378.3726413595 6675899.999468008) + +LINESTRING (2549268.0268390137 6676290.379071409, 2549266.9626487847 6676319.63578667, 2549239.9371666913 6676363.955959431) + +LINESTRING (2552810.485124206 6672890.968808513, 2552808.521734481 6672946.281504375) + +LINESTRING (2553836.9502220294 6677263.742486442, 2553887.3466414767 6677312.983788745) + +LINESTRING (2553853.2513064668 6676916.302738979, 2553859.9004330137 6676935.297098734, 2553861.665833859 6676940.8583752075, 2554058.054303554 6677147.885894006) + +LINESTRING (2554121.295251579 6673000.804018868, 2554186.6315819155 6673045.404255911) + +LINESTRING (2551626.5116229593 6671587.909718794, 2551528.9278538246 6671397.786079925) + +LINESTRING (2549108.893276869 6677580.975300541, 2549012.5304391594 6677563.851370105) + +LINESTRING (2553376.1723519615 6675692.741896406, 2553378.308981956 6675698.413198134) + +LINESTRING (2546995.551724271 6674662.875512308, 2546961.010914281 6674653.793427708) + +LINESTRING (2550841.0979863014 6672371.139492662, 2550768.287575752 6672318.807480953, 2550834.0116343116 6672229.256926513) + +LINESTRING (2553275.9652301692 6673721.07934287, 2553270.223552655 6673799.537351251) + +LINESTRING (2551612.3884162 6672988.061093998, 2551565.597044272 6672958.694353483) + +LINESTRING (2551034.7063621427 6673639.970726099, 2550919.047858189 6673708.456445551) + +LINESTRING (2553181.2193016447 6674994.361597945, 2553211.3631085954 6675027.989316478) + +LINESTRING (2552889.218702076 6674644.061193879, 2552884.483468034 6674669.336995405, 2552878.6675446895 6674750.075527232) + +LINESTRING (2550212.0295683974 6676319.9658624325, 2550206.040404783 6676338.910210708) + +LINESTRING (2550780.4556423235 6675311.55440286, 2550697.3498100247 6675261.432898526) + +LINESTRING (2551759.16417243 6676018.126581594, 2551752.52329542 6676030.069322799, 2551750.5021589384 6676061.95664186, 2551773.28737919 6676110.43776968, 2551776.083972117 6676132.332795221) + +LINESTRING (2552608.387975143 6671893.399837605, 2552600.121939411 6671928.927992343, 2552568.922191768 6672052.846435207) + +LINESTRING (2553085.706166211 6673889.8780870605, 2553078.578566538 6673990.511185264) + +LINESTRING (2554223.0532862633 6675657.343771514, 2554288.6783503825 6675625.7565213265) + +LINESTRING (2548977.4369102134 6671973.518227091, 2549000.560361468 6672094.435981209) + +LINESTRING (2553645.173243326 6673111.869511608, 2553541.649807797 6673179.044930308) + +LINESTRING (2552752.218646786 6675728.200035074, 2552670.1605056426 6675797.155862429, 2552657.6542080683 6675811.769216616) + +LINESTRING (2551121.9534618445 6672693.903576347, 2551127.200167159 6672617.045935297) + +LINESTRING (2553069.644318337 6672961.244938916, 2553001.2886575833 6672957.1539999265) + +LINESTRING (2553373.021028958 6675488.214951562, 2553322.5008664606 6675477.422474376) + +LINESTRING (2553586.8572686864 6671931.4285662975, 2553627.296497387 6671954.933961465, 2553641.700188393 6671969.757363864, 2553651.4263921133 6671986.521211651, 2553655.7656483958 6672008.526262446, 2553650.584939374 6672047.015096746, 2553639.505811642 6672079.432537486, 2553636.5689765913 6672147.208093935, 2553619.970908834 6672194.188877382) + +LINESTRING (2549318.1510237516 6672494.647841398, 2549345.3167479686 6672520.313732461, 2549364.967144289 6672546.389717653, 2549372.375228209 6672567.2044952465, 2549376.425750708 6672603.612852016, 2549377.060965031 6672608.403951712) + +LINESTRING (2552926.5643545296 6674030.050260625, 2552926.457110553 6674058.066691205, 2552918.3478160175 6674178.664371858) + +LINESTRING (2553226.0967810676 6673638.8804758545, 2553105.2658176287 6673629.888411916) + +LINESTRING (2553548.2989343437 6675506.369118467, 2553542.9862327357 6675506.95925392) + +LINESTRING (2551639.6118871733 6673470.691871709, 2551617.6186224413 6673499.048380348) + +LINESTRING (2550210.858134192 6672667.677556718, 2550188.3451486505 6672696.864255909, 2550177.2330227713 6672701.135236222) + +LINESTRING (2553479.8277800772 6673656.594541744, 2553466.348037177 6673655.7443466) + +LINESTRING (2551013.0513284137 6672686.051774131, 2551019.5107156173 6672608.303928754) + +LINESTRING (2554333.258846486 6675718.607833386, 2554288.6783503825 6675625.7565213265) + +LINESTRING (2554049.235548866 6673047.824811499, 2554070.6100983485 6673083.382973124, 2554139.3122396413 6673072.140392628, 2554164.2258403506 6673085.173384075) + +LINESTRING (2551388.9662148743 6676831.1531946985, 2551384.4124706388 6676851.817937854, 2551337.670595931 6676913.342059418) + +LINESTRING (2551509.392951017 6673395.794680639, 2551482.5324596562 6673422.460801285) + +LINESTRING (2550543.784685124 6676559.450831154, 2550562.0491592865 6676561.37127195, 2550571.9321042034 6676566.042344097, 2550631.271021389 6676633.227765093, 2550637.3426803695 6676641.399640774) + +LINESTRING (2552882.0003575 6675879.524768473, 2552896.948517925 6675897.6289238995) + +LINESTRING (2552526.4948247327 6676386.961239808, 2552532.2200031737 6676404.985376868, 2552525.5543775535 6676433.6319520855) + +LINESTRING (2547892.4331002603 6672653.104211714, 2547888.7043096907 6672669.0778781315) + +LINESTRING (2551618.7735575736 6671352.915780894, 2551528.9278538246 6671397.786079925) + +LINESTRING (2552640.7756560645 6672516.932956476, 2552483.811722061 6672500.92928317) + +LINESTRING (2550483.3898272463 6675641.560148716, 2550462.5267490367 6675622.205706312, 2550428.8438908597 6675606.102010048, 2550397.7678862666 6675625.326422607, 2550389.617344048 6675636.388961779) + +LINESTRING (2552250.077599912 6673094.855606426, 2552188.3380675586 6673180.105173664) + +LINESTRING (2552692.162019911 6673088.934247302, 2552681.874847698 6673207.531468792) + +LINESTRING (2549849.701668814 6677531.543954618, 2549848.8849646845 6677579.775025043, 2549847.0948152295 6677683.998947445) + +LINESTRING (2552903.548147252 6674407.876982776, 2552903.457402349 6674408.627154963, 2552897.8477174207 6674454.86776852) + +LINESTRING (2551132.743855794 6674162.540671003, 2551107.195040762 6674255.151927963) + +LINESTRING (2553462.404758654 6675946.380113707, 2553322.855596537 6675884.6059347475, 2553268.3674069066 6675867.261953803, 2553257.552264347 6675848.59766981) + +LINESTRING (2549125.4665960157 6671310.466037451, 2549078.518482892 6671515.843177441) + +LINESTRING (2549818.6834109775 6676321.926312412, 2549749.923522928 6676376.828914146) + +LINESTRING (2552385.361751577 6671970.1474534, 2552345.508239979 6671956.984432107, 2552336.9369713906 6671956.874406853, 2552325.9403390246 6671965.876473087) + +LINESTRING (2547872.848700233 6675061.517012053, 2547834.2408686704 6675052.2848930145, 2547791.145289166 6675062.09714521) + +LINESTRING (2552526.3050853894 6672709.167079763, 2552471.2311786567 6672787.425042226) + +LINESTRING (2552881.315645957 6673879.1456236495, 2552938.220949828 6673883.426606258) + +LINESTRING (2551121.9947095276 6675479.472945019, 2551136.216910727 6675513.700801301) + +LINESTRING (2553525.5384627027 6674020.678109446, 2553449.865462933 6674015.21685593) + +LINESTRING (2551433.653954954 6677147.515809061, 2551430.832613417 6677164.879794598, 2551339.3205032623 6677142.04455325, 2551214.2657770542 6677298.630494248) + +LINESTRING (2548500.8199297613 6676253.8306824975, 2548485.550037406 6676246.569015735, 2548478.719421053 6676250.2398582995) + +LINESTRING (2549012.5304391594 6677563.851370105, 2549023.073347009 6677550.848385544, 2549035.0764228473 6677536.014980848, 2549064.7417566716 6677496.265857276, 2549080.6138652028 6677466.809096098) + +LINESTRING (2552824.451589769 6674628.01751139, 2552804.8754392783 6674643.401042354, 2552784.3010948515 6674675.568425699) + +LINESTRING (2550510.1348250937 6675681.119228668, 2550483.3898272463 6675641.560148716) + +LINESTRING (2550184.0718886615 6676346.001838442, 2550165.947656622 6676333.578987038) + +LINESTRING (2552084.14641956 6674019.7879051175, 2551996.1238634125 6674305.1834116345) + +LINESTRING (2549907.3411814477 6676348.252355, 2549851.7393043684 6676412.307057406) + +LINESTRING (2552202.6262650513 6673614.574897022, 2552195.9111422114 6673612.1843483215) + +LINESTRING (2551108.061242111 6672405.627408636, 2550926.0434652753 6672273.377053357) + +LINESTRING (2549248.326945473 6676428.60079729, 2549241.5128281927 6676430.541242678) + +LINESTRING (2552242.166294256 6676709.885360226, 2552115.643150523 6676678.328116926) + +LINESTRING (2551681.816516719 6674680.479552944, 2551510.0446644127 6674631.928409054) + +LINESTRING (2549314.974952138 6671750.76709927, 2549333.726148963 6671842.288105985) + +LINESTRING (2551552.7772643045 6673792.965842899, 2551536.0142058143 6673781.683253219, 2551492.902127236 6673776.792130565) + +LINESTRING (2551290.1450152406 6673526.754739758, 2551286.4904705007 6673553.3408420365, 2551280.9302827925 6673584.327954475) + +LINESTRING (2549724.193218089 6677406.3752247775, 2549712.602619084 6677411.716450743) + +LINESTRING (2547888.7043096907 6672669.0778781315, 2547881.403469748 6672694.513716391) + +LINESTRING (2549326.1448247735 6672446.546800818, 2549321.8468161747 6672457.649349174, 2549318.1510237516 6672494.647841398) + +LINESTRING (2551223.793991895 6672702.8256242145, 2551121.9534618445 6672693.903576347) + +LINESTRING (2552454.3361275797 6675092.164046433, 2552373.597912302 6675153.17805091) + +LINESTRING (2553058.119715625 6673058.3372244015, 2552994.8622685266 6673053.926211947) + +LINESTRING (2551849.810081235 6674219.603768633, 2551844.6623703605 6674216.3330179015) + +LINESTRING (2553505.937563602 6677026.928130704, 2553467.412227406 6677039.220952262, 2553418.81420695 6677066.027105048) + +LINESTRING (2551010.510471123 6674129.593108585, 2551015.4271949716 6674107.267984324, 2551014.2392616924 6674078.951484869, 2551005.090525538 6674055.06600246, 2550970.731205355 6674013.506463345, 2550957.655689751 6673913.943610793, 2550959.4458392058 6673875.394762719, 2550972.37286315 6673819.982043899, 2550981.414355328 6673794.056093143, 2551025.4503820115 6673705.495765989, + 2551039.1363633284 6673648.872769374) + +LINESTRING (2547785.263369528 6677662.604036695, 2547626.23705136 6677528.873341636, 2547565.3719698926 6677523.182035317) + +LINESTRING (2551245.6800126503 6674810.619423806, 2551126.16072554 6675032.970459795) + +LINESTRING (2550420.9243356674 6672772.641649011, 2550362.7733517606 6672722.400117126, 2550348.5181524144 6672712.20777769) + +LINESTRING (2553153.5008584717 6677426.869928905, 2553224.2818830027 6677495.7457378935) + +LINESTRING (2551197.78320281 6673927.316680299, 2551221.475872094 6673934.808399865, 2551230.715353152 6673946.261028575) + +LINESTRING (2553220.5695915064 6676858.439457684, 2553213.62348164 6676806.227473525) + +LINESTRING (2552470.90119719 6675959.90321765, 2552558.552524188 6676065.787521157) + +LINESTRING (2553388.769394439 6672466.181307505, 2553389.990325865 6672501.109324494, 2553349.3036110643 6672558.85257824, 2553318.409096278 6672569.254965888, 2553299.9218846257 6672575.486396182) + +LINESTRING (2553433.2838942492 6674233.7470149165, 2553434.3233358683 6674261.343349073) + +LINESTRING (2549421.1959861545 6671189.488269557, 2549433.265058286 6671187.85789534, 2549472.846335174 6671138.376537938, 2549484.469932326 6671130.134646186) + +LINESTRING (2553483.0615984476 6674205.110441996, 2553466.0675529307 6674218.483511502, 2553459.682411557 6674219.213679096, 2553394.453325197 6674215.742882448, 2553367.3288486637 6674217.343249778, 2553304.7891112543 6674245.439698726, 2553285.9141713795 6674257.772529467) + +LINESTRING (2550964.453307958 6675509.989949552, 2550867.628496195 6675527.724020034, 2550856.120392557 6675532.655151872, 2550832.5184681765 6675572.254241007) + +LINESTRING (2551354.903878011 6674102.476884628, 2551349.6159250126 6674103.367088956) + +LINESTRING (2550510.1348250937 6675681.119228668, 2550499.765157514 6675692.401818348, 2550491.9033490783 6675711.406180399) + +LINESTRING (2552289.78261985 6673123.612206896, 2552250.077599912 6673094.855606426) + +LINESTRING (2553501.804545736 6675744.633807099, 2553523.5090766847 6675735.681752344) + +LINESTRING (2552869.494059925 6674900.820127474, 2552861.3352681696 6675041.022307926) + +LINESTRING (2552942.890187577 6674846.207592319, 2553006.1971318955 6674929.916806002) + +LINESTRING (2550574.0522351246 6672733.982775682, 2550466.775260416 6672725.760888521, 2550455.6218868536 6672731.802275194, 2550424.3313943073 6672768.740753642) + +LINESTRING (2549342.239670795 6671574.806711275, 2549323.9009508025 6671664.947401169) + +LINESTRING (2550933.6990352944 6673730.841583586, 2550952.3512376794 6673762.378822294, 2550956.591499522 6673790.235216142, 2550954.025893621 6673808.149327948, 2550946.8735453384 6673823.68289335, 2550935.695423166 6673836.845914644, 2550919.9223090746 6673848.198520395, 2550889.720755367 6673857.050552192, 2550856.8546013194 6673849.638850993, 2550839.654317386 6673838.396270496, + 2550818.6674961266 6673809.159559825, 2550817.034087868 6673801.027693327) + +LINESTRING (2547493.01528386 6677618.133829498, 2547492.503812587 6677591.537724922, 2547506.0907994634 6677552.968872257, 2547534.6341963024 6677531.023835236, 2547565.3719698926 6677523.182035317) + +LINESTRING (2551194.4091423173 6675230.625827413, 2551183.536253001 6675259.012342939, 2551120.806776249 6675346.8525047945) + +LINESTRING (2550826.0508314357 6675180.984433278, 2550729.4157590168 6675166.941209953) + +LINESTRING (2548500.8199297613 6676253.8306824975, 2548542.612082474 6676286.008068138) + +LINESTRING (2552599.197991305 6673743.634519935, 2552585.5862558186 6673738.883429423, 2552548.2323538284 6673736.992995514) + +LINESTRING (2549239.9371666913 6676363.955959431, 2549241.22409441 6676393.252683876, 2549256.3784932517 6676421.319125935) + +LINESTRING (2553687.9883385845 6676119.429833619, 2553689.547501013 6676086.742330892) + +LINESTRING (2549950.8244891753 6676393.332702243, 2549945.9902606932 6676330.10819039, 2549996.2051903345 6676318.665563976) + +LINESTRING (2553456.7455765065 6675159.909595994, 2553584.547398422 6675077.290632555) + +LINESTRING (2552747.310172474 6672343.373119477, 2552739.555608015 6672439.63521441) + +LINESTRING (2553635.9420118053 6673348.1437433725, 2553667.240753888 6673396.284793135) + +LINESTRING (2551520.2328421865 6675118.18001785, 2551503.1398022296 6675145.046184412) + +LINESTRING (2552243.915196028 6677050.3635098, 2552237.761041681 6677048.793149358, 2552211.659507693 6677042.151624936) + +LINESTRING (2552110.0169665217 6675223.784257075, 2552115.544156083 6675204.8399088, 2552129.799355429 6675149.907300179, 2552131.2677729544 6675131.773137865, 2552123.7689441317 6675083.262003157, 2552115.6266514496 6675038.991841876, 2552121.393077574 6674982.378847557, 2552141.422952581 6674921.104783389, 2552161.4693266614 6674891.928086493, 2552177.8116587824 6674881.545703436) + +LINESTRING (2549102.912362791 6676997.70142233, 2549086.5535315974 6676993.160380029, 2549076.84382695 6676995.090823121, 2548934.143341829 6677096.614125654, 2548918.2299856143 6677103.31566385, 2548899.899515159 6677105.536173522, 2548817.9156198455 6677099.934887865, 2548806.64675277 6677095.843948876, 2548804.7906070217 6677084.011232926, 2548812.825655727 6677068.397649157, + 2548816.042975024 6677024.077476396) + +LINESTRING (2549209.8346074237 6675962.77387655, 2549169.8903509225 6676020.817199169, 2549159.636176856 6676030.589442181) + +LINESTRING (2553670.9777939944 6673151.3385708975, 2553690.9416727084 6673181.575511149) + +LINESTRING (2553368.6157763824 6673912.273227392, 2553362.238884545 6674010.265719501) + +LINESTRING (2553598.3653723253 6675496.806923667, 2553586.964512663 6675522.4128009565) + +LINESTRING (2549151.9146105433 6672527.495380857, 2549104.7932571494 6672573.485937019, 2549085.4563432215 6672590.609867455, 2549055.428029784 6672650.013502306, 2549047.6404671785 6672675.379324496, 2549039.0114518334 6672734.862977713, 2549033.096534049 6672754.637516541) + +LINESTRING (2553446.7141399295 6676834.023853597, 2553463.3369562966 6676927.245250602) + +LINESTRING (2553309.4995966866 6672526.205084696, 2553300.3673596056 6672508.3609889615) + +LINESTRING (2552559.377477854 6675010.015190897, 2552621.125259744 6675091.723945417) + +LINESTRING (2550592.003226894 6672735.4731177585, 2550574.0522351246 6672733.982775682) + +LINESTRING (2549495.722300329 6671447.877577371, 2549446.34057389 6671492.427802935) + +LINESTRING (2552847.575041023 6676242.638113479, 2552762.827550929 6676310.513692887) + +LINESTRING (2552769.3446848895 6673764.979419206, 2552784.020610605 6673770.010574002, 2552809.51167888 6673793.335927845) + +LINESTRING (2549446.34057389 6671492.427802935, 2549455.844040121 6671499.289377864, 2549517.5423247907 6671512.252353243) + +LINESTRING (2554372.741128934 6673408.547607805, 2554325.1000547307 6673409.557839682, 2554315.1511135204 6673404.156599942) + +LINESTRING (2551655.096267482 6673173.833734188, 2551675.6128651514 6673254.372220098) + +LINESTRING (2551027.08379027 6674989.990594673, 2550981.0348766414 6674998.84262647) + +LINESTRING (2553560.4587513786 6676211.180893138, 2553426.9235014855 6676340.810646913) + +LINESTRING (2551505.3176799077 6675498.977421859, 2551509.4506977736 6675542.217346672, 2551526.3952460703 6675568.953483388, 2551550.203408867 6675581.776426624) + +LINESTRING (2553943.575483342 6672977.868754562, 2553993.171697734 6672961.66503534, 2554065.3551434968 6672955.5536325965) + +LINESTRING (2553105.2658176287 6673629.888411916, 2553098.567193862 6673709.276633807) + +LINESTRING (2548270.1051380294 6675336.150048272, 2548239.4828579524 6675325.857685877, 2548199.8273352343 6675306.153163119, 2548176.58014093 6675291.92989847, 2548061.268117516 6675199.688726455, 2548011.5481600743 6675168.821641566, 2547958.4541421393 6675148.797045343, 2547822.9555025217 6675118.270038513) + +LINESTRING (2554621.7368939016 6675740.422840561, 2554646.3700103643 6675744.243717562, 2554658.0348551995 6675732.87110722, 2554808.597148756 6675683.019664873) + +LINESTRING (2552844.803196706 6675835.484659996, 2552882.0003575 6675879.524768473) + +LINESTRING (2552238.1652689767 6677047.272800393, 2552237.761041681 6677048.793149358, 2552237.274319018 6677050.573558013) + +LINESTRING (2553183.7354103257 6674109.328457262, 2553164.7944741575 6674108.238207018) + +LINESTRING (2550202.946828536 6676304.2822625935, 2550208.795750027 6676310.083594167, 2550212.0295683974 6676319.9658624325) + +LINESTRING (2549230.012974091 6676428.090680203, 2549233.6675188304 6676433.521926831, 2549237.6107973536 6676439.403276771, 2549243.731953554 6676448.505365963, 2549247.0317682177 6676474.431316718, 2549239.970164838 6676507.618934236) + +LINESTRING (2553547.647220948 6674163.500891401, 2553528.970269953 6674165.071251844, 2553483.0615984476 6674205.110441996) + +LINESTRING (2551910.081196063 6674119.950895418, 2551932.222952455 6674128.192787171, 2551949.7284692447 6674120.340984955, 2551978.9235794796 6674133.013893754) + +LINESTRING (2550700.913609861 6672866.723243455, 2550583.902181895 6672856.730949935) + +LINESTRING (2550919.047858189 6673708.456445551, 2550933.6990352944 6673730.841583586) + +LINESTRING (2552959.414009504 6676398.26383408, 2552897.088760048 6676448.3853384135, 2552892.8484982057 6676458.207592905, 2552830.52324875 6676508.329097238, 2552800.2474492127 6676481.492937565, 2552790.8677260317 6676479.262425598) + +LINESTRING (2552444.3624377595 6674745.6045010025, 2552427.888113052 6674754.026434079, 2552403.601477129 6674773.840982091, 2552339.2138435086 6674836.525369969, 2552326.559054274 6674854.969603454, 2552318.4662588118 6674879.665271823, 2552318.202273639 6674898.279544337, 2552324.851400186 6674921.624902771, 2552366.511560312 6674975.827343798, 2552390.534211062 6675006.754442461) + +LINESTRING (2551083.634364065 6675615.144085466, 2550961.4174784673 6675529.0743299695, 2550964.453307958 6675509.989949552) + +LINESTRING (2552970.2621502103 6675288.579129371, 2552964.3967296463 6675371.508163981, 2552951.370711262 6675393.493210184) + +LINESTRING (2548948.6130291284 6671255.803490818, 2548945.4699556613 6671269.13655114) + +LINESTRING (2551895.075288881 6673445.706136761, 2551893.5491245994 6673447.066448992, 2551818.5030896156 6673548.549742341) + +LINESTRING (2553078.578566538 6673990.511185264, 2553073.3731089067 6674056.326291733) + +LINESTRING (2553236.9036740907 6674889.257473511, 2553272.3601826495 6674925.315749927) + +LINESTRING (2553530.5459314547 6676630.687181955, 2553528.33505563 6676650.701775882) + +LINESTRING (2552389.9319948857 6672339.512233292, 2552343.1571220313 6672403.776983909) + +LINESTRING (2548988.252052773 6670889.139330796, 2548981.5204308596 6670859.882615535) + +LINESTRING (2553248.6180161457 6676044.322594336, 2553144.0138913146 6676147.986388173) + +LINESTRING (2553521.9581637927 6676760.566993125, 2553522.444886456 6676778.801178398) + +LINESTRING (2554656.4179460146 6675619.875171387, 2554628.592258865 6675609.082694202) + +LINESTRING (2552565.003661855 6673149.448136989, 2552559.517719977 6673146.45745054) + +LINESTRING (2551263.861991446 6675722.718776966, 2551257.212864899 6675722.818799925) + +LINESTRING (2551757.291527609 6676327.267538378, 2551741.6669051773 6676328.14774041, 2551734.0773314512 6676333.679009996, 2551727.032227145 6676349.022531778) + +LINESTRING (2552956.9143998967 6673618.665836011, 2552952.212164001 6673697.553943111) + +LINESTRING (2552665.84599797 6672078.382296425, 2552615.251589643 6672065.289291202, 2552568.922191768 6672052.846435207) + +LINESTRING (2553369.1437467285 6674168.962144917, 2553366.421399631 6674205.580549899) + +LINESTRING (2552118.0437656906 6673737.923209025, 2552177.8364073923 6673801.157723173, 2552199.0789642883 6673818.001589327, 2552221.748691026 6673826.953644082, 2552240.5658841445 6673806.108859601, 2552297.924912532 6673716.958396994, 2552318.0207838323 6673714.7078804355, 2552341.8371961657 6673705.855848638, 2552354.4919854 6673692.762843415, 2552359.6396962753 6673678.47956499, + 2552359.0127314893 6673658.444966471) + +LINESTRING (2552558.552524188 6676065.787521157, 2552502.199939273 6676110.617811005) + +LINESTRING (2552264.671030261 6672803.6187591525, 2552203.5997103774 6672890.538709792) + +LINESTRING (2551899.2743030405 6673441.985282717, 2551895.075288881 6673445.706136761) + +LINESTRING (2552380.428528655 6675843.006386449, 2552342.0186859723 6675795.485479027) + +LINESTRING (2552733.0467235916 6672525.654958427, 2552640.7756560645 6672516.932956476) + +LINESTRING (2548636.6155526987 6675562.331963558, 2548634.6851611207 6675566.472914025, 2548621.320911734 6675563.552243647) + +LINESTRING (2552918.3973132377 6677227.804237575, 2552968.026525776 6677252.339869212, 2553044.7884643846 6677290.308584129) + +LINESTRING (2551166.9711833904 6674761.498149053, 2551038.2949105892 6674683.780310564, 2551017.9515531887 6674672.917817308, 2551006.8394273096 6674670.747319115) + +LINESTRING (2553805.0740123806 6673063.04830573, 2553911.3857913003 6672994.122485262, 2553943.575483342 6672977.868754562) + +LINESTRING (2548750.5581530277 6676134.883380654, 2548760.630837288 6676158.868886021, 2548765.753799553 6676176.332894515, 2548768.806128117 6676207.8601309275, 2548772.9391459827 6676261.5324502755, 2548757.5455105775 6676303.45207204, 2548758.914933663 6676332.778803373) + +LINESTRING (2550252.6502869045 6676539.466244114, 2550234.880784942 6676700.8732916955) + +LINESTRING (2553561.6796828043 6674022.26847448, 2553558.1158829676 6674022.108437747) + +LINESTRING (2553450.8719064053 6675500.657807557, 2553373.021028958 6675488.214951562) + +LINESTRING (2551197.78320281 6673927.316680299, 2551195.696070036 6673935.398535319) + +LINESTRING (2549333.726148963 6671842.288105985, 2549362.112804605 6671831.315587475, 2549409.993115372 6671796.01748554, 2549496.7534924108 6671701.165714318, 2549395.812161856 6671681.411180082) + +LINESTRING (2553224.11689227 6672386.7130672475, 2553240.327231804 6672440.575430216) + +LINESTRING (2548966.861004217 6677556.069583959, 2548962.216515078 6677555.539462281) + +LINESTRING (2547680.6179970135 6672805.239131074, 2547673.3171570706 6672763.109461098, 2547670.50406507 6672746.875734989, 2547665.834827321 6672719.939552356) + +LINESTRING (2551503.1398022296 6675145.046184412, 2551517.848726092 6675159.679543191, 2551572.3121671122 6675236.177101592) + +LINESTRING (2553104.2841227665 6672154.279717077, 2553023.9996320046 6672035.852534615) + +LINESTRING (2554142.290322375 6674448.276255577, 2554189.4694225257 6674406.646700392, 2554158.731648936 6674242.238964064) + +LINESTRING (2553224.2818830027 6677495.7457378935, 2553192.3231779872 6677528.62328424, 2553250.2101767207 6677586.04646452) + +LINESTRING (2548102.3838082226 6676803.586867429, 2548035.6450566542 6676890.086721646, 2548013.2558141625 6676917.543023661, 2548002.613911873 6676926.014968216, 2547947.927733363 6676937.697649729, 2547879.547324 6676971.225345305, 2547841.0632354873 6676976.256500101, 2547817.79954211 6676989.749597156, 2547808.3373235622 6677001.832370502, 2547758.4853735343 6677106.116306678, + 2547743.512464499 6677123.490294511, 2547626.9547610492 6677181.243550552, 2547611.5776247173 6677186.774820139, 2547570.989904357 6677188.935316035) + +LINESTRING (2551150.8268401497 6677498.466362355, 2551069.0574327894 6677537.415302263, 2550922.133184899 6677611.7023532875, 2550907.853236943 6677625.3754916685, 2550898.514761445 6677640.66900197, 2550893.301054277 6677658.333056382, 2550893.103065397 6677671.966185579, 2550896.155393961 6677691.5306761945, 2550903.3819880737 6677707.824416079, 2550950.742578031 6677759.3762487145, + 2550958.6786322966 6677784.922112228, 2550960.6090238746 6677807.277243377, 2550962.2424321333 6677826.231593948) + +LINESTRING (2552952.212164001 6673697.553943111, 2552938.220949828 6673883.426606258) + +LINESTRING (2549180.0125324028 6676455.486968443, 2549179.0968338335 6676455.867055684) + +LINESTRING (2551431.6740661557 6675050.304438443, 2551482.2107277266 6674984.909428399) + +LINESTRING (2551509.392951017 6673395.794680639, 2551422.005609192 6673330.089599425) + +LINESTRING (2551435.5678474586 6674092.2645406, 2551406.347988614 6674187.896490896, 2551504.6329683647 6674213.782432468) + +LINESTRING (2553322.5008664606 6675477.422474376, 2553331.484611882 6675578.275623089, 2553335.7413727976 6675585.597303625) + +LINESTRING (2549038.92070693 6671689.052934085, 2549097.913143576 6671757.208577774) + +LINESTRING (2553010.6683807643 6672823.043217626, 2553001.2886575833 6672957.1539999265) + +LINESTRING (2551966.2852893183 6672312.3359955605, 2551946.3131610677 6672357.306317548, 2551931.958967282 6672378.671221412) + +LINESTRING (2550491.9033490783 6675711.406180399, 2550534.8834350696 6675717.747635946) + +LINESTRING (2552437.820555189 6672563.973753698, 2552398.7095018905 6672619.206431193) + +LINESTRING (2553474.5315775424 6676055.495158763, 2553556.903201079 6676140.89476044) + +LINESTRING (2551971.977469613 6673992.021531933, 2551977.1334300246 6673995.322289552) + +LINESTRING (2553785.118383203 6675669.196492055, 2553789.9443621486 6675657.043702639, 2553790.076354735 6675645.090959139) + +LINESTRING (2553220.5695915064 6676858.439457684, 2553314.507065438 6676848.127090698) + +LINESTRING (2552841.239396869 6675808.408445221, 2552850.0086543374 6675677.598420541) + +LINESTRING (2553693.9775021984 6675997.621875172, 2553689.1515232534 6675997.631877468) + +LINESTRING (2552777.0415025917 6673358.90621367, 2552773.2384661925 6673412.668553681) + +LINESTRING (2549007.9024490938 6672133.264893567, 2549025.952435303 6672226.416274501) + +LINESTRING (2553044.8379616044 6675707.055181718, 2553044.549227821 6675712.136347993) + +LINESTRING (2552891.050099214 6674779.41226086, 2552873.899312501 6674769.630015552) + +LINESTRING (2549714.590757419 6672194.158870495, 2549743.554880627 6672207.791999692, 2549743.3486422105 6672210.512624154, 2549732.6407436277 6672352.875300502) + +LINESTRING (2551188.7252115593 6672244.900517169, 2551136.70363339 6672030.9214027785) + +LINESTRING (2552507.603385784 6675416.78855714, 2552531.2795559946 6675436.293033981, 2552546.07922476 6675458.068031972, 2552606.457583565 6675546.97843948) + +LINESTRING (2552889.8539163987 6674627.117304767, 2552824.451589769 6674628.01751139) + +LINESTRING (2548337.0088803307 6671880.666915031, 2548291.694175465 6671876.545969155, 2548242.8156707627 6671879.316605096, 2548201.2710041497 6671887.038377466, 2548168.124365855 6671897.640811031) + +LINESTRING (2551223.793991895 6672702.8256242145, 2551257.5428463654 6672705.786303776, 2551259.7454726533 6672681.020619336) + +LINESTRING (2547916.323758424 6671737.954158329, 2547874.358365441 6671779.45368367) + +LINESTRING (2553933.3460578853 6673124.282360716, 2553929.732760829 6673152.818910679, 2553941.0511251246 6673227.276000733) + +LINESTRING (2551606.0610215827 6673728.901138199, 2551590.560142201 6673751.856407096) + +LINESTRING (2552904.6453356277 6673047.974845936, 2552892.741254229 6673220.99455896) + +LINESTRING (2552708.001130296 6672220.484913082, 2552727.4617872736 6672281.32887853, 2552747.310172474 6672343.373119477) + +LINESTRING (2552436.0221561976 6676165.820481613, 2552389.684508786 6676201.32863176) + +LINESTRING (2551039.7138308943 6675190.116529359, 2551009.223543404 6675172.982596626) + +LINESTRING (2551376.443418226 6672068.390002904, 2551374.3892835984 6672043.314247294) + +LINESTRING (2549467.888363642 6672609.60422721, 2549401.025869024 6672617.32599958, 2549389.913743145 6672615.455570263, 2549377.060965031 6672608.403951712) + +LINESTRING (2553841.6277093147 6673119.391238062, 2553846.4701873334 6673125.522645397, 2553901.791580166 6673127.503099969, 2553933.3460578853 6673124.282360716) + +LINESTRING (2552817.4477331457 6672794.546676847, 2552714.666755916 6672784.95447516) + +LINESTRING (2550373.1430193405 6675437.223247492, 2550334.7826738777 6675495.67666424, 2550286.663126548 6675596.609831319, 2550229.6918263836 6675698.6632555295, 2550164.8587177834 6675796.825786667, 2550115.213006172 6675854.679065666, 2550112.045184095 6675878.084437876) + +LINESTRING (2552179.725551287 6676372.537929242, 2552190.870675313 6676370.797529769, 2552206.9655213337 6676352.793397301) + +LINESTRING (2553388.769394439 6672466.181307505, 2553364.771492299 6672479.764425224, 2553347.34022134 6672495.868121487, 2553314.4080709983 6672538.807977425, 2553314.078089532 6672538.948009566, 2553302.165758597 6672544.049180432) + +LINESTRING (2554257.7920851326 6675124.461459623, 2554012.665352858 6674852.439022612) + +LINESTRING (2550170.1466707815 6676695.852139196, 2550234.880784942 6676700.8732916955) + +LINESTRING (2552621.125259744 6675091.723945417, 2552658.1574298046 6675140.395116857) + +LINESTRING (2554266.635588431 6673100.146820912, 2554229.141444317 6673170.67300871) + +LINESTRING (2553055.669603237 6673293.861283979, 2553039.1292822366 6673301.743093083) + +LINESTRING (2553280.774710041 6675290.619597717, 2553253.6502335076 6675255.651571545, 2553221.9472641284 6675203.719651668) + +LINESTRING (2553284.569496904 6677555.169377336, 2553252.429302082 6677585.92643697, 2553250.2101767207 6677586.04646452) + +LINESTRING (2552773.2384661925 6673412.668553681, 2552766.5315928888 6673507.540329495, 2552766.267607716 6673511.301192722) + +LINESTRING (2551398.9151560846 6673860.871429194, 2551398.321189445 6673860.751401644) + +LINESTRING (2551450.2025254914 6676362.16554848, 2551442.010735589 6676377.138985316, 2551422.3025925118 6676389.811894115, 2551417.0146395136 6676405.98560645) + +LINESTRING (2553485.148731222 6673735.572669507, 2553526.9903811547 6673921.875431376, 2553457.3477926827 6673918.384630135) + +LINESTRING (2548776.5689421124 6672470.202230424, 2548793.9754644623 6672558.962603494) + +LINESTRING (2553031.4242149973 6673429.042311932, 2552971.7305677356 6673425.081402789) + +LINESTRING (2551467.757539501 6675888.4568186365, 2551467.4770552544 6675888.946931132) + +LINESTRING (2551403.8153808597 6676457.767491889, 2551441.26827729 6676467.169649956) + +LINESTRING (2551617.6186224413 6673499.048380348, 2551602.5879666493 6673488.706006474) + +LINESTRING (2552982.6364551983 6676025.478269019, 2552995.1510023093 6676016.166131615) + +LINESTRING (2553667.677979331 6675589.258143894, 2553769.3782672584 6675563.292183956) + +LINESTRING (2548546.0686383336 6672346.333799038, 2548510.232651089 6672320.717919454, 2548503.195796319 6672312.626062139, 2548493.263354182 6672291.731266179, 2548487.9176544272 6672268.936034014) + +LINESTRING (2552705.7820049347 6675432.572179938, 2552697.260233566 6675557.060753663) + +LINESTRING (2549328.726929748 6672406.747665767, 2549307.8886001483 6672378.991294878, 2549287.2235108186 6672359.856902982, 2549261.2457198803 6672344.803447778, 2549230.4501995337 6672337.281721325, 2549094.9103122326 6672312.786098871, 2549044.2334085386 6672322.608353363) + +LINESTRING (2554413.601084004 6673201.910178543, 2554438.489936103 6673219.214150305, 2554482.8311956436 6673273.916706122, 2554440.9317989545 6673360.586599368) + +LINESTRING (2553634.0281193005 6673094.815597242, 2553645.173243326 6673111.869511608) + +LINESTRING (2552243.8079520515 6676703.5339023825, 2552260.175032782 6676640.179360684) + +LINESTRING (2551902.1451417976 6673644.191694933, 2551743.440555559 6673647.422436481) + +LINESTRING (2550848.6793104904 6672658.8755364, 2550854.3137440286 6672591.750129179, 2550611.983604681 6672531.376271633) + +LINESTRING (2552559.517719977 6673146.45745054, 2552473.318311431 6673253.912114491, 2552440.104393391 6673297.548247428, 2552408.7574375407 6673338.7315830095, 2552398.0412894213 6673352.814815518, 2552387.0611561285 6673365.997841404, 2552275.9398973365 6673509.820852942, 2552256.454491749 6673534.296470803, 2552195.9111422114 6673612.1843483215, 2552172.432960881 6673639.590638857, + 2552153.657015446 6673654.484057328, 2552149.2847610167 6673657.954853976, 2552146.0756912567 6673660.495437113, 2552144.1535492153 6673662.015786077, 2552140.721741965 6673665.156506963, 2552137.4466759115 6673668.147193412, 2552124.4206575276 6673683.880804731, 2552092.0164775327 6673747.715456628, 2552068.1670670523 6673793.766026565, 2552022.431635817 6673885.937182508, + 2551970.2203183044 6673991.151332197, 2551943.3598269443 6674056.316289438, 2551910.081196063 6674119.950895418, 2551906.723634643 6674125.11208006, 2551861.5739205102 6674198.388899207, 2551849.810081235 6674219.603768633, 2551800.86558024 6674295.731242088, 2551770.499035799 6674351.273990754, 2551761.5729668215 6674388.38925647, 2551760.913074202 6674391.1331395805, + 2551737.2616526014 6674473.952148937, 2551726.108279039 6674513.03111869, 2551681.816516719 6674680.479552944, 2551677.856739123 6674695.442987485, 2551640.0986098363 6674817.1909321565, 2551637.1205271026 6674824.482605807, 2551634.975647571 6674829.743813406, 2551583.8285202878 6674895.818979566, 2551512.1730448706 6674985.079467428, 2551501.1186657483 6674998.4825438205, + 2551447.7276644935 6675063.277416117, 2551330.3532569148 6675214.352092121, 2551307.84852091 6675247.109610918, 2551200.670540641 6675403.125421056, 2551140.25918369 6675519.112043337) + +LINESTRING (2553320.273491563 6674457.528379207, 2553336.030106581 6674451.717045338, 2553487.0213760436 6674460.4490495855, 2553489.306497698 6674471.071487742) + +LINESTRING (2553335.7413727976 6675585.597303625, 2553376.1723519615 6675692.741896406) + +LINESTRING (2553193.4616140462 6676196.987635376, 2553138.2804633365 6676243.708359132) + +LINESTRING (2551416.2309335307 6675277.816659073, 2551282.134715145 6675460.818663321) + +LINESTRING (2550208.8039995637 6675386.541614592, 2550159.6615096885 6675417.678761467, 2550143.310928031 6675430.631734549, 2550136.1750788214 6675442.2143931035) + +LINESTRING (2551949.7779664644 6673099.606696938, 2551845.421327733 6673126.922966811) + +LINESTRING (2551363.8216271386 6674239.708383223, 2551370.726489322 6674304.233193532) + +LINESTRING (2553077.761862409 6676172.722065726, 2553121.4349094797 6676223.603744541) + +LINESTRING (2553062.029996001 6675431.351899847, 2553057.575246205 6675500.387745569) + +LINESTRING (2553960.9407580085 6675785.733240607, 2554075.4360772935 6676018.516671131) + +LINESTRING (2553041.0431747413 6676562.551542857, 2553015.626352296 6676580.125576605, 2553014.2899273573 6676578.445190908) + +LINESTRING (2553558.1158829676 6674022.108437747, 2553525.5384627027 6674020.678109446) + +LINESTRING (2553161.263672468 6674509.460299083, 2553142.891954329 6674532.305542727, 2553139.113666539 6674623.78654026) + +LINESTRING (2550942.872520059 6672249.761632935, 2550859.799685906 6672193.228656984) + +LINESTRING (2549827.799148985 6676060.336269938, 2549830.537995156 6676063.476990825) + +LINESTRING (2549568.351221071 6676074.7895873925, 2549512.188375499 6676168.281046384, 2549472.194621778 6676181.0539781405) + +LINESTRING (2551162.9124113545 6674054.935972615, 2551160.1818147204 6674064.618194965) + +LINESTRING (2551471.230594434 6675882.435436555, 2551477.1372626815 6675872.183083344, 2551478.481937157 6675866.881866561, 2551519.176901494 6675706.635085294, 2551525.3310558414 6675682.409524828, 2551530.2807778367 6675662.94505717) + +LINESTRING (2552411.248797612 6675882.315409006, 2552312.856573884 6675890.1672112215) + +LINESTRING (2551200.670540641 6675403.125421056, 2551196.801507948 6675400.394794297) + +LINESTRING (2552135.6565264566 6672092.005423326, 2552050.5543062864 6672064.16903407) + +LINESTRING (2553378.4492240795 6675698.783283079, 2553378.6637120326 6675701.753964936) + +LINESTRING (2551510.0446644127 6674631.928409054, 2551485.098065557 6674678.779162656) + +LINESTRING (2550776.0256411377 6675619.855166795, 2550689.6034951024 6675859.940273265) + +LINESTRING (2553525.8354460225 6674880.815535842, 2553532.7980549624 6674875.254259368) + +LINESTRING (2550060.4113341486 6675332.179136832, 2550028.972349942 6675392.222918616, 2549999.9999771975 6675407.366394481, 2549928.410498074 6675428.821319006, 2549867.9991411227 6675427.120928718) + +LINESTRING (2552714.930741089 6672774.342039299, 2552714.666755916 6672784.95447516) + +LINESTRING (2548914.6744353147 6672439.865267213, 2548776.5689421124 6672470.202230424) + +LINESTRING (2553241.3996715695 6673442.8554824535, 2553195.4827505276 6673439.704759272) + +LINESTRING (2553151.1827386706 6674957.58315623, 2553181.2193016447 6674994.361597945) + +LINESTRING (2550853.835270902 6674980.93851696, 2550799.998794668 6674969.555904321) + +LINESTRING (2553991.158810789 6675540.406931129, 2554009.365538195 6675583.956927111, 2553923.545608335 6675605.651906736, 2553830.028860773 6675634.458518687, 2553790.076354735 6675645.090959139, 2553666.993267788 6675679.168780983, 2553662.860249922 6675680.22902434) + +LINESTRING (2552766.482095669 6673692.762843415, 2552780.927034358 6673737.673151629, 2552809.51167888 6673793.335927845) + +LINESTRING (2552965.9063948547 6671923.686789336, 2552951.6016982887 6671978.96947831) + +LINESTRING (2551376.443418226 6672068.390002904, 2551364.993061344 6672039.063271573, 2551189.7811522516 6672020.549022017) + +LINESTRING (2554427.1468231976 6673177.164498694, 2554413.601084004 6673201.910178543) + +LINESTRING (2553073.7113399096 6675267.234230099, 2553062.029996001 6675431.351899847) + +LINESTRING (2547371.3676162916 6674760.517924064, 2547353.226885179 6674758.287412097, 2547309.7683260613 6674744.554259941, 2547036.0816978747 6674673.447938986) + +LINESTRING (2553361.900653542 6672271.626651589, 2553429.7530925595 6672314.686535077, 2553444.2970256885 6672322.428312038, 2553455.615389984 6672324.588807935, 2553476.354725144 6672321.208031949, 2553486.146925158 6672313.646296312, 2553500.154638404 6672290.120896553, 2553502.6377489385 6672279.798527271, 2553499.816407401 6672266.725526639) + +LINESTRING (2551990.976152538 6677584.696154584, 2552002.7482413496 6677585.026230346, 2552056.5517194374 6677587.526804301, 2552127.934960144 6677602.610266391) + +LINESTRING (2551970.2203183044 6673991.151332197, 2551971.977469613 6673992.021531933) + +LINESTRING (2552652.5477448767 6673607.583292247, 2552643.258766599 6673756.567488425) + +LINESTRING (2549000.560361468 6672094.435981209, 2549004.124161304 6672112.680168778) + +LINESTRING (2550954.124888061 6674486.334991157, 2550963.917088075 6674445.405596678, 2550869.96311507 6674403.3559450675, 2550881.6692075883 6674437.123695742, 2550954.124888061 6674486.334991157) + +LINESTRING (2551229.33768053 6672340.972568481, 2551228.2487416905 6672315.8267968, 2551215.453710333 6672284.3195649795, 2551188.7252115593 6672244.900517169) + +LINESTRING (2553126.3186351815 6676295.190175696, 2553165.0089621106 6676347.372152968) + +LINESTRING (2551458.9717829595 6675914.192725771, 2551704.9729661196 6676045.46285606, 2551713.659728221 6676052.784536597, 2551715.8293563626 6676064.487222701, 2551694.933280006 6676090.3431573855, 2551681.618527839 6676127.911780471, 2551633.457732826 6676168.98120709, 2551638.489950188 6676195.097201467, 2551619.318026993 6676238.087068884, 2551592.4327870226 6676276.495884816, + 2551586.5921150683 6676283.857574537, 2551566.2652567415 6676286.59820359, 2551550.7066306034 6676302.861936587, 2551539.9657338737 6676322.26639047) + +LINESTRING (2549063.232091463 6676502.957864385, 2549067.1588709126 6676512.280004086) + +LINESTRING (2553241.3996715695 6673442.8554824535, 2553233.3316247175 6673542.7184038805) + +LINESTRING (2553112.269674252 6673535.126661356, 2553105.2658176287 6673629.888411916) + +LINESTRING (2553370.8101531332 6676594.448864214, 2553310.629783209 6676647.3510067845) + +LINESTRING (2552706.5574613805 6672882.976974156, 2552599.255738062 6672877.725768852) + +LINESTRING (2552116.3031134554 6672159.020805294, 2552089.277631362 6672241.849816945) + +LINESTRING (2553960.9407580085 6675785.733240607, 2554077.547958678 6675727.719924875) + +LINESTRING (2548812.1409441847 6672129.604053299, 2548815.8862338276 6672149.328580648) + +LINESTRING (2550999.4395929268 6676040.931816055, 2551013.6452950533 6676017.246379563, 2551040.208803094 6676032.699926599) + +LINESTRING (2553112.4016668387 6673434.35353101, 2553031.4242149973 6673429.042311932) + +LINESTRING (2551613.040129596 6676809.068125537, 2551592.0780569464 6676894.527740988) + +LINESTRING (2552510.1359935384 6673580.497075177, 2552510.0452486356 6673575.045823957) + +LINESTRING (2552823.7008819333 6674624.656739996, 2552819.2956293575 6674595.420029325, 2552815.443095738 6674590.959005391, 2552805.2301693545 6674579.116287146, 2552722.2975773253 6674530.445115705) + +LINESTRING (2553211.3631085954 6675027.989316478, 2553289.4367235326 6675126.671966998) + +LINESTRING (2550488.116811752 6672823.123235993, 2550582.7142486162 6672922.015934725) + +LINESTRING (2553330.849397559 6676983.47815768, 2553326.1636607368 6676944.679252209) + +LINESTRING (2553362.2306350083 6676160.339223506, 2553366.2564088977 6676164.4401647905) + +LINESTRING (2552345.054515463 6673566.843941389, 2552330.0568578173 6673585.108133548, 2552322.863261851 6673626.757693326) + +LINESTRING (2551179.4774809647 6677181.763669935, 2551167.730140763 6677175.432216683, 2551135.202217718 6677166.980276719) + +LINESTRING (2551452.718634172 6675067.47838036, 2551520.2328421865 6675118.18001785) + +LINESTRING (2552644.8674262473 6673602.582144339, 2552616.431273385 6673583.687807542, 2552591.657914799 6673579.55685937, 2552587.524896933 6673579.326806567) + +LINESTRING (2548793.9754644623 6672558.962603494, 2548809.996064653 6672643.512010026) + +LINESTRING (2553794.621849434 6676343.101172655, 2553861.583338492 6676381.239926601, 2553868.826431678 6676435.22231712) + +LINESTRING (2550732.600080167 6675458.888220229, 2550684.191799054 6675388.912158701) + +LINESTRING (2553050.1506632124 6676074.869605758, 2553084.064508416 6676100.765549626) + +LINESTRING (2550591.8217370873 6672639.351054966, 2550599.9805288427 6672638.240800131, 2550602.612131037 6672640.021208786, 2550605.8789475537 6672642.231716162, 2550606.4316665097 6672647.732978861, 2550592.003226894 6672735.4731177585) + +LINESTRING (2551136.70363339 6672030.9214027785, 2551093.929785815 6672039.913466717, 2551041.6359729357 6672111.649932309) + +LINESTRING (2553672.2564721764 6676175.662740696, 2553601.8796749418 6676338.080020156, 2553574.9119396047 6676442.674027503) + +LINESTRING (2551444.196862804 6673225.965699981, 2551433.3982193177 6673228.386255568) + +LINESTRING (2552322.863261851 6673626.757693326, 2552361.289603607 6673630.088457832, 2552359.0127314893 6673658.444966471) + +LINESTRING (2553209.2099795276 6675696.742814733, 2553210.7361438093 6675702.444123347) + +LINESTRING (2552924.1307412153 6672763.979660833, 2552920.7484311853 6672816.4917138675) + +LINESTRING (2547389.6320904535 6674622.506246395, 2547594.0061116344 6674640.880463809, 2547626.294798116 6674630.097988919) + +LINESTRING (2553677.1649464886 6676162.439705627, 2553672.2564721764 6676175.662740696) + +LINESTRING (2548987.8560750135 6671081.663520661, 2548997.6977722473 6671043.674801152, 2549002.408257679 6671005.846118377) + +LINESTRING (2552599.197991305 6673743.634519935, 2552588.985064922 6673860.221279966) + +LINESTRING (2552110.0169665217 6675223.784257075, 2551996.445595342 6675190.92671532) + +LINESTRING (2549044.2334085386 6672322.608353363, 2548896.2449704194 6672351.384958426) + +LINESTRING (2548573.811830117 6676310.843768649, 2548600.4413344506 6676332.238679399) + +LINESTRING (2552576.7427525204 6673055.246514994, 2552568.979938525 6673125.642672947, 2552559.517719977 6673146.45745054) + +LINESTRING (2551511.1253537154 6676314.984719116, 2551476.716536312 6676306.292724052, 2551469.9106685687 6676307.222937563, 2551463.451281365 6676308.113141891, 2551450.2025254914 6676362.16554848) + +LINESTRING (2551307.7165283235 6674304.733308323, 2551113.5801821356 6674256.752295293) + +LINESTRING (2552350.5899545606 6672084.733754268, 2552360.4316517944 6672117.5012753615) + +LINESTRING (2551899.2743030405 6673441.985282717, 2551844.0519046476 6673402.756278528) + +LINESTRING (2552903.548147252 6674407.876982776, 2552903.457402349 6674408.627154963, 2552923.602770869 6674449.906629795) + +LINESTRING (2551776.083972117 6676132.332795221, 2551788.986247451 6676173.062143784, 2551789.1512381844 6676198.487979748, 2551757.291527609 6676327.267538378) + +LINESTRING (2549145.2159867766 6672828.484466551, 2549078.8402148215 6672792.656242938, 2549060.9634688823 6672780.5134558175, 2549033.096534049 6672754.637516541) + +LINESTRING (2548962.3320085914 6670994.503514921, 2548962.200016005 6671025.150549301, 2548975.498269099 6671054.2172209425, 2548985.8761862153 6671068.8205728335, 2548987.8560750135 6671081.663520661) + +LINESTRING (2552037.8417702955 6673754.316971866, 2551963.950670444 6673689.02198478, 2551925.4665819313 6673646.552236745) + +LINESTRING (2549179.492811593 6676363.095761991, 2549207.4174931827 6676384.580693403, 2549225.8717066883 6676391.872367053) + +LINESTRING (2551378.6872921977 6676593.868731056, 2551366.758462189 6676642.349858876, 2551359.7711046394 6676670.486317007, 2551347.6525352877 6676718.627366769, 2551344.360970161 6676731.710369696, 2551342.133595263 6676740.562401493) + +LINESTRING (2551358.9049032903 6674237.5978988055, 2551259.0442620376 6674199.259098943, 2551138.2462967453 6674164.10102915) + +LINESTRING (2550107.7059278125 6677196.186980502, 2550100.479333699 6677351.662666664) + +LINESTRING (2552520.4974115817 6672638.460850639, 2552526.3050853894 6672709.167079763) + +LINESTRING (2552518.484524637 6672622.867271462, 2552520.4974115817 6672638.460850639) + +LINESTRING (2554373.49183677 6675472.6113700885, 2554389.0999601283 6675470.040780064, 2554414.9292594064 6675465.779802047, 2554390.57662719 6675476.172187399, 2554372.8318738374 6675483.753927628, 2554167.1296772542 6675553.870021298, 2554127.870132296 6675559.891403379, 2554104.5899398453 6675563.462222985, 2554060.1661849385 6675561.271720201, 2554008.3260965757 6675547.978669061, + 2553991.158810789 6675540.406931129) + +LINESTRING (2551114.611374218 6675220.503504047, 2551061.5256058197 6675212.5716834655) + +LINESTRING (2551999.085447073 6675223.374162947, 2551953.482008424 6675207.050416175, 2551919.683656734 6675194.957640533, 2551887.5682105217 6675183.465002641) + +LINESTRING (2551768.7088863445 6672875.395233927, 2551671.7025847756 6672805.259135666) + +LINESTRING (2548815.8862338276 6672149.328580648, 2548721.940510359 6672165.17221722) + +LINESTRING (2553026.2517555123 6674463.809820979, 2553026.474493002 6674457.848452673) + +LINESTRING (2553225.5193135017 6675458.598153651, 2553062.029996001 6675431.351899847) + +LINESTRING (2552275.651163554 6673509.600802434, 2552271.1386670014 6673506.220026447) + +LINESTRING (2553743.8212026902 6675464.299462265, 2553746.485803031 6675474.401781039, 2553789.5813825354 6675557.130769733) + +LINESTRING (2551124.766553845 6672382.372070864, 2550942.872520059 6672249.761632935) + +LINESTRING (2553277.4088990847 6674161.500432238, 2553182.3164900206 6674153.00848309) + +LINESTRING (2553115.338501889 6674468.290849505, 2553123.670533914 6674458.848682255, 2553136.2345782453 6674456.94824605, 2553269.0768670593 6674453.607479247, 2553301.3325553946 6674456.0780463135, 2553320.273491563 6674457.528379207) + +LINESTRING (2547570.989904357 6677188.935316035, 2547474.643565721 6677223.763310066) + +LINESTRING (2552787.3864215617 6675675.978048619, 2552759.907214952 6675718.927906852) + +LINESTRING (2550089.9611744597 6676277.016004199, 2550010.88111605 6676239.047289281, 2549999.9999771975 6676233.115927863, 2549951.401956741 6676210.480732432, 2549897.6067281906 6676183.144457966) + +LINESTRING (2553601.029972666 6677072.078494017, 2553630.315827804 6677124.7905929675) + +LINESTRING (2552325.082387212 6677081.18058321, 2552308.9297944345 6677147.625834315) + +LINESTRING (2554346.812835216 6675966.984843087, 2554353.486710373 6675957.302620738, 2554357.7187226787 6675935.927714579) + +LINESTRING (2552454.3361275797 6675092.164046433, 2552515.5064419033 6675173.012603514) + +LINESTRING (2552393.388550746 6672896.21001152, 2552330.7745675067 6672982.3197762) + +LINESTRING (2553370.414175374 6674668.426786486, 2553341.0788230156 6674602.941755779) + +LINESTRING (2553580.340134726 6677032.019299274, 2553593.201162377 6677057.985259213, 2553601.029972666 6677072.078494017) + +LINESTRING (2552965.9063948547 6671923.686789336, 2552898.4829317434 6671882.237275475, 2552730.662607497 6671826.484478597, 2552542.1771939206 6671766.670749617, 2552501.8287101234 6671761.049459368, 2552459.665328261 6671765.190409836, 2552434.7929752353 6671777.543245168, 2552393.5865396257 6671805.229599987) + +LINESTRING (2547570.989904357 6677188.935316035, 2547464.2903972142 6677171.6913580485, 2547461.78253807 6677184.794365567, 2547463.4984416952 6677204.308844704, 2547474.643565721 6677223.763310066) + +LINESTRING (2548809.996064653 6672643.512010026, 2548828.4502781588 6672776.87262014) + +LINESTRING (2552809.51167888 6673793.335927845, 2552833.5590782403 6673841.386956944) + +LINESTRING (2552888.7732270965 6673293.051098018, 2552782.3212060533 6673285.5993876355) + +LINESTRING (2552338.562130112 6673159.190373113, 2552289.78261985 6673123.612206896) + +LINESTRING (2548650.2767854054 6676182.624338584, 2548594.0479435404 6676199.928310346) + +LINESTRING (2549281.407587474 6675541.397158415, 2549278.1325214207 6675538.666531657) + +LINESTRING (2551520.2328421865 6675118.18001785, 2551555.186129009 6675081.411578431) + +LINESTRING (2552714.666755916 6672784.95447516, 2552710.1872575106 6672835.416057551) + +LINESTRING (2552098.2201290997 6676377.8591506155, 2552118.926466113 6676376.908932513, 2552177.9519009055 6676372.667959087) + +LINESTRING (2552483.811722061 6672500.92928317, 2552462.948643851 6672493.047474067, 2552343.1571220313 6672403.776983909) + +LINESTRING (2549446.34057389 6671492.427802935, 2549366.6830479144 6671568.48526032, 2549357.1300844634 6671575.086775558, 2549342.239670795 6671574.806711275) + +LINESTRING (2549009.032635616 6677388.471115267, 2548966.861004217 6677556.069583959) + +LINESTRING (2552714.930741089 6672774.342039299, 2552686.56058452 6672754.707532612) + +LINESTRING (2553718.792108468 6677258.8113546055, 2553744.1181860096 6677247.3487236) + +LINESTRING (2550136.1750788214 6675442.2143931035, 2550137.123775537 6675459.318318949, 2550130.4911480634 6675468.40040355, 2550115.4852408813 6675466.359935204, 2550109.718814757 6675452.346718766, 2550117.357885703 6675441.164152043, 2550124.4772358392 6675438.383513806, 2550136.1750788214 6675442.2143931035) + +LINESTRING (2551492.3824064266 6676385.590925281, 2551477.401247855 6676380.349722274, 2551450.2025254914 6676362.16554848) + +LINESTRING (2551364.7703238544 6672731.342169586, 2551354.7636358873 6672659.835756798, 2551338.1655681306 6672600.862220667, 2551303.789748874 6672527.155302799, 2551280.3115675435 6672498.72877809) + +LINESTRING (2552796.015436907 6673098.0563410865, 2552788.4341127174 6673214.002954185) + +LINESTRING (2547822.9555025217 6675118.270038513, 2547774.8607038017 6675095.06471222) + +LINESTRING (2548654.855278251 6677031.539189075, 2548602.3469774188 6677077.829814111, 2548580.5846997136 6677097.014217487, 2548569.3983280044 6677113.988113486, 2548566.1727591706 6677126.911079681) + +LINESTRING (2550698.306756277 6672645.982577093, 2550602.612131037 6672640.021208786, 2550591.8217370873 6672639.351054966) + +LINESTRING (2547036.0816978747 6674673.447938986, 2547028.5911185886 6674671.497491302) + +LINESTRING (2553233.0593900075 6674893.908541065, 2553151.1827386706 6674957.58315623) + +LINESTRING (2549709.2533072005 6677274.374926895, 2549697.596711902 6677264.142578275, 2549679.752964109 6677240.377123416, 2549675.9251790997 6677233.775608178) + +LINESTRING (2549176.6384719093 6674324.00773236, 2549165.8893256434 6674317.4062171215, 2549159.4629365862 6674308.824247311, 2549155.47841038 6674299.692151231, 2549155.7836432364 6674288.779646496, 2549160.5601249617 6674278.587307059, 2549165.608841397 6674274.036262463, 2549171.9527350874 6674274.026260167, 2549187.016389026 6674286.979233249, 2549184.0300567555 6674306.553726161, + 2549176.6384719093 6674324.00773236) + +LINESTRING (2551312.9137364184 6673244.529961015, 2551308.689973649 6673268.8555444395, 2551291.341198056 6673494.177262286) + +LINESTRING (2551419.852480124 6674939.328966365, 2551348.1227588775 6675039.96206457) + +LINESTRING (2550044.2834899807 6675203.259546061, 2550023.618400651 6675252.000733572, 2550003.7205182305 6675282.347699078, 2550013.2899807543 6675295.570734146, 2550079.055286997 6675306.313199853) + +LINESTRING (2551840.6200973974 6673766.099676338, 2551813.8668500134 6673803.158182336) + +LINESTRING (2551878.6422118573 6673047.834813794, 2551725.456565643 6672934.608825157) + +LINESTRING (2551370.726489322 6674304.233193532, 2551366.3872330394 6674304.313211898) + +LINESTRING (2551918.421477625 6673645.842073742, 2551902.1451417976 6673644.191694933) + +LINESTRING (2550277.86912047 6675871.0628262125, 2550276.367704798 6675786.623444934, 2550277.4483941 6675759.607243936, 2550358.244356135 6675759.827294444, 2550356.982177026 6675644.510825981, 2550369.504973674 6675638.7595058875, 2550389.617344048 6675636.388961779) + +LINESTRING (2548030.670586049 6676706.914678369, 2548038.4498991184 6676718.547348402, 2548066.6963126375 6676745.033427723, 2548084.0945854504 6676770.6693119) + +LINESTRING (2553504.419648857 6675758.016878901, 2553630.299328731 6675725.599438162, 2553642.0796670793 6675728.370074103, 2553667.5707353544 6675743.563561447) + +LINESTRING (2553561.778677244 6675698.003104005, 2553510.6645481074 6675701.463898358) + +LINESTRING (2552920.7484311853 6672816.4917138675, 2552911.063475148 6672951.98281299) + +LINESTRING (2547805.7964662714 6671466.201783306, 2547800.0712878304 6671470.022660308, 2547792.7951964973 6671504.690617605, 2547796.9034657534 6671533.207162976, 2547791.739255805 6671569.015381997, 2547797.2499462934 6671583.92880506) + +LINESTRING (2548758.914933663 6676332.778803373, 2548866.5796365947 6676319.20568795) + +LINESTRING (2547852.6125868093 6672839.406973582, 2547680.6179970135 6672805.239131074) + +LINESTRING (2552879.3357571587 6673419.2100551445, 2552773.2384661925 6673412.668553681) + +LINESTRING (2548293.6328165797 6677280.036226327, 2548166.3012182536 6677325.906754939, 2548140.9008948817 6677341.25027672, 2548118.3136635106 6677359.964572192, 2548097.5248311306 6677385.360401268) + +LINESTRING (2554164.2258403506 6673085.173384075, 2554117.6819545226 6673171.423180896) + +LINESTRING (2551443.5286503346 6675059.75660799, 2551431.6740661557 6675050.304438443) + +LINESTRING (2553015.3458680497 6672745.815491632, 2553010.6683807643 6672823.043217626) + +LINESTRING (2551280.3115675435 6672498.72877809, 2551249.6480397834 6672471.852609233, 2551124.766553845 6672382.372070864) + +LINESTRING (2551398.321189445 6673860.751401644, 2551393.924186406 6673859.821188133) + +LINESTRING (2551150.8268401497 6677498.466362355, 2551198.616406013 6677595.068535346) + +LINESTRING (2552535.767303937 6675312.314577342, 2552527.2290334953 6675345.632224705, 2552518.4927741736 6675379.730051141) + +LINESTRING (2553687.9883385845 6676119.429833619, 2553683.145860566 6676146.346011659, 2553677.1649464886 6676162.439705627) + +LINESTRING (2553725.5237303814 6676562.6115566315, 2553715.475794731 6676674.007125134) + +LINESTRING (2552321.658829499 6676728.859715389, 2552320.0749184606 6676735.381212261) + +LINESTRING (2550173.908459498 6675874.073517254, 2550173.900209961 6675890.127202038, 2550169.725944412 6675893.497975728, 2549999.9999771975 6676012.935390066, 2549943.771135332 6676064.087130869, 2549906.334737975 6676109.547565352, 2549884.6219574898 6676141.955003796, 2549880.1094609373 6676167.43085124) + +LINESTRING (2547352.8804046395 6672617.556052384, 2547351.0902551846 6672623.937517114, 2547340.877328801 6672631.979362951, 2547316.7309350013 6672639.5110917, 2547304.3566300133 6672649.373355375, 2547324.5597452903 6672707.85677901, 2547337.445521551 6672722.830215847) + +LINESTRING (2552638.878262633 6673862.84188147, 2552588.985064922 6673860.221279966) + +LINESTRING (2552891.2563376306 6674758.197391435, 2552891.050099214 6674779.41226086) + +LINESTRING (2552914.355040275 6674234.33715037, 2552908.753604884 6674299.502107611) + +LINESTRING (2552679.7877149233 6675641.640167083, 2552695.668072991 6675661.664763306) + +LINESTRING (2550802.3251640056 6673777.652328005, 2550686.8728984683 6673844.287622731, 2550673.723137034 6673835.385579455, 2550665.052874006 6673832.985028459, 2550654.493467083 6673834.665414156, 2550611.1504014786 6673856.980536122) + +LINESTRING (2551230.294626782 6677103.4156868085, 2551179.4774809647 6677181.763669935) + +LINESTRING (2549903.752633001 6676653.942519727, 2549872.2064048187 6676641.549675211, 2549861.416010869 6676633.217762796, 2549853.0922283805 6676621.895163933, 2549847.160811523 6676590.908051495) + +LINESTRING (2553001.9073728328 6676024.287995817, 2552925.293925884 6676084.411795967, 2552908.720606737 6676093.823956329, 2552891.322333924 6676098.715078983) + +LINESTRING (2553686.016699323 6675827.962933542, 2553746.098074808 6675814.919939798, 2553773.280298098 6675939.628564031) + +LINESTRING (2553281.9791423935 6672606.85359586, 2553277.1036662282 6672627.408313762, 2553263.2774427882 6672652.123986724, 2553117.945355473 6672841.277402899, 2553103.302427904 6672864.422715417, 2553080.822440509 6672916.394644477) + +LINESTRING (2552227.2511319774 6673298.412328576, 2552147.7668462717 6673412.808585823) + +LINESTRING (2550799.998794668 6674969.555904321, 2550707.1420100383 6674958.32332612) + +LINESTRING (2549363.721464254 6672660.605933576, 2549348.2948307022 6672665.777120513, 2549296.5207386324 6672713.648108288, 2549283.3132304423 6672723.470362779, 2549262.2274147426 6672731.002091528, 2549256.980709428 6672738.653847828) + +LINESTRING (2552525.5543775535 6676433.6319520855, 2552511.98388975 6676505.76850951) + +LINESTRING (2553044.4502333812 6674744.374218617, 2553060.644073842 6674756.637033287) + +LINESTRING (2554503.1993016535 6675004.303879986, 2554471.224097565 6675007.54462383, 2554459.1302768234 6675014.6662584515) + +LINESTRING (2551501.1186657483 6674998.4825438205, 2551482.2107277266 6674984.909428399) + +LINESTRING (2551429.8426690176 6673767.009885257, 2551326.8967010546 6673752.106464491) + +LINESTRING (2551188.6674648025 6675605.251814904, 2551183.5280034645 6675613.4036859935) + +LINESTRING (2553233.5956098903 6676956.431949793, 2553326.1636607368 6676944.679252209) + +LINESTRING (2553069.644318337 6672961.244938916, 2553064.4636093155 6673023.979338273, 2553058.119715625 6673058.3372244015) + +LINESTRING (2552125.790080613 6672703.615805584, 2552058.515109162 6672648.903247471, 2552052.253710838 6672642.651812586) + +LINESTRING (2553897.2378359307 6675544.497870117, 2553923.545608335 6675605.651906736) + +LINESTRING (2548659.037793337 6672031.391510681, 2548499.7227413855 6671940.530655489) + +LINESTRING (2553694.431226715 6675125.751755783, 2553711.9862407246 6675111.1083947085) + +LINESTRING (2551557.9002265697 6674544.118254086, 2551546.0621414646 6674536.906598803, 2551518.9211658575 6674539.787259997) + +LINESTRING (2552178.768605035 6672482.044948669, 2552135.4420385035 6672451.177863781, 2552032.2815825874 6672414.099353191) + +LINESTRING (2552373.597912302 6675153.17805091, 2552433.3163081734 6675233.786552891) + +LINESTRING (2549061.2027054452 6677165.359904797, 2549053.3408970097 6677195.266769286) + +LINESTRING (2551658.899303881 6673651.903465007, 2551649.1483515506 6673666.116727361) + +LINESTRING (2552322.863261851 6673626.757693326, 2552317.179331093 6673633.669279735) + +LINESTRING (2547371.3676162916 6674760.517924064, 2547369.51972008 6674773.991016528, 2547365.81567812 6674799.196801984, 2547360.288488559 6674811.499625837, 2547352.4926764164 6674819.611487744, 2547331.2088718372 6674825.532846867, 2547266.8707354367 6674835.175060034, 2547250.330414436 6674830.3439511545, 2547207.1523395646 6674787.63414802, 2547189.729318142 6674775.731416, + 2547154.3718040227 6674762.088284506, 2547129.020977871 6674761.358116913) + +LINESTRING (2553491.401880009 6676038.891347708, 2553485.651952958 6676036.060697992) + +LINESTRING (2549900.155835018 6677138.173664769, 2549861.6882455787 6677157.047996974, 2549848.6127299746 6677171.911408556, 2549808.6932220836 6677175.1521524) + +LINESTRING (2553024.99782594 6676248.229396841, 2553064.108879239 6676298.801004486) + +LINESTRING (2551189.6904073483 6673933.678140438, 2551121.846217868 6673914.833815121) + +LINESTRING (2552521.652346714 6673397.1649951665, 2552514.763983604 6673499.378456109) + +LINESTRING (2552089.277631362 6672241.849816945, 2552001.873790464 6672212.112991484) + +LINESTRING (2553064.108879239 6676298.801004486, 2553086.8858499536 6676325.957237626, 2553126.3186351815 6676295.190175696) + +LINESTRING (2551337.5056051975 6674079.57162721, 2551349.888159722 6674101.536668821) + +LINESTRING (2551814.8402953395 6672778.893083896, 2551733.574109715 6672719.2894031275) + +LINESTRING (2551263.861991446 6675722.718776966, 2551358.2779385042 6675811.469147742, 2551398.395435275 6675843.786565523, 2551467.757539501 6675888.4568186365) + +LINESTRING (2554361.727997495 6673132.004133086, 2554348.165759228 6673156.739810638) + +LINESTRING (2553112.030437689 6673518.282795202, 2552966.162130491 6673509.980889674) + +LINESTRING (2553314.507065438 6676848.127090698, 2553446.7141399295 6676834.023853597) + +LINESTRING (2552510.4824740784 6672559.752784863, 2552518.484524637 6672622.867271462) + +LINESTRING (2549483.4552393174 6677575.083948306, 2549481.1536185895 6677584.786175247, 2549453.9713952993 6677720.547336357, 2549450.3086010227 6677780.991209973) + +LINESTRING (2549819.5166141796 6677095.683912143, 2549842.103845551 6677073.208753444, 2549847.7630276987 6677004.182910019, 2549858.734911455 6676968.274668039) + +LINESTRING (2553557.5136667914 6673231.256914468, 2553565.499218277 6673219.764276574, 2553670.9777939944 6673151.3385708975) + +LINESTRING (2551421.2878995026 6674540.157344943, 2551422.6490730513 6674549.74954663) + +LINESTRING (2552103.912309394 6674035.331472816, 2552113.457023308 6674034.611307517, 2552123.8679385716 6674040.122572511, 2552211.725503986 6674130.563331279, 2552231.623386407 6674164.851201337, 2552240.7556234878 6674189.7869248055) + +LINESTRING (2549124.59214513 6672070.870572267, 2549110.600930957 6671998.894051576, 2549103.4898303575 6671983.080421891, 2549092.765432701 6671971.107673799, 2549077.0500653666 6671962.415678735, 2549062.629875287 6671959.03490275, 2548977.4369102134 6671973.518227091) + +LINESTRING (2552309.0287888744 6675070.719124204, 2552373.597912302 6675153.17805091) + +LINESTRING (2553288.8592559667 6674230.566284847, 2553285.9141713795 6674257.772529467) + +LINESTRING (2546907.7601551497 6672996.583050033, 2546952.1096642264 6672967.336337067) + +LINESTRING (2553789.5813825354 6675557.130769733, 2553830.028860773 6675634.458518687) + +LINESTRING (2553265.8842963725 6672521.714053876, 2553279.570277689 6672525.154843636, 2553302.165758597 6672544.049180432) + +LINESTRING (2553417.0405565687 6676416.538028535, 2553413.179773412 6676420.128852733) + +LINESTRING (2551491.2522199047 6671144.017832778, 2551481.427021744 6671124.963459249) + +LINESTRING (2550691.5338866804 6672743.7150095105, 2550698.306756277 6672645.982577093) + +LINESTRING (2553943.575483342 6672977.868754562, 2553960.9655066184 6673004.774930307, 2553978.339030822 6673032.391269054) + +LINESTRING (2552662.2162018404 6673501.088848694, 2552514.763983604 6673499.378456109) + +LINESTRING (2552785.5962721067 6673513.141615152, 2552777.759212281 6673637.510161328) + +LINESTRING (2550508.748902935 6675864.831395919, 2550508.6251598853 6675902.209975383, 2550509.837841774 6675965.304457391) + +LINESTRING (2549256.0485117855 6676792.624351216, 2549236.2331247316 6676935.287096438, 2549227.653606606 6676936.2273122445, 2549153.2922831653 6676924.864704198) + +LINESTRING (2547927.3038917165 6672968.396580424, 2547903.784462703 6673080.352277492, 2547875.340060304 6673213.862922044, 2547867.255514378 6673234.787724891) + +LINESTRING (2554689.003615816 6675483.063769217, 2554664.0982646435 6675481.57342714, 2554651.063996723 6675416.008378066, 2554630.2999129533 6675311.604414339, 2554597.2110214154 6675262.33310515, 2554544.80996456 6675146.876604547, 2554507.6045542294 6675084.892377375, 2554459.1302768234 6675014.6662584515) + +LINESTRING (2554395.4933510385 6675847.697463186, 2554468.641992591 6675824.642171331) + +LINESTRING (2550915.244821789 6675393.543221664, 2550835.207817127 6675345.372165014) + +LINESTRING (2553076.243947664 6672827.414220898, 2553070.947745129 6672902.731508393, 2553080.822440509 6672916.394644477) + +LINESTRING (2551027.050792123 6675395.103579811, 2550999.72832671 6675440.514002815) + +LINESTRING (2551996.445595342 6675190.92671532, 2551973.6768741645 6675184.345204673) + +LINESTRING (2552621.125259744 6675091.723945417, 2552515.5064419033 6675173.012603514) + +LINESTRING (2551498.759298264 6673658.705026162, 2551463.7812628313 6673709.036578707, 2551435.485352092 6673768.170151572) + +LINESTRING (2553366.2564088977 6676164.4401647905, 2553372.7487942483 6676171.031677733) + +LINESTRING (2551424.051494283 6673230.496739985, 2551388.8424718245 6673240.47903121, 2551388.174259355 6673250.431315547, 2551397.3229955095 6673270.465914066) + +LINESTRING (2553319.63827724 6676115.9590369705, 2553362.2306350083 6676160.339223506) + +LINESTRING (2553181.2193016447 6674994.361597945, 2553117.0709045874 6675047.643827756) + +LINESTRING (2549381.598210193 6676613.453226265, 2549301.7509448742 6676642.039787706, 2549256.0485117855 6676792.624351216) + +LINESTRING (2553522.444886456 6676778.801178398, 2553532.6248146924 6676765.988237457, 2553552.6051924797 6676754.265546761, 2553584.1679197354 6676747.223930507) + +LINESTRING (2551136.7613801467 6675525.22344608, 2551136.216910727 6675513.700801301) + +LINESTRING (2549007.9024490938 6672133.264893567, 2548860.705966494 6672161.711422868) + +LINESTRING (2550961.97844696 6677649.9311278965, 2550946.510565725 6677618.803983317, 2551055.668434792 6677563.991402245, 2551081.2337488974 6677617.86376751, 2551097.378092138 6677639.008620866, 2551119.981822583 6677645.470103962, 2551165.2717788387 6677625.995634008, 2551176.5406459146 6677607.7214395525, 2551187.595025037 6677598.1392401615, 2551198.616406013 6677595.068535346) + +LINESTRING (2553477.5591574963 6672131.244429813, 2553501.581808246 6672095.446213087, 2553524.688760427 6672067.959904185, 2553578.236502878 6672029.551088251, 2553588.5484237014 6672013.887493004, 2553596.9794501667 6671997.5837508235, 2553598.4066200084 6671985.601000437, 2553597.391926999 6671967.896936842, 2553586.8572686864 6671931.4285662975) + +LINESTRING (2552394.4032437545 6672059.577980291, 2552350.5899545606 6672084.733754268) + +LINESTRING (2551113.5801821356 6674256.752295293, 2551107.195040762 6674255.151927963) + +LINESTRING (2551527.558430739 6673498.808325248, 2551528.9031052147 6673530.415580027, 2551499.6584977596 6673564.653438604, 2551457.841596437 6673570.304735741) + +LINESTRING (2552698.3739210153 6674904.100880502, 2552559.377477854 6675010.015190897) + +LINESTRING (2553060.644073842 6674756.637033287, 2552942.890187577 6674846.207592319) + +LINESTRING (2553326.1636607368 6676944.679252209, 2553463.3369562966 6676927.245250602) + +LINESTRING (2553259.6476466586 6676174.48246979, 2553214.3329417924 6676218.312530055) + +LINESTRING (2551944.9354884457 6673645.44198191, 2551933.69136998 6673623.536954073, 2551893.7883611624 6673596.390723228) + +LINESTRING (2552697.260233566 6675557.060753663, 2552695.668072991 6675661.664763306) + +LINESTRING (2554229.4796753204 6673415.939304413, 2554253.1888436773 6673374.27974234, 2554099.54122341 6673290.140429935) + +LINESTRING (2549097.913143576 6671757.208577774, 2549023.337332182 6671822.0034500705) + +LINESTRING (2551832.4695551787 6673402.116131595, 2551755.715866107 6673348.653860459) + +LINESTRING (2551818.5030896156 6673548.549742341, 2551799.743643254 6673574.965805591) + +LINESTRING (2554266.635588431 6673100.146820912, 2554348.165759228 6673156.739810638) + +LINESTRING (2552203.5997103774 6672890.538709792, 2552122.746001586 6673002.154328803) + +LINESTRING (2553456.7455765065 6675159.909595994, 2553453.15702806 6675162.200121736) + +LINESTRING (2551725.456565643 6672934.608825157, 2551661.514407002 6673021.638801052) + +LINESTRING (2552592.647859198 6677083.961221446, 2552585.050035936 6677084.691389041) + +LINESTRING (2553939.2444765964 6674917.794023474, 2554012.665352858 6674852.439022612) + +LINESTRING (2553295.112404754 6677200.097878166, 2553230.4030392035 6677208.139724001, 2553195.0702736946 6677226.874024065, 2553139.6416368852 6677282.486788802, 2553044.7884643846 6677290.308584129) + +LINESTRING (2551887.972437818 6673592.839908214, 2551869.00675304 6673620.5562699195) + +LINESTRING (2550591.8217370873 6672639.351054966, 2550611.983604681 6672531.376271633) + +LINESTRING (2551912.597304744 6677299.730746788, 2551918.2234887453 6677300.160845508) + +LINESTRING (2551651.7139574517 6676399.724169269, 2551628.912238127 6676351.483096548) + +LINESTRING (2554440.9317989545 6673360.586599368, 2554443.794388175 6673363.117180209) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553207.576571269 6672316.246893224) + +LINESTRING (2551050.322735037 6675236.387149803, 2551042.675414555 6675236.6272049025, 2551019.4859670075 6675223.744247892) + +LINESTRING (2551282.134715145 6675460.818663321, 2551206.618456572 6675407.336387593) + +LINESTRING (2551182.323571112 6675106.617363887, 2551117.9029393448 6675203.829676922, 2551114.611374218 6675220.503504047) + +LINESTRING (2551301.966601272 6673840.286704404, 2551230.7978485185 6673825.183237722) + +LINESTRING (2550294.6239294237 6676116.669199973, 2550300.010876862 6676128.551927403, 2550301.9247693666 6676177.083066702, 2550320.692465265 6676206.41980033) + +LINESTRING (2551737.756624801 6673535.516750893, 2551639.6118871733 6673470.691871709) + +LINESTRING (2552760.872410741 6674986.329754405, 2552824.4103420856 6675069.158766056) + +LINESTRING (2552222.5653951555 6672317.377152652, 2552144.277292265 6672259.273816257, 2552089.277631362 6672241.849816945) + +LINESTRING (2547859.484450846 6671575.806940856, 2547856.9518430918 6671583.99882113, 2547844.5445399573 6671595.151380965, 2547838.2336444133 6671608.824519346) + +LINESTRING (2552271.1386670014 6673506.220026447, 2552212.113232209 6673461.839839912) + +LINESTRING (2551966.153296732 6673989.120866146, 2551924.608630119 6673968.396109215) + +LINESTRING (2551518.9211658575 6674539.787259997, 2551428.7124824952 6674549.12940429) + +LINESTRING (2550636.89720539 6671631.9498272715, 2550578.80396824 6671730.592468609) + +LINESTRING (2549216.590977947 6671328.23011482, 2549195.0019405116 6671318.957986599, 2549146.8493950353 6671308.6956310915, 2549125.4665960157 6671310.466037451) + +LINESTRING (2549197.047825603 6676615.883784148, 2549155.041184937 6676773.579979982) + +LINESTRING (2548889.6453410923 6671241.990320295, 2548841.591790056 6671231.327872955) + +LINESTRING (2552909.710551136 6672140.6265832875, 2552883.7245106613 6672239.799346303) + +LINESTRING (2551318.944147716 6672449.857560733, 2551336.358919602 6672432.703623409, 2551376.443418226 6672068.390002904) + +LINESTRING (2551555.186129009 6675081.411578431, 2551562.206484705 6675046.233504047, 2551592.251297216 6675000.002892785, 2551619.3015279197 6674963.924611777) + +LINESTRING (2553289.5852151928 6673546.189200528, 2553282.366870616 6673641.751134754) + +LINESTRING (2554037.1829758077 6675028.579451931, 2553939.2444765964 6674917.794023474) + +LINESTRING (2551755.715866107 6673348.653860459, 2551655.7479808778 6673452.047592308) + +LINESTRING (2549751.8044172856 6677393.642302204, 2549724.193218089 6677406.3752247775) + +LINESTRING (2548394.1946684485 6675373.758680539, 2548379.9147204924 6675369.337665789) + +LINESTRING (2552669.1210640236 6673406.247079767, 2552521.652346714 6673397.1649951665) + +LINESTRING (2552982.661203808 6674691.5821013, 2552978.453940112 6674694.902863511) + +LINESTRING (2553099.4993915046 6672962.855308542, 2553107.575687893 6672931.678152484, 2553127.2673318973 6672894.5896395985, 2553233.8843436735 6672761.339054738, 2553267.4847064842 6672712.667883297, 2553291.820839627 6672670.948307449, 2553306.8844935657 6672626.918201268, 2553317.8811259316 6672579.957422412) + +LINESTRING (2552526.4948247327 6676386.961239808, 2552308.921544898 6676450.095730999) + +LINESTRING (2551629.9186815997 6674060.237189397, 2551497.6291117417 6674081.552081781) + +LINESTRING (2551325.197296503 6672931.528118047, 2551327.4741686205 6672946.5315617705, 2551311.15658511 6673112.779720527, 2551314.926623363 6673157.730037924) + +LINESTRING (2548687.185212416 6675823.651944045, 2548650.2355377222 6675857.319671761, 2548612.0071848463 6675902.550053441, 2548587.390567457 6675960.003240609) + +LINESTRING (2549314.974952138 6671750.76709927, 2549129.1046416825 6671709.017516534) + +LINESTRING (2553532.6743119126 6673185.456401926, 2553555.352288187 6673221.024565848, 2553557.5136667914 6673231.256914468) + +LINESTRING (2551481.427021744 6671124.963459249, 2551445.178557666 6671054.67732655, 2551435.180119236 6671046.105359036, 2551419.3410088513 6671039.603866755, 2551404.846572942 6671040.844151436, 2551386.400608973 6671047.835756212, 2551312.4600119023 6671088.845169057, 2551297.338611207 6671100.237783992, 2551288.8415884483 6671108.17960687, 2551285.1210474153 6671126.433796734, + 2551335.657708986 6671225.196465621, 2551491.2522199047 6671144.017832778) + +LINESTRING (2552037.8417702955 6673754.316971866, 2551998.169748504 6673877.825320601, 2552022.431635817 6673885.937182508) + +LINESTRING (2553937.437828068 6677596.8189371135, 2553995.3083277284 6677545.697203198, 2554055.67018746 6677619.424125657) + +LINESTRING (2552192.6443256945 6671895.100227893, 2552225.469232059 6671927.747721436) + +LINESTRING (2552299.6078180103 6672464.140839159, 2552179.7832980435 6672378.541191566) + +LINESTRING (2552098.558360103 6676362.415605876, 2552100.9919734173 6676362.5956472) + +LINESTRING (2551160.1818147204 6674064.618194965, 2551154.9681075523 6674083.052426154) + +LINESTRING (2551422.6490730513 6674549.74954663, 2551429.7849222613 6674569.754138262, 2551442.9264341583 6674602.751712158, 2551482.5324596562 6674683.330207252) + +LINESTRING (2548911.3581215777 6677552.868849298, 2548946.872376893 6677554.739278615, 2548962.216515078 6677555.539462281) + +LINESTRING (2547062.1089860327 6672970.096970713, 2547022.8411915377 6673003.024528539) + +LINESTRING (2550839.241840553 6672755.957819589, 2550691.5338866804 6672743.7150095105) + +LINESTRING (2554621.7368939016 6675740.422840561, 2554656.4179460146 6675619.875171387) + +LINESTRING (2553452.7775493735 6675965.714551519, 2553292.45605395 6675895.708483104, 2553217.0387898167 6675881.695266665) + +LINESTRING (2553743.8212026902 6675464.299462265, 2553755.156066059 6675460.858672505, 2553813.6040332853 6675423.950200944, 2553820.904873228 6675424.610352468, 2553878.9733617683 6675535.2157396) + +LINESTRING (2549227.925841316 6676190.726198195, 2549244.3506688033 6676218.202504802, 2549265.477732186 6676267.933919598, 2549268.0268390137 6676290.379071409) + +LINESTRING (2553875.335316102 6676875.273321543, 2553852.5830939976 6676827.292308513, 2553857.3925738693 6676805.917402355) + +LINESTRING (2553213.62348164 6676806.227473525, 2553210.9423822258 6676786.052842864) + +LINESTRING (2548946.2949093273 6675985.529099531, 2548935.883994064 6676001.412745286, 2548924.912110308 6676010.804901058, 2548787.3180883788 6676110.747840851) + +LINESTRING (2553482.7728646644 6676798.655735592, 2553476.230982094 6676802.706665398) + +LINESTRING (2548681.3692890718 6675476.232201174, 2548655.1852597175 6675463.219214317, 2548570.033542327 6675432.772225854) + +LINESTRING (2549819.5166141796 6677095.683912143, 2549853.554202433 6677127.181141667, 2549900.155835018 6677138.173664769) + +LINESTRING (2548379.9147204924 6675369.337665789, 2548386.299861866 6675357.264894739, 2548397.8987104082 6675334.049566151, 2548404.671580005 6675331.829056479) + +LINESTRING (2550165.221697396 6676312.714197966, 2550098.169463435 6676278.076247555, 2550089.9611744597 6676277.016004199) + +LINESTRING (2551630.2239144556 6672865.68300469, 2551565.597044272 6672958.694353483) + +LINESTRING (2553183.413678396 6675229.635600127, 2553158.59082259 6675246.599493831, 2553156.561436572 6675275.50612874, 2553180.1221132693 6675310.7242123075, 2553203.32805989 6675312.814692133) + +LINESTRING (2553376.667324161 6676318.205458369, 2553348.371413422 6676346.65198767) + +LINESTRING (2550170.1466707815 6676695.852139196, 2550164.2812502175 6676695.402035885) + +LINESTRING (2551949.8274636846 6673239.518810811, 2551928.378668372 6673231.466962679, 2551871.4321168177 6673231.22690758) + +LINESTRING (2552341.7794494093 6672696.104081427, 2552264.671030261 6672803.6187591525) + +LINESTRING (2551717.042038251 6676584.5265867645, 2551731.693215357 6676588.177424737, 2551941.041707143 6676640.42941808) + +LINESTRING (2548600.4413344506 6676332.238679399, 2548574.6615323927 6676365.506315283, 2548526.2779998896 6676474.191261618) + +LINESTRING (2550253.879467867 6672593.780595229, 2550268.200663506 6672568.444779928, 2550317.9948667777 6672508.10092927) + +LINESTRING (2551370.503751832 6673963.615011815, 2551351.8597989837 6674088.353642936) + +LINESTRING (2552080.145394281 6673330.999808344, 2552006.798763849 6673277.947631336, 2551949.8274636846 6673239.518810811) + +LINESTRING (2547662.6175080244 6672750.346531636, 2547670.50406507 6672746.875734989, 2547680.098276204 6672742.66476845) + +LINESTRING (2551006.2619597437 6672888.91833787, 2550832.7989524226 6672878.625975476, 2550815.9781471756 6672914.404187609, 2550792.821697775 6672954.823465002, 2550728.731047474 6673032.95139762, 2550585.098364711 6673131.2839677865) + +LINESTRING (2554656.4179460146 6675619.875171387, 2554681.63677958 6675543.857723186, 2554687.790933927 6675517.851754064, 2554689.003615816 6675483.063769217) + +LINESTRING (2553523.5090766847 6675735.681752344, 2553510.6645481074 6675701.463898358) + +LINESTRING (2549191.801120288 6675634.038422262, 2549210.791553676 6675643.120506863, 2549219.4370680945 6675651.492428461) + +LINESTRING (2551679.712884871 6673895.7394324085, 2551613.0318800593 6673913.813580948) + +LINESTRING (2552032.2815825874 6672414.099353191, 2551931.958967282 6672378.671221412) + +LINESTRING (2552118.0437656906 6673737.923209025, 2552017.9191392646 6673946.871168619) + +LINESTRING (2552720.0207052073 6675222.293914999, 2552715.260722555 6675284.768254665) + +LINESTRING (2553528.33505563 6676650.701775882, 2553524.127791934 6676688.710499983, 2553521.553936497 6676745.293487415) + +LINESTRING (2551983.931048231 6672903.211618591, 2551826.9588646907 6672789.355485318) + +LINESTRING (2551890.472047426 6673874.094464263, 2551864.411761121 6673781.5132141905, 2551840.6200973974 6673766.099676338) + +LINESTRING (2547895.0977006014 6671978.22930842, 2547919.3513383777 6672037.772975412) + +LINESTRING (2552970.3528951136 6676142.775192053, 2552847.575041023 6676242.638113479) + +LINESTRING (2549077.8915181058 6676275.975765434, 2549013.116156262 6676354.843867943, 2549006.3185380553 6676357.754536025) + +LINESTRING (2552303.6418414363 6676096.304525692, 2552295.2520626546 6676099.89534989, 2552210.298334144 6676197.557766237) + +LINESTRING (2552521.652346714 6673397.1649951665, 2552480.8583879373 6673392.573941387, 2552448.388211649 6673384.4020657055, 2552422.245429978 6673371.049000791, 2552398.0412894213 6673352.814815518) + +LINESTRING (2550817.5785572873 6675557.160776621, 2550776.0256411377 6675619.855166795) + +LINESTRING (2553433.0446576863 6673508.920646318, 2553466.348037177 6673655.7443466) + +LINESTRING (2552971.7305677356 6673425.081402789, 2552930.1703346907 6673422.44040407, 2552879.3357571587 6673419.2100551445) + +LINESTRING (2552192.578329401 6675949.250772606, 2552079.675170691 6676035.16049137) + +LINESTRING (2552686.56058452 6672754.707532612, 2552655.97130259 6672798.9676915975) + +LINESTRING (2550060.518578125 6676537.765853825, 2550061.96224704 6676520.11180171, 2550059.215151333 6676507.308863065, 2549999.9999771975 6676444.304401721) + +LINESTRING (2553071.0549891056 6675017.826983929, 2553063.374670476 6675121.190708891) + +LINESTRING (2551393.924186406 6673859.821188133, 2551301.966601272 6673840.286704404) + +LINESTRING (2551557.9002265697 6674544.118254086, 2551510.0446644127 6674631.928409054) + +LINESTRING (2551291.341198056 6673494.177262286, 2551265.536647388 6673504.27958106, 2551193.0974659882 6673547.3694714345) + +LINESTRING (2549224.3372928696 6676511.139742363, 2549197.047825603 6676615.883784148) + +LINESTRING (2550697.3498100247 6675261.432898526, 2550628.1856946787 6675291.009687254) + +LINESTRING (2553426.9647491686 6676010.044726576, 2553319.63827724 6676115.9590369705) + +LINESTRING (2547440.4327371973 6677617.333645832, 2547446.7766308878 6677560.290552794, 2547475.171536067 6677510.249066827, 2547526.1536726174 6677484.703203312, 2547570.173200228 6677473.680673324, 2547565.3719698926 6677523.182035317) + +LINESTRING (2553219.7776359874 6673717.488518672, 2553098.567193862 6673709.276633807) + +LINESTRING (2549218.620363965 6674576.805756812, 2549226.6554126707 6674589.978780402, 2549231.134911076 6674614.2443500515, 2549251.7175050396 6674640.600399526) + +LINESTRING (2552747.310172474 6672343.373119477, 2552507.9168681772 6672319.74769676) + +LINESTRING (2548650.2767854054 6676182.624338584, 2548623.878268098 6676319.195685655, 2548600.4413344506 6676332.238679399) + +LINESTRING (2552073.859247347 6673797.806954075, 2552068.1670670523 6673793.766026565) + +LINESTRING (2553657.3000622145 6675681.659352642, 2553597.4826719025 6675694.122213229, 2553561.778677244 6675698.003104005) + +LINESTRING (2551890.472047426 6673874.094464263, 2551850.932018221 6673967.375875042) + +LINESTRING (2551386.895581173 6673427.361926234, 2551376.9053922794 6673436.063923595, 2551339.2215088224 6673456.338577214, 2551291.341198056 6673494.177262286) + +LINESTRING (2553108.3923920225 6676400.944449359, 2553161.931884937 6676468.279904791, 2553041.0431747413 6676562.551542857) + +LINESTRING (2551705.5504336855 6674335.160292194, 2551631.1726111714 6674317.166162021) + +LINESTRING (2551046.1402199515 6673142.6865850175, 2551022.521796498 6673186.146560337, 2551003.4901154265 6673197.489163793, 2550911.12005346 6673225.3055484565, 2550899.7851900905 6673215.853378911, 2550904.9411505023 6673194.278426835, 2550915.3850639123 6673178.004691543, 2550966.045468533 6673150.9284767695, 2550989.6473929132 6673144.18692939, 2551046.1402199515 6673142.6865850175) + +LINESTRING (2552655.97130259 6672798.9676915975, 2552526.3050853894 6672709.167079763) + +LINESTRING (2553058.119715625 6673058.3372244015, 2553059.7036266634 6673072.410454614, 2553050.2414081157 6673236.108027938) + +LINESTRING (2553086.96834532 6675006.344348332, 2553071.0549891056 6675017.826983929) + +LINESTRING (2553001.610389513 6674456.808213908, 2553026.474493002 6674457.848452673) + +LINESTRING (2548401.3222681214 6672567.384536571, 2548394.7721360144 6672592.170225603) + +LINESTRING (2553824.559417968 6675403.835584058, 2553890.89394224 6675364.116467373) + +LINESTRING (2552056.98894488 6672339.2921827845, 2552032.2815825874 6672414.099353191) + +LINESTRING (2553675.4572924 6677195.976932289, 2553752.7554508913 6677214.321142816, 2553793.5741582783 6677229.294579652) + +LINESTRING (2552349.6825055284 6675299.091542274, 2552385.1720122336 6675326.887922346, 2552490.262859728 6675410.267060268, 2552507.603385784 6675416.78855714) + +LINESTRING (2550180.2771017984 6676468.249897904, 2550173.9249585713 6676467.729778522) + +LINESTRING (2552146.09219033 6673240.589056464, 2552016.7147069126 6673148.767980873) + +LINESTRING (2550700.913609861 6672866.723243455, 2550700.550630248 6672872.334531408) + +LINESTRING (2553020.4605807783 6676178.553404187, 2552817.901457662 6676342.330995877, 2552812.2175269043 6676373.698195556) + +LINESTRING (2550396.332466888 6677132.652397479, 2550485.9636826837 6677154.5574253155, 2550495.5826424276 6677159.528566336, 2550523.6558156773 6677204.928987045, 2550561.76867504 6677241.207313969, 2550583.6464462588 6677256.880911512, 2550609.56649044 6677255.010482195, 2550657.3395572305 6677238.786758382, 2550724.4660370215 6677199.517745008, 2550736.3123716633 6677197.447269774) + +LINESTRING (2550692.136102856 6672000.934519922, 2550779.399701631 6671848.84961204) + +LINESTRING (2549580.527537179 6675520.572378526, 2549585.370015198 6675542.347376517, 2549589.305044184 6675593.18904615, 2549568.0542377513 6675623.075906048, 2549549.723767296 6675639.769737765, 2549518.738507606 6675693.672109917, 2549495.606806815 6675723.839034098, 2549475.5274345884 6675739.022519146, 2549453.171190243 6675762.447895947, 2549442.5787851736 6675782.422480692, + 2549433.677535119 6675822.911774155, 2549389.6992551917 6675872.5131591065, 2549385.1950081764 6675885.236079384, 2549378.3726413595 6675899.999468008) + +LINESTRING (2551245.6800126503 6674810.619423806, 2551166.9711833904 6674761.498149053) + +LINESTRING (2548787.3180883788 6676110.747840851, 2548750.5581530277 6676134.883380654) + +LINESTRING (2552956.9143998967 6673618.665836011, 2552867.3904280774 6673610.51396492) + +LINESTRING (2552531.1145652616 6673268.445450311, 2552521.652346714 6673397.1649951665) + +LINESTRING (2551840.6200973974 6673766.099676338, 2551749.36372288 6673705.585786651) + +LINESTRING (2550905.988841658 6672124.8129536025, 2550884.144068586 6672115.780880481, 2550692.136102856 6672000.934519922) + +LINESTRING (2549880.1094609373 6676167.43085124, 2549897.6067281906 6676183.144457966) + +LINESTRING (2552715.260722555 6675284.768254665, 2552710.8142222962 6675361.675907194) + +LINESTRING (2547920.50627351 6672635.070072358, 2547903.0502539403 6672620.406706692, 2547890.1892262893 6672621.67699826, 2547718.00489715 6672586.118836634, 2547710.035844738 6672587.629183303, 2547706.455545828 6672588.299337123, 2547688.455056839 6672619.506500068, 2547682.754627008 6672635.990283573, 2547679.520808638 6672648.253098243, 2547679.702298444 6672689.502566188, + 2547676.1549976813 6672704.17593415, 2547665.834827321 6672719.939552356) + +LINESTRING (2552179.7832980435 6672378.541191566, 2552056.98894488 6672339.2921827845) + +LINESTRING (2548381.4326352375 6676426.870400113, 2548433.4377143336 6676459.667928094) + +LINESTRING (2552087.8834596667 6676362.1955553675, 2552093.938619574 6676362.085530113) + +LINESTRING (2547872.848700233 6675061.517012053, 2547920.885752196 6674999.992890489) + +LINESTRING (2553160.356223435 6674832.194375881, 2553236.9036740907 6674889.257473511) + +LINESTRING (2551342.133595263 6676740.562401493, 2551323.192659095 6676814.979482364) + +LINESTRING (2548526.2779998896 6676474.191261618, 2548515.0998777174 6676498.586861114) + +LINESTRING (2551392.612510077 6674494.64689898, 2551400.622810173 6674507.299803187, 2551419.8442305876 6674530.035021577) + +LINESTRING (2551661.473159319 6674188.036523038, 2551631.1726111714 6674317.166162021) + +LINESTRING (2551259.217502307 6671729.32217704, 2551175.3114649523 6671566.634835593) + +LINESTRING (2547028.5911185886 6674671.497491302, 2546995.551724271 6674662.875512308) + +LINESTRING (2551214.2657770542 6677298.630494248, 2551161.617234099 6677403.9746737825, 2551157.9956875057 6677442.863599914, 2551332.7786206924 6677569.032559337) + +LINESTRING (2553208.2117855917 6675870.282647139, 2553136.102585659 6675907.461180687, 2553110.512522944 6675923.704909092, 2553070.3290298795 6675956.22237279) + +LINESTRING (2553207.576571269 6672316.246893224, 2553198.6258239946 6672295.572147773, 2553104.2841227665 6672154.279717077) + +LINESTRING (2552883.7245106613 6672239.799346303, 2552850.64386866 6672373.590055137) + +LINESTRING (2551388.034017232 6674495.0769977, 2551281.2190165757 6674505.089295812) + +LINESTRING (2549023.337332182 6671822.0034500705, 2548826.6848773137 6671777.543245168) + +LINESTRING (2553213.62348164 6676312.414129091, 2553363.6083076303 6676465.00915406) + +LINESTRING (2549254.77808314 6675452.666792232, 2549255.6937817093 6675409.146803136) + +LINESTRING (2552872.472142659 6673518.93294443, 2552785.5962721067 6673513.141615152) + +LINESTRING (2548318.8434006083 6676596.559348631, 2548357.2614928274 6676661.654289802) + +LINESTRING (2548909.716463783 6676167.730920114, 2548995.0001737596 6676208.860360509) + +LINESTRING (2549341.2497263956 6674960.123739366, 2549335.5245479546 6674985.489561556) + +LINESTRING (2552849.2414474282 6672948.622041596, 2552841.9571065586 6673043.233757719) + +LINESTRING (2551379.2647597636 6673289.070184284, 2551346.2583635924 6673254.562263719, 2551328.051636187 6673245.920280133, 2551312.9137364184 6673244.529961015) + +LINESTRING (2553221.9472641284 6675203.719651668, 2553194.6165491785 6675154.058252942) + +LINESTRING (2553293.561491862 6675401.385021583, 2553315.167028371 6675433.792460027) + +LINESTRING (2550835.207817127 6675345.372165014, 2550780.4556423235 6675311.55440286) + +LINESTRING (2554229.141444317 6673170.67300871, 2554314.8953778837 6673219.284166375) + +LINESTRING (2550853.835270902 6674980.93851696, 2550826.0508314357 6675180.984433278) + +LINESTRING (2549333.726148963 6671842.288105985, 2549353.97876146 6671967.826920771, 2549356.0658942345 6671993.012701636, 2549354.2509961696 6672050.675937015) + +LINESTRING (2549831.841421948 6676785.922813019, 2549802.349328393 6676808.938095691, 2549823.5341385324 6676897.908516974, 2549805.4099064935 6676950.990700869) + +LINESTRING (2553715.475794731 6676674.007125134, 2553722.1084222044 6676732.620578615) + +LINESTRING (2550060.4113341486 6675332.179136832, 2550035.8112158324 6675329.4385077795, 2549999.9999771975 6675316.555550768) + +LINESTRING (2548981.5204308596 6670859.882615535, 2548953.2740173405 6670834.056687738, 2548932.815166427 6670813.882057077, 2548922.008273404 6670796.768128936, 2548905.7814347968 6670779.634196203, 2548880.546102158 6670770.632129969, 2548861.6299145995 6670760.719854815, 2548855.046784346 6670753.228135249) + +LINESTRING (2552050.5543062864 6672064.16903407, 2552039.310187821 6672058.027624439) + +LINESTRING (2550210.858134192 6672667.677556718, 2550201.123680935 6672664.926925369) + +LINESTRING (2553183.7354103257 6674109.328457262, 2553182.3164900206 6674153.00848309) + +LINESTRING (2553218.944432785 6676004.253397298, 2553248.6180161457 6676044.322594336) + +LINESTRING (2548706.2746402444 6676511.199756138, 2548763.4934265087 6676617.1940848995) + +LINESTRING (2549322.729516597 6674567.503621703, 2549334.089128576 6674507.3298100745, 2549338.684120495 6674500.588262695) + +LINESTRING (2553346.457520917 6673362.567053939, 2553352.6364238746 6673359.166273362) + +LINESTRING (2552897.798220201 6673998.282969113, 2552914.2312972248 6674016.43713602) + +LINESTRING (2549489.089672855 6677575.774106717, 2549483.7522226367 6677565.541758097, 2549485.872353558 6677535.024753562) + +LINESTRING (2552378.5476342966 6673187.666909302, 2552338.562130112 6673159.190373113) + +LINESTRING (2549148.062076924 6671625.868431415, 2549129.1046416825 6671709.017516534) + +LINESTRING (2552978.453940112 6674694.902863511, 2553044.4502333812 6674744.374218617) + +LINESTRING (2553345.1045969054 6676349.882729218, 2553413.179773412 6676420.128852733) + +LINESTRING (2547200.2309783082 6677308.102668386, 2547175.515366479 6677256.300778355) + +LINESTRING (2550421.0645777904 6672772.481612277, 2550420.9243356674 6672772.641649011) + +LINESTRING (2553388.9756328557 6672231.9875532705, 2553432.656929463 6672199.62012401) + +LINESTRING (2553398.0666222535 6675779.061709298, 2553353.255139124 6675804.357515416) + +LINESTRING (2549925.0941843367 6676424.229794018, 2549972.1247928278 6676490.164928037, 2549982.6759502143 6676534.105013556) + +LINESTRING (2552782.3212060533 6673285.5993876355, 2552677.906820565 6673285.539373861) + +LINESTRING (2551364.5310872914 6671947.522260265, 2551259.217502307 6671729.32217704) + +LINESTRING (2550955.7665458564 6671748.946681431, 2550991.9407641045 6671685.38209152, 2551028.362468452 6671646.51316998, 2551045.8267375585 6671634.44039893, 2551175.3114649523 6671566.634835593) + +LINESTRING (2552982.661203808 6674691.5821013, 2553013.4567241548 6674652.943232563, 2553018.1837086603 6674640.120289327, 2553020.485329388 6674618.795394648) + +LINESTRING (2552755.2627258133 6675724.529192509, 2552752.218646786 6675728.200035074) + +LINESTRING (2554503.1993016535 6675004.303879986, 2554472.5275243567 6674914.133183205, 2554417.3463736475 6674644.131209949, 2554392.5235178415 6674574.94532979, 2554380.767928103 6674553.6904511815) + +LINESTRING (2547849.4447647324 6673884.136769262, 2547841.5582076865 6673905.411652463, 2547838.0604041433 6673949.501772419, 2547845.2375010364 6673963.655020999, 2547865.2756255805 6673966.245615615, 2547882.0221849973 6673958.613863908) + +LINESTRING (2552604.708681793 6675769.549525977, 2552553.124329067 6675812.019274011, 2552405.6226136102 6675821.431434374, 2552380.428528655 6675843.006386449) + +LINESTRING (2551019.5107156173 6672608.303928754, 2551020.7646451895 6672593.250473551) + +LINESTRING (2549239.970164838 6676507.618934236, 2549236.2578733414 6676538.766083406) + +LINESTRING (2549385.1372614196 6671366.5889192745, 2549216.590977947 6671328.23011482) + +LINESTRING (2553366.421399631 6674205.580549899, 2553288.8592559667 6674230.566284847) + +LINESTRING (2550206.040404783 6676338.910210708, 2550193.3443678655 6676346.541962416, 2550185.5485557234 6676347.022072615, 2550184.0718886615 6676346.001838442) + +LINESTRING (2553132.0438136226 6676137.233920171, 2553144.0138913146 6676147.986388173) + +LINESTRING (2553711.1447879854 6677259.091418888, 2553718.792108468 6677258.8113546055) + +LINESTRING (2553209.226478601 6675582.396568964, 2553207.4693272924 6675690.261327044) + +LINESTRING (2551330.3532569148 6675214.352092121, 2551325.9562538755 6675211.121350572) + +LINESTRING (2553651.7646231162 6677048.413062117, 2553651.1294087935 6677055.354655413, 2553661.4825773 6677073.878907264, 2553669.253640833 6677122.400044267, 2553680.621502348 6677139.573986183, 2553793.5741582783 6677229.294579652) + +LINESTRING (2548433.4377143336 6676459.667928094, 2548455.4557276755 6676472.760933317, 2548515.0998777174 6676498.586861114) + +LINESTRING (2550245.200955302 6676539.066152281, 2550252.6502869045 6676539.466244114) + +LINESTRING (2551597.547499751 6675089.953539058, 2551572.3121671122 6675236.177101592) + +LINESTRING (2553824.567667505 6673093.225232207, 2553841.6277093147 6673119.391238062) + +LINESTRING (2553820.1294167824 6677524.132253419, 2553835.143573501 6677575.974152633, 2553848.2355881785 6677638.898595612) + +LINESTRING (2551868.6767715737 6676065.037348972, 2551871.465114964 6676056.955493952) + +LINESTRING (2553533.6147590918 6675507.999492685, 2553450.8719064053 6675500.657807557) + +LINESTRING (2553794.621849434 6676343.101172655, 2553749.983606574 6676452.306238374, 2553746.3785590543 6676467.58974638) + +LINESTRING (2553289.4367235326 6675126.671966998, 2553340.5838508164 6675161.20989445, 2553381.2045693235 6675208.450737589) + +LINESTRING (2551121.846217868 6673914.833815121, 2551116.9047454093 6673924.63606502, 2551105.1574052074 6673931.647674387, 2551100.4386702385 6673938.219182739, 2551075.632313506 6674031.200524644, 2551082.7021664227 6674042.903210748, 2551160.1818147204 6674064.618194965) + +LINESTRING (2551506.1838812567 6676962.873428298, 2551478.52318484 6676979.617271494, 2551438.611926486 6676969.8050192995, 2551415.5627210615 6676944.07911446, 2551351.9175457405 6676936.557388007, 2551337.670595931 6676913.342059418) + +LINESTRING (2552880.9444168075 6675375.529086899, 2552808.4227400413 6675372.088297138) + +LINESTRING (2550158.292086603 6676693.161521622, 2550164.2812502175 6676695.402035885) + +LINESTRING (2549281.407587474 6675541.397158415, 2549286.9760247185 6675548.868873389, 2549293.6004026555 6675568.97348798) + +LINESTRING (2550839.7863099724 6674532.4455748685, 2550842.021934407 6674568.053747973, 2550837.4186929516 6674744.194177292, 2550827.280012398 6674766.469290074, 2550736.0483864904 6674893.578465303, 2550706.3913022024 6674939.969113298) + +LINESTRING (2550838.3096429105 6671750.977147481, 2550636.89720539 6671631.9498272715) + +LINESTRING (2549867.9991411227 6675427.120928718, 2549780.628298371 6675419.579197672, 2549666.5784540656 6675469.230594103, 2549580.527537179 6675520.572378526) + +LINESTRING (2553362.238884545 6674010.265719501, 2553358.3863509255 6674072.089909939) + +LINESTRING (2554021.5006066198 6675608.172485282, 2554094.5090060486 6675578.185602426, 2554099.6319683134 6675575.384959597, 2554127.870132296 6675559.891403379, 2554186.8213212583 6675527.573985597) + +LINESTRING (2552471.2311786567 6672787.425042226, 2552393.388550746 6672896.21001152) + +LINESTRING (2549270.600694451 6671125.503583223, 2549260.956986097 6671135.005764248, 2549216.590977947 6671328.23011482) + +LINESTRING (2553574.9119396047 6676442.674027503, 2553560.401004622 6676505.198378649, 2553553.6941313185 6676530.764246753) + +LINESTRING (2552658.1574298046 6675140.395116857, 2552685.7521299277 6675175.6432073135) + +LINESTRING (2549574.587870785 6672493.267524575, 2549545.178272597 6672487.866284834) + +LINESTRING (2552260.175032782 6676640.179360684, 2552265.1000061673 6676621.154994043) + +LINESTRING (2548857.076170364 6672141.0166728245, 2548815.8862338276 6672149.328580648) + +LINESTRING (2548542.612082474 6676286.008068138, 2548507.6917937975 6676329.1279654, 2548433.4377143336 6676459.667928094) + +LINESTRING (2553793.5741582783 6677229.294579652, 2553836.9502220294 6677263.742486442) + +LINESTRING (2547389.6320904535 6674622.506246395, 2547329.2784802592 6674612.283900071, 2547310.337544091 6674601.021314982, 2547287.882305306 6674563.502703377, 2547283.312061997 6674549.50949153, 2547270.3190417597 6674435.803392694, 2547275.5739966114 6674405.4564271895) + +LINESTRING (2553394.2553363172 6675336.7501860205, 2553372.5013081483 6675350.283292259, 2553295.5331311235 6675340.91114108, 2553266.585506988 6675361.155787812) + +LINESTRING (2547874.358365441 6671779.45368367, 2547987.030537125 6671903.372126534) + +LINESTRING (2552565.003661855 6673149.448136989, 2552576.849996497 6673154.089202248, 2552643.456755479 6673204.110683623, 2552681.874847698 6673207.531468792, 2552788.4341127174 6673214.002954185, 2552892.741254229 6673220.99455896, 2552983.1231778613 6673226.425805588, 2552993.2701079515 6673230.756799676, 2553050.2414081157 6673236.108027938, 2553055.265375941 6673247.010530378, + 2553055.669603237 6673293.861283979, 2553119.9004956614 6673301.242978292, 2553205.6544292276 6673309.334835607, 2553290.806146618 6673314.916116672, 2553304.1373978583 6673315.44623835, 2553311.495984558 6673318.586959236, 2553315.5877547404 6673324.248258668, 2553324.134274719 6673336.040965435, 2553344.139401116 6673364.037391424, 2553379.109187012 6673412.298468736, + 2553382.615240092 6673431.512878998, 2553383.2587039513 6673452.957801227, 2553384.355892327 6673489.416169477, 2553390.7657823106 6673499.708531871, 2553398.388354183 6673503.7994708605, 2553399.287553679 6673503.929500706, 2553433.0446576863 6673508.920646318, 2553438.126372268 6673509.670818504, 2553443.909297466 6673513.061596786, 2553451.424625362 6673526.524686954, + 2553479.8277800772 6673656.594541744, 2553493.3322715876 6673718.438736775, 2553545.51884049 6673950.411981339, 2553561.6796828043 6674022.26847448, 2553559.7905389094 6674043.833424259, 2553548.8516533 6674160.680243981, 2553547.647220948 6674163.500891401, 2553538.020011667 6674185.976050099, 2553503.4132053843 6674218.46350691, 2553481.741672582 6674232.366698094, + 2553470.2088203332 6674233.837035579, 2553446.1614209735 6674233.516962113, 2553433.2838942492 6674233.7470149165, 2553381.4190572766 6674234.637219245, 2553366.974118587 6674236.167570504, 2553355.1937802387 6674240.948667904, 2553331.1958780987 6674260.173080462, 2553328.6632703445 6674268.35495844, 2553317.6418893686 6674303.933124657, 2553310.6380327456 6674361.746394473, + 2553308.1714212843 6674396.504372434, 2553303.452686316 6674437.443769208, 2553301.3325553946 6674456.0780463135, 2553296.5148259858 6674498.487780573, 2553292.9180280026 6674525.553993051, 2553290.3854202484 6674548.879346894, 2553291.6228507473 6674559.161706992, 2553292.8767803195 6674569.574096937, 2553318.961815234 6674603.681925669, 2553350.2193096336 6674645.361492335, + 2553370.414175374 6674668.426786486, 2553403.107089152 6674705.765356767, 2553423.037969719 6674726.15003564, 2553532.7980549624 6674875.254259368, 2553603.3563420037 6674962.294237559, 2553719.84804916 6675104.546888653, 2553778.3455136064 6675172.792553006, 2553801.2297282973 6675205.690103944, 2553801.5432106904 6675206.240230214) + +LINESTRING (2549236.2578733414 6676538.766083406, 2549231.959864742 6676574.844364415) + +LINESTRING (2553462.6109970706 6676365.146232633, 2553476.7919505867 6676372.117832817, 2553537.5745366877 6676433.151841886, 2553570.1519569526 6676441.513761188) + +LINESTRING (2553142.867205719 6676968.46471166, 2553233.5956098903 6676956.431949793) + +LINESTRING (2551949.8274636846 6673239.518810811, 2551919.6341595137 6673281.248388955) + +LINESTRING (2554452.00267715 6673194.558491118, 2554481.4617725583 6673226.675862984, 2554513.494723404 6673266.004890132, 2554514.872396026 6673280.898308602, 2554469.673184673 6673376.390226757) + +LINESTRING (2551121.9534618445 6672693.903576347, 2551013.0513284137 6672686.051774131) + +LINESTRING (2551291.341198056 6673494.177262286, 2551290.1450152406 6673526.754739758) + +LINESTRING (2551530.2807778367 6675662.94505717, 2551580.149226938 6675639.339639044, 2551631.708831054 6675614.914032662, 2551657.6371247726 6675606.672140909, 2551676.0995878144 6675605.081775875, 2551720.820326041 6675610.763079898) + +LINESTRING (2550568.9540214697 6676046.99320732, 2550565.035491557 6676041.211880337) + +LINESTRING (2552630.0925060916 6672212.543090205, 2552530.1906171557 6672202.120697964) + +LINESTRING (2553233.5956098903 6676956.431949793, 2553220.5695915064 6676858.439457684) + +LINESTRING (2553430.7842846415 6676540.6965264985, 2553480.28975413 6676596.439321081) + +LINESTRING (2550848.6793104904 6672658.8755364, 2550759.0233460846 6672651.183770917, 2550698.306756277 6672645.982577093) + +LINESTRING (2548472.3342796788 6677228.03429038, 2548438.131700692 6677232.1152270725, 2548387.5455419016 6677245.3982759155) + +LINESTRING (2553224.09214366 6675516.841522187, 2553056.9400318824 6675511.130211276) + +LINESTRING (2552784.3010948515 6674675.568425699, 2552778.4934210437 6674690.971961255, 2552785.95925172 6674704.225003212, 2552834.5655217124 6674743.253961485, 2552856.402045248 6674760.487917176) + +LINESTRING (2552974.5601588096 6674697.973568327, 2552891.2563376306 6674758.197391435) + +LINESTRING (2552521.487355981 6672986.790802429, 2552459.211603745 6673074.480929848) + +LINESTRING (2553657.3000622145 6675681.659352642, 2553662.860249922 6675680.22902434, 2553667.3479978647 6675699.133363432, 2553670.9035481643 6675714.12680486, 2553673.889880435 6675727.699920283) + +LINESTRING (2551018.1247934587 6672888.988353942, 2551006.2619597437 6672888.91833787) + +LINESTRING (2550574.2914716876 6675776.061020553, 2550552.025972246 6675743.113458135) + +LINESTRING (2549005.14710385 6676746.133680263, 2548840.502851217 6676797.405448616, 2548826.3961435305 6676796.665278725) + +LINESTRING (2552847.53379334 6675231.235967458, 2552842.6418181015 6675292.620056881) + +LINESTRING (2552938.220949828 6673883.426606258, 2553085.706166211 6673889.8780870605) + +LINESTRING (2548872.9647779684 6672919.015245981, 2548857.389652757 6672908.682874403, 2548845.477321822 6672891.298884274, 2548836.732812964 6672864.812804954, 2548834.2249538195 6672841.207386828) + +LINESTRING (2551445.7807738422 6677291.28880912, 2551490.7077504853 6677321.915838908, 2551491.862685617 6677333.628527309, 2551488.8103570538 6677348.812012357, 2551479.859609779 6677362.795221908, 2551465.1341868434 6677369.146679751, 2551442.546955472 6677361.174849985, 2551435.048126649 6677367.406280279, 2551429.405443575 6677382.089650537, 2551427.532798753 6677405.685066367, + 2551436.1040673414 6677417.707825937, 2551446.300494652 6677423.239095524) + +LINESTRING (2552599.255738062 6672877.725768852, 2552579.465099618 6673027.760206092) + +LINESTRING (2553204.730481122 6674219.923842099, 2553185.104833411 6674226.165274688, 2553164.414995471 6674250.2107938295, 2553163.4662987553 6674260.113066687) + +LINESTRING (2552238.9902226427 6676326.42734553, 2552206.9655213337 6676352.793397301) + +LINESTRING (2549966.5811041933 6677201.048096268, 2549865.2272968055 6677248.68903124, 2549851.2525817053 6677259.631542862) + +LINESTRING (2553399.287553679 6673503.929500706, 2553386.5337700048 6673649.462904828) + +LINESTRING (2553508.379426453 6674894.768738505, 2553525.8354460225 6674880.815535842) + +LINESTRING (2552559.517719977 6673146.45745054, 2552554.469003542 6673143.706819191) + +LINESTRING (2551872.100329287 6675074.399969064, 2551853.2666370953 6675077.610706021, 2551844.88510785 6675079.171064168, 2551779.0455557774 6675118.97019922, 2551762.79396856 6675123.291191013, 2551597.547499751 6675089.953539058) + +LINESTRING (2551799.743643254 6673574.965805591, 2551737.756624801 6673535.516750893) + +LINESTRING (2550317.9948667777 6672508.10092927, 2550357.790631619 6672459.869858845, 2550399.5992834046 6672418.320322026, 2550580.9900954547 6672513.142086362) + +LINESTRING (2553311.256747995 6674964.184671468, 2553352.5456789713 6675010.225239109) + +LINESTRING (2552443.66947668 6672192.648523826, 2552434.603235892 6672210.672660887, 2552435.131206238 6672218.544467694, 2552484.5789289703 6672314.256436356, 2552493.257441535 6672339.082134572, 2552487.8622445604 6672410.318485373) + +LINESTRING (2553378.8781999857 6675704.80466516, 2553379.6784050413 6675715.9272181075, 2553398.0666222535 6675779.061709298) + +LINESTRING (2550018.5036879224 6675800.976739431, 2549999.9999771975 6675735.031603116, 2549985.497291751 6675712.356398501, 2549929.0622114697 6675715.5371285705, 2549894.19966955 6675720.718317803, 2549883.3267802345 6675725.689458824, 2549714.0710366094 6675864.361288016, 2549707.7023943085 6675872.543165994, 2549685.8081240165 6675916.403233146) + +LINESTRING (2551925.4665819313 6673646.552236745, 2551918.421477625 6673645.842073742) + +LINESTRING (2552515.5064419033 6675173.012603514, 2552552.216880034 6675219.863357116) + +LINESTRING (2549354.2509961696 6672050.675937015, 2549314.974952138 6672054.146733663, 2549130.2678263513 6672089.474842485) + +LINESTRING (2549442.8097722 6672281.278867052, 2549559.3922242597 6672476.66371352, 2549574.587870785 6672493.267524575) + +LINESTRING (2550391.8694675555 6676050.253955755, 2550394.3855762365 6676057.865702871, 2550440.8057190147 6676125.491224883) + +LINESTRING (2548598.576939166 6672504.560116551, 2548589.1642178386 6672506.290513727, 2548482.0522338627 6672525.845002048, 2548409.3490672903 6672539.118048595) + +LINESTRING (2553766.878657651 6676675.6274970565, 2553777.9165377 6676572.463818011) + +LINESTRING (2551448.1896385467 6673225.065493357, 2551444.196862804 6673225.965699981) + +LINESTRING (2553282.366870616 6673641.751134754, 2553226.0967810676 6673638.8804758545) + +LINESTRING (2547302.789218048 6672862.042169013, 2547457.2205442977 6672804.628991029) + +LINESTRING (2552548.2323538284 6673736.992995514, 2552540.7087763953 6673856.620453472) + +LINESTRING (2553391.442244317 6676304.272260297, 2553426.9235014855 6676340.810646913) + +LINESTRING (2553260.291110518 6674990.400688802, 2553352.397187311 6675115.039296964) + +LINESTRING (2553412.2310766964 6676283.58751255, 2553391.442244317 6676304.272260297) + +LINESTRING (2550335.93760901 6676264.013019638, 2550341.3410555213 6676302.441840163, 2550353.7648577294 6676318.595547906, 2550370.8661472225 6676327.617618732, 2550473.8038656493 6676379.129442184) + +LINESTRING (2552087.8834596667 6676362.1955553675, 2552066.946135627 6676364.3160420805, 2552056.9229485868 6676370.257405795, 2552051.288515049 6676379.01941693, 2552029.122010047 6676463.828883153, 2552022.9101089435 6676473.691146828, 2551967.8527012835 6676502.227696791, 2551956.7818230875 6676503.728041164, 2551906.0059249536 6676502.46775189, 2551894.4648231682 6676498.436826677, + 2551876.4973323257 6676480.502710278, 2551871.7373496736 6676465.50926885, 2551871.374370061 6676451.686096033, 2551878.0069975345 6676411.426855373, 2551883.7156769023 6676397.683700923, 2551905.6676939507 6676368.146921378) + +LINESTRING (2552915.658467067 6674300.512339488, 2552992.4286552123 6674304.88334276, 2553005.4134259126 6674311.614887844, 2553009.026722969 6674320.076830104, 2553001.5361436834 6674453.237394302) + +LINESTRING (2551952.4673154154 6673511.141155989, 2551893.7883611624 6673596.390723228) + +LINESTRING (2551749.36372288 6673705.585786651, 2551745.2059564036 6673693.513015602, 2551743.5972967553 6673653.503832337) + +LINESTRING (2552697.260233566 6675557.060753663, 2552609.3944186154 6675551.299431273) + +LINESTRING (2553542.9862327357 6675506.95925392, 2553600.2957639033 6675537.96637095, 2553627.865715416 6675565.582709698, 2553640.1080278177 6675591.688701778, 2553662.860249922 6675680.22902434) + +LINESTRING (2552433.3163081734 6675233.786552891, 2552349.6825055284 6675299.091542274) + +LINESTRING (2553210.9423822258 6676786.052842864, 2553107.6086860397 6676796.775303979) + +LINESTRING (2551325.9562538755 6675211.121350572, 2551182.323571112 6675106.617363887) + +LINESTRING (2551753.9422157253 6673510.250951662, 2551737.756624801 6673535.516750893) + +LINESTRING (2553520.0360217514 6676177.143080477, 2553560.4587513786 6676211.180893138) + +LINESTRING (2553694.0022508088 6676087.94260639, 2553689.547501013 6676086.742330892) + +LINESTRING (2551073.289445095 6672891.4089095285, 2551059.8921975615 6672896.0199679) + +LINESTRING (2551193.0974659882 6673547.3694714345, 2551034.7063621427 6673639.970726099) + +LINESTRING (2548977.016183844 6676651.702005465, 2549005.14710385 6676746.133680263) + +LINESTRING (2549331.0615486223 6674700.614174422, 2549323.2327383333 6674692.792379094, 2549309.8519898728 6674665.146033458) + +LINESTRING (2551121.9947095276 6675479.472945019, 2550964.453307958 6675509.989949552) + +LINESTRING (2552349.6825055284 6675299.091542274, 2552326.006335318 6675290.629600014, 2552150.274705416 6675237.957510246) + +LINESTRING (2549346.0179585842 6675556.560638872, 2549299.6638120995 6675557.690898299, 2549293.6004026555 6675568.97348798) + +LINESTRING (2548935.2405302045 6672531.896391016, 2548949.437982794 6672609.114114715, 2548949.437982794 6672623.877503339, 2548954.800181622 6672666.117198571, 2548973.5431289105 6672751.016685456, 2549033.096534049 6672754.637516541) + +LINESTRING (2551135.086724205 6677249.159139142, 2551214.2657770542 6677298.630494248) + +LINESTRING (2552222.5653951555 6672317.377152652, 2552179.7832980435 6672378.541191566) + +LINESTRING (2551686.7332405676 6673273.27655919, 2551680.8183227833 6673274.816912746, 2551676.5285637206 6673275.937169877) + +LINESTRING (2549293.6004026555 6675568.97348798, 2549273.9087586515 6675647.701558347, 2549271.5328920935 6675657.503808246, 2549263.555590145 6675667.216037484) + +LINESTRING (2551577.534123817 6674201.5996361645, 2551512.4040318974 6674180.384766739) + +LINESTRING (2547323.437808305 6672915.76449984, 2547293.978712897 6672958.504309862) + +LINESTRING (2548140.6864069286 6676740.502387718, 2548084.0945854504 6676770.6693119) + +LINESTRING (2548442.149225045 6672027.670656638, 2548417.697598389 6672011.827020066, 2548383.8002522583 6671995.793339873, 2548323.8426198238 6671981.420040785) + +LINESTRING (2548138.4177843477 6671814.501728209, 2548168.124365855 6671897.640811031) + +LINESTRING (2547400.950454749 6672752.236965545, 2547374.4446934653 6672743.174885537, 2547353.400125449 6672735.943225661, 2547337.445521551 6672722.830215847) + +LINESTRING (2552891.050099214 6674779.41226086, 2552876.2669295217 6674787.4441044, 2552867.010949391 6674787.104026343, 2552859.4626233485 6674782.643002409) + +LINESTRING (2553482.7728646644 6676798.655735592, 2553521.9581637927 6676760.566993125) + +LINESTRING (2550732.600080167 6675458.888220229, 2550624.6383939153 6675563.242172477, 2550544.1476647374 6675483.043764625) + +LINESTRING (2553438.2088676346 6676092.903745115, 2553520.0360217514 6676177.143080477) + +LINESTRING (2551217.6480870843 6672787.2850100845, 2551115.9395496203 6672778.863077007) + +LINESTRING (2552808.4227400413 6675372.088297138, 2552803.943241636 6675439.963876545) + +LINESTRING (2553667.240753888 6673396.284793135, 2553671.6212578537 6673408.037490718) + +LINESTRING (2552459.211603745 6673074.480929848, 2552378.5476342966 6673187.666909302) + +LINESTRING (2553195.4827505276 6673439.704759272, 2553112.4016668387 6673434.35353101) + +LINESTRING (2549012.5304391594 6677563.851370105, 2548972.1902048984 6677556.679724004) + +LINESTRING (2549063.232091463 6676502.957864385, 2548937.352411589 6676552.259180462) + +LINESTRING (2553522.774867922 6676791.444080309, 2553482.7728646644 6676798.655735592) + +LINESTRING (2549851.2525817053 6677259.631542862, 2549833.0788524467 6677248.138904969, 2549773.979171824 6677189.7354997005) + +LINESTRING (2551327.3586751074 6672469.292021504, 2551318.944147716 6672449.857560733) + +LINESTRING (2549545.178272597 6672487.866284834, 2549326.1448247735 6672446.546800818) + +LINESTRING (2552210.298334144 6676197.557766237, 2552169.166144364 6676242.988193833, 2552170.9892919655 6676245.178696617, 2552238.9902226427 6676326.42734553) + +LINESTRING (2553042.544590413 6675720.218203013, 2553030.3187770853 6675902.430025891, 2553036.877158729 6675914.892886478) + +LINESTRING (2552268.3998208307 6672073.281125559, 2552274.289990005 6672061.3383843545) + +LINESTRING (2553299.9218846257 6672575.486396182, 2553283.6702974085 6672585.738749393) + +LINESTRING (2552568.922191768 6672052.846435207, 2552528.078735771 6672041.643863893, 2552487.458017264 6672030.541315537) + +LINESTRING (2553485.0002395622 6676211.250909209, 2553447.770080622 6676247.48922695) + +LINESTRING (2554193.1817140225 6675672.157171616, 2554223.0532862633 6675657.343771514) + +LINESTRING (2549737.2604841567 6676245.558783858, 2549665.1760328333 6676316.775130067) + +LINESTRING (2548768.484396187 6676625.876077668, 2548733.5311093642 6676597.609589692, 2548701.324918249 6676537.875879079, 2548695.286257415 6676526.673307765, 2548706.2746402444 6676511.199756138) + +LINESTRING (2553260.291110518 6674990.400688802, 2553211.3631085954 6675027.989316478) + +LINESTRING (2550245.200955302 6676539.066152281, 2550242.5281054243 6676550.75883609, 2550205.858914977 6676548.138234586, 2550175.8718492226 6676545.997743282, 2550060.518578125 6676537.765853825) + +LINESTRING (2553693.9775021984 6675997.621875172, 2553779.318958932 6676056.795457219) + +LINESTRING (2548865.771182002 6672820.342597757, 2548907.002366222 6672855.460658366, 2548917.9165032213 6672870.314067652, 2548921.406057228 6672890.508702905, 2548918.337229591 6672900.330957397, 2548909.37823278 6672911.323480498, 2548893.1183960256 6672918.2350669075, 2548872.9647779684 6672919.015245981) + +LINESTRING (2551871.4321168177 6673231.22690758, 2551844.225144917 6673251.511563495, 2551789.984441387 6673311.995446294, 2551764.122143962 6673339.771821775) + +LINESTRING (2550566.1079313224 6674753.706360613, 2550514.3503383263 6674728.170499395) + +LINESTRING (2554380.767928103 6674553.6904511815, 2554276.8402652773 6674370.588423975) + +LINESTRING (2552841.833363509 6675831.963851868, 2552675.0277322712 6675969.9955341285) + +LINESTRING (2547781.8480613516 6673283.718956022, 2547780.17340541 6673331.900014968, 2547792.498213178 6673425.58151758, 2547811.3731530528 6673483.524817241, 2547813.278796021 6673514.251869988) + +LINESTRING (2552411.215799465 6671838.257180772, 2552394.7992215143 6671836.756836399) + +LINESTRING (2553330.758652656 6676200.098349375, 2553412.2310766964 6676283.58751255) + +LINESTRING (2549907.8031555004 6676812.688956622, 2549931.718562274 6676739.702204053, 2549942.0964793903 6676719.857649154, 2549965.4591672076 6676688.620479321) + +LINESTRING (2552729.771657538 6674428.26166165, 2552726.925567391 6674469.901219131) + +LINESTRING (2553217.0387898167 6675881.695266665, 2553208.2117855917 6675870.282647139) + +LINESTRING (2551721.8515181234 6671541.018956009, 2551626.5116229593 6671587.909718794) + +LINESTRING (2552710.8142222962 6675361.675907194, 2552705.7820049347 6675432.572179938) + +LINESTRING (2553062.029996001 6675431.351899847, 2552990.085786801 6675421.389613215, 2552973.6609593136 6675416.438476786) + +LINESTRING (2553667.240753888 6673396.284793135, 2553678.61686494 6673400.075663249, 2553775.755159096 6673404.646712436) + +LINESTRING (2552971.598575149 6675260.302639099, 2552970.2621502103 6675288.579129371) + +LINESTRING (2549053.3408970097 6677195.266769286, 2549049.678102733 6677212.420706611, 2549044.6953825913 6677254.21029853) + +LINESTRING (2551837.279035051 6671991.542364151, 2551808.9418766284 6672073.831251829, 2552011.946474724 6672145.087607222) + +LINESTRING (2551122.7041696804 6675711.97631126, 2551098.277291634 6675748.374665734, 2551072.9182159454 6675776.581139935, 2550887.460382323 6675939.538543369) + +LINESTRING (2551572.3121671122 6675236.177101592, 2551666.0681512374 6675261.562928372, 2551683.4911726606 6675270.384953282, 2551710.8961334405 6675294.860571143, 2551720.4903445747 6675308.883789877, 2551727.584946101 6675326.957938417, 2551730.6125260545 6675343.751793092, 2551730.653773738 6675398.674399417) + +LINESTRING (2549732.6407436277 6672352.875300502, 2549689.767901613 6672346.7338908715, 2549673.697804202 6672341.062589143, 2549647.629268361 6672324.998902063, 2549601.2751218756 6672288.420506264) + +LINESTRING (2552312.856573884 6675890.1672112215, 2552277.210325982 6675900.209516221, 2552246.5797963687 6675914.24273725) + +LINESTRING (2553289.5852151928 6673546.189200528, 2553233.3316247175 6673542.7184038805) + +LINESTRING (2548946.2949093273 6675985.529099531, 2548968.4696638654 6675987.399528848, 2549049.7440990265 6675969.815492803, 2549072.760306304 6675967.805031344, 2549090.208076337 6675973.50633996, 2549103.696068774 6675984.218798779, 2549123.7589419275 6676008.904464852, 2549148.9200287363 6676040.821790801) + +LINESTRING (2553104.2841227665 6672154.279717077, 2553078.108342949 6672215.473762878) + +LINESTRING (2549335.5245479546 6674985.489561556, 2549336.143263204 6675010.9654089995, 2549321.087858802 6675040.412167882, 2549326.9697784395 6675075.220157321, 2549334.328365139 6675116.519636745, 2549332.2989791213 6675124.761528498, 2549292.28047679 6675185.145388338, 2549273.413786452 6675211.841515871, 2549256.5269849114 6675243.788848707, 2549256.4857372283 6675255.791603686) + +LINESTRING (2553257.552264347 6675848.59766981, 2553208.2117855917 6675870.282647139) + +LINESTRING (2553180.9635660085 6672364.467961353, 2553140.9945608974 6672433.893896611, 2553137.735993917 6672468.141757485) + +LINESTRING (2552117.3260560012 6676671.07645246, 2552115.643150523 6676678.328116926) + +LINESTRING (2550942.872520059 6672249.761632935, 2550926.0434652753 6672273.377053357) + +LINESTRING (2551229.33768053 6672340.972568481, 2551159.1588721746 6672286.410044805) + +LINESTRING (2550697.168320218 6672918.5151311895, 2550657.999520163 6672973.347716853) + +LINESTRING (2549467.888363642 6672609.60422721, 2549499.434591825 6672635.6101963315, 2549563.904720812 6672711.237554996) + +LINESTRING (2548526.2779998896 6676474.191261618, 2548639.7916243123 6676523.892669528, 2548656.3484443864 6676539.556264776) + +LINESTRING (2549966.5811041933 6677201.048096268, 2549959.4040073003 6677175.08213633, 2549961.2849016585 6677138.453729052) + +LINESTRING (2551105.107907987 6674254.621806284, 2551101.9400859103 6674253.821622619) + +LINESTRING (2553150.877505814 6674825.012727485, 2553160.356223435 6674832.194375881) + +LINESTRING (2549836.40341572 6676274.085331525, 2549808.1900003473 6676243.87839816, 2549770.6876066974 6676212.531203073) + +LINESTRING (2550729.4157590168 6675166.941209953, 2550585.213858224 6675185.965576595) + +LINESTRING (2553009.851676635 6676469.220120599, 2552992.040926989 6676445.14459457, 2552959.414009504 6676398.26383408) + +LINESTRING (2554199.8968368624 6673020.008426835, 2554186.6315819155 6673045.404255911) + +LINESTRING (2551363.8216271386 6674239.708383223, 2551358.9049032903 6674237.5978988055) + +LINESTRING (2551326.104745535 6672791.0058641285, 2551288.899335205 6672793.17636232, 2551217.6480870843 6672787.2850100845) + +LINESTRING (2553201.7441488514 6675946.3501068195, 2553203.616793673 6675966.5547443675, 2553218.944432785 6676004.253397298) + +LINESTRING (2553224.2818830027 6677495.7457378935, 2553284.569496904 6677555.169377336) + +LINESTRING (2551230.715353152 6673946.261028575, 2551337.0023834617 6674078.751438953) + +LINESTRING (2553293.561491862 6675401.385021583, 2553271.7744655465 6675414.678072723, 2553214.7784167724 6675407.696470243, 2553205.431691738 6675413.437788041, 2553193.997833929 6675415.13817833, 2553184.139637622 6675413.457792633, 2553169.1997267334 6675400.264764451, 2553137.793740674 6675394.893531599, 2553126.500124988 6675385.761435519, 2553121.1296766233 6675372.718441775, + 2553123.942768624 6675325.787669806, 2553131.986066866 6675319.296179822) + +LINESTRING (2553824.559417968 6675403.835584058, 2553897.2378359307 6675544.497870117) + +LINESTRING (2549278.1325214207 6675538.666531657, 2549269.511755612 6675533.285296508, 2549254.316109087 6675511.960401828) + +LINESTRING (2549263.555590145 6675667.216037484, 2549249.820111608 6675681.469309022, 2549247.188509414 6675693.352036451) + +LINESTRING (2550684.191799054 6675388.912158701, 2550576.972571102 6675431.792000864, 2550564.0372976214 6675440.664037253, 2550553.7831235547 6675457.637933252, 2550544.1476647374 6675483.043764625) + +LINESTRING (2547838.2336444133 6671608.824519346, 2547825.570605642 6671595.781525602, 2547797.2499462934 6671583.92880506) + +LINESTRING (2551923.44544545 6672987.520970024, 2551768.7088863445 6672875.395233927) + +LINESTRING (2551613.0318800593 6673913.813580948, 2551502.8840665934 6673926.796560917, 2551483.992627645 6673920.395091594, 2551469.6384338588 6673908.462352687, 2551460.3907032646 6673891.558472757, 2551458.163328367 6673872.90419106) + +LINESTRING (2551923.44544545 6672987.520970024, 2551878.6422118573 6673047.834813794) + +LINESTRING (2554314.8953778837 6673219.284166375, 2554383.251038637 6673258.043062663) + +LINESTRING (2552914.2312972248 6674016.43713602, 2552926.5643545296 6674030.050260625) + +LINESTRING (2552135.6565264566 6672092.005423326, 2552150.8604225186 6672095.106135029, 2552159.3244471303 6672103.238001527, 2552186.6056648605 6672156.870311692, 2552186.1766889542 6672165.952396294) + +LINESTRING (2552483.9272155743 6676831.203206178, 2552478.927996359 6676850.72768761) + +LINESTRING (2549749.923522928 6676376.828914146, 2549665.1760328333 6676316.775130067) + +LINESTRING (2549170.682306442 6672890.508702905, 2549163.067984106 6672916.744724831, 2549155.024685864 6672944.45108424) + +LINESTRING (2551924.608630119 6673968.396109215, 2551912.547807524 6673967.015792393, 2551863.776546798 6673999.603272161) + +LINESTRING (2550469.3408663166 6675291.659836482, 2550451.5301166708 6675278.866900134, 2550450.639166712 6675271.535217301, 2550457.758516848 6675225.844730013, 2550463.566190656 6675208.390723814, 2550475.2970317844 6675199.878770075, 2550509.458363088 6675189.166311257) + +LINESTRING (2553172.078815027 6676175.132619018, 2553179.189915627 6676182.39428578) + +LINESTRING (2553265.8842963725 6672521.714053876, 2553156.4129449124 6672481.784888978, 2553137.735993917 6672468.141757485) + +LINESTRING (2551020.7646451895 6672593.250473551, 2551022.645539548 6672570.415232203) + +LINESTRING (2551263.5815071994 6673683.270664685, 2551224.519951121 6673823.852932379) + +LINESTRING (2550808.454569743 6675266.964168113, 2550721.677693631 6675219.033166562) + +LINESTRING (2551564.483356823 6676702.513668209, 2551507.5450548055 6676688.010339276) + +LINESTRING (2551749.36372288 6673705.585786651, 2551686.840484544 6673785.184056754) + +LINESTRING (2551280.9302827925 6673584.327954475, 2551263.5815071994 6673683.270664685) + +LINESTRING (2552308.921544898 6676450.095730999, 2552269.175277277 6676461.388322975) + +LINESTRING (2547457.2205442977 6672804.628991029, 2547410.511667737 6672769.750985519, 2547400.950454749 6672752.236965545) + +LINESTRING (2552982.6364551983 6676025.478269019, 2552891.322333924 6676098.715078983) + +LINESTRING (2552707.5061580963 6671918.555611582, 2552608.387975143 6671893.399837605) + +LINESTRING (2551539.9657338737 6676322.26639047, 2551511.1253537154 6676314.984719116) + +LINESTRING (2548275.4590873206 6676549.548558296, 2548219.485981092 6676599.440009826, 2548132.222382317 6676658.373536774) + +LINESTRING (2549323.9009508025 6671664.947401169, 2549148.062076924 6671625.868431415) + +LINESTRING (2550887.460382323 6675939.538543369, 2550892.3276089514 6675946.170065495, 2550912.9349515247 6675974.236507555, 2550933.3773033647 6676001.932864669, 2550999.4395929268 6676040.931816055) + +LINESTRING (2553250.2101767207 6677586.04646452, 2553222.2607465214 6677614.683037441, 2553277.0046717883 6677667.925258069, 2553291.6805975037 6677679.627944174, 2553314.325575632 6677671.686121296, 2553325.759433441 6677672.556321032, 2553341.854279462 6677678.067586026, 2553352.0342076984 6677687.259695881) + +LINESTRING (2551351.8597989837 6674088.353642936, 2551349.888159722 6674101.536668821) + +LINESTRING (2548987.8560750135 6671081.663520661, 2548948.6130291284 6671255.803490818) + +LINESTRING (2550362.4351207577 6676788.45339386, 2550425.519327586 6676792.49432137, 2550460.002390819 6676788.523409931, 2550546.1440526084 6676794.594803491) + +LINESTRING (2549190.6544346926 6676779.691382726, 2549153.2922831653 6676924.864704198) + +LINESTRING (2550817.5785572873 6675557.160776621, 2550752.2834746344 6675483.593890894) + +LINESTRING (2551027.2157828566 6675701.483902949, 2551019.692205424 6675699.373418532) + +LINESTRING (2549248.326945473 6676428.60079729, 2549256.419740935 6676435.472374516, 2549271.1781620174 6676475.901654203, 2549240.0774088143 6676592.25836143) + +LINESTRING (2552733.0467235916 6672525.654958427, 2552728.443482136 6672593.18045748, 2552716.8776317406 6672731.242146628) + +LINESTRING (2550834.0116343116 6672229.256926513, 2550722.7913810797 6672165.142210333, 2550709.979850649 6672163.261778719, 2550702.3490292397 6672166.552534043, 2550687.1781313247 6672187.567357552) + +LINESTRING (2553369.1437467285 6674168.962144917, 2553277.4088990847 6674161.500432238) + +LINESTRING (2551879.533161816 6675072.8796201, 2551872.100329287 6675074.399969064) + +LINESTRING (2553258.6824508696 6671752.257441346, 2553257.8327485938 6671759.619131067, 2553231.310488236 6671810.2207456, 2553213.2687515635 6671834.346283107) + +LINESTRING (2553432.013465604 6674720.138655854, 2553477.0229376135 6674682.069917979, 2553482.112901732 6674669.877119379, 2553482.0469054384 6674652.503131547) + +LINESTRING (2551082.545425226 6675357.174874077, 2551107.6982624982 6675444.574934917, 2551121.9947095276 6675479.472945019) + +LINESTRING (2549883.797003824 6677289.668437197, 2549872.0414140853 6677300.270870762, 2549873.0973547776 6677359.424448218, 2549850.52662248 6677359.834542346) + +LINESTRING (2553932.7438417096 6677359.32442526, 2554055.3649546034 6677487.163768083, 2554104.1774630123 6677538.065451491) + +LINESTRING (2552378.5476342966 6673187.666909302, 2552318.9612310114 6673271.776214818) + +LINESTRING (2549219.4370680945 6675651.492428461, 2549191.6691277013 6675671.056919077, 2549181.365456415 6675683.029667169, 2549181.5716948314 6675696.03265173, 2549186.5379159 6675707.305239114, 2549192.840561907 6675712.016320444, 2549207.0462640333 6675711.896292893, 2549247.188509414 6675693.352036451) + +LINESTRING (2548669.62194887 6672165.182219516, 2548665.950905057 6672184.466645849, 2548659.9204937597 6672196.569423786, 2548634.5696676075 6672218.634488356, 2548616.8661619383 6672245.690698538) + +LINESTRING (2552681.874847698 6673207.531468792, 2552677.906820565 6673285.539373861) + +LINESTRING (2553777.2400756944 6673026.169841057, 2553645.173243326 6673111.869511608) + +LINESTRING (2551347.883522314 6673674.828727017, 2551326.8967010546 6673752.106464491) + +LINESTRING (2551457.841596437 6673570.304735741, 2551455.746214126 6673563.933273306) + +LINESTRING (2549665.1760328333 6676316.775130067, 2549612.2717542415 6676275.79572411, 2549600.30167655 6676266.513593592) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553224.11689227 6672386.7130672475) + +LINESTRING (2550905.988841658 6672124.8129536025, 2550885.983715261 6672158.480681319) + +LINESTRING (2553296.217842666 6673446.466311243, 2553289.5852151928 6673546.189200528) + +LINESTRING (2551135.086724205 6677249.159139142, 2551086.199969966 6677327.237060282, 2551096.1654102495 6677357.283956913, 2551150.496858683 6677464.988678259, 2551161.3779975357 6677492.394968795, 2551150.8268401497 6677498.466362355) + +LINESTRING (2549044.2334085386 6672322.608353363, 2549063.058851193 6672410.918623122) + +LINESTRING (2553575.431660414 6676664.514946405, 2553616.250367801 6676649.051397073, 2553643.440840628 6676627.106360053, 2553660.8803611244 6676599.1299386555, 2553672.6606994728 6676552.929334282) + +LINESTRING (2548482.283220889 6676658.733619423, 2548452.378650502 6676674.817311095) + +LINESTRING (2548625.7014156994 6676035.630599272, 2548594.0479435404 6676199.928310346) + +LINESTRING (2553504.419648857 6675758.016878901, 2553523.0058549484 6675833.664242157) + +LINESTRING (2553166.5351263923 6671840.257639934, 2553136.6388055417 6671827.364680628) + +LINESTRING (2549594.5599990357 6677577.114414356, 2549601.1843769723 6677593.118087661, 2549641.13688301 6677689.6502445815) + +LINESTRING (2552868.586610893 6674750.745681051, 2552878.6675446895 6674750.075527232) + +LINESTRING (2551737.2616526014 6674473.952148937, 2551633.1360008963 6674446.5158515135) + +LINESTRING (2550317.9948667777 6672508.10092927, 2550408.599527899 6672561.513188927) + +LINESTRING (2551697.0286623174 6673975.887828781, 2551708.858497886 6674048.154416052) + +LINESTRING (2553073.3731089067 6674056.326291733, 2553070.4445233927 6674102.01677902) + +LINESTRING (2548339.5249890117 6676671.62657873, 2548366.888702108 6676720.467789199) + +LINESTRING (2549903.752633001 6676653.942519727, 2549869.121078108 6676706.494581944, 2549831.841421948 6676785.922813019) + +LINESTRING (2551257.600593122 6673682.420469541, 2551173.7605520603 6673670.577751296) + +LINESTRING (2553265.8842963725 6672521.714053876, 2553279.4795327857 6672551.920987239) + +LINESTRING (2548834.2249538195 6672841.207386828, 2548832.525549268 6672807.819723395) + +LINESTRING (2551136.7613801467 6675525.22344608, 2551150.595853123 6675546.5983522395, 2551183.5280034645 6675613.4036859935) + +LINESTRING (2551019.692205424 6675699.373418532, 2551015.2374556283 6675697.262934115) + +LINESTRING (2552510.0452486356 6673575.045823957, 2552363.5334775783 6673567.544102095, 2552348.164590783 6673563.0530712735) + +LINESTRING (2552643.258766599 6673756.567488425, 2552622.8329138323 6673749.445853804) + +LINESTRING (2553001.6021399763 6674456.22808075, 2553001.610389513 6674456.808213908) + +LINESTRING (2552320.0749184606 6676735.381212261, 2552285.4433635673 6676872.1926144315, 2552238.1652689767 6677047.272800393) + +LINESTRING (2551318.944147716 6672449.857560733, 2551241.8109799577 6672263.934886106, 2551189.7811522516 6672020.549022017) + +LINESTRING (2553353.255139124 6675804.357515416, 2553257.552264347 6675848.59766981) + +LINESTRING (2549326.9037821465 6677768.028234595, 2549276.5898580654 6677758.235986992, 2549246.701786751 6677743.112515718, 2549227.826846876 6677725.628502632, 2549216.5662293374 6677710.1649533, 2549180.680744872 6677643.199582812, 2549162.1852836837 6677615.78328998, 2549153.976994708 6677604.080603876, 2549126.506037635 6677585.756397941, 2549108.893276869 6677580.975300541) + +LINESTRING (2553226.0967810676 6673638.8804758545, 2553219.7776359874 6673717.488518672) + +LINESTRING (2553932.14987507 6675424.730380017, 2553933.700787962 6675426.800855252, 2553957.409956319 6675458.508132988, 2553991.1505612526 6675498.237251969, 2554003.94559261 6675521.082495613, 2554008.3260965757 6675547.978669061) + +LINESTRING (2549363.721464254 6672660.605933576, 2549366.9222844774 6672680.400476996, 2549410.9500616244 6672715.178459547, 2549456.974226643 6672783.074043546) + +LINESTRING (2548760.7710794113 6677439.552839999, 2548739.8750030547 6677437.032261454, 2548728.8866202254 6677437.8524497105, 2548709.2857211246 6677445.674245039, 2548638.4304507636 6677488.664112455, 2548604.7723411964 6677507.0383298695, 2548580.93942979 6677511.469346916, 2548561.817003815 6677519.291142244, 2548484.3786032004 6677568.612462913, 2548468.869474282 6677590.167410396, + 2548464.35697773 6677596.738918747) + +LINESTRING (2550948.0037318603 6675344.031857374, 2550808.454569743 6675266.964168113) + +LINESTRING (2552049.0941382977 6672646.4926941795, 2551986.7936374517 6672734.5429042475) + +LINESTRING (2548897.482400918 6671325.33945133, 2548906.3836509725 6671330.020525771, 2548928.781143001 6671341.783225651) + +LINESTRING (2551189.7811522516 6672020.549022017, 2551164.661313126 6671899.611263307, 2551154.4318876695 6671886.578271858, 2551139.9539508335 6671884.217730046, 2551120.270556366 6671890.589192481) + +LINESTRING (2553528.33505563 6676650.701775882, 2553545.065115974 6676689.320640028, 2553555.5090293833 6676707.694857442, 2553589.6703606867 6676747.243935098) + +LINESTRING (2551923.008220007 6677196.5270585595, 2551948.4250424523 6677202.8885186985, 2551973.231399185 6677208.489804355) + +LINESTRING (2553149.5493304124 6672557.952371617, 2552844.266976823 6672450.797776541) + +LINESTRING (2548433.4377143336 6676459.667928094, 2548381.6966204103 6676528.623755449, 2548318.8434006083 6676596.559348631) + +LINESTRING (2551390.7481147926 6674544.158263269, 2551397.8509658556 6674549.759548926, 2551406.422234444 6674551.429932327) + +LINESTRING (2549354.2509961696 6672050.675937015, 2549370.4613357037 6672094.926093705, 2549390.202476928 6672176.984928579, 2549415.743042423 6672237.188747095, 2549434.428242955 6672267.625733263, 2549442.8097722 6672281.278867052) + +LINESTRING (2549251.7175050396 6674640.600399526, 2549277.876785784 6674641.560619924, 2549297.230198785 6674652.653165985, 2549309.8519898728 6674665.146033458) + +LINESTRING (2551140.25918369 6675519.112043337, 2551136.7613801467 6675525.22344608) + +LINESTRING (2549605.7958679646 6676198.618009593, 2549626.0072327782 6676205.119501874, 2549651.97677418 6676213.151345414) + +LINESTRING (2548287.684900649 6672795.936995965, 2548263.2415235294 6672807.75970962, 2548243.285894352 6672806.419401981) + +LINESTRING (2553182.3164900206 6674153.00848309, 2553179.3384072864 6674191.97742759) + +LINESTRING (2549202.9957415336 6677369.356727963, 2549229.6252458678 6677307.102438805, 2549254.588343797 6677276.985526103, 2549267.127639518 6677269.363776691, 2549260.016538918 6677253.920231951, 2549273.3065424752 6677182.453828346, 2549271.9206203166 6677176.532469223, 2549259.4803190352 6677171.941415444, 2549187.4536144687 6677164.309663736, 2549153.9439965617 6677347.191640435, + 2549202.9957415336 6677369.356727963) + +LINESTRING (2550252.6502869045 6676539.466244114, 2550329.32148061 6676544.68744253, 2550543.784685124 6676559.450831154) + +LINESTRING (2548866.5796365947 6676319.20568795, 2548947.969565269 6676316.775130067) + +LINESTRING (2549976.010324594 6677259.201444142, 2549935.241114427 6677258.001168644, 2549883.797003824 6677289.668437197) + +LINESTRING (2548828.4502781588 6672776.87262014, 2548831.1808747924 6672807.259594829, 2548834.2249538195 6672841.207386828) + +LINESTRING (2551918.2234887453 6677300.160845508, 2551943.054594088 6677304.081745468, 2551952.8797922484 6677302.121295488) + +LINESTRING (2553218.944432785 6676004.253397298, 2553105.1255755057 6676116.769222932) + +LINESTRING (2551998.8214619 6676091.633453546, 2552044.6311389655 6676120.79014585, 2552058.5481073083 6676134.943394429, 2552071.5741256927 6676153.207586589, 2552079.4524332015 6676178.173316945, 2552088.09794762 6676239.567408664, 2552098.558360103 6676362.415605876) + +LINESTRING (2553609.6342394007 6673306.284135383, 2553635.9420118053 6673348.1437433725) + +LINESTRING (2553594.125110483 6673282.258620833, 2553707.4902432454 6673207.421443538) + +LINESTRING (2552089.277631362 6672241.849816945, 2552056.98894488 6672339.2921827845) + +LINESTRING (2547665.834827321 6672719.939552356, 2547553.4348903475 6672766.520243971) + +LINESTRING (2551005.1565218316 6672769.690971744, 2550953.1679418087 6672765.389984543, 2550839.241840553 6672755.957819589) + +LINESTRING (2553020.485329388 6674618.795394648, 2553026.2517555123 6674463.809820979) + +LINESTRING (2552923.602770869 6674449.906629795, 2552924.328730095 6674453.757513684) + +LINESTRING (2552824.451589769 6674628.01751139, 2552823.7008819333 6674624.656739996) + +LINESTRING (2551763.684918519 6673879.0255961, 2551719.459152492 6673928.1468708515) + +LINESTRING (2553787.7499853973 6675169.691841302, 2553778.3455136064 6675172.792553006) + +LINESTRING (2551887.972437818 6673592.839908214, 2551818.5030896156 6673548.549742341) + +LINESTRING (2553203.32805989 6675312.814692133, 2553197.1326578595 6675362.035989843) + +LINESTRING (2552762.827550929 6676310.513692887, 2552742.8141749953 6676471.2505866485) + +LINESTRING (2552850.0086543374 6675677.598420541, 2552787.3864215617 6675675.978048619) + +LINESTRING (2552821.9107324784 6672739.764102663, 2552716.8776317406 6672731.242146628) + +LINESTRING (2552692.5414985977 6673061.627979725, 2552582.5586758647 6673055.516576981) + +LINESTRING (2551446.300494652 6677423.239095524, 2551456.472173352 6677434.2616255125, 2551466.181877999 6677452.24575339, 2551455.647219686 6677474.280811072, 2551435.518350239 6677496.315868755, 2551332.7786206924 6677569.032559337, 2551262.0223447713 6677605.4509184025, 2551230.6658559316 6677544.656964433, 2551188.494224533 6677522.451867722) + +LINESTRING (2552975.046881472 6675965.034395403, 2552915.419230504 6675895.128349946, 2552907.631667898 6675890.297241067, 2552896.948517925 6675897.6289238995) + +LINESTRING (2552951.6016982887 6671978.96947831, 2552932.009048724 6672051.656162005) + +LINESTRING (2553376.452836208 6673806.188877968, 2553368.6157763824 6673912.273227392) + +LINESTRING (2554413.601084004 6673201.910178543, 2554383.251038637 6673258.043062663) + +LINESTRING (2553619.970908834 6672194.188877382, 2553581.255833295 6672168.172905965, 2553554.2550998116 6672157.400433371, 2553503.8999280473 6672151.739133939, 2553477.5591574963 6672131.244429813) + +LINESTRING (2549225.8717066883 6676391.872367053, 2549256.3784932517 6676421.319125935) + +LINESTRING (2552698.3739210153 6674904.100880502, 2552760.872410741 6674986.329754405) + +LINESTRING (2554612.423167014 6675880.555004942, 2554597.4255093685 6675833.024095225, 2554597.260518635 6675818.020651501, 2554621.7368939016 6675740.422840561) + +LINESTRING (2548983.7478057574 6674894.218612235, 2548997.4750347575 6674898.389569591, 2549009.428613376 6674897.039259655, 2549031.091896641 6674889.337491877, 2549086.7927681603 6674882.215857256, 2549105.6594584985 6674871.443384662, 2549120.731361974 6674873.913951729, 2549157.8047797177 6674893.198378062, 2549195.595907151 6674905.581220282, 2549232.3640920385 6674913.663075302, + 2549285.705596073 6674955.702724616, 2549305.116755831 6674955.132593755, 2549335.5245479546 6674985.489561556) + +LINESTRING (2551117.853442125 6675055.035524365, 2551105.0584107675 6675048.4140045345, 2551027.08379027 6674989.990594673) + +LINESTRING (2551602.5879666493 6673488.706006474, 2551597.6629932644 6673472.942388268, 2551592.012060653 6673468.18129546, 2551482.5324596562 6673422.460801285) + +LINESTRING (2551479.6698704357 6674688.431378118, 2551411.710187442 6674802.077463179, 2551347.5947885313 6674889.117441369) + +LINESTRING (2552820.5495589296 6672756.447932084, 2552924.1307412153 6672763.979660833) + +LINESTRING (2552098.558360103 6676362.415605876, 2552098.2201290997 6676377.8591506155) + +LINESTRING (2552496.0292858523 6674925.59581421, 2552559.377477854 6675010.015190897) + +LINESTRING (2548914.6744353147 6672439.865267213, 2548919.9211406293 6672451.737992347, 2548935.2405302045 6672531.896391016) + +LINESTRING (2554358.2549425615 6673315.616277379, 2554393.620706217 6673334.840689938) + +LINESTRING (2551590.560142201 6673751.856407096, 2551577.2866377174 6673756.917568779, 2551552.7772643045 6673792.965842899) + +LINESTRING (2552179.725551287 6676372.537929242, 2552177.9519009055 6676372.667959087) + +LINESTRING (2548995.0001737596 6676208.860360509, 2549047.1372454423 6676236.466696961, 2549061.2687017387 6676249.349653972, 2549077.8915181058 6676275.975765434) + +LINESTRING (2553598.3653723253 6675496.806923667, 2553607.8523394824 6675496.936953513, 2553615.6316525517 6675486.274506173, 2553742.2207925785 6675405.495965163, 2553766.6806687713 6675410.677154397, 2553760.716253767 6675434.342586297, 2553742.055801845 6675446.555389488, 2553740.68637876 6675458.218066409, 2553743.8212026902 6675464.299462265) + +LINESTRING (2553335.7413727976 6675585.597303625, 2553221.831770615 6675582.566607993) + +LINESTRING (2552859.4626233485 6674782.643002409, 2552873.899312501 6674769.630015552) + +LINESTRING (2552496.0292858523 6674925.59581421, 2552390.534211062 6675006.754442461) + +LINESTRING (2550552.025972246 6675743.113458135, 2550534.8834350696 6675717.747635946) + +LINESTRING (2550264.9668451357 6676363.455844641, 2550263.853157687 6676338.050013267, 2550268.2584102624 6676306.862854914, 2550283.841785011 6676283.797560762, 2550298.5919565563 6676272.344932053, 2550335.93760901 6676264.013019638) + +LINESTRING (2553584.547398422 6675077.290632555, 2553627.972959393 6675041.482413534) + +LINESTRING (2553070.3290298795 6675956.22237279, 2553007.682048494 6676005.383656725) + +LINESTRING (2554452.00267715 6673194.558491118, 2554459.6005004128 6673182.305678744, 2554569.0553527996 6673247.020532673) + +LINESTRING (2548933.681367776 6676543.0970774945, 2548937.352411589 6676552.259180462) + +LINESTRING (2548817.0659175697 6676739.162080079, 2548714.095200997 6676795.715060622) + +LINESTRING (2552839.267757608 6675828.933156236, 2552841.833363509 6675831.963851868) + +LINESTRING (2552917.786847525 6674607.622830221, 2552918.2075738944 6674625.356900703, 2552933.370222273 6674652.893221084, 2552945.810523554 6674663.585675311, 2552982.661203808 6674691.5821013) + +LINESTRING (2551507.5450548055 6676688.010339276, 2551482.788195293 6676787.943276773, 2551483.6378975688 6676806.277485004, 2551520.8268088256 6676869.451985378) + +LINESTRING (2550311.5932263304 6677127.911309262, 2550312.2449397263 6677209.930134953, 2550268.8688759753 6677303.451600832) + +LINESTRING (2551433.653954954 6677147.515809061, 2551295.399970092 6677111.777606111) + +LINESTRING (2551553.511473067 6674752.816156286, 2551550.475643577 6674756.647035583) + +LINESTRING (2553073.7113399096 6675267.234230099, 2552971.598575149 6675260.302639099) + +LINESTRING (2553457.3477926827 6673918.384630135, 2553449.865462933 6674015.21685593) + +LINESTRING (2552521.487355981 6672986.790802429, 2552393.388550746 6672896.21001152) + +LINESTRING (2551347.5947885313 6674889.117441369, 2551238.7091541737 6675037.991612294) + +LINESTRING (2551813.8668500134 6673803.158182336, 2551813.734857427 6673812.670365657, 2551763.684918519 6673879.0255961) + +LINESTRING (2554288.6783503825 6675625.7565213265, 2554347.439800002 6675597.4800310545) + +LINESTRING (2551182.323571112 6675106.617363887, 2551117.853442125 6675055.035524365) + +LINESTRING (2551660.623457043 6676332.648773527, 2551628.912238127 6676351.483096548) + +LINESTRING (2553651.9296138496 6677408.825787253, 2553628.212195956 6677344.641055002) + +LINESTRING (2549638.7692659893 6671457.529792833, 2549726.395844377 6671483.115665531) + +LINESTRING (2551553.511473067 6674752.816156286, 2551637.1205271026 6674824.482605807) + +LINESTRING (2549004.124161304 6672112.680168778, 2549007.9024490938 6672133.264893567) + +LINESTRING (2548140.6864069286 6676740.502387718, 2548133.6248035487 6676704.284074569, 2548135.1014706106 6676667.505632854, 2548132.222382317 6676658.373536774) + +LINESTRING (2553163.4662987553 6674260.113066687, 2553128.925488766 6674268.164914819, 2553107.33645133 6674270.555463519, 2553091.6540821423 6674268.094898748, 2553075.1385097513 6674260.663192958, 2552952.7153857374 6674183.425464666, 2552923.314037086 6674179.344527974) + +LINESTRING (2552994.8622685266 6673053.926211947, 2552904.6453356277 6673047.974845936) + +LINESTRING (2552518.484524637 6672622.867271462, 2552437.820555189 6672563.973753698) + +LINESTRING (2551342.133595263 6676740.562401493, 2551420.0669680773 6676761.497206636, 2551406.438733517 6676812.348878564, 2551388.9662148743 6676831.1531946985) + +LINESTRING (2549002.408257679 6671005.846118377, 2549015.07129645 6670999.594683492, 2549029.912212899 6671001.155041639, 2549033.822493275 6670974.598946247, 2549029.9204624356 6670966.0169764375, 2549001.8637882597 6670970.698050879) + +LINESTRING (2551136.8603745867 6673805.238659865, 2551115.337333444 6673889.147919466, 2551121.829718794 6673902.991096875, 2551121.846217868 6673914.833815121) + +LINESTRING (2551195.696070036 6673935.398535319, 2551189.6904073483 6673933.678140438) + +LINESTRING (2551337.670595931 6676913.342059418, 2551273.0354762105 6676879.604315631) + +LINESTRING (2554049.235548866 6673047.824811499, 2554121.295251579 6673000.804018868) + +LINESTRING (2552848.3504974693 6676699.5529886475, 2552894.7211430273 6676764.197826507) + +LINESTRING (2551879.533161816 6675072.8796201, 2551862.407123713 6675002.063365723, 2551849.1006210824 6674976.097405785, 2551769.170860397 6674914.493265854, 2551681.7587699625 6674858.290365664, 2551637.1205271026 6674824.482605807) + +LINESTRING (2553026.474493002 6674457.848452673, 2553093.7824626 6674467.150587782, 2553115.338501889 6674468.290849505) + +LINESTRING (2548656.3484443864 6676539.556264776, 2548591.7710714224 6676574.744341456, 2548530.0315390695 6676632.577615865, 2548482.283220889 6676658.733619423) + +LINESTRING (2553315.167028371 6675433.792460027, 2553303.205200216 6675442.1943885125, 2553296.729313939 6675472.141262185) + +LINESTRING (2551388.034017232 6674495.0769977, 2551389.1229560706 6674501.588492276, 2551386.895581173 6674536.536513858, 2551390.7481147926 6674544.158263269) + +LINESTRING (2551754.164953215 6677609.0417426005, 2551890.076069666 6677588.156948937, 2551941.0829548263 6677586.416549465, 2551990.976152538 6677584.696154584) + +LINESTRING (2552739.555608015 6672439.63521441, 2552733.0467235916 6672525.654958427) + +LINESTRING (2550933.6990352944 6673730.841583586, 2550817.034087868 6673801.027693327) + +LINESTRING (2553373.384008571 6673347.723646948, 2553377.95425188 6673345.213070698, 2553557.5136667914 6673231.256914468) + +LINESTRING (2551906.43490086 6671776.923102828, 2551921.572800629 6671722.220547011, 2551916.697324463 6671708.97750735, 2551897.690392002 6671693.523960315, 2551873.7749852287 6671666.857839669, 2551855.8652411425 6671639.501560613, 2551795.7261189013 6671523.915030164, 2551805.782304088 6671476.494145701, 2551804.5366240526 6671466.011739685, 2551679.473648308 6671222.705893962, + 2551671.422100529 6671215.784305258, 2551660.813196386 6671215.63427082, 2551571.1077347603 6671261.264744333, 2551561.926000459 6671263.085162171, 2551553.84970407 6671260.544579034, 2551547.093333547 6671252.882820439, 2551491.2522199047 6671144.017832778) + +LINESTRING (2551661.514407002 6673021.638801052, 2551612.3884162 6672988.061093998) + +LINESTRING (2552726.925567391 6674469.901219131, 2552722.2975773253 6674530.445115705) + +LINESTRING (2549665.1760328333 6676316.775130067, 2549602.042328785 6676379.159449072, 2549658.056682697 6676441.84383695, 2549668.5583428633 6676466.379468586, 2549689.866896053 6676465.299220638, 2549749.923522928 6676376.828914146) + +LINESTRING (2549009.032635616 6677388.471115267, 2549004.0911631575 6677387.730945377) + +LINESTRING (2553361.900653542 6672271.626651589, 2553373.746988184 6672246.000769708, 2553388.9756328557 6672231.9875532705) + +LINESTRING (2549323.9009508025 6671664.947401169, 2549315.1646914813 6671719.489920253, 2549314.974952138 6671750.76709927) + +LINESTRING (2548543.758768069 6677234.355741335, 2548505.4974170467 6677228.174322521, 2548472.3342796788 6677228.03429038) + +LINESTRING (2551492.902127236 6673776.792130565, 2551439.808109301 6673769.050353603) + +LINESTRING (2552147.7668462717 6673412.808585823, 2552067.267867557 6673354.565217286) + +LINESTRING (2550981.0348766414 6674998.84262647, 2550967.0766606154 6675000.773069562) + +LINESTRING (2547400.950454749 6672752.236965545, 2547382.7519768802 6672686.15179709) + +LINESTRING (2552274.289990005 6672061.3383843545, 2552281.6980739245 6672052.986467348, 2552283.8017057725 6672035.132369317, 2552277.0370857124 6672028.170771429, 2552217.137200034 6672017.598344752) + +LINESTRING (2549219.4370680945 6675651.492428461, 2549263.555590145 6675667.216037484) + +LINESTRING (2553633.310409611 6675342.781570397, 2553603.7440702263 6675357.674988868, 2553578.863467664 6675383.090822536, 2553572.445328144 6675410.377085522, 2553572.0411008475 6675438.963646964, 2553595.733770131 6675476.042157553, 2553592.9206781304 6675488.995130635, 2553598.3653723253 6675496.806923667) + +LINESTRING (2551263.5815071994 6673683.270664685, 2551257.600593122 6673682.420469541) + +LINESTRING (2553453.15702806 6675162.200121736, 2553477.4766621296 6675206.120202664, 2553496.8548237407 6675248.269877233, 2553505.3188483524 6675278.136732539, 2553513.0239155916 6675335.189827873) + +LINESTRING (2552330.7745675067 6672982.3197762, 2552250.077599912 6673094.855606426) + +LINESTRING (2548894.9580427003 6676442.353954037, 2548933.681367776 6676543.0970774945) + +LINESTRING (2551520.8268088256 6676869.451985378, 2551500.928926405 6676943.1288963575, 2551506.1838812567 6676962.873428298) + +LINESTRING (2551902.1451417976 6673644.191694933, 2551896.26322216 6673640.000732986) + +LINESTRING (2552833.7735661934 6674460.779125347, 2552834.870754569 6674435.793390399, 2552729.771657538 6674428.26166165) + +LINESTRING (2552270.379709629 6672251.59205307, 2552183.701827957 6672186.897203732, 2552186.1766889542 6672165.952396294) + +LINESTRING (2553409.723217552 6676423.349591986, 2553363.6083076303 6676465.00915406) + +LINESTRING (2552217.0959523506 6673619.726079367, 2552205.0351297557 6673700.734673181, 2552169.0589003875 6673672.218127809, 2552146.0756912567 6673660.495437113) + +LINESTRING (2552471.2311786567 6672787.425042226, 2552341.7794494093 6672696.104081427) + +LINESTRING (2550947.8057429804 6675665.505644899, 2550942.9055182054 6675672.607274928, 2550798.2911405796 6675798.536179251, 2550791.0727960034 6675808.058364868, 2550779.630688658 6675836.554905647, 2550770.3169617704 6675846.057086673, 2550769.4590099575 6675857.869798032) + +LINESTRING (2551445.2198053496 6672682.380931567, 2551422.2695943653 6672714.018193233, 2551410.9264814593 6672738.213746811, 2551404.1536118626 6672792.616233755) + +LINESTRING (2553314.507065438 6676848.127090698, 2553309.557343443 6676796.075143272) + +LINESTRING (2549097.913143576 6671757.208577774, 2549147.600102871 6671811.280988956) + +LINESTRING (2551710.425909851 6676414.177486723, 2551691.2787352665 6676490.985116294) + +LINESTRING (2549851.2525817053 6677259.631542862, 2549847.8785212124 6677340.410083871, 2549842.4503260907 6677349.362138627) + +LINESTRING (2553006.1971318955 6674929.916806002, 2553071.0549891056 6675017.826983929) + +LINESTRING (2549850.52662248 6677359.834542346, 2549849.701668814 6677531.543954618) + +LINESTRING (2552644.8674262473 6673602.582144339, 2552652.5477448767 6673607.583292247) + +LINESTRING (2554121.295251579 6673000.804018868, 2554124.149591263 6672992.832189103, 2554136.8043804974 6672976.648474473) + +LINESTRING (2553430.7842846415 6676540.6965264985, 2553370.8101531332 6676594.448864214) + +LINESTRING (2553078.108342949 6672215.473762878, 2552909.710551136 6672140.6265832875) + +LINESTRING (2552742.8141749953 6676471.2505866485, 2552731.2648236733 6676473.191032037, 2552525.5543775535 6676433.6319520855) + +LINESTRING (2552859.4626233485 6674782.643002409, 2552854.6696425495 6674775.111273659, 2552853.984931007 6674765.168991618) + +LINESTRING (2551337.0023834617 6674078.751438953, 2551351.8597989837 6674088.353642936) + +LINESTRING (2553326.1636607368 6676944.679252209, 2553314.507065438 6676848.127090698) + +LINESTRING (2553241.9111428424 6675316.725589797, 2553280.774710041 6675290.619597717) + +LINESTRING (2551086.298964406 6671839.64749989, 2551235.038110361 6671764.340214692, 2551250.3904980826 6671753.617753577, 2551259.217502307 6671729.32217704) + +LINESTRING (2548763.4934265087 6676617.1940848995, 2548768.484396187 6676625.876077668) + +LINESTRING (2553299.9218846257 6672575.486396182, 2553290.7566493982 6672596.851300045, 2553281.9791423935 6672606.85359586) + +LINESTRING (2553233.3316247175 6673542.7184038805, 2553226.0967810676 6673638.8804758545) + +LINESTRING (2553180.9635660085 6672364.467961353, 2553042.4950931934 6672305.494425222) + +LINESTRING (2552978.882916019 6673298.132264293, 2552971.7305677356 6673425.081402789) + +LINESTRING (2550184.7236020574 6677117.4989193175, 2550170.7983841775 6677132.052259729, 2550124.073008543 6677166.50016652, 2550109.628069854 6677182.573855896, 2550107.7059278125 6677196.186980502) + +LINESTRING (2553453.15702806 6675162.200121736, 2553448.322799578 6675165.300833439) + +LINESTRING (2551528.069902012 6674337.650863852, 2551387.6545385453 6674303.813097107, 2551376.426919153 6674304.123168278) + +LINESTRING (2547927.510130133 6672506.360529798, 2547923.6658460503 6672523.004350035) + +LINESTRING (2554199.8968368624 6673020.008426835, 2554280.189577161 6673075.421145655) + +LINESTRING (2553766.004206765 6673008.675825675, 2553881.6792097925 6672937.079392225) + +LINESTRING (2550343.865413739 6672709.737210624, 2550330.047439836 6672702.395525495) + +LINESTRING (2551349.888159722 6674101.536668821, 2551349.6159250126 6674103.367088956) + +LINESTRING (2553679.953289879 6675760.077351839, 2553681.495953234 6675776.52112616, 2553686.016699323 6675827.962933542) + +LINESTRING (2549278.6687413035 6675887.736653338, 2549209.8346074237 6675962.77387655) + +LINESTRING (2548366.888702108 6676720.467789199, 2548369.190322836 6676726.649208013, 2548259.430237593 6676785.932815314, 2548161.1617569155 6676779.191267935, 2548155.8325562337 6676774.85027155) + +LINESTRING (2551101.9400859103 6674253.821622619, 2550917.7691800063 6674209.481445267) + +LINESTRING (2553589.6703606867 6676747.243935098, 2553722.1084222044 6676732.620578615) + +LINESTRING (2550885.983715261 6672158.480681319, 2550679.3163228887 6672035.902546095, 2550677.328184554 6672029.341040039, 2550692.136102856 6672000.934519922) + +LINESTRING (2551424.051494283 6673230.496739985, 2551411.6689397586 6673254.942350959, 2551397.3229955095 6673270.465914066) + +LINESTRING (2548058.941748178 6672108.509211423, 2548033.566173416 6672145.257646251) + +LINESTRING (2553715.475794731 6676674.007125134, 2553766.878657651 6676675.6274970565) + +LINESTRING (2552061.534439579 6673087.613944255, 2552016.7147069126 6673148.767980873) + +LINESTRING (2548788.6215151707 6672008.0761591345, 2548812.1409441847 6672129.604053299) + +LINESTRING (2553619.970908834 6672194.188877382, 2553578.599482491 6672290.310940173) + +LINESTRING (2553690.9416727084 6673181.575511149, 2553707.4902432454 6673207.421443538) + +LINESTRING (2552531.1145652616 6673268.445450311, 2552514.153517891 6673262.224022313, 2552491.153809687 6673261.063755998, 2552478.6805102592 6673256.062608091) + +LINESTRING (2549159.636176856 6676030.589442181, 2549148.9200287363 6676040.821790801) + +LINESTRING (2553001.2886575833 6672957.1539999265, 2552911.063475148 6672951.98281299) + +LINESTRING (2552038.6089772047 6676658.383539069, 2552037.3715467057 6676663.8147856975) + +LINESTRING (2553672.239973103 6677388.731174959, 2553693.0370550198 6677366.976181559, 2553709.89910795 6677340.320063209, 2553706.681788653 6677314.424119342, 2553689.45675611 6677291.298811415) + +LINESTRING (2553322.5008664606 6675477.422474376, 2553296.729313939 6675472.141262185) + +LINESTRING (2552540.7087763953 6673856.620453472, 2552537.656447832 6673859.791181246, 2552526.197841413 6673969.586382417, 2552522.6257920396 6673981.93921775, 2552497.6379455007 6674020.528075008, 2552484.6531748 6674074.850543585, 2552475.850919185 6674149.257622159, 2552457.3059607767 6674203.500072369, 2552433.3163081734 6674251.000975199, 2552457.9659237093 6674315.865863565, + 2552469.9772490845 6674314.32551001, 2552538.7948838905 6674256.922334322, 2552572.4117457746 6674236.2575911665, 2552769.740662649 6674190.066989088, 2552873.2723477148 6674175.9337451, 2552913.356846339 6674178.394309871) + +LINESTRING (2549124.6828900333 6676320.435970336, 2549179.492811593 6676363.095761991) + +LINESTRING (2552394.7992215143 6671836.756836399, 2552326.2620709543 6671842.438140423, 2552268.0945879743 6671857.091503793, 2552210.3148332173 6671883.367534901, 2552192.6443256945 6671895.100227893) + +LINESTRING (2553258.6824508696 6671752.257441346, 2553307.899186575 6671743.005317716, 2553327.4588379925 6671743.275379703, 2553356.2414713944 6671753.047622715, 2553364.416762223 6671759.249046122, 2553372.229073439 6671765.190409836, 2553384.3393932534 6671781.114064775, 2553425.45508396 6671872.695085266, 2553439.4132999866 6671885.367994064, 2553475.3317825985 6671896.300503392, + 2553498.7274685623 6671899.161159995, 2553558.3551195306 6671918.175524341, 2553586.8572686864 6671931.4285662975) + +LINESTRING (2553350.22755917 6673302.153187211, 2553415.7866269965 6673260.363595292, 2553532.6743119126 6673185.456401926) + +LINESTRING (2551463.451281365 6675895.268382087, 2551458.9717829595 6675914.192725771) + +LINESTRING (2551435.485352092 6673768.170151572, 2551429.8426690176 6673767.009885257) + +LINESTRING (2554289.3300637784 6673267.365202363, 2554358.0404546084 6673304.683768053) + +LINESTRING (2549231.959864742 6676574.844364415, 2549240.0774088143 6676592.25836143) + +LINESTRING (2551850.932018221 6673967.375875042, 2551763.684918519 6673879.0255961) + +LINESTRING (2549024.7315038773 6676405.455484771, 2549059.3878073804 6676493.845772897) + +LINESTRING (2551458.9717829595 6675914.192725771, 2551446.9357089745 6675949.9809402, 2551411.8999267854 6676054.074832757, 2551406.933705717 6676075.159672338, 2551422.145851315 6676111.508015333, 2551406.95020479 6676174.962579989, 2551416.321678434 6676189.485913513, 2551433.290975341 6676202.248842975) + +LINESTRING (2553426.9647491686 6676010.044726576, 2553377.5747731933 6675988.449769909) + +LINESTRING (2553788.31095389 6675212.56168117, 2553801.5432106904 6675206.240230214, 2553809.4462668095 6675220.2734512435, 2553844.490298535 6675282.827809277, 2553895.4559360123 6675361.215801586, 2553932.14987507 6675424.730380017) + +LINESTRING (2552445.847354358 6672020.799079413, 2552448.3469639653 6672005.375539265, 2552444.9811530085 6672000.17434544, 2552421.1729902118 6671985.530984365, 2552385.361751577 6671970.1474534) + +LINESTRING (2551482.5324596562 6674683.330207252, 2551501.1186657483 6674707.125668998, 2551553.511473067 6674752.816156286) + +LINESTRING (2549224.3372928696 6676511.139742363, 2549211.6495054886 6676506.808748274, 2549195.8268941776 6676492.755522653, 2549179.0968338335 6676455.867055684) + +LINESTRING (2551719.459152492 6673928.1468708515, 2551694.4713059533 6673958.533845541, 2551697.0286623174 6673975.887828781) + +LINESTRING (2551512.4040318974 6674180.384766739, 2551504.6329683647 6674213.782432468) + +LINESTRING (2554058.054303554 6677147.885894006, 2554132.5393700446 6677080.760486785) + +LINESTRING (2553418.81420695 6677066.027105048, 2553340.9633295024 6677092.623209623, 2553336.2775926804 6677118.009036404, 2553329.323233277 6677136.193210198, 2553298.9814374465 6677186.844836209, 2553295.112404754 6677200.097878166) + +LINESTRING (2551073.264696485 6676084.111727092, 2551160.544794333 6676135.153442642) + +LINESTRING (2552498.4628991666 6676774.4501797175, 2552483.9272155743 6676831.203206178) + +LINESTRING (2553279.925007765 6674932.947501635, 2553304.4673793246 6674957.413117201) + +LINESTRING (2553125.0647056093 6676868.411746613, 2553115.660233819 6676816.599854286, 2553213.62348164 6676806.227473525) + +LINESTRING (2548499.7227413855 6671940.530655489, 2548442.149225045 6672027.670656638) + +LINESTRING (2549711.7116691247 6672521.834081425, 2549698.487661861 6672567.874649066, 2549671.7426640135 6672615.655616179, 2549641.5823579896 6672652.103982132, 2549623.037399581 6672670.518208729, 2549563.904720812 6672711.237554996) + +LINESTRING (2548940.256248493 6676559.490840337, 2548977.016183844 6676651.702005465) + +LINESTRING (2553368.6157763824 6673912.273227392, 2553263.7229177677 6673904.271390739) + +LINESTRING (2552978.453940112 6674694.902863511, 2552974.5601588096 6674697.973568327) + +LINESTRING (2551672.841020834 6676567.80274816, 2551598.925172373 6676549.378519267) + +LINESTRING (2553284.1240219246 6676080.130813357, 2553224.7521065925 6676137.994094653, 2553179.189915627 6676182.39428578) + +LINESTRING (2552924.328730095 6674453.757513684, 2553001.610389513 6674456.808213908) + +LINESTRING (2552707.5061580963 6671918.555611582, 2552699.033883948 6671952.633433427, 2552689.9841422336 6671988.821739689) + +LINESTRING (2552795.2482299977 6675564.042356142, 2552787.3864215617 6675675.978048619) + +LINESTRING (2548750.5581530277 6676134.883380654, 2548701.465160372 6676163.649983421, 2548650.2767854054 6676182.624338584) + +LINESTRING (2549842.4503260907 6677349.362138627, 2549850.52662248 6677359.834542346) + +LINESTRING (2554393.620706217 6673334.840689938, 2554372.056417391 6673374.309749227, 2554372.741128934 6673408.547607805) + +LINESTRING (2551597.547499751 6675089.953539058, 2551555.186129009 6675081.411578431) + +LINESTRING (2552652.5477448767 6673607.583292247, 2552719.2287496882 6673650.273090789, 2552757.3251099777 6673680.650063182, 2552766.482095669 6673692.762843415) + +LINESTRING (2551179.551726795 6675619.705132358, 2551122.7041696804 6675711.97631126) + +LINESTRING (2552856.402045248 6674760.487917176, 2552859.124392345 6674755.216707281, 2552868.586610893 6674750.745681051) + +LINESTRING (2552908.753604884 6674299.502107611, 2552903.548147252 6674407.876982776) + +LINESTRING (2551919.6341595137 6673281.248388955, 2551892.3364427104 6673318.977048773) + +LINESTRING (2549607.280784563 6676221.383234871, 2549566.148594783 6676225.97428865, 2549536.821491962 6676235.3564421255, 2549528.33271874 6676231.06545722, 2549524.859663807 6676222.803560876, 2549525.14839759 6676214.041549741, 2549533.4721800783 6676195.32725427) + +LINESTRING (2552065.320976905 6672790.54575852, 2551983.931048231 6672903.211618591) + +LINESTRING (2552914.2312972248 6674016.43713602, 2552910.4942571186 6674007.865168505, 2552913.191855606 6673994.342064562, 2552919.956475666 6673982.849426669, 2552930.6726237857 6673980.708935365) + +LINESTRING (2550180.648330948 6676468.279904791, 2550180.2771017984 6676468.249897904) + +LINESTRING (2550583.3164647925 6672862.86235727, 2550583.902181895 6672856.730949935) + +LINESTRING (2552769.3446848895 6673764.979419206, 2552762.6213125126 6673869.363378341) + +LINESTRING (2549580.527537179 6675520.572378526, 2549553.7000439656 6675531.724938361, 2549401.991064813 6675544.987982613, 2549346.0179585842 6675556.560638872) + +LINESTRING (2554008.3260965757 6675547.978669061, 2554008.458089162 6675550.689291228) + +LINESTRING (2552400.565647639 6672187.877428723, 2552253.088680792 6672172.793966631) + +LINESTRING (2552217.0959523506 6673619.726079367, 2552202.6262650513 6673614.574897022) + +LINESTRING (2547923.6658460503 6672523.004350035, 2547906.465562117 6672604.613081598, 2547909.526140217 6672616.255753928, 2547920.50627351 6672635.070072358) + +LINESTRING (2551224.519951121 6673823.852932379, 2551219.034009243 6673822.6826637685) + +LINESTRING (2553480.28975413 6676596.439321081, 2553420.3156226217 6676650.6617666995, 2553370.8101531332 6676594.448864214) + +LINESTRING (2553630.315827804 6677124.7905929675, 2553636.857710374 6677136.563295143) + +LINESTRING (2548809.996064653 6672643.512010026, 2548822.9478372075 6672676.96968953, 2548837.4257740434 6672728.601540533, 2548854.1310857767 6672765.329970769, 2548864.5749991867 6672779.653258377, 2548894.5703144777 6672807.949753241, 2548982.9063530182 6672863.72255471) + +LINESTRING (2551214.2657770542 6677298.630494248, 2551320.000088408 6677364.695658113, 2551436.0545701217 6677437.212302779, 2551446.300494652 6677423.239095524) + +LINESTRING (2549965.4591672076 6676688.620479321, 2549986.2397500505 6676663.294666315, 2549999.9999771975 6676652.972297033, 2550049.0269735595 6676600.850333536, 2550055.1398802237 6676588.627528049, 2550060.518578125 6676537.765853825) + +LINESTRING (2552878.6675446895 6674750.075527232, 2552891.2563376306 6674758.197391435) + +LINESTRING (2554186.6315819155 6673045.404255911, 2554266.635588431 6673100.146820912) + +LINESTRING (2554582.9888202157 6676112.848322972, 2554627.9240463953 6675932.62695696, 2554612.423167014 6675880.555004942) + +LINESTRING (2550050.2314059115 6677193.356330786, 2550043.483284925 6677192.91622977) + +LINESTRING (2552692.5414985977 6673061.627979725, 2552692.162019911 6673088.934247302) + +LINESTRING (2548594.0479435404 6676199.928310346, 2548573.811830117 6676310.843768649) + +LINESTRING (2551523.4666605564 6677169.820928731, 2551433.653954954 6677147.515809061) + +LINESTRING (2551645.3123170044 6673652.453591277, 2551507.2315724124 6673658.074881526) + +LINESTRING (2550469.3408663166 6675291.659836482, 2550391.011515743 6675410.187041901, 2550373.1430193405 6675437.223247492) + +LINESTRING (2552137.7189106215 6677020.596677452, 2552035.4659037376 6676994.45067619) + +LINESTRING (2552068.1670670523 6673793.766026565, 2552063.959803357 6673790.795344708) + +LINESTRING (2550063.059435416 6676747.674033819, 2550113.6950914264 6676703.503895495, 2550132.6937743514 6676691.5711565865, 2550158.292086603 6676693.161521622) + +LINESTRING (2552483.811722061 6672500.92928317, 2552510.4824740784 6672559.752784863) + +LINESTRING (2551906.43490086 6671776.923102828, 2551837.279035051 6671991.542364151) + +LINESTRING (2548860.705966494 6672161.711422868, 2548857.076170364 6672141.0166728245) + +LINESTRING (2550391.8694675555 6676050.253955755, 2550294.6239294237 6676116.669199973) + +LINESTRING (2552061.534439579 6673087.613944255, 2551923.44544545 6672987.520970024) + +LINESTRING (2552853.984931007 6674765.168991618, 2552856.402045248 6674760.487917176) + +LINESTRING (2553288.8592559667 6674230.566284847, 2553275.363013993 6674225.595143827, 2553204.730481122 6674219.923842099) + +LINESTRING (2552891.050099214 6674779.41226086, 2552942.890187577 6674846.207592319) + +LINESTRING (2551871.465114964 6676056.955493952, 2551963.5216945377 6676082.97146537, 2551998.8214619 6676091.633453546) + +LINESTRING (2554117.6819545226 6673171.423180896, 2554115.636069431 6673175.21405101) + +LINESTRING (2553477.9386361823 6676032.269827878, 2553426.9647491686 6676010.044726576) + +LINESTRING (2549341.2497263956 6674960.123739366, 2549344.145313763 6674946.490610169, 2549349.4662649077 6674942.769756126, 2549344.425798009 6674937.468539343, 2549338.9893533513 6674916.443713538, 2549318.283016338 6674889.847608964, 2549302.6088966867 6674852.118949146, 2549295.2750585973 6674810.4193778895, 2549304.605284558 6674782.392945013, 2549319.8504283032 6674725.119799171, + 2549324.709405395 6674705.355262639, 2549331.0615486223 6674700.614174422) + +LINESTRING (2550305.4720701296 6676712.665998463, 2550341.9845193806 6676750.574699605, 2550362.4351207577 6676788.45339386) + +LINESTRING (2550107.7059278125 6677196.186980502, 2550050.2314059115 6677193.356330786) + +LINESTRING (2553584.1679197354 6676747.223930507, 2553589.6703606867 6676747.243935098) + +LINESTRING (2551577.534123817 6674201.5996361645, 2551570.9674926368 6674229.8961310275) + +LINESTRING (2551465.6374085797 6673661.9857791895, 2551347.883522314 6673674.828727017) + +LINESTRING (2551562.841699028 6677338.039539764, 2551603.297426802 6677433.98156123) + +LINESTRING (2549240.0774088143 6676592.25836143, 2549190.6544346926 6676779.691382726) + +LINESTRING (2552056.98894488 6672339.2921827845, 2551966.2852893183 6672312.3359955605) + +LINESTRING (2548168.124365855 6671897.640811031, 2548115.25308541 6671920.756116661, 2548047.9203672023 6671965.126300901, 2547982.023068373 6672014.387607794, 2547919.3513383777 6672037.772975412) + +LINESTRING (2553780.1521621346 6673315.01613963, 2553933.329558812 6673324.638348205) + +LINESTRING (2549562.2795620905 6677397.083091965, 2549575.264332791 6677395.272676422, 2549595.4509489946 6677401.234044729, 2549630.7424668204 6677416.157470086, 2549641.392618647 6677444.533983315) + +LINESTRING (2554035.524818939 6675640.069806639, 2554077.547958678 6675727.719924875) + +LINESTRING (2554223.0532862633 6675657.343771514, 2554326.5684722555 6675869.682509391) + +LINESTRING (2547971.0181864705 6672303.113878818, 2547945.8323510517 6672417.580152135) + +LINESTRING (2553304.4673793246 6674957.413117201, 2553260.291110518 6674990.400688802) + +LINESTRING (2552951.6016982887 6671978.96947831, 2552890.6046242346 6671963.876013924, 2552707.5061580963 6671918.555611582) + +LINESTRING (2553006.271377725 6676006.523918448, 2552995.1510023093 6676016.166131615) + +LINESTRING (2552097.857149487 6671828.464933168, 2552023.157595043 6671823.333755414, 2551985.721197686 6671814.581746575, 2551951.163888623 6671802.518977821, 2551906.43490086 6671776.923102828) + +LINESTRING (2551009.223543404 6675172.982596626, 2551002.9621450803 6675192.977185962, 2550993.1864441396 6675199.478678242) + +LINESTRING (2553381.666543376 6673728.240986674, 2553275.9652301692 6673721.07934287) + +LINESTRING (2548625.7014156994 6676035.630599272, 2548672.723774654 6676058.695893425) + +LINESTRING (2550100.479333699 6677351.662666664, 2550037.131141698 6677349.362138627) + +LINESTRING (2553672.6606994728 6676552.929334282, 2553725.5237303814 6676562.6115566315) + +LINESTRING (2551705.5504336855 6674335.160292194, 2551683.6644129306 6674375.029443317) + +LINESTRING (2552921.309399678 6673955.193078739, 2552929.47644097 6673963.905078394, 2552932.8422519267 6673978.828503751, 2552932.619514437 6673980.83896521, 2552928.601990084 6674017.417361009, 2552926.5643545296 6674030.050260625) + +LINESTRING (2548452.378650502 6676674.817311095, 2548366.888702108 6676720.467789199) + +LINESTRING (2553671.6212578537 6673408.037490718, 2553774.7487156233 6673413.858826883, 2553846.5279340902 6673417.569678631, 2553929.122295116 6673383.371829236, 2553962.6731607066 6673372.999448475, 2554024.099210667 6673341.062117935, 2554045.5892536626 6673323.128001537) + +LINESTRING (2551564.483356823 6676702.513668209, 2551540.584449123 6676790.563878277) + +LINESTRING (2552622.8329138323 6673749.445853804, 2552599.197991305 6673743.634519935) + +LINESTRING (2551602.5879666493 6673488.706006474, 2551527.558430739 6673498.808325248) + +LINESTRING (2552951.370711262 6675393.493210184, 2552920.5256936955 6675379.3899730835, 2552880.9444168075 6675375.529086899) + +LINESTRING (2548442.6524467813 6676602.390687092, 2548410.7927362053 6676628.9067733, 2548357.2614928274 6676661.654289802) + +LINESTRING (2553557.5136667914 6673231.256914468, 2553594.125110483 6673282.258620833) + +LINESTRING (2549002.408257679 6671005.846118377, 2549001.8637882597 6670970.698050879) + +LINESTRING (2550234.880784942 6676700.8732916955, 2550219.437652317 6676822.0010940265, 2550219.7346356367 6676905.580277865) + +LINESTRING (2552639.3567357594 6673853.58975784, 2552638.878262633 6673862.84188147) + +LINESTRING (2552473.318311431 6673253.912114491, 2552468.145851946 6673251.841639256) + +LINESTRING (2549247.0812654374 6672845.548383213, 2549207.2030052296 6672804.628991029, 2549169.931598606 6672778.703040275, 2549164.742640048 6672751.576814022) + +LINESTRING (2553594.125110483 6673282.258620833, 2553609.6342394007 6673306.284135383) + +LINESTRING (2549078.5514810383 6677099.384761594, 2549106.962885291 6676998.751663391, 2549127.4134866674 6676931.256171225, 2549142.2461535796 6676882.284930909, 2549199.143207914 6676677.207859796, 2549222.4811471216 6676594.02876779, 2549236.2578733414 6676538.766083406, 2549249.1106514554 6676487.214250771, 2549251.0327934967 6676472.100781793, 2549248.1949528866 6676444.04434203, + 2549248.326945473 6676428.60079729, 2549258.9688477623 6676424.309812385, 2549305.5374822007 6676406.915819961, 2549398.204527487 6676372.2978741415, 2549467.2284007096 6676343.601287446, 2549500.1028042943 6676330.738335026, 2549534.6766124307 6676310.113601054, 2549556.2574003297 6676298.991048107, 2549596.680129957 6676263.692946172, 2549607.06629661 6676254.200767443, + 2549651.97677418 6676213.151345414, 2549716.207666604 6676154.457873566, 2549810.7061090283 6676078.2503817445, 2549830.537995156 6676063.476990825, 2549989.9437920107 6675953.431732257, 2550072.9093821864 6675894.198136435, 2550098.0704689953 6675883.225617925, 2550112.045184095 6675878.084437876, 2550173.908459498 6675874.073517254, 2550230.508530513 6675872.463147627, + 2550277.86912047 6675871.0628262125, 2550369.2079903544 6675868.362206343, 2550494.980426252 6675865.161471682, 2550508.748902935 6675864.831395919, 2550600.854979729 6675862.360828853, 2550689.6034951024 6675859.940273265, 2550769.4590099575 6675857.869798032, 2550821.79407052 6675856.429467434, 2550825.6548536764 6675860.640433973, 2550829.325897489 6675864.911414286, + 2550833.4836639655 6675869.752525461) + +LINESTRING (2553689.1515232534 6675997.631877468, 2553689.5640000864 6676056.635420486, 2553689.547501013 6676086.742330892) + +LINESTRING (2552629.432543159 6674742.873874244, 2552589.166554728 6674742.313745678, 2552534.587620195 6674734.912046775, 2552494.8083544266 6674732.471486595, 2552471.5199124394 6674736.012299314, 2552444.3624377595 6674745.6045010025) + +LINESTRING (2551629.9186815997 6674060.237189397, 2551642.8869532268 6674154.408804504) + +LINESTRING (2553055.9253388736 6676203.589150614, 2553024.99782594 6676248.229396841) + +LINESTRING (2551745.329699454 6676011.725112272, 2551737.5751349945 6676032.799949557, 2551736.189212836 6676059.68612071, 2551756.1613410865 6676105.786702125, 2551776.083972117 6676132.332795221) + +LINESTRING (2551727.032227145 6676349.022531778, 2551710.425909851 6676414.177486723) + +LINESTRING (2552837.8075896194 6672534.056886912, 2552787.726166266 6672530.040305593, 2552733.0467235916 6672525.654958427) + +LINESTRING (2550585.213858224 6675185.965576595, 2550541.268576443 6675202.969479483, 2550521.6841764157 6675217.10272347, 2550507.13199375 6675234.166640132, 2550469.3408663166 6675291.659836482) + +LINESTRING (2553076.243947664 6672827.414220898, 2553010.6683807643 6672823.043217626) + +LINESTRING (2550752.2834746344 6675483.593890894, 2550732.600080167 6675458.888220229) + +LINESTRING (2551731.78396026 6673845.057799509, 2551686.840484544 6673785.184056754) + +LINESTRING (2552514.763983604 6673499.378456109, 2552509.9710028055 6673570.4747747695) + +LINESTRING (2552192.578329401 6675949.250772606, 2552265.0752575574 6676038.461248988, 2552232.7618224653 6676067.0878196135, 2552153.6735145194 6676048.263498888, 2552100.0185280913 6676044.772697648, 2552086.423291678 6676040.941818351, 2552079.675170691 6676035.16049137) + +LINESTRING (2551061.5256058197 6675212.5716834655, 2551058.6547670625 6675226.064780521, 2551050.322735037 6675236.387149803) + +LINESTRING (2551655.7479808778 6673452.047592308, 2551656.8781673997 6673439.724763864, 2551487.0284571354 6673323.158008425) + +LINESTRING (2553789.837118172 6677473.050528687, 2553781.42259078 6677475.131006217) + +LINESTRING (2551238.7091541737 6675037.991612294, 2551138.5267809913 6675037.811570969, 2551126.16072554 6675032.970459795) + +LINESTRING (2550915.244821789 6675393.543221664, 2550817.5785572873 6675557.160776621) + +LINESTRING (2550373.1430193405 6675437.223247492, 2550365.462700711 6675431.962039893, 2550350.778525459 6675435.36282047, 2550313.630861885 6675470.320844347, 2550297.2307830076 6675479.382924356, 2550288.890501446 6675480.093087359, 2550275.6252464987 6675475.802102454, 2550235.037526138 6675422.629897896, 2550208.8039995637 6675386.541614592) + +LINESTRING (2548225.2359081428 6672756.537952746, 2548260.279939869 6672778.793060937, 2548287.684900649 6672795.936995965) + +LINESTRING (2551376.426919153 6674304.123168278, 2551370.726489322 6674304.233193532) + +LINESTRING (2552267.0221482087 6672090.435062883, 2552261.4207128175 6672125.6131372675) + +LINESTRING (2551414.6140243458 6672657.84529993, 2551389.2219505105 6672629.378766038, 2551355.9928168496 6672543.769116149) + +LINESTRING (2551720.820326041 6675610.763079898, 2551724.5903642937 6675620.265260924) + +LINESTRING (2552861.3352681696 6675041.022307926, 2552824.4103420856 6675069.158766056) + +LINESTRING (2551511.1253537154 6676314.984719116, 2551492.3824064266 6676385.590925281) + +LINESTRING (2553001.5361436834 6674453.237394302, 2553001.6021399763 6674456.22808075) + +LINESTRING (2551173.7605520603 6673670.577751296, 2551039.1363633284 6673648.872769374) + +LINESTRING (2552777.759212281 6673637.510161328, 2552766.482095669 6673692.762843415) + +LINESTRING (2552918.3478160175 6674178.664371858, 2552914.355040275 6674234.33715037) + +LINESTRING (2553575.431660414 6676664.514946405, 2553559.9472801057 6676667.755690249) + +LINESTRING (2551040.208803094 6676032.699926599, 2551086.826934752 6676059.896168922, 2551073.264696485 6676084.111727092) + +LINESTRING (2552891.322333924 6676098.715078983, 2552795.8091984903 6676178.813463878) + +LINESTRING (2551973.6768741645 6675184.345204673, 2551924.394142166 6675166.101017104, 2551904.3725166954 6675154.928452678, 2551897.0551776793 6675143.11574132, 2551894.4565736316 6675131.533082765) + +LINESTRING (2552140.721741965 6673665.156506963, 2552144.871258904 6673684.150866718, 2552118.0437656906 6673737.923209025) + +LINESTRING (2551392.612510077 6674494.64689898, 2551388.034017232 6674495.0769977) + +LINESTRING (2551005.1565218316 6672769.690971744, 2551013.0513284137 6672686.051774131) + +LINESTRING (2549268.0268390137 6676290.379071409, 2549286.316061786 6676346.481948641, 2549298.0304038413 6676382.410195212, 2549305.5374822007 6676406.915819961) + +LINESTRING (2553627.972959393 6675041.482413534, 2553694.431226715 6675125.751755783) + +LINESTRING (2551710.425909851 6676414.177486723, 2551651.7139574517 6676399.724169269) + +LINESTRING (2547849.4447647324 6673884.136769262, 2547904.6176659055 6673856.210359343, 2547915.3833112447 6673845.657937258) + +LINESTRING (2549442.8097722 6672281.278867052, 2549425.9147211234 6672289.940855228, 2549360.0751690506 6672276.497769652) + +LINESTRING (2553609.6342394007 6673306.284135383, 2553780.1521621346 6673315.01613963) + +LINESTRING (2548905.8061834066 6677564.9516226435, 2548569.4725738345 6677555.019342898, 2548515.0421309606 6677581.565435994, 2548508.5167474635 6677588.046923683, 2548494.0470601646 6677711.075162219) + +LINESTRING (2549124.6828900333 6676320.435970336, 2549063.3228363665 6676394.432954783, 2549024.7315038773 6676405.455484771) + +LINESTRING (2547927.3038917165 6672968.396580424, 2547830.4048341243 6672948.171938284) + +LINESTRING (2552854.6036462565 6673878.245417026, 2552885.225926333 6673938.009134526) + +LINESTRING (2548387.5455419016 6677245.3982759155, 2548378.4628020404 6677225.823783004, 2548367.7961511407 6677212.650759415, 2548332.917110148 6677186.094664023, 2548321.0625259695 6677179.963256688, 2548278.758901984 6677179.363118939, 2548191.058077766 6677205.839195964, 2548079.9615675844 6677262.472194874) + +LINESTRING (2552393.388550746 6672896.21001152, 2552264.671030261 6672803.6187591525) + +LINESTRING (2552016.7147069126 6673148.767980873, 2551949.7779664644 6673099.606696938) + +LINESTRING (2552909.710551136 6672140.6265832875, 2552665.84599797 6672078.382296425) + +LINESTRING (2551042.279436795 6676028.979072555, 2551040.208803094 6676032.699926599) + +LINESTRING (2551347.883522314 6673674.828727017, 2551269.785158767 6673683.120630248) + +LINESTRING (2552917.786847525 6674607.622830221, 2552898.128201667 6674630.238021061) + +LINESTRING (2552981.4980191393 6675115.589423234, 2552971.598575149 6675260.302639099) + +LINESTRING (2549247.188509414 6675693.352036451, 2549239.3926972714 6675839.795649492, 2549255.6525340257 6675860.590422493, 2549278.6687413035 6675887.736653338) + +LINESTRING (2551708.858497886 6674048.154416052, 2551629.9186815997 6674060.237189397) + +LINESTRING (2551759.16417243 6676018.126581594, 2551871.465114964 6676056.955493952) + +LINESTRING (2553426.9235014855 6676340.810646913, 2553447.621588962 6676361.925493381, 2553462.6109970706 6676365.146232633) + +LINESTRING (2551550.475643577 6674756.647035583, 2551419.852480124 6674939.328966365) + +LINESTRING (2553462.6109970706 6676365.146232633, 2553458.708966231 6676375.618636353, 2553417.0405565687 6676416.538028535) + +LINESTRING (2551724.5903642937 6675620.265260924, 2551725.4895637897 6675628.787216959) + +LINESTRING (2553044.7884643846 6677290.308584129, 2553047.461314262 6677319.92538204, 2553153.5008584717 6677426.869928905) + +LINESTRING (2548394.7721360144 6672592.170225603, 2548393.798690689 6672633.859794564, 2548393.1057296093 6672663.72664987, 2548391.084593128 6672704.085913488, 2548384.880941561 6672719.839529398, 2548344.44171286 6672753.367224973, 2548287.684900649 6672795.936995965) + +LINESTRING (2553553.6941313185 6676530.764246753, 2553672.6606994728 6676552.929334282) + +LINESTRING (2548866.5796365947 6676319.20568795, 2548877.1885407376 6676399.684160085, 2548894.9580427003 6676442.353954037) + +LINESTRING (2554393.620706217 6673334.840689938, 2554440.9317989545 6673360.586599368) + +LINESTRING (2552924.328730095 6674453.757513684, 2552925.557911057 6674460.349026627) + +LINESTRING (2551397.3229955095 6673270.465914066, 2551379.2647597636 6673289.070184284) + +LINESTRING (2553722.001178228 6675102.756477702, 2553737.5268062195 6675085.582535787, 2553827.0672771125 6675014.906313551, 2553939.2444765964 6674917.794023474) + +LINESTRING (2552393.5865396257 6671805.229599987, 2552305.316497378 6671800.688557687, 2552220.1730295243 6671809.450568821, 2552097.857149487 6671828.464933168) + +LINESTRING (2552376.0067770057 6676504.918314366, 2552388.669815777 6676500.647334052, 2552477.071850611 6676504.3081743205, 2552511.98388975 6676505.76850951) + +LINESTRING (2550079.055286997 6675306.313199853, 2550060.4113341486 6675332.179136832) + +LINESTRING (2547597.809148034 6672788.495287878, 2547662.6175080244 6672750.346531636) + +LINESTRING (2550832.7989524226 6672878.625975476, 2550700.913609861 6672866.723243455) + +LINESTRING (2552050.5543062864 6672064.16903407, 2552022.74511821 6672148.888479631) + +LINESTRING (2548931.025016972 6677383.429958176, 2548929.284364737 6677350.252342954, 2548922.1897632107 6677330.997923509, 2548913.601995549 6677313.193836956, 2548900.526479945 6677301.221088865, 2548877.1225444446 6677290.578646117, 2548687.754430446 6677257.911147982, 2548550.6883788626 6677235.486000762, 2548543.758768069 6677234.355741335) + +LINESTRING (2551946.024427285 6672514.9625042, 2551849.595593282 6672448.047145191) + +LINESTRING (2551508.7907348406 6674414.018392407, 2551506.7201011395 6674427.801556041, 2551513.327980003 6674483.304295525) + +LINESTRING (2552859.5616177884 6673878.415456055, 2552854.6036462565 6673878.245417026) + +LINESTRING (2552389.9319948857 6672339.512233292, 2552270.379709629 6672251.59205307) + +LINESTRING (2553707.4902432454 6673207.421443538, 2553841.6277093147 6673119.391238062) + +LINESTRING (2551437.63848116 6676658.973674523, 2551453.8818188407 6676593.818719577, 2551410.984228216 6676582.966228617, 2551378.6872921977 6676593.868731056) + +LINESTRING (2551428.7124824952 6674549.12940429, 2551422.6490730513 6674549.74954663) + +LINESTRING (2553673.889880435 6675727.699920283, 2553675.4737914735 6675736.161862543) + +LINESTRING (2551201.2315091337 6673936.978898058, 2551195.696070036 6673935.398535319) + +LINESTRING (2551655.7479808778 6673452.047592308, 2551639.6118871733 6673470.691871709) + +LINESTRING (2554229.141444317 6673170.67300871, 2554201.9262228804 6673221.8547564) + +LINESTRING (2553225.5193135017 6675458.598153651, 2553224.09214366 6675516.841522187) + +LINESTRING (2552246.5797963687 6675914.24273725, 2552192.578329401 6675949.250772606) + +LINESTRING (2547876.132015823 6672722.87022503, 2547873.426167799 6672736.283303719) + +LINESTRING (2551447.7276644935 6675063.277416117, 2551443.5286503346 6675059.75660799) + +LINESTRING (2552321.658829499 6676728.859715389, 2552242.166294256 6676709.885360226) + +LINESTRING (2553744.1181860096 6677247.3487236, 2553781.2740991204 6677241.407359885, 2553799.6128191124 6677243.167763949, 2553818.916734894 6677251.309632743, 2553836.9502220294 6677263.742486442) + +LINESTRING (2548894.9580427003 6676442.353954037, 2548758.5602035867 6676483.003284233, 2548706.2746402444 6676511.199756138) + +LINESTRING (2547743.636207549 6675073.6597991735, 2547687.234125414 6675004.573941973, 2547628.4479271844 6674898.609620099) + +LINESTRING (2552250.077599912 6673094.855606426, 2552122.746001586 6673002.154328803) + +LINESTRING (2552318.9612310114 6673271.776214818, 2552292.5049669473 6673307.024305273, 2552245.845587606 6673274.606864533, 2552227.2511319774 6673298.412328576) + +LINESTRING (2551671.7025847756 6672805.259135666, 2551560.8783093034 6672723.220305383) + +LINESTRING (2548896.2449704194 6672351.384958426, 2548908.512031431 6672421.230990108, 2548914.6744353147 6672439.865267213) + +LINESTRING (2547915.3833112447 6673845.657937258, 2547954.9068413763 6673787.444575609, 2547982.2870535464 6673722.389643622) + +LINESTRING (2551027.050792123 6675395.103579811, 2550948.0037318603 6675344.031857374) + +LINESTRING (2553363.6083076303 6676465.00915406, 2553317.5263958555 6676505.718498031) + +LINESTRING (2554340.8071725285 6673346.863449508, 2554315.1511135204 6673404.156599942) + +LINESTRING (2553651.9296138496 6677408.825787253, 2553550.889288855 6677295.089681529, 2553498.512980609 6677339.8299507145, 2553420.142382352 6677243.287791499, 2553382.8627261915 6677214.731236944, 2553355.8289945615 6677204.708936537, 2553295.112404754 6677200.097878166) + +LINESTRING (2552677.906820565 6673285.539373861, 2552531.1145652616 6673268.445450311) + +LINESTRING (2550362.4351207577 6676788.45339386, 2550370.659908806 6676809.608249511, 2550386.4577715076 6676872.182612135) + +LINESTRING (2552529.26666905 6671861.652550685, 2552495.9550400223 6671994.583062079) + +LINESTRING (2553183.413678396 6675229.635600127, 2553241.9111428424 6675316.725589797) + +LINESTRING (2553007.682048494 6676005.383656725, 2552975.046881472 6675965.034395403) + +LINESTRING (2551642.8869532268 6674154.408804504, 2551586.2951317485 6674163.840969459, 2551577.534123817 6674201.5996361645) + +LINESTRING (2553795.603544296 6675666.425856114, 2553804.1335652014 6675701.3238662165) + +LINESTRING (2552735.637078102 6676535.095240842, 2552785.5550244236 6676634.308013041, 2552796.3784165196 6676639.20913799) + +LINESTRING (2551303.7237525806 6672909.38303511, 2551073.289445095 6672891.4089095285) + +LINESTRING (2547582.9599820487 6674466.060337538, 2547514.439330562 6674425.63105785, 2547503.739681516 6674414.138419957, 2547498.682715544 6674402.2756971195, 2547497.618525315 6674376.589801464, 2547529.6019789404 6674324.277794347, 2547535.591142555 6674307.073845543, 2547536.5233401973 6674253.351514716, 2547540.2356316936 6674218.303470177, 2547531.2683853456 6674184.245652923, + 2547532.4315700145 6674137.264869476, 2547537.0925582265 6674094.465045679, 2547540.9863395295 6674079.161533081, 2547553.3853931273 6674054.625901445, 2547582.5970024355 6674017.757439067, 2547658.220504985 6673958.333799625, 2547691.1691544 6673914.113649822, 2547700.161149358 6673908.902453702, 2547741.219093308 6673902.38095683) + +LINESTRING (2553203.32805989 6675312.814692133, 2553241.9111428424 6675316.725589797) + +LINESTRING (2549711.7116691247 6672521.834081425, 2549574.587870785 6672493.267524575) + +LINESTRING (2553207.576571269 6672316.246893224, 2553290.179181832 6672173.0340217315) + +LINESTRING (2553609.947721794 6676055.125073818, 2553593.5723915263 6676093.823956329, 2553572.247339264 6676125.241167488, 2553556.903201079 6676140.89476044) + +LINESTRING (2553296.217842666 6673446.466311243, 2553241.3996715695 6673442.8554824535) + +LINESTRING (2552079.675170691 6676035.16049137, 2552011.3442585478 6676081.291079672, 2552003.3009603056 6676087.112415837) + +LINESTRING (2551487.0284571354 6673323.158008425, 2551456.760907135 6673262.224022313, 2551448.1896385467 6673225.065493357) + +LINESTRING (2552981.4980191393 6675115.589423234, 2552968.340008169 6675103.746704988) + +LINESTRING (2552543.8683489356 6675273.965775183, 2552535.767303937 6675312.314577342) + +LINESTRING (2552995.1510023093 6676016.166131615, 2553001.9073728328 6676024.287995817) + +LINESTRING (2551519.869862573 6672942.42061819, 2551528.4658797714 6672922.285996713, 2551458.0890825368 6672869.863964342) + +LINESTRING (2553766.004206765 6673008.675825675, 2553777.2400756944 6673026.169841057) + +LINESTRING (2553792.3119791695 6676168.631126737, 2553800.4542718516 6676199.43819785, 2553808.761555267 6676271.624766754, 2553794.621849434 6676343.101172655) + +LINESTRING (2550926.0434652753 6672273.377053357, 2550841.0979863014 6672371.139492662) + +LINESTRING (2549153.2922831653 6676924.864704198, 2549135.1927997363 6676990.2697165385, 2549118.380244026 6677001.492292444, 2549112.5973188286 6677000.211998579) + +LINESTRING (2552608.387975143 6671893.399837605, 2552538.3164107646 6671874.825574275, 2552529.26666905 6671861.652550685) + +LINESTRING (2552122.746001586 6673002.154328803, 2551983.931048231 6672903.211618591) + +LINESTRING (2552350.466211511 6676058.945950819, 2552436.0221561976 6676165.820481613) + +LINESTRING (2552338.562130112 6673159.190373113, 2552312.8235757374 6673194.928576063, 2552264.5060395277 6673160.330634836, 2552289.78261985 6673123.612206896) + +LINESTRING (2552317.179331093 6673633.669279735, 2552217.0959523506 6673619.726079367) + +LINESTRING (2552983.1231778613 6673226.425805588, 2552978.882916019 6673298.132264293) + +LINESTRING (2551117.853442125 6675055.035524365, 2551115.1310950276 6675065.297879872, 2551039.7138308943 6675190.116529359) + +LINESTRING (2547626.294798116 6674630.097988919, 2547641.1027164184 6674614.624437292, 2547652.0003543445 6674596.350242836, 2547655.060932445 6674568.603874243, 2547650.589683576 6674551.209881819, 2547605.258479637 6674486.815101356, 2547582.9599820487 6674466.060337538) + +LINESTRING (2553266.585506988 6675361.155787812, 2553246.514384298 6675367.957348966, 2553197.1326578595 6675362.035989843) + +LINESTRING (2553414.920425647 6675381.700503417, 2553450.8719064053 6675500.657807557) + +LINESTRING (2552445.847354358 6672020.799079413, 2552441.5823439052 6672039.053269276, 2552394.4032437545 6672059.577980291) + +LINESTRING (2550184.7236020574 6677117.4989193175, 2550232.8843970704 6677124.780590671) + +LINESTRING (2551282.134715145 6675460.818663321, 2551248.1466241116 6675513.0006405935, 2551188.6674648025 6675605.251814904) + +LINESTRING (2553150.877505814 6674825.012727485, 2553134.0567005672 6674833.564690407, 2553006.1971318955 6674929.916806002) + +LINESTRING (2551765.8792952704 6674350.123726735, 2551705.5504336855 6674335.160292194) + +LINESTRING (2547873.426167799 6672736.283303719, 2547869.6396304728 6672755.077617558, 2547852.6125868093 6672839.406973582) + +LINESTRING (2553671.6212578537 6673408.037490718, 2553616.0936266044 6673442.715450312, 2553602.605634168 6673420.700397221, 2553500.204135624 6673413.6287740795, 2553504.9971164227 6673339.791826366, 2553635.9420118053 6673348.1437433725) + +LINESTRING (2553501.804545736 6675744.633807099, 2553504.419648857 6675758.016878901) + +LINESTRING (2551649.1483515506 6673666.116727361, 2551606.0610215827 6673728.901138199) + +LINESTRING (2548147.929500115 6676753.445358505, 2548140.6864069286 6676740.502387718) + +LINESTRING (2554375.158243175 6675410.9972278625, 2554355.705835734 6675308.943803652, 2554331.8151775706 6675252.130763418, 2554295.15423666 6675200.79898129, 2554239.172880894 6675133.953638352) + +LINESTRING (2552039.310187821 6672058.027624439, 2551837.279035051 6671991.542364151) + +LINESTRING (2550311.5932263304 6677127.911309262, 2550396.332466888 6677132.652397479) + +LINESTRING (2552921.309399678 6673955.193078739, 2552908.118390561 6673973.387254828, 2552897.798220201 6673998.282969113) + +LINESTRING (2552478.6805102592 6673256.062608091, 2552473.318311431 6673253.912114491) + +LINESTRING (2552890.282892305 6674615.774701311, 2552893.1042338423 6674626.937263441, 2552894.655146734 6674628.927720309, 2552908.341128051 6674646.5417632405, 2552942.172477888 6674673.387925211, 2552974.5601588096 6674697.973568327) + +LINESTRING (2551613.0318800593 6673913.813580948, 2551598.677686273 6673821.96249847, 2551567.4531900203 6673802.518035403) + +LINESTRING (2553386.5337700048 6673649.462904828, 2553282.366870616 6673641.751134754) + +LINESTRING (2550700.550630248 6672872.334531408, 2550697.168320218 6672918.5151311895) + +LINESTRING (2552080.145394281 6673330.999808344, 2552067.267867557 6673354.565217286) + +LINESTRING (2553271.7909646197 6672331.730447147, 2553309.2603601236 6672316.446939141, 2553351.654729012 6672284.369576459, 2553361.900653542 6672271.626651589) + +LINESTRING (2553007.682048494 6676005.383656725, 2553006.271377725 6676006.523918448) + +LINESTRING (2548768.3524036007 6676634.418038295, 2548768.154414721 6676647.020931022, 2548817.0659175697 6676739.162080079) + +LINESTRING (2553457.3477926827 6673918.384630135, 2553368.6157763824 6673912.273227392) + +LINESTRING (2553785.2338767163 6673218.283936794, 2553941.0511251246 6673227.276000733) + +LINESTRING (2550707.1420100383 6674958.32332612, 2550688.9600312426 6674974.777102737, 2550585.040617954 6675171.722307353, 2550585.213858224 6675185.965576595) + +LINESTRING (2553636.857710374 6677136.563295143, 2553644.7360178833 6677147.805875639) + +LINESTRING (2552253.088680792 6672172.793966631, 2552186.1766889542 6672165.952396294) + +LINESTRING (2552387.3498899117 6672630.489020874, 2552249.4588846625 6672531.896391016) + +LINESTRING (2552268.3998208307 6672073.281125559, 2552267.0221482087 6672090.435062883) + +LINESTRING (2552210.298334144 6676197.557766237, 2552244.7731478405 6676238.127078067, 2552287.5634944886 6676204.559373308, 2552328.299706509 6676252.960482761) + +LINESTRING (2550999.4395929268 6676040.931816055, 2551073.264696485 6676084.111727092) + +LINESTRING (2551584.183250364 6677169.180781798, 2551552.6535212547 6677235.265950254) + +LINESTRING (2553302.165758597 6672544.049180432, 2553279.4795327857 6672551.920987239) + +LINESTRING (2549489.089672855 6677575.774106717, 2549483.4552393174 6677575.083948306) + +LINESTRING (2549413.3176786457 6671230.407661741, 2549385.1372614196 6671366.5889192745) + +LINESTRING (2552003.3009603056 6676087.112415837, 2551998.8214619 6676091.633453546) + +LINESTRING (2553548.2989343437 6675506.369118467, 2553586.964512663 6675522.4128009565) + +LINESTRING (2553378.308981956 6675698.413198134, 2553378.4492240795 6675698.783283079) + +LINESTRING (2554186.8213212583 6675527.573985597, 2554226.39434861 6675509.909931187, 2554373.49183677 6675472.6113700885) + +LINESTRING (2548594.9883907195 6676006.493911561, 2548604.929082393 6676020.107036166, 2548625.7014156994 6676035.630599272) + +LINESTRING (2551635.99034058 6676720.5178006785, 2551613.040129596 6676809.068125537) + +LINESTRING (2554348.165759228 6673156.739810638, 2554314.8953778837 6673219.284166375) + +LINESTRING (2553887.3466414767 6677312.983788745, 2553932.7438417096 6677359.32442526) + +LINESTRING (2553795.603544296 6675666.425856114, 2553995.0360930185 6675615.344131382) + +LINESTRING (2553510.6645481074 6675701.463898358, 2553488.4485458857 6675700.293629747, 2553378.6637120326 6675701.753964936) + +LINESTRING (2548532.481651457 6677913.871709888, 2548656.1009582863 6677845.055914674, 2548711.7110849023 6677814.088806828, 2548742.605599689 6677792.513854752, 2548766.8262393186 6677769.898663913, 2548876.8503097347 6677627.956083989, 2548905.8061834066 6677564.9516226435) + +LINESTRING (2551490.402517629 6673659.335170798, 2551465.6374085797 6673661.9857791895) + +LINESTRING (2552360.4316517944 6672117.5012753615, 2552400.565647639 6672187.877428723) + +LINESTRING (2548937.352411589 6676552.259180462, 2548940.256248493 6676559.490840337) + +LINESTRING (2551906.43490086 6671776.923102828, 2551795.3878878984 6671740.494741467, 2551728.9956168695 6671713.738600159, 2551700.7657024236 6671694.3841577545, 2551668.7245020415 6671661.246551717, 2551626.5116229593 6671587.909718794) + +LINESTRING (2552785.5962721067 6673513.141615152, 2552766.267607716 6673511.301192722) + +LINESTRING (2553381.2045693235 6675208.450737589, 2553397.5139032975 6675244.609036964, 2553402.2903850228 6675266.914156633, 2553404.6910001906 6675304.092690182, 2553396.4332139953 6675319.626255584) + +LINESTRING (2553033.420602869 6672024.900020697, 2553023.9996320046 6672035.852534615) + +LINESTRING (2553675.4737914735 6675736.161862543, 2553675.9275159896 6675738.582418131) + +LINESTRING (2552487.8622445604 6672410.318485373, 2552481.39460782 6672484.615538694, 2552483.811722061 6672500.92928317) + +LINESTRING (2551708.858497886 6674048.154416052, 2551717.462764621 6674058.216725643, 2551765.689555927 6674150.397883883, 2551774.252574979 6674172.703003552) + +LINESTRING (2552808.521734481 6672946.281504375, 2552800.2309501395 6673040.093036833) + +LINESTRING (2551349.393187523 6674103.407098139, 2551344.7569479207 6674104.177274917) + +LINESTRING (2552117.3260560012 6676671.07645246, 2552148.039080981 6676544.507401205) + +LINESTRING (2552710.8142222962 6675361.675907194, 2552559.1299917544 6675350.793409347, 2552527.2290334953 6675345.632224705, 2552520.2664245553 6675344.511967573, 2552392.6708410564 6675305.753071287, 2552362.5765313255 6675300.39184073) + +LINESTRING (2553211.3631085954 6675027.989316478, 2553143.370427455 6675083.712106469) + +LINESTRING (2553480.3310018135 6676496.446369809, 2553476.9651908567 6676499.447058554) + +LINESTRING (2552398.7095018905 6672619.206431193, 2552387.3498899117 6672630.489020874) + +LINESTRING (2551635.99034058 6676720.5178006785, 2551564.483356823 6676702.513668209) + +LINESTRING (2551530.2807778367 6675662.94505717, 2551550.203408867 6675581.776426624) + +LINESTRING (2550832.5184681765 6675572.254241007, 2550817.5785572873 6675557.160776621) + +LINESTRING (2552733.706686524 6674363.156718183, 2552629.5150385257 6674398.8349073585, 2552625.6212572227 6674406.356633812, 2552620.910771791 6674472.971923946, 2552722.2975773253 6674530.445115705) + +LINESTRING (2547830.4048341243 6672948.171938284, 2547782.706013164 6673175.964223197, 2547776.2631250336 6673220.1143569285, 2547776.114633374 6673256.982819306, 2547781.8480613516 6673283.718956022) + +LINESTRING (2550674.9523179964 6674116.500103362, 2550664.4836559766 6674113.329375588, 2550650.0139686773 6674100.476425465, 2550640.1475228337 6674080.841918779, 2550633.943871266 6674042.0630179, 2550645.8562022015 6673991.161334492, 2550645.410727222 6673981.349082297, 2550637.8129039593 6673962.314713359, 2550616.265114207 6673944.200555637, 2550609.1292649973 6673933.918195537, + 2550602.87611621 6673919.264832167, 2550599.832037183 6673900.880612458, 2550603.0493564797 6673873.6943724295, 2550611.1504014786 6673856.980536122) + +LINESTRING (2553001.2886575833 6672957.1539999265, 2552994.8622685266 6673053.926211947) + +LINESTRING (2551560.8783093034 6672723.220305383, 2551463.3192887786 6672655.414742047) + +LINESTRING (2550509.837841774 6675965.304457391, 2550490.0389537932 6675983.398610522, 2550391.8694675555 6676050.253955755) + +LINESTRING (2547382.7519768802 6672686.15179709, 2547352.8804046395 6672617.556052384) + +LINESTRING (2553270.3472957048 6675135.784058486, 2553180.0973646594 6675129.492614418) + +LINESTRING (2549456.974226643 6672783.074043546, 2549398.130281657 6672818.872260272, 2549328.4051978183 6672844.458132968, 2549301.915935607 6672849.559303835, 2549247.0812654374 6672845.548383213) + +LINESTRING (2551349.6159250126 6674103.367088956, 2551349.393187523 6674103.407098139) + +LINESTRING (2548642.7614575094 6676395.353165997, 2548758.914933663 6676332.778803373) + +LINESTRING (2549485.872353558 6677535.024753562, 2549502.478670852 6677517.680772617, 2549521.9970745863 6677456.316687787, 2549562.2795620905 6677397.083091965) + +LINESTRING (2551120.806776249 6675346.8525047945, 2551082.545425226 6675357.174874077) + +LINESTRING (2549278.1325214207 6675538.666531657, 2549222.052171215 6675576.615241983, 2549201.4365791054 6675599.540503993, 2549191.850617508 6675620.275263219, 2549191.801120288 6675634.038422262) + +LINESTRING (2552842.6418181015 6675292.620056881, 2552885.8281425093 6675295.880805316) + +LINESTRING (2548097.5248311306 6677385.360401268, 2548075.5150673254 6677429.980642904, 2548070.5158481104 6677449.985234535, 2548067.6120112063 6677488.89416526, 2548071.0685670665 6677526.152717174, 2548090.7849596804 6677600.879869215, 2548092.880341992 6677652.181644455) + +LINESTRING (2552408.7574375407 6673338.7315830095, 2552318.9612310114 6673271.776214818) + +LINESTRING (2549006.3185380553 6676357.754536025, 2549024.7315038773 6676405.455484771) + +LINESTRING (2550582.7142486162 6672922.015934725, 2550589.2643807232 6672929.837730054, 2550647.398865557 6672972.077425284, 2550657.999520163 6672973.347716853) + +LINESTRING (2554427.1468231976 6673177.164498694, 2554452.00267715 6673194.558491118) + +LINESTRING (2551931.958967282 6672378.671221412, 2551873.2635139558 6672421.351017659, 2551849.595593282 6672448.047145191) + +LINESTRING (2547988.259718087 6672227.376494899, 2547971.0181864705 6672303.113878818) + +LINESTRING (2551613.040129596 6676809.068125537, 2551540.584449123 6676790.563878277) + +LINESTRING (2551348.1227588775 6675039.96206457, 2551238.7091541737 6675037.991612294) + +LINESTRING (2549112.5973188286 6677000.211998579, 2549106.962885291 6676998.751663391) + +LINESTRING (2553544.9578719973 6676563.851841313, 2553544.215413698 6676566.452438225) + +LINESTRING (2549709.2533072005 6677274.374926895, 2549727.0558073097 6677290.018517551, 2549744.2478417065 6677314.104045875, 2549756.671643914 6677340.920200958, 2549752.3406371684 6677363.415364249, 2549751.8044172856 6677393.642302204) + +LINESTRING (2549162.54001376 6674500.83832009, 2549159.2401990965 6674523.213455831, 2549165.62534047 6674539.967301322, 2549182.9906151365 6674551.269895594, 2549218.620363965 6674576.805756812) + +LINESTRING (2553766.878657651 6676675.6274970565, 2553901.849326923 6676679.838463595, 2553948.896434487 6676643.070024176, 2553986.9845452397 6676557.180310003, 2553950.4143492323 6676520.931989967) + +LINESTRING (2552689.9841422336 6671988.821739689, 2552665.84599797 6672078.382296425) + +LINESTRING (2553304.4673793246 6674957.413117201, 2553311.256747995 6674964.184671468) + +LINESTRING (2553574.9119396047 6676442.674027503, 2553570.1519569526 6676441.513761188) + +LINESTRING (2550706.3913022024 6674939.969113298, 2550699.494689556 6674935.358054927, 2550621.289082032 6674881.005579462, 2550591.8382361606 6674776.4315767065, 2550584.339407338 6674764.808908969, 2550566.1079313224 6674753.706360613) + +LINESTRING (2552817.4477331457 6672794.546676847, 2552810.485124206 6672890.968808513) + +LINESTRING (2552054.934810252 6676918.343207326, 2552036.455848137 6676990.389744088) + +LINESTRING (2550799.998794668 6674969.555904321, 2550779.0367220184 6674988.640284738, 2550768.3535720455 6675015.296403088, 2550758.2231410285 6675084.822361304, 2550750.2293400066 6675100.58597951, 2550736.634103593 6675116.409611491, 2550729.4157590168 6675166.941209953) + +LINESTRING (2552677.906820565 6673285.539373861, 2552669.1210640236 6673406.247079767) + +LINESTRING (2552192.6443256945 6671895.100227893, 2552162.4427719875 6671917.265315422, 2552112.112348833 6671967.386819756, 2552091.9999784594 6671994.202974838, 2552071.8133622557 6672026.100296195, 2552059.4473068044 6672054.976924215, 2552050.5543062864 6672064.16903407) + +LINESTRING (2549966.5811041933 6677201.048096268, 2549976.9837699197 6677229.954731176, 2549976.010324594 6677259.201444142) + +LINESTRING (2551503.742018406 6673652.123515515, 2551490.402517629 6673659.335170798) + +LINESTRING (2552911.063475148 6672951.98281299, 2552904.6453356277 6673047.974845936) + +LINESTRING (2548478.719421053 6676250.2398582995, 2548471.3113371334 6676236.576722215, 2548474.1244291337 6676208.450266381) + +LINESTRING (2549972.3722789274 6675285.618449809, 2549972.0092993146 6675272.9955524895, 2549980.1020947765 6675239.887953339, 2549999.2410198245 6675194.307491305, 2549997.2941291733 6675180.0342151765, 2549972.8590015904 6675148.416958102, 2549969.89741793 6675137.904545199, 2549971.6710683117 6675131.152995524) + +LINESTRING (2553060.644073842 6674756.637033287, 2553075.270502338 6674767.719577051) + +LINESTRING (2553256.4880741183 6674002.824011413, 2553078.578566538 6673990.511185264) + +LINESTRING (2552904.6453356277 6673047.974845936, 2552841.9571065586 6673043.233757719) + +LINESTRING (2552022.74511821 6672148.888479631, 2552001.873790464 6672212.112991484) + +LINESTRING (2548168.124365855 6671897.640811031, 2548200.495547704 6671992.0024697585) + +LINESTRING (2551154.9681075523 6674083.052426154, 2551132.743855794 6674162.540671003) + +LINESTRING (2551528.069902012 6674337.650863852, 2551508.7907348406 6674414.018392407) + +LINESTRING (2551388.9662148743 6676831.1531946985, 2551323.192659095 6676814.979482364) + +LINESTRING (2549395.812161856 6671681.411180082, 2549517.5423247907 6671512.252353243) + +LINESTRING (2551166.9711833904 6674761.498149053, 2551107.1290444685 6674890.877845433, 2551070.2783642146 6674941.749521953, 2551027.08379027 6674989.990594673) + +LINESTRING (2552269.175277277 6676461.388322975, 2552229.0907786526 6676469.600207839, 2552199.953415174 6676469.200116007, 2552176.112254231 6676463.628837237, 2552093.8891223543 6676457.64746434) + +LINESTRING (2548972.1902048984 6677556.679724004, 2548966.861004217 6677556.069583959) + +LINESTRING (2553243.536301564 6676573.534063662, 2553310.629783209 6676647.3510067845) + +LINESTRING (2552739.555608015 6672439.63521441, 2552498.9166236827 6672416.219839904) + +LINESTRING (2551731.78396026 6673845.057799509, 2551679.712884871 6673895.7394324085) + +LINESTRING (2551894.4565736316 6675131.533082765, 2551884.235397712 6675157.539051886, 2551887.5682105217 6675183.465002641) + +LINESTRING (2553701.558826388 6676964.403779559, 2553853.2513064668 6676916.302738979) + +LINESTRING (2554689.003615816 6675483.063769217, 2554673.997708634 6675411.237282962, 2554645.842040018 6675276.456346842, 2554539.5880078548 6675080.421351145, 2554519.4921365543 6675024.808586408, 2554503.1993016535 6675004.303879986) + +LINESTRING (2553210.7361438093 6675702.444123347, 2553255.448632499 6675777.9514544625, 2553136.3335726853 6675843.806570115, 2553036.877158729 6675914.892886478) + +LINESTRING (2551999.085447073 6675223.374162947, 2551999.836154909 6675231.335990416, 2552005.198353737 6675330.548762615, 2552011.3030108646 6675365.086690067, 2552030.169701203 6675410.377085522, 2552054.712072762 6675461.248762041, 2552048.7806559047 6675498.237251969, 2551956.270351815 6675854.0589233255, 2551924.6168796555 6675975.806867997, 2551878.3452285375 6676036.390773755, + 2551873.568746812 6676050.864095801) + +LINESTRING (2551433.3982193177 6673228.386255568, 2551424.051494283 6673230.496739985) + +LINESTRING (2548605.9107772554 6675559.371283996, 2548595.2441263557 6675550.059146591, 2548561.0085492227 6675514.49098267) + +LINESTRING (2553172.078815027 6676175.132619018, 2553121.4349094797 6676223.603744541) + +LINESTRING (2551592.0780569464 6676894.527740988, 2551535.783218788 6676880.344485521, 2551520.8268088256 6676869.451985378) + +LINESTRING (2552705.7820049347 6675432.572179938, 2552534.9011025876 6675418.879036965) + +LINESTRING (2553501.804545736 6675744.633807099, 2553398.0666222535 6675779.061709298) + +LINESTRING (2552125.790080613 6672703.615805584, 2552065.320976905 6672790.54575852) + +LINESTRING (2551651.7139574517 6676399.724169269, 2551634.3321837117 6676410.656678596, 2551631.593337541 6676420.688981299, 2551618.6828126702 6676472.390848372) + +LINESTRING (2553609.947721794 6676055.125073818, 2553547.3172394815 6676053.524706488, 2553491.401880009 6676038.891347708) + +LINESTRING (2552275.9398973365 6673509.820852942, 2552275.651163554 6673509.600802434) + +LINESTRING (2548828.4502781588 6672776.87262014, 2548832.525549268 6672807.819723395) + +LINESTRING (2553481.741672582 6674232.366698094, 2553434.3233358683 6674261.343349073) + +LINESTRING (2553670.9777939944 6673151.3385708975, 2553805.0740123806 6673063.04830573) + +LINESTRING (2552932.009048724 6672051.656162005, 2552909.710551136 6672140.6265832875) + +LINESTRING (2553248.6180161457 6676044.322594336, 2553284.1240219246 6676080.130813357) + +LINESTRING (2554628.592258865 6675609.082694202, 2554618.8495560708 6675592.478883147, 2554608.5623838576 6675549.84909838, 2554616.7129260763 6675534.875661543, 2554630.959875886 6675521.212525458, 2554637.8564885324 6675500.547782303, 2554633.59147808 6675465.359705622, 2554623.0238216203 6675421.849718823, 2554615.458996504 6675390.722574243, 2554594.686663198 6675384.011033751, + 2554435.9490788123 6675418.588970386, 2554418.1960759233 6675429.631504968, 2554413.4278437346 6675436.513084489, 2554417.3463736475 6675464.429492111, 2554417.577360674 6675465.189666593, 2554433.705204841 6675518.5819216585, 2554453.2236085758 6675553.930035072) + +LINESTRING (2551832.205570006 6673236.458108292, 2551686.7332405676 6673273.27655919) + +LINESTRING (2552859.5616177884 6673878.415456055, 2552881.315645957 6673879.1456236495) + +LINESTRING (2551126.696945423 6674160.830278418, 2551010.510471123 6674129.593108585) + +LINESTRING (2552965.9063948547 6671923.686789336, 2552984.8143328764 6671922.006403638, 2553000.430705771 6671913.354417758, 2553136.6388055417 6671827.364680628) + +LINESTRING (2553217.0387898167 6675881.695266665, 2553206.4793828935 6675916.143173455, 2553201.7441488514 6675946.3501068195) + +LINESTRING (2552498.4628991666 6676774.4501797175, 2552471.6106573427 6676767.9386851415, 2552396.135646453 6676748.2741715675, 2552321.658829499 6676728.859715389) + +LINESTRING (2554429.1597101423 6676121.850389206, 2554406.572478771 6676113.638504341, 2554385.791895928 6676101.185646051, 2554362.7756886506 6676066.617711711, 2554376.2801801604 6676032.549892161, 2554377.773346296 6676022.447573387, 2554374.828261709 6676016.516211968, 2554346.812835216 6675966.984843087) + +LINESTRING (2547873.426167799 6672736.283303719, 2547884.785779778 6672749.516341084, 2547916.3072593505 6672756.8680285085, 2547939.174974968 6672759.738687407, 2547955.566804309 6672757.418154778, 2547968.4113328867 6672749.226274505, 2547975.844165416 6672737.33354478, 2547977.477573674 6672724.620626798, 2547974.3839974273 6672712.217779986, 2547968.3123384467 6672704.125922671, + 2547948.818683322 6672694.033606193, 2547920.7125119264 6672681.830805297) + +LINESTRING (2550948.0037318603 6675344.031857374, 2550915.244821789 6675393.543221664) + +LINESTRING (2551513.327980003 6674483.304295525, 2551398.0159565886 6674494.136781894) + +LINESTRING (2552685.7521299277 6675175.6432073135, 2552720.0207052073 6675222.293914999) + +LINESTRING (2551136.70363339 6672030.9214027785, 2551110.0823785923 6671906.722895632, 2551120.270556366 6671890.589192481) + +LINESTRING (2550817.034087868 6673801.027693327, 2550802.3251640056 6673777.652328005) + +LINESTRING (2553052.246045524 6675578.855756246, 2553044.8379616044 6675707.055181718) + +LINESTRING (2549972.3722789274 6675285.618449809, 2549900.4775669477 6675292.219965048, 2549883.937245947 6675298.161328763, 2549878.641043412 6675305.392988637, 2549875.687709288 6675363.916421456, 2549867.9991411227 6675427.120928718) + +LINESTRING (2554429.1597101423 6676121.850389206, 2554510.19490874 6676193.726886939) + +LINESTRING (2553179.189915627 6676182.39428578, 2553193.4616140462 6676196.987635376) + +LINESTRING (2548768.484396187 6676625.876077668, 2548712.4122955184 6676660.293977571, 2548639.8576206057 6676699.823050635) + +LINESTRING (2549854.4699010025 6676293.439773928, 2549818.6834109775 6676321.926312412) + +LINESTRING (2548672.723774654 6676058.695893425, 2548650.2767854054 6676182.624338584) + +LINESTRING (2551919.6341595137 6673281.248388955, 2551890.1090678126 6673280.268163965, 2551880.2013742854 6673268.035356183) + +LINESTRING (2551753.9422157253 6673510.250951662, 2551673.154503227 6673459.269249887, 2551655.7479808778 6673452.047592308) + +LINESTRING (2549907.3411814477 6676348.252355, 2549818.6834109775 6676321.926312412) + +LINESTRING (2551138.2462967453 6674164.10102915, 2551132.743855794 6674162.540671003) + +LINESTRING (2550808.454569743 6675266.964168113, 2550780.4556423235 6675311.55440286) + +LINESTRING (2553547.036755235 6676556.150073535, 2553545.9395668595 6676560.361040073, 2553544.9578719973 6676563.851841313) + +LINESTRING (2549130.2678263513 6672089.474842485, 2549124.59214513 6672070.870572267) + +LINESTRING (2552270.379709629 6672251.59205307, 2552222.5653951555 6672317.377152652) + +LINESTRING (2552973.6609593136 6675416.438476786, 2552951.370711262 6675393.493210184) + +LINESTRING (2548499.7227413855 6671940.530655489, 2548460.0177214476 6671918.765659794, 2548410.3802593728 6671897.950882201, 2548337.0088803307 6671880.666915031) + +LINESTRING (2551422.005609192 6673330.089599425, 2551379.2647597636 6673289.070184284) + +LINESTRING (2553933.3460578853 6673124.282360716, 2553953.829657409 6673110.059096065, 2554049.235548866 6673047.824811499) + +LINESTRING (2551238.7091541737 6675037.991612294, 2551182.323571112 6675106.617363887) + +LINESTRING (2552872.472142659 6673518.93294443, 2552867.3904280774 6673610.51396492) + +LINESTRING (2553506.539779778 6675989.219946686, 2553500.468120797 6675986.279271716) + +LINESTRING (2552116.3031134554 6672159.020805294, 2552022.74511821 6672148.888479631) + +LINESTRING (2553272.3601826495 6674925.315749927, 2553181.2193016447 6674994.361597945) + +LINESTRING (2551675.596366078 6672560.723007558, 2551619.8624964124 6672639.221025121) + +LINESTRING (2552238.1652689767 6677047.272800393, 2552210.496323024 6677039.921112969) + +LINESTRING (2553853.2513064668 6676916.302738979, 2553869.098666388 6676902.529577641, 2553874.35362124 6676889.326547164, 2553875.335316102 6676875.273321543) + +LINESTRING (2553064.108879239 6676298.801004486, 2553003.6562746046 6676350.1027797265, 2553034.5095417076 6676389.601845903, 2553063.3499218663 6676427.160466692) + +LINESTRING (2553075.270502338 6674767.719577051, 2553135.203386163 6674688.311350568, 2553164.942965817 6674647.952086951, 2553169.719447543 6674624.686746883) + +LINESTRING (2548381.4326352375 6676426.870400113, 2548306.3041048874 6676519.7117098775, 2548275.4590873206 6676549.548558296) + +LINESTRING (2550330.047439836 6672702.395525495, 2550210.858134192 6672667.677556718) + +LINESTRING (2552135.6565264566 6672092.005423326, 2552116.3031134554 6672159.020805294) + +LINESTRING (2551375.3132317043 6673964.885303384, 2551370.503751832 6673963.615011815) + +LINESTRING (2554011.683657996 6675583.416803137, 2554009.365538195 6675583.956927111) + +LINESTRING (2548616.8661619383 6672245.690698538, 2548621.246665904 6672251.612057662, 2548653.172372773 6672422.691325298, 2548639.8246224592 6672424.961846448) + +LINESTRING (2551458.163328367 6673872.90419106, 2551403.881377153 6673861.881661071) + +LINESTRING (2551417.0146395136 6676405.98560645, 2551381.360142075 6676397.223595315, 2551349.071455593 6676416.277968844, 2551334.692513197 6676477.602044492, 2551356.6197816357 6676511.8799122535, 2551378.530551001 6676517.991314997) + +LINESTRING (2550833.4836639655 6675869.752525461, 2550887.460382323 6675939.538543369) + +LINESTRING (2549247.0812654374 6672845.548383213, 2549184.987003008 6672841.267400604) + +LINESTRING (2553532.6743119126 6673185.456401926, 2553521.784923523 6673168.482505926, 2553634.0281193005 6673094.815597242) + +LINESTRING (2554126.7481953106 6677564.881606573, 2554136.325907371 6677577.5645176675, 2554153.674682964 6677612.782601235, 2554188.215492954 6677694.001243262, 2554236.805263873 6677810.818056095) + +LINESTRING (2549147.600102871 6671811.280988956, 2549087.155747773 6671835.766609114, 2549023.337332182 6671822.0034500705) + +LINESTRING (2554136.8043804974 6672976.648474473, 2554199.8968368624 6673020.008426835) + +LINESTRING (2550628.1856946787 6675291.009687254, 2550586.8967637024 6675200.808983586, 2550585.213858224 6675185.965576595) + +LINESTRING (2551355.9928168496 6672543.769116149, 2551327.3586751074 6672469.292021504) + +LINESTRING (2551217.6480870843 6672787.2850100845, 2551223.793991895 6672702.8256242145) + +LINESTRING (2552861.3352681696 6675041.022307926, 2552913.992060662 6675108.397772542, 2552949.8940442 6675112.718764335, 2552968.340008169 6675103.746704988) + +LINESTRING (2552343.1571220313 6672403.776983909, 2552222.5653951555 6672317.377152652) + +LINESTRING (2552227.2511319774 6673298.412328576, 2552146.09219033 6673240.589056464) + +LINESTRING (2548594.0479435404 6676199.928310346, 2548523.1679245695 6676221.733315224, 2548516.0898221163 6676225.894270283, 2548500.8199297613 6676253.8306824975) + +LINESTRING (2553513.0239155916 6675335.189827873, 2553526.313919149 6675457.6179286605, 2553535.635895573 6675490.305431387, 2553542.9862327357 6675506.95925392) + +LINESTRING (2553722.001178228 6675102.756477702, 2553719.84804916 6675104.546888653) + +LINESTRING (2553270.3472957048 6675135.784058486, 2553292.38180812 6675144.28600993, 2553301.406801224 6675151.717715722, 2553389.0168805392 6675286.878739082, 2553387.3174759876 6675305.573029962, 2553396.4332139953 6675319.626255584) + +LINESTRING (2549819.5166141796 6677095.683912143, 2549720.0354516134 6676995.820990716) + +LINESTRING (2549563.904720812 6672711.237554996, 2549460.1997954766 6672780.91354765, 2549456.974226643 6672783.074043546) + +LINESTRING (2551662.3888578876 6673646.772287253, 2551658.899303881 6673651.903465007) + +LINESTRING (2553525.5384627027 6674020.678109446, 2553529.522988909 6673971.076724494, 2553533.8044984345 6673961.534534286, 2553545.51884049 6673950.411981339) + +LINESTRING (2553391.442244317 6676304.272260297, 2553376.667324161 6676318.205458369) + +LINESTRING (2549025.952435303 6672226.416274501, 2549044.2334085386 6672322.608353363) + +LINESTRING (2552246.5797963687 6675914.24273725, 2552316.148139011 6675998.602100162, 2552366.965284828 6675955.152127137) + +LINESTRING (2551825.407951799 6673124.782475507, 2551801.1295654126 6673120.011380402, 2551661.514407002 6673021.638801052) + +LINESTRING (2548155.8325562337 6676774.85027155, 2548102.3838082226 6676803.586867429) + +LINESTRING (2553677.1649464886 6676162.439705627, 2553622.610760565 6676152.527430474, 2553560.4587513786 6676211.180893138) + +LINESTRING (2550776.0256411377 6675619.855166795, 2550752.167981121 6675631.477834533, 2550574.2914716876 6675776.061020553) + +LINESTRING (2552847.53379334 6675231.235967458, 2552881.9508602796 6675233.456477129, 2552893.7559472383 6675234.216651611, 2552962.7385727777 6675287.52888831, 2552970.2621502103 6675288.579129371) + +LINESTRING (2548008.8175634407 6672181.105874455, 2547988.259718087 6672227.376494899) + +LINESTRING (2551924.608630119 6673968.396109215, 2551933.96360469 6673947.37128341, 2551890.472047426 6673874.094464263) + +LINESTRING (2553194.6165491785 6675154.058252942, 2553150.3000382483 6675182.89487178, 2553138.3299605567 6675184.435225335, 2553112.492411742 6675202.859454229, 2553108.136656386 6675209.631008496, 2553103.8716459335 6675268.684562993) + +LINESTRING (2551230.7978485185 6673825.183237722, 2551224.519951121 6673823.852932379) + +LINESTRING (2548409.3490672903 6672539.118048595, 2548401.3222681214 6672567.384536571) + +LINESTRING (2553466.348037177 6673655.7443466, 2553485.148731222 6673735.572669507) + +LINESTRING (2553394.2553363172 6675336.7501860205, 2553376.0981061314 6675330.688794756, 2553311.2897461415 6675320.656492053, 2553302.7762243096 6675316.665576022, 2553280.774710041 6675290.619597717) + +LINESTRING (2551672.841020834 6676567.80274816, 2551653.759842543 6676648.441257029) + +LINESTRING (2551845.421327733 6673126.922966811, 2551871.4321168177 6673231.22690758) + +LINESTRING (2552389.684508786 6676201.32863176, 2552328.299706509 6676252.960482761) + +LINESTRING (2553396.4332139953 6675319.626255584, 2553394.2553363172 6675336.7501860205) + +LINESTRING (2547673.2016635574 6672803.978841801, 2547658.3359984984 6672803.0786351785, 2547575.386907396 6672830.9850405045) + +LINESTRING (2553238.7845684486 6676995.460908067, 2553177.177028682 6677003.472747016, 2553148.9966114564 6676999.151755223, 2553142.867205719 6676968.46471166) + +LINESTRING (2547970.531463808 6673861.74162893, 2547968.0731018833 6673884.196783037, 2547976.7433649115 6673921.085250006, 2547971.51315867 6673970.53660052, 2547966.0354663287 6673981.489114438) + +LINESTRING (2551562.9076953214 6672521.093911535, 2551522.3364740345 6672575.816471944, 2551463.3192887786 6672655.414742047) + +LINESTRING (2552178.768605035 6672482.044948669, 2552141.472449801 6672536.617474641, 2552153.3187844427 6672560.252899654, 2552203.3439747407 6672596.1711439295) + +LINESTRING (2552878.6675446895 6674750.075527232, 2552873.899312501 6674769.630015552) + +LINESTRING (2550839.241840553 6672755.957819589, 2550848.6793104904 6672658.8755364) + +LINESTRING (2547892.251610454 6672653.174227784, 2547892.4331002603 6672653.104211714) + +LINESTRING (2551764.122143962 6673339.771821775, 2551699.338532582 6673290.820586051, 2551690.173297354 6673282.138593283, 2551686.7332405676 6673273.27655919) + +LINESTRING (2548995.0001737596 6676208.860360509, 2548968.387168499 6676255.9511692105, 2548959.6261605676 6676296.040370841, 2548947.969565269 6676316.775130067) + +LINESTRING (2553363.6083076303 6676465.00915406, 2553430.7842846415 6676540.6965264985) + +LINESTRING (2551869.00675304 6673620.5562699195, 2551799.743643254 6673574.965805591) + +LINESTRING (2549805.7481374964 6676012.335252318, 2549851.805300662 6675947.4303547675, 2549884.4899649033 6675910.291830403, 2549889.5304318015 6675901.299766464, 2549888.358997596 6675878.784598582) + +LINESTRING (2553112.4016668387 6673434.35353101, 2553108.070660093 6673450.797305332, 2553106.907475424 6673495.867650278, 2553112.030437689 6673518.282795202) + +LINESTRING (2554061.725347367 6673270.4559117695, 2554040.408544641 6673309.844952693, 2554045.5892536626 6673323.128001537) + +LINESTRING (2546874.984746005 6677366.115984119, 2547013.139736427 6677294.529552964) + +LINESTRING (2553410.886402221 6674736.8424898675, 2553423.037969719 6674726.15003564) + +LINESTRING (2550389.617344048 6675636.388961779, 2550382.3660013247 6675657.583826613, 2550401.381183323 6675692.631871152, 2550421.963777286 6675704.894685823, 2550448.065311274 6675711.066102341, 2550491.9033490783 6675711.406180399) + +LINESTRING (2554383.251038637 6673258.043062663, 2554422.9148108917 6673280.538225953, 2554393.620706217 6673334.840689938) + +LINESTRING (2547680.6179970135 6672805.239131074, 2547673.2016635574 6672803.978841801) + +LINESTRING (2552833.5590782403 6673841.386956944, 2552854.6036462565 6673878.245417026) + +LINESTRING (2549360.0751690506 6672276.497769652, 2549336.184510887 6672395.064984254, 2549328.726929748 6672406.747665767) + +LINESTRING (2552350.466211511 6676058.945950819, 2552303.6418414363 6676096.304525692) + +LINESTRING (2553078.108342949 6672215.473762878, 2553042.4950931934 6672305.494425222) + +LINESTRING (2551441.26827729 6676467.169649956, 2551458.15507883 6676471.6406761855, 2551467.4358075713 6676486.134002823, 2551454.2118003075 6676538.886110956) + +LINESTRING (2553139.113666539 6674623.78654026, 2553169.719447543 6674624.686746883) + +LINESTRING (2554336.4761657827 6675725.299369287, 2554333.258846486 6675718.607833386) + +LINESTRING (2553578.599482491 6672290.310940173, 2553499.816407401 6672266.725526639) + +LINESTRING (2552925.557911057 6674460.349026627, 2552918.4798086043 6674594.769880097, 2552917.786847525 6674607.622830221) + +LINESTRING (2552103.912309394 6674035.331472816, 2552084.14641956 6674019.7879051175) + +LINESTRING (2554412.3554039686 6675566.242861222, 2554390.57662719 6675476.172187399, 2554389.0999601283 6675470.040780064, 2554388.472995342 6675467.460187743, 2554379.431503164 6675430.071605983, 2554375.158243175 6675410.9972278625, 2554288.1503800363 6675429.891564659, 2554273.8456834704 6675439.653805375, 2554238.446921668 6675479.002837115, 2554207.3379189284 6675494.726446138, + 2554173.8860477777 6675504.448677671, 2554079.6020933064 6675514.631014812, 2554042.000705216 6675510.840144698, 2554007.4763943 6675496.876939738, 2553978.9164983877 6675474.841882056, 2553933.700787962 6675426.800855252, 2553991.158810789 6675540.406931129, 2554008.458089162 6675550.689291228, 2554046.6369448183 6675568.053276764, 2554062.0553288334 6675571.724119329, + 2554093.4943130394 6675575.6750261765, 2554099.6319683134 6675575.384959597, 2554162.3449459923 6675572.354263965, 2554200.2515669386 6675562.872087532, 2554275.4873412657 6675529.864511339, 2554327.5254185083 6675517.011561216, 2554364.772076522 6675514.701030882, 2554378.4168101554 6675519.092038745, 2554390.2218971136 6675529.964534298, 2554412.3554039686 6675566.242861222, + 2554425.736152429 6675609.322749301, 2554468.641992591 6675824.642171331, 2554480.909053602 6675905.650765144, 2554476.825532956 6675953.481743736, 2554451.334464681 6676058.205780929, 2554429.1597101423 6676121.850389206, 2554414.8467640397 6676158.238741385, 2554379.8934772173 6676217.332305065, 2554291.7966752397 6676321.246156297, 2554048.9550646194 6676589.457718601, + 2553915.7250475828 6676736.621496942, 2553857.3925738693 6676805.917402355, 2553716.66372801 6676949.040253185, 2553701.558826388 6676964.403779559) + +LINESTRING (2551050.380481794 6676014.395725255, 2551042.279436795 6676028.979072555) + +LINESTRING (2551538.4973163484 6673054.476338216, 2551573.186617998 6673194.328438315) + +LINESTRING (2553295.4341366836 6676235.586494929, 2553376.667324161 6676318.205458369) + +LINESTRING (2547544.550139366 6672841.367423561, 2547323.437808305 6672915.76449984) + +LINESTRING (2553480.28975413 6676596.439321081, 2553496.8795723505 6676603.560955702, 2553534.563455807 6676611.812849751) + +LINESTRING (2547688.4220586927 6671938.630219284, 2547751.8279974507 6671890.749229213, 2547781.815063205 6671864.313161372) + +LINESTRING (2551691.2787352665 6676490.985116294, 2551672.841020834 6676567.80274816) + +LINESTRING (2551871.4321168177 6673231.22690758, 2551832.205570006 6673236.458108292) + +LINESTRING (2548499.7227413855 6671940.530655489, 2548540.4259552592 6671865.733487378, 2548540.2032177695 6671862.14266318, 2548536.7961591296 6671858.001712712, 2548470.478133931 6671825.244193915, 2548401.0252848016 6671801.218679365, 2548349.498678832 6671792.986789908) + +LINESTRING (2553769.510259845 6677815.879217778, 2553671.97598793 6677718.726918519, 2553652.3668392925 6677695.211521055, 2553640.3472643807 6677626.775813082, 2553644.331790587 6677613.362734393, 2553545.9973136163 6677513.6598497, 2553651.9296138496 6677408.825787253) + +LINESTRING (2553362.238884545 6674010.265719501, 2553256.4880741183 6674002.824011413) + +LINESTRING (2553777.2400756944 6673026.169841057, 2553796.700732672 6673056.456792788, 2553805.0740123806 6673063.04830573) + +LINESTRING (2553137.735993917 6672468.141757485, 2553122.548596929 6672469.622097266, 2552850.64386866 6672373.590055137) + +LINESTRING (2554201.9262228804 6673221.8547564, 2554289.3300637784 6673267.365202363) + +LINESTRING (2548672.723774654 6676058.695893425, 2548762.0250089834 6676100.105398103, 2548787.3180883788 6676110.747840851) + +LINESTRING (2551302.5853165216 6672478.3741061045, 2551292.9663567776 6672469.262014616, 2551260.9499050057 6672387.213182039, 2551229.33768053 6672340.972568481) + +LINESTRING (2552651.4093088177 6676573.384029225, 2552698.406919162 6676542.1468593925, 2552735.637078102 6676535.095240842) + +LINESTRING (2553470.3408129197 6675572.594319065, 2553560.7969823815 6675669.756620621, 2553561.778677244 6675698.003104005) + +LINESTRING (2549255.6937817093 6675409.146803136, 2549256.4857372283 6675255.791603686) + +LINESTRING (2552841.833363509 6675831.963851868, 2552844.803196706 6675835.484659996) + +LINESTRING (2548642.7614575094 6676395.353165997, 2548706.2746402444 6676511.199756138) + +LINESTRING (2550691.5338866804 6672743.7150095105, 2550592.003226894 6672735.4731177585) + +LINESTRING (2550706.3913022024 6674939.969113298, 2550707.1420100383 6674958.32332612) + +LINESTRING (2550578.80396824 6671730.592468609, 2550450.4741759785 6671955.414071664) + +LINESTRING (2551404.1536118626 6672792.616233755, 2551406.587225177 6672821.662900805, 2551411.949424005 6672836.316264175, 2551458.0890825368 6672869.863964342) + +LINESTRING (2551455.746214126 6673563.933273306, 2551448.5938658426 6673542.218289089, 2551445.1950567393 6673509.880866717) + +LINESTRING (2551122.7041696804 6675711.97631126, 2551027.2157828566 6675701.483902949) + +LINESTRING (2552212.113232209 6673461.839839912, 2552147.7668462717 6673412.808585823) + +LINESTRING (2552883.7245106613 6672239.799346303, 2552708.001130296 6672220.484913082) + +LINESTRING (2547919.3513383777 6672037.772975412, 2547917.4126972626 6672072.730999289, 2547919.3348393044 6672089.184775907, 2547941.9715678957 6672164.342026668, 2548008.8175634407 6672181.105874455) + +LINESTRING (2547822.9555025217 6675118.270038513, 2547815.8774000686 6675135.994106699, 2547787.639236086 6675171.432240775, 2547832.689955779 6675216.082489297, 2547969.0712958192 6675331.919077141, 2547992.9702035193 6675351.2235080665, 2548071.4397962163 6675384.621173795, 2548114.2713905475 6675401.815120303, 2548130.036255102 6675412.527579122, 2548133.360818376 6675415.518265571, + 2548161.7639730913 6675445.2650933275, 2548197.1462358204 6675461.698865353, 2548265.4029021338 6675448.585855539, 2548284.533577645 6675458.298084776, 2548320.2128236936 6675473.841652474, 2548327.4889150267 6675467.790263506, 2548394.1946684485 6675373.758680539) + +LINESTRING (2548937.352411589 6676552.259180462, 2548815.5315037514 6676605.441387315, 2548768.484396187 6676625.876077668) + +LINESTRING (2547553.4348903475 6672766.520243971, 2547523.7778060595 6672778.823067824) + +LINESTRING (2551183.5280034645 6675613.4036859935, 2551208.35085927 6675648.341705279, 2551226.400845479 6675678.278576656, 2551263.861991446 6675722.718776966) + +LINESTRING (2552511.98388975 6676505.76850951, 2552553.7842919994 6676511.5998479705, 2552589.2078024116 6676524.672848602, 2552619.137121409 6676542.797008621, 2552651.4093088177 6676573.384029225) + +LINESTRING (2551173.7605520603 6673670.577751296, 2551136.8603745867 6673805.238659865) + +LINESTRING (2550955.7665458564 6671748.946681431, 2550924.7647870933 6671798.608080157, 2550838.3096429105 6671750.977147481) + +LINESTRING (2550661.109595483 6675351.45356087, 2550653.817005077 6675339.81088854) + +LINESTRING (2549795.757948603 6676017.0063244635, 2549779.102134089 6675997.05174431, 2549712.5613714005 6675949.000715211, 2549685.8081240165 6675916.403233146) + +LINESTRING (2549328.726929748 6672406.747665767, 2549331.507023602 6672421.851132449, 2549326.1448247735 6672446.546800818) + +LINESTRING (2553221.831770615 6675582.566607993, 2553209.226478601 6675582.396568964) + +LINESTRING (2554009.365538195 6675583.956927111, 2554014.3977555563 6675594.989459396) + +LINESTRING (2551863.776546798 6673999.603272161, 2551820.4664793406 6674029.830210117) + +LINESTRING (2553001.9073728328 6676024.287995817, 2553011.047859451 6676035.290521215) + +LINESTRING (2548911.3581215777 6677552.868849298, 2548910.599164205 6677542.696514454, 2548894.8342996505 6677531.013832941, 2548761.0020664376 6677528.1531763375, 2548756.134839809 6677524.542347548, 2548757.4300170643 6677447.924761597, 2548760.7710794113 6677439.552839999) + +LINESTRING (2549077.8915181058 6676275.975765434, 2549095.2897909186 6676295.980357066, 2549124.6828900333 6676320.435970336) + +LINESTRING (2552052.253710838 6672642.651812586, 2551976.613709215 6672545.169437564, 2551946.024427285 6672514.9625042) + +LINESTRING (2551551.655327319 6676622.915398106, 2551521.882749518 6676641.889753269, 2551510.382895416 6676676.017586593, 2551507.5450548055 6676688.010339276) + +LINESTRING (2552949.778550687 6675961.593605643, 2552994.7880226965 6676015.726030599, 2552995.1510023093 6676016.166131615) + +LINESTRING (2554379.431503164 6675430.071605983, 2554367.1066953964 6675424.100235381, 2554353.3217196395 6675423.900189465, 2554294.1890408704 6675436.4830776015, 2554281.855983566 6675442.054356371, 2554269.580673018 6675455.857524597, 2554268.0380096626 6675465.76979975, 2554271.923541429 6675474.811875168, 2554289.198071192 6675483.313826611) + +LINESTRING (2548669.62194887 6672165.182219516, 2548629.306463219 6672152.449296942, 2548615.0925115566 6672144.657508502, 2548442.149225045 6672027.670656638) + +LINESTRING (2552665.84599797 6672078.382296425, 2552708.001130296 6672220.484913082) + +LINESTRING (2550348.5181524144 6672712.20777769, 2550343.865413739 6672709.737210624) + +LINESTRING (2549574.587870785 6672493.267524575, 2549538.3806543904 6672527.685424478) + +LINESTRING (2552093.938619574 6676362.085530113, 2552098.558360103 6676362.415605876) + +LINESTRING (2549326.1448247735 6672446.546800818, 2549119.807413868 6672406.457599188, 2549077.182057953 6672407.657874686, 2549063.058851193 6672410.918623122) + +LINESTRING (2548574.620284709 6672699.644894145, 2548705.9364092415 6672731.972314223, 2548736.5339407083 6672735.183051179, 2548754.3116922076 6672731.622233869, 2548770.0930558355 6672725.5208334215, 2548784.678236648 6672715.07843659, 2548794.495185272 6672701.275268364, 2548801.829023361 6672684.271365476, 2548809.996064653 6672643.512010026) + +LINESTRING (2551639.6118871733 6673470.691871709, 2551567.55218446 6673434.563579222, 2551509.392951017 6673395.794680639) + +LINESTRING (2553275.9652301692 6673721.07934287, 2553219.7776359874 6673717.488518672) + +LINESTRING (2553103.8716459335 6675268.684562993, 2553073.7113399096 6675267.234230099) + +LINESTRING (2553584.547398422 6675077.290632555, 2553603.58732903 6675089.783500029, 2553670.887049091 6675123.511241521, 2553688.0130871944 6675129.492614418, 2553694.431226715 6675125.751755783) + +LINESTRING (2553071.9954362847 6674487.645291909, 2553066.311505527 6674620.17571147) + +LINESTRING (2549078.518482892 6671515.843177441, 2549038.92070693 6671689.052934085) + +LINESTRING (2551538.4973163484 6673054.476338216, 2551467.823535794 6673072.66051201, 2551502.2900999538 6673211.672419259) + +LINESTRING (2553266.585506988 6675361.155787812, 2553293.561491862 6675401.385021583) + +LINESTRING (2552760.872410741 6674986.329754405, 2552621.125259744 6675091.723945417) + +LINESTRING (2547945.8323510517 6672417.580152135, 2547791.3185294354 6672384.562573647) + +LINESTRING (2553319.63827724 6676115.9590369705, 2553259.6476466586 6676174.48246979) + +LINESTRING (2552376.0067770057 6676504.918314366, 2552364.094446071 6676554.389669471, 2552321.658829499 6676728.859715389) + +LINESTRING (2553781.42259078 6677475.131006217, 2553733.57527816 6677483.712976026, 2553724.929763742 6677480.2121724915, 2553651.9296138496 6677408.825787253) + +LINESTRING (2552686.56058452 6672754.707532612, 2552520.4974115817 6672638.460850639) + +LINESTRING (2548566.1727591706 6677126.911079681, 2548561.2972830054 6677146.435561113, 2548554.5491620186 6677173.441759816) + +LINESTRING (2548204.9172993526 6672577.186786471, 2548100.7339008907 6672588.679424363, 2548021.6950901644 6672605.643318067, 2547920.50627351 6672635.070072358) + +LINESTRING (2551482.2107277266 6674984.909428399, 2551419.852480124 6674939.328966365) + +LINESTRING (2551337.5056051975 6674079.57162721, 2551337.0023834617 6674078.751438953) + +LINESTRING (2552894.242669901 6677276.845493961, 2552868.842346529 6677328.447338075) + +LINESTRING (2550574.0522351246 6672733.982775682, 2550591.8217370873 6672639.351054966) + +LINESTRING (2552416.008780264 6676004.983564893, 2552350.466211511 6676058.945950819) + +LINESTRING (2550305.4720701296 6676712.665998463, 2550319.603526426 6676708.114953866, 2550358.986814434 6676710.765562258, 2550374.264956326 6676708.565057178, 2550419.4311695322 6676691.251083121, 2550483.3073318796 6676692.771432085, 2550494.8319345918 6676690.410890272, 2550508.2044335157 6676682.489071986, 2550520.0507681575 6676671.396525926, 2550528.589038599 6676657.773399024, + 2550535.328910049 6676638.418956621, 2550543.784685124 6676559.450831154) + +LINESTRING (2552706.5574613805 6672882.976974156, 2552692.5414985977 6673061.627979725) + +LINESTRING (2551132.743855794 6674162.540671003, 2551126.696945423 6674160.830278418) + +LINESTRING (2548570.033542327 6675432.772225854, 2548526.8142197724 6675418.729002528) + +LINESTRING (2553330.849397559 6676983.47815768, 2553238.7845684486 6676995.460908067) + +LINESTRING (2552657.6542080683 6675811.769216616, 2552641.9140921235 6675816.30025662, 2552596.244657181 6675853.968902663, 2552590.024506541 6675868.522243075) + +LINESTRING (2551871.4321168177 6673231.22690758, 2551880.2013742854 6673268.035356183) + +LINESTRING (2552782.3212060533 6673285.5993876355, 2552777.0415025917 6673358.90621367) + +LINESTRING (2551463.451281365 6675895.268382087, 2551467.4770552544 6675888.946931132) + +LINESTRING (2552303.6418414363 6676096.304525692, 2552389.684508786 6676201.32863176) + +LINESTRING (2547743.636207549 6675073.6597991735, 2547725.6439680965 6675076.490448889, 2547677.2356869834 6675058.496318717, 2547636.771709673 6675048.904117029, 2547558.4588581724 6675044.473099982, 2547539.988145594 6675039.401936004, 2547498.9302016436 6675002.653501176, 2547471.178760324 6674967.065332663) + +LINESTRING (2547867.255514378 6673234.787724891, 2547845.6499778694 6673261.033749111, 2547829.291146675 6673272.336343383, 2547811.760881276 6673279.317945863, 2547781.8480613516 6673283.718956022) + +LINESTRING (2550488.116811752 6672823.123235993, 2550464.160157295 6672807.159571871, 2550420.9243356674 6672772.641649011) + +LINESTRING (2553169.5132091264 6676352.803399596, 2553165.0089621106 6676347.372152968) + +LINESTRING (2548945.4699556613 6671269.13655114, 2548928.781143001 6671341.783225651) + +LINESTRING (2551506.1838812567 6676962.873428298, 2551525.6445382345 6676994.560701444, 2551527.01396132 6677015.125421641, 2551515.621351194 6677049.0932182325, 2551487.490431188 6677068.067573395) + +LINESTRING (2551160.388053137 6674084.392733793, 2551154.9681075523 6674083.052426154) + +LINESTRING (2552543.8683489356 6675273.965775183, 2552715.260722555 6675284.768254665) + +LINESTRING (2552716.8776317406 6672731.242146628, 2552714.930741089 6672774.342039299) + +LINESTRING (2551286.2512339377 6673585.218158802, 2551280.9302827925 6673584.327954475) + +LINESTRING (2553413.179773412 6676420.128852733, 2553409.723217552 6676423.349591986) + +LINESTRING (2551127.200167159 6672617.045935297, 2551019.5107156173 6672608.303928754) + +LINESTRING (2552824.4103420856 6675069.158766056, 2552786.1159929163 6675098.67554101) + +LINESTRING (2551653.759842543 6676648.441257029, 2551551.655327319 6676622.915398106) + +LINESTRING (2553628.212195956 6677344.641055002, 2553624.0461799433 6677340.470097646, 2553623.9801836503 6677315.544376473, 2553618.0322677195 6677295.939876674, 2553611.8863629084 6677290.038522143, 2553589.249634317 6677247.3487236, 2553559.435808833 6677212.880812218) + +LINESTRING (2553579.878160673 6676443.8843052965, 2553574.9119396047 6676442.674027503) + +LINESTRING (2552850.64386866 6672373.590055137, 2552747.310172474 6672343.373119477) + +LINESTRING (2547867.255514378 6673234.787724891, 2547873.038439576 6673239.588826882, 2547884.703284411 6673269.705739584, 2547911.2502933787 6673313.465783779, 2547925.3405019916 6673358.026011638, 2547929.160037465 6673369.318603615, 2547937.1620880235 6673384.182015197) + +LINESTRING (2550945.1988893966 6672062.238590978, 2550905.988841658 6672124.8129536025) + +LINESTRING (2551820.4664793406 6674029.830210117, 2551774.252574979 6674172.703003552) + +LINESTRING (2552103.912309394 6674035.331472816, 2552115.816390793 6674056.896422595, 2552118.159259204 6674071.259719387, 2552103.541080245 6674163.490889105, 2552103.6483242214 6674198.088830333, 2552109.596240152 6674212.962244211, 2552214.6540894997 6674348.383327263, 2552243.164488192 6674399.625088728, 2552256.8504695087 6674439.934340866, 2552263.9120728886 6674476.642766511, + 2552262.1714206534 6674516.3718854925, 2552255.5717913266 6674537.866819201) + +LINESTRING (2549176.6384719093 6674324.00773236, 2549204.851887282 6674370.64843775, 2549202.0552943544 6674387.532313087, 2549178.5936120977 6674436.473546514, 2549162.54001376 6674500.83832009) + +LINESTRING (2548387.5455419016 6677245.3982759155, 2548293.6328165797 6677280.036226327) + +LINESTRING (2553063.374670476 6675121.190708891, 2553054.192936175 6675255.401514149, 2553073.7113399096 6675267.234230099) + +LINESTRING (2552211.659507693 6677042.151624936, 2552211.106788737 6677041.501475708, 2552210.496323024 6677039.921112969) + +LINESTRING (2553194.6165491785 6675154.058252942, 2553180.0973646594 6675129.492614418) + +LINESTRING (2549090.0018379204 6676584.716630385, 2549079.1206990676 6676585.386784204, 2548977.016183844 6676651.702005465) + +LINESTRING (2551642.8869532268 6674154.408804504, 2551656.515187787 6674153.24853819, 2551661.473159319 6674188.036523038) + +LINESTRING (2552070.9719095165 6676855.328743686, 2552054.934810252 6676918.343207326) + +LINESTRING (2549311.691636548 6674650.87275733, 2549312.7805753867 6674658.094414908, 2549312.343349944 6674663.885744186, 2549311.204913885 6674666.406322732, 2549309.8519898728 6674665.146033458) + +LINESTRING (2549385.1372614196 6671366.5889192745, 2549342.239670795 6671574.806711275) + +LINESTRING (2549907.8031555004 6676812.688956622, 2549831.841421948 6676785.922813019) + +LINESTRING (2551502.2900999538 6673211.672419259, 2551448.1896385467 6673225.065493357) + +LINESTRING (2552498.9166236827 6672416.219839904, 2552493.422432268 6672477.253848974, 2552483.811722061 6672500.92928317) + +LINESTRING (2550177.2330227713 6672701.135236222, 2550110.8902489627 6672783.254084871, 2550231.5479721315 6672874.485025008) + +LINESTRING (2548681.3692890718 6675476.232201174, 2548659.9204937597 6675512.400502845, 2548636.6155526987 6675562.331963558) + +LINESTRING (2550981.0348766414 6674998.84262647, 2551009.223543404 6675172.982596626) + +LINESTRING (2551370.726489322 6674304.233193532, 2551383.092544773 6674405.416418006) + +LINESTRING (2551349.6159250126 6674103.367088956, 2551363.8216271386 6674239.708383223) + +LINESTRING (2552518.4927741736 6675379.730051141, 2552509.789512999 6675412.50757453) + +LINESTRING (2551314.926623363 6673157.730037924, 2551055.066218616 6673137.355361347, 2551046.1402199515 6673142.6865850175) + +LINESTRING (2552759.907214952 6675718.927906852, 2552755.2627258133 6675724.529192509) + +LINESTRING (2551737.756624801 6673535.516750893, 2551662.3888578876 6673646.772287253) + +LINESTRING (2554383.251038637 6673258.043062663, 2554358.0404546084 6673304.683768053) + +LINESTRING (2549395.812161856 6671681.411180082, 2549323.9009508025 6671664.947401169) + +LINESTRING (2551183.5280034645 6675613.4036859935, 2551179.551726795 6675619.705132358) + +LINESTRING (2553707.4902432454 6673207.421443538, 2553711.3592759385 6673214.263013876, 2553785.2338767163 6673218.283936794) + +LINESTRING (2549216.590977947 6671328.23011482, 2549148.062076924 6671625.868431415) + +LINESTRING (2553513.0239155916 6675335.189827873, 2553507.9339514733 6675335.729951847) + +LINESTRING (2549377.060965031 6672608.403951712, 2549370.750069487 6672621.827032697, 2549363.721464254 6672660.605933576) + +LINESTRING (2551619.3015279197 6674963.924611777, 2551597.547499751 6675089.953539058) + +LINESTRING (2553483.0615984476 6674205.110441996, 2553460.3671230995 6674213.062267169, 2553366.421399631 6674205.580549899) + +LINESTRING (2551019.4859670075 6675223.744247892, 2550948.0037318603 6675344.031857374) + +LINESTRING (2547742.1430414137 6672483.21521728, 2547716.033257889 6672484.285462932, 2547672.855183018 6672483.2852333505, 2547621.081090948 6672474.443203849, 2547588.4294248535 6672461.920329488) + +LINESTRING (2549757.9255734864 6677481.262413552, 2549744.9490523227 6677469.449702193, 2549739.232123418 6677456.1766556455, 2549751.8044172856 6677393.642302204) + +LINESTRING (2553787.7499853973 6675169.691841302, 2553923.867340265 6675169.641829823, 2553945.72861241 6675174.152865237, 2553962.425674607 6675185.365438846, 2554002.2709366684 6675228.945441716, 2554011.444421433 6675235.837023534, 2554028.2899752897 6675236.907269185, 2554040.1528090048 6675232.85633938, 2554053.7892931015 6675222.083866786, 2554176.6496425583 6675114.949276302, + 2554188.5454744203 6675108.357763359, 2554212.931104783 6675112.068615107, 2554239.172880894 6675133.953638352) + +LINESTRING (2548472.3342796788 6677228.03429038, 2548452.221909305 6677348.741996286, 2548434.0894277296 6677375.8282133555, 2548419.2485112804 6677386.240603301, 2548391.010347298 6677396.202889933, 2548355.471343373 6677398.4334019, 2548342.2885837923 6677396.432942737, 2548319.7343505677 6677381.069416364, 2548311.2785754926 6677367.286252729, 2548308.6634723716 6677355.553559737, + 2548305.462652148 6677327.097028141, 2548293.6328165797 6677280.036226327) + +LINESTRING (2553240.327231804 6672440.575430216, 2553257.577012957 6672503.50987549, 2553265.8842963725 6672521.714053876) + +LINESTRING (2553923.430114822 6672945.05122199, 2553943.575483342 6672977.868754562) + +LINESTRING (2552786.1159929163 6675098.67554101, 2552819.089390941 6675143.055727544, 2552813.149724547 6675228.055237388) + +LINESTRING (2553214.3329417924 6676218.312530055, 2553227.655943496 6676231.925654661) + +LINESTRING (2553449.865462933 6674015.21685593, 2553442.6636174303 6674102.896981052) + +LINESTRING (2552920.0719691794 6676682.969182185, 2552978.965411385 6676635.118199002, 2552999.341766932 6676614.383439776, 2553014.2899273573 6676578.445190908) + +LINESTRING (2550491.9033490783 6675711.406180399, 2550480.032265826 6675730.450551632, 2550476.66645487 6675752.545623089, 2550483.5218198327 6675772.360171101, 2550499.2124385578 6675777.501351151, 2550552.025972246 6675743.113458135) + +LINESTRING (2553485.651952958 6676036.060697992, 2553477.9386361823 6676032.269827878) + +LINESTRING (2551845.421327733 6673126.922966811, 2551825.407951799 6673124.782475507) + +LINESTRING (2553569.1702620904 6675865.6115749935, 2553564.418528975 6675862.490858698) + +LINESTRING (2552640.7756560645 6672516.932956476, 2552637.005617812 6672559.452715989, 2552630.043008872 6672569.124936043, 2552510.4824740784 6672559.752784863) + +LINESTRING (2551760.913074202 6674391.1331395805, 2551754.717672171 6674389.842843421) + +LINESTRING (2553209.226478601 6675582.396568964, 2553052.246045524 6675578.855756246) + +LINESTRING (2554288.274123086 6677394.042394036, 2554323.4088997156 6677433.221386747, 2554345.5671551805 6677468.3994611325, 2554369.5898059304 6677532.834250779, 2554377.0968842898 6677580.555204117, 2554376.148187574 6677595.79870294, 2554366.7519653197 6677629.8965293765, 2554365.0195626216 6677647.730622817, 2554367.7749078656 6677663.394218065, 2554428.00477501 6677820.860361095, + 2554430.0754087116 6677849.676975341) + +LINESTRING (2553517.874643147 6675334.66970849, 2553526.3386677587 6675339.550828849, 2553746.7085405206 6675232.42624066, 2553788.31095389 6675212.56168117) + +LINESTRING (2552312.856573884 6675890.1672112215, 2552366.965284828 6675955.152127137) + +LINESTRING (2551743.440555559 6673647.422436481, 2551658.899303881 6673651.903465007) + +LINESTRING (2552633.0953374356 6673626.467626747, 2552631.82490879 6673613.684692694, 2552625.340772976 6673601.6919400105, 2552611.53104861 6673592.439816381, 2552587.524896933 6673579.326806567) + +LINESTRING (2549773.979171824 6677189.7354997005, 2549709.2533072005 6677274.374926895) + +LINESTRING (2553523.5090766847 6675735.681752344, 2553667.3479978647 6675699.133363432, 2553785.118383203 6675669.196492055) + +LINESTRING (2553432.656929463 6672199.62012401, 2553477.5591574963 6672131.244429813) + +LINESTRING (2552710.1872575106 6672835.416057551, 2552655.97130259 6672798.9676915975) + +LINESTRING (2547774.8607038017 6675095.06471222, 2547743.636207549 6675073.6597991735) + +LINESTRING (2553006.1971318955 6674929.916806002, 2552861.3352681696 6675041.022307926) + +LINESTRING (2553224.09214366 6675516.841522187, 2553221.831770615 6675582.566607993) + +LINESTRING (2553205.6544292276 6673309.334835607, 2553195.4827505276 6673439.704759272) + +LINESTRING (2551675.6128651514 6673254.372220098, 2551680.8183227833 6673274.816912746, 2551682.5094777984 6673281.458437167, 2551699.751009415 6673299.7926453985, 2551760.599591809 6673343.492675818, 2551763.5364268594 6673345.603160235, 2551774.2773235887 6673347.453584962, 2551828.163297043 6673385.082221821, 2551837.3615304176 6673395.314570441, 2551844.0519046476 6673402.756278528) + +LINESTRING (2553213.2687515635 6671834.346283107, 2553224.356128833 6671841.2578695165) + +LINESTRING (2553078.578566538 6673990.511185264, 2552932.619514437 6673980.83896521, 2552930.6726237857 6673980.708935365) + +LINESTRING (2549594.5599990357 6677577.114414356, 2549574.2083920985 6677584.546120147) + +LINESTRING (2553719.84804916 6675104.546888653, 2553711.9862407246 6675111.1083947085) + +LINESTRING (2548033.566173416 6672145.257646251, 2548023.21300491 6672136.2355754245, 2548022.3963007806 6672124.182808966, 2548035.315075188 6672111.339861139, 2548058.941748178 6672108.509211423) + +LINESTRING (2552911.063475148 6672951.98281299, 2552849.2414474282 6672948.622041596) + +LINESTRING (2553686.016699323 6675827.962933542, 2553688.194577001 6675852.658601912, 2553689.1515232534 6675997.631877468) + +LINESTRING (2552579.465099618 6673027.760206092, 2552521.487355981 6672986.790802429) + +LINESTRING (2552796.015436907 6673098.0563410865, 2552692.162019911 6673088.934247302) + +LINESTRING (2553282.366870616 6673641.751134754, 2553275.9652301692 6673721.07934287) + +LINESTRING (2552203.3439747407 6672596.1711439295, 2552125.790080613 6672703.615805584) + +LINESTRING (2553299.34441706 6673391.583714101, 2553340.542603133 6673366.31791487) + +LINESTRING (2552813.149724547 6675228.055237388, 2552847.53379334 6675231.235967458) + +LINESTRING (2551416.2309335307 6675277.816659073, 2551335.641209913 6675218.222980602) + +LINESTRING (2552812.2175269043 6676373.698195556, 2552790.8677260317 6676479.262425598) + +LINESTRING (2553263.0299566886 6676267.053717567, 2553345.1045969054 6676349.882729218) + +LINESTRING (2551871.465114964 6676056.955493952, 2551873.568746812 6676050.864095801) + +LINESTRING (2552925.557911057 6674460.349026627, 2552897.8477174207 6674454.86776852) + +LINESTRING (2553044.549227821 6675712.136347993, 2553044.136750988 6675713.786726803) + +LINESTRING (2552510.0452486356 6673575.045823957, 2552509.9710028055 6673570.4747747695) + +LINESTRING (2552606.5565780047 6675885.096047242, 2552675.0277322712 6675969.9955341285) + +LINESTRING (2547348.615394187 6672592.810372535, 2547344.9773485204 6672580.867631331, 2547326.7293734318 6672553.111260442, 2547291.611095876 6672520.353741645, 2547280.828951463 6672518.693360539) + +LINESTRING (2549239.970164838 6676507.618934236, 2549224.3372928696 6676511.139742363) + +LINESTRING (2548721.940510359 6672165.17221722, 2548687.9441697886 6672168.032873823, 2548669.62194887 6672165.182219516) + +LINESTRING (2551006.8394273096 6674670.747319115, 2550983.7984714224 6674773.430887962, 2550976.794614799 6674834.884993455, 2550973.9485246516 6674920.554657119, 2550981.0348766414 6674998.84262647) + +LINESTRING (2552433.3163081734 6675233.786552891, 2552450.920819403 6675243.6588188615, 2552543.8683489356 6675273.965775183) + +LINESTRING (2549851.2525817053 6677259.631542862, 2549883.797003824 6677289.668437197) + +LINESTRING (2551733.574109715 6672719.2894031275, 2551671.7025847756 6672805.259135666) + +LINESTRING (2553067.763423979 6676432.941793674, 2553063.3499218663 6676427.160466692) + +LINESTRING (2551507.2315724124 6673658.074881526, 2551498.759298264 6673658.705026162) + +LINESTRING (2554065.3551434968 6672955.5536325965, 2554105.736625441 6672962.695271809, 2554136.8043804974 6672976.648474473) + +LINESTRING (2550852.053370984 6672955.323579793, 2550885.084515765 6672967.196304926, 2550914.815845883 6672972.847602062) + +LINESTRING (2551136.7613801467 6675525.22344608, 2551083.634364065 6675615.144085466, 2551078.63514485 6675623.606027726, 2551019.692205424 6675699.373418532, 2551000.2975447397 6675718.547819612, 2550829.325897489 6675864.911414286) + +LINESTRING (2551676.5285637206 6673275.937169877, 2551487.0284571354 6673323.158008425) + +LINESTRING (2549179.0968338335 6676455.867055684, 2549063.232091463 6676502.957864385) + +LINESTRING (2554058.054303554 6677147.885894006, 2554288.274123086 6677394.042394036) + +LINESTRING (2552188.3380675586 6673180.105173664, 2552146.09219033 6673240.589056464) + +LINESTRING (2553414.920425647 6675381.700503417, 2553390.493547601 6675388.72211508, 2553324.8272357984 6675380.0601269035, 2553293.561491862 6675401.385021583) + +LINESTRING (2553233.3316247175 6673542.7184038805, 2553112.269674252 6673535.126661356) + +LINESTRING (2548546.0686383336 6672346.333799038, 2548531.5329547413 6672368.868971512, 2548512.40227923 6672390.203868487, 2548473.464466201 6672415.589695268, 2548466.4358609677 6672419.700638848) + +LINESTRING (2553995.0360930185 6675615.344131382, 2554020.494163147 6675608.592581706, 2554020.7251501735 6675608.492558748, 2554021.5006066198 6675608.172485282) + +LINESTRING (2554347.439800002 6675597.4800310545, 2554412.3554039686 6675566.242861222) + +LINESTRING (2551758.8424405004 6674218.34347936, 2551750.089682106 6674243.499253337, 2551705.5504336855 6674335.160292194) + +LINESTRING (2552590.024506541 6675868.522243075, 2552585.817242845 6675882.675491655, 2552491.29405181 6675961.683626305) + +LINESTRING (2552393.5865396257 6671805.229599987, 2552394.7992215143 6671836.756836399) + +LINESTRING (2553125.0647056093 6676868.411746613, 2553220.5695915064 6676858.439457684) + +LINESTRING (2550201.123680935 6672664.926925369, 2550192.3956711497 6672662.466360598, 2549999.9999771975 6672608.183901205, 2549867.1164407 6672570.705298782) + +LINESTRING (2549925.0941843367 6676424.229794018, 2549851.7393043684 6676412.307057406) + +LINESTRING (2549067.1588709126 6676512.280004086, 2549090.7525457563 6676573.754114171, 2549090.0018379204 6676584.716630385) + +LINESTRING (2552755.2627258133 6675724.529192509, 2552780.927034358 6675748.19462441, 2552833.2043481637 6675821.75150784) + +LINESTRING (2548339.5249890117 6676671.62657873, 2548231.63754859 6676726.789240154, 2548157.7464487385 6676748.194153201, 2548147.929500115 6676753.445358505) + +LINESTRING (2551073.289445095 6672891.4089095285, 2551050.693964187 6672889.168395266, 2551018.1247934587 6672888.988353942) + +LINESTRING (2551617.6186224413 6673499.048380348, 2551503.742018406 6673652.123515515) + +LINESTRING (2553780.1521621346 6673315.01613963, 2553775.755159096 6673404.646712436) + +LINESTRING (2547582.9599820487 6674466.060337538, 2547591.2012691707 6674453.197385118, 2547602.6351269796 6674444.545399237, 2547616.783082349 6674439.844320204, 2547705.729586602 6674440.104379895, 2547705.8945773356 6674405.196367498, 2547700.3921363843 6674381.110839173) + +LINESTRING (2553530.776918481 6676863.170543605, 2553536.576342752 6676888.54636809, 2553543.2667169822 6676917.793081056, 2553551.4997545676 6676953.7513345145, 2553570.820169422 6677006.193371478, 2553580.340134726 6677032.019299274) + +LINESTRING (2551757.291527609 6676327.267538378, 2551753.7442268454 6676516.801041795, 2551746.872362809 6676550.868861344, 2551731.693215357 6676588.177424737, 2551726.999228998 6676599.710071813, 2551691.509722293 6676652.712237342, 2551682.9632023145 6676821.631009081, 2551662.3063625214 6676893.987617014, 2551653.61960042 6676966.014149185, 2551637.326765519 6677060.915931887, + 2551629.761940403 6677082.770948244, 2551584.183250364 6677169.180781798) + +LINESTRING (2553485.148731222 6673735.572669507, 2553381.666543376 6673728.240986674) + +LINESTRING (2550294.6239294237 6676116.669199973, 2550132.2070516883 6676228.944970507, 2550105.5033015246 6676255.961171506, 2550089.9611744597 6676277.016004199) + +LINESTRING (2553302.165758597 6672544.049180432, 2553306.0677894363 6672556.502038723, 2553299.9218846257 6672575.486396182) + +LINESTRING (2551230.715353152 6673946.261028575, 2551201.2315091337 6673936.978898058) + +LINESTRING (2552554.469003542 6673143.706819191, 2552508.7708714856 6673110.496865532, 2552459.211603745 6673074.480929848, 2552330.7745675067 6672982.3197762, 2552261.900555275 6672932.613958296, 2552203.5997103774 6672890.538709792, 2552065.320976905 6672790.54575852, 2551986.7936374517 6672734.5429042475, 2551898.243110958 6672671.248376324, 2551824.970726356 6672617.436024834, + 2551800.230365917 6672605.523290517, 2551795.8003647313 6672629.388768334, 2551790.0999349 6672641.201479693, 2551733.574109715 6672719.2894031275, 2551619.8624964124 6672639.221025121, 2551531.089232429 6672581.677817292, 2551522.3364740345 6672575.816471944, 2551503.8905100655 6672563.463636612, 2551487.9111575577 6672562.0333083095) + +LINESTRING (2551273.0354762105 6676879.604315631, 2551260.479681416 6676899.398859051, 2551251.314446188 6676921.94403382) + +LINESTRING (2554358.2549425615 6673315.616277379, 2554340.8071725285 6673346.863449508) + +LINESTRING (2547582.9599820487 6674466.060337538, 2547542.9167311075 6674519.542613266, 2547507.509719769 6674549.019379036, 2547495.011671731 6674555.540875907, 2547479.6840326195 6674554.390611889, 2547475.724255023 6674550.169643054, 2547444.42551294 6674512.861079661, 2547421.4588028826 6674474.592295869) + +LINESTRING (2553386.5337700048 6673649.462904828, 2553381.666543376 6673728.240986674) + +LINESTRING (2548899.0168147366 6671469.6525753625, 2548880.521353548 6671546.580232482, 2548856.308963455 6671647.263342166) + +LINESTRING (2552498.4628991666 6676774.4501797175, 2552526.346333073 6676765.578143329, 2552545.7822414404 6676691.581158883) + +LINESTRING (2551567.4531900203 6673802.518035403, 2551552.7772643045 6673792.965842899) + +LINESTRING (2553495.114171506 6674905.331162887, 2553498.2324963626 6674913.0729398485, 2553522.0654077693 6674982.108785571, 2553538.919211163 6675013.97610004, 2553584.547398422 6675077.290632555) + +LINESTRING (2550327.4653348615 6676216.322073188, 2550332.8522822997 6676228.294821279, 2550335.93760901 6676264.013019638) + +LINESTRING (2551120.270556366 6671890.589192481, 2551105.64412787 6671861.78258053, 2551086.298964406 6671839.64749989) + +LINESTRING (2553694.0022508088 6676087.94260639, 2553783.4189786515 6676147.836353736, 2553792.3119791695 6676168.631126737) + +LINESTRING (2553283.6702974085 6672585.738749393, 2553281.9791423935 6672606.85359586) + +LINESTRING (2552795.2482299977 6675564.042356142, 2552697.260233566 6675557.060753663) + +LINESTRING (2551108.061242111 6672405.627408636, 2551124.766553845 6672382.372070864) + +LINESTRING (2554186.6315819155 6673045.404255911, 2554164.2258403506 6673085.173384075) + +LINESTRING (2553887.3466414767 6677312.983788745, 2554058.054303554 6677147.885894006) + +LINESTRING (2551422.005609192 6673330.089599425, 2551396.1680603772 6673358.336082809, 2551386.895581173 6673427.361926234) + +LINESTRING (2547523.7778060595 6672778.823067824, 2547468.7121488634 6672802.398479062, 2547457.2205442977 6672804.628991029) + +LINESTRING (2550375.279649335 6674757.977340926, 2550446.2669122824 6674787.824191641, 2550462.5514976466 6674789.864659987, 2550480.403494976 6674769.309942086, 2550507.346481703 6674724.719707338) + +LINESTRING (2551959.4134252816 6676980.72752633, 2551934.4338282794 6677088.602286705, 2551917.8770082057 6677195.676863415) + +LINESTRING (2553092.8007677374 6673789.244988856, 2553085.706166211 6673889.8780870605) + +LINESTRING (2546952.1096642264 6672967.336337067, 2547067.850663547 6672968.146523029) + +LINESTRING (2550792.821697775 6672954.823465002, 2550821.6620779335 6672950.57248928, 2550852.053370984 6672955.323579793) + +LINESTRING (2553073.3731089067 6674056.326291733, 2553186.1607741034 6674064.068068695, 2553184.535615382 6674084.792825625) + +LINESTRING (2552261.4207128175 6672125.6131372675, 2552253.088680792 6672172.793966631) + +LINESTRING (2553011.047859451 6676035.290521215, 2553026.622984662 6676054.694975098, 2553038.9560419666 6676066.327645131) + +LINESTRING (2550826.0508314357 6675180.984433278, 2550817.223827211 6675252.830924124, 2550808.454569743 6675266.964168113) + +LINESTRING (2548030.670586049 6676706.914678369, 2547928.285586579 6676742.162768824, 2547906.9852829264 6676785.8728015395, 2547891.335911885 6676809.258169157) + +LINESTRING (2553513.964362771 6675992.810770884, 2553506.539779778 6675989.219946686) + +LINESTRING (2551969.535606762 6673214.333029946, 2551949.8274636846 6673239.518810811) + +LINESTRING (2553634.0281193005 6673094.815597242, 2553650.980917134 6673081.342504778, 2553766.004206765 6673008.675825675) + +LINESTRING (2552487.8622445604 6672410.318485373, 2552389.9319948857 6672339.512233292) + +LINESTRING (2553164.7944741575 6674108.238207018, 2553070.4445233927 6674102.01677902) + +LINESTRING (2552468.145851946 6673251.841639256, 2552378.5476342966 6673187.666909302) + +LINESTRING (2551224.519951121 6673823.852932379, 2551197.78320281 6673927.316680299) + +LINESTRING (2552067.267867557 6673354.565217286, 2552027.958825378 6673407.947470056, 2551903.242330173 6673321.147546966, 2551892.3364427104 6673318.977048773) + +LINESTRING (2552348.164590783 6673563.0530712735, 2552308.443071772 6673535.956851909, 2552288.5451893513 6673519.573091362) + +LINESTRING (2547352.8804046395 6672617.556052384, 2547348.615394187 6672592.810372535) + +LINESTRING (2552034.0222348226 6677000.342028425, 2552009.4716137266 6677102.07537917) + +LINESTRING (2553565.094990981 6674021.468290815, 2553856.6418660334 6673963.835062323) + +LINESTRING (2553340.542603133 6673366.31791487, 2553344.139401116 6673364.037391424) + +LINESTRING (2552912.630887113 6676335.909521963, 2552853.6549495407 6676381.670025322, 2552812.2175269043 6676373.698195556) + +LINESTRING (2554244.320591769 6674631.058209318, 2554142.290322375 6674448.276255577) + +LINESTRING (2553142.867205719 6676968.46471166, 2553125.0647056093 6676868.411746613) + +LINESTRING (2548349.498678832 6671792.986789908, 2548337.0088803307 6671880.666915031) + +LINESTRING (2552325.082387212 6677081.18058321, 2552286.730291286 6677071.018250661, 2552283.0262493263 6677059.885695417, 2552252.7999470094 6677053.694274307, 2552243.915196028 6677050.3635098) + +LINESTRING (2549202.9957415336 6677369.356727963, 2549174.642084038 6677437.23230737, 2549140.010529145 6677495.725733302, 2549124.2704132004 6677529.353451835, 2549112.6633151216 6677565.671787943, 2549108.893276869 6677580.975300541) + +LINESTRING (2554380.767928103 6674553.6904511815, 2554244.320591769 6674631.058209318) + +LINESTRING (2552579.465099618 6673027.760206092, 2552578.499903829 6673039.14281873, 2552576.7427525204 6673055.246514994) + +LINESTRING (2551818.5030896156 6673548.549742341, 2551753.9422157253 6673510.250951662) + +LINESTRING (2552150.274705416 6675237.957510246, 2552110.0169665217 6675223.784257075) + +LINESTRING (2551527.558430739 6673498.808325248, 2551445.1950567393 6673509.880866717) + +LINESTRING (2553099.4993915046 6672962.855308542, 2553069.644318337 6672961.244938916) + +LINESTRING (2553449.865462933 6674015.21685593, 2553362.238884545 6674010.265719501) + +LINESTRING (2551917.8770082057 6677195.676863415, 2551912.597304744 6677299.730746788) + +LINESTRING (2553056.9400318824 6675511.130211276, 2553052.246045524 6675578.855756246) + +LINESTRING (2553895.4559360123 6675361.215801586, 2553890.89394224 6675364.116467373) + +LINESTRING (2548721.940510359 6672165.17221722, 2548733.1928783613 6672244.160347278, 2548776.5689421124 6672470.202230424) + +LINESTRING (2549982.6759502143 6676534.105013556, 2549957.399369892 6676568.973016771) + +LINESTRING (2551193.0974659882 6673547.3694714345, 2551173.7605520603 6673670.577751296) + +LINESTRING (2553156.487190742 6676159.188959487, 2553172.078815027 6676175.132619018) + +LINESTRING (2551086.298964406 6671839.64749989, 2551006.228961597 6671778.523470159, 2550955.7665458564 6671748.946681431) + +LINESTRING (2549538.3806543904 6672527.685424478, 2549467.888363642 6672609.60422721) + +LINESTRING (2551552.6535212547 6677235.265950254, 2551546.309627564 6677275.405163364, 2551550.2199079404 6677303.381584761, 2551562.841699028 6677338.039539764) + +LINESTRING (2553328.457031928 6673316.036373803, 2553350.22755917 6673302.153187211) + +LINESTRING (2550043.483284925 6677192.91622977, 2550038.23657961 6677192.576151712) + +LINESTRING (2553263.7229177677 6673904.271390739, 2553256.4880741183 6674002.824011413) + +LINESTRING (2553317.8811259316 6672579.957422412, 2553318.409096278 6672569.254965888, 2553319.2010517973 6672553.201281104, 2553314.078089532 6672538.948009566, 2553309.4995966866 6672526.205084696) + +LINESTRING (2549063.7600618093 6676756.946162039, 2549005.14710385 6676746.133680263) + +LINESTRING (2547680.098276204 6672742.66476845, 2547809.995480431 6672685.101556029, 2547892.251610454 6672653.174227784) + +LINESTRING (2553403.569063205 6676127.341649609, 2553485.0002395622 6676211.250909209) + +LINESTRING (2551758.8424405004 6674218.34347936, 2551661.473159319 6674188.036523038) + +LINESTRING (2551403.8153808597 6676457.767491889, 2551389.015712094 6676511.099733179, 2551378.530551001 6676517.991314997) + +LINESTRING (2552100.9919734173 6676362.5956472, 2552118.0272666174 6676363.825929586, 2552175.114060295 6676360.845245432, 2552206.9655213337 6676352.793397301) + +LINESTRING (2551508.7907348406 6674414.018392407, 2551446.316993725 6674397.454590537, 2551383.092544773 6674405.416418006) + +LINESTRING (2549239.9371666913 6676363.955959431, 2549225.8717066883 6676391.872367053) + +LINESTRING (2551097.724572678 6677066.147132598, 2551084.2695783875 6677140.354165257, 2551106.7083180994 6677169.640887406, 2551135.202217718 6677166.980276719) + +LINESTRING (2553792.3119791695 6676168.631126737, 2553672.726695766 6676456.377172771) + +LINESTRING (2549989.1023392715 6676433.011809745, 2549925.0941843367 6676424.229794018) + +LINESTRING (2552669.1210640236 6673406.247079767, 2552662.2162018404 6673501.088848694) + +LINESTRING (2553476.230982094 6676802.706665398, 2553470.250068017 6676807.127680148, 2553464.351649306 6676818.980400691, 2553463.7081854464 6676833.56374799, 2553474.2180951494 6676871.282405512, 2553481.9726596083 6676885.0855737375, 2553491.1543939095 6676891.84712571, 2553508.0741935964 6676893.167428757, 2553536.576342752 6676888.54636809, 2553587.4264867157 6676880.294474042) + +LINESTRING (2551498.759298264 6673658.705026162, 2551490.402517629 6673659.335170798) + +LINESTRING (2550187.511945448 6676468.529962187, 2550217.3670186154 6676473.071004488, 2550243.9552752664 6676528.713776112, 2550245.200955302 6676539.066152281) + +LINESTRING (2550583.902181895 6672856.730949935, 2550538.711220079 6672846.538610498, 2550506.7607646002 6672835.546087396, 2550488.116811752 6672823.123235993) + +LINESTRING (2550038.23657961 6677192.576151712, 2549999.9999771975 6677191.315862439, 2549987.1636981564 6677192.166057584, 2549966.5811041933 6677201.048096268) + +LINESTRING (2552889.8539163987 6674627.117304767, 2552889.218702076 6674644.061193879) + +LINESTRING (2553743.8212026902 6675464.299462265, 2553753.002936991 6675454.077115942, 2553803.0116282157 6675416.47848597, 2553824.559417968 6675403.835584058) + +LINESTRING (2550835.207817127 6675345.372165014, 2550752.2834746344 6675483.593890894) + +LINESTRING (2547859.484450846 6671575.806940856, 2547853.231302059 6671555.482275759, 2547843.2493627016 6671535.617716269, 2547844.4702941272 6671521.584495239, 2547834.447107087 6671504.880661226) + +LINESTRING (2554443.794388175 6673363.117180209, 2554469.673184673 6673376.390226757) + +LINESTRING (2549270.600694451 6671125.503583223, 2549256.7249737913 6671116.801585862, 2549174.402847475 6671097.657191671) + +LINESTRING (2547575.386907396 6672830.9850405045, 2547544.550139366 6672841.367423561) + +LINESTRING (2551482.5324596562 6673422.460801285, 2551456.6949108415 6673412.728567456, 2551395.8133303006 6673420.730404109, 2551386.895581173 6673427.361926234) + +LINESTRING (2553077.761862409 6676172.722065726, 2553055.9253388736 6676203.589150614) + +LINESTRING (2552017.9191392646 6673946.871168619, 2552033.906741309 6673956.733432294, 2552084.14641956 6674019.7879051175) + +LINESTRING (2552898.128201667 6674630.238021061, 2552894.655146734 6674628.927720309, 2552889.8539163987 6674627.117304767) + +LINESTRING (2551887.5682105217 6675183.465002641, 2551878.8484502737 6675197.97833387, 2551866.4246480656 6675239.847944155, 2551838.846447016 6675286.888741378, 2551824.6407448896 6675301.782159848, 2551783.3683129866 6675328.158213914, 2551763.7179166656 6675347.282603514, 2551747.2683405685 6675368.607498194, 2551730.653773738 6675398.674399417) + +LINESTRING (2553523.146097072 6676805.30726231, 2553530.776918481 6676863.170543605) + +LINESTRING (2547791.145289166 6675062.09714521, 2547780.4456401197 6675083.752115652, 2547774.8607038017 6675095.06471222) + +LINESTRING (2551878.6422118573 6673047.834813794, 2551825.407951799 6673124.782475507) + +LINESTRING (2551570.9674926368 6674229.8961310275, 2551504.6329683647 6674213.782432468) + +LINESTRING (2549858.734911455 6676968.274668039, 2549805.4099064935 6676950.990700869) + +LINESTRING (2551719.459152492 6673928.1468708515, 2551679.712884871 6673895.7394324085) + +LINESTRING (2550187.511945448 6676468.529962187, 2550180.648330948 6676468.279904791) + +LINESTRING (2552559.377477854 6675010.015190897, 2552454.3361275797 6675092.164046433) + +LINESTRING (2547923.6658460503 6672523.004350035, 2547742.1430414137 6672483.21521728) + +LINESTRING (2552443.66947668 6672192.648523826, 2552440.7491407027 6672213.753367998, 2552505.9039812325 6672310.61560068, 2552507.9168681772 6672319.74769676) + +LINESTRING (2552302.6766456473 6675735.471704132, 2552357.709304697 6675678.488624868, 2552369.860872195 6675671.186948922, 2552391.4664087044 6675686.430447746) + +LINESTRING (2552854.6036462565 6673878.245417026, 2552847.962769246 6673878.025366519) + +LINESTRING (2548132.222382317 6676658.373536774, 2548030.670586049 6676706.914678369) + +LINESTRING (2552742.8141749953 6676471.2505866485, 2552735.637078102 6676535.095240842) + +LINESTRING (2553039.1292822366 6673301.743093083, 2553031.4242149973 6673429.042311932) + +LINESTRING (2553193.4616140462 6676196.987635376, 2553214.3329417924 6676218.312530055) + +LINESTRING (2553470.3408129197 6675572.594319065, 2553335.7413727976 6675585.597303625) + +LINESTRING (2550852.053370984 6672955.323579793, 2550859.1149743637 6672960.734821829, 2550867.2655165824 6672976.258384936, 2550869.4433942605 6673004.914962448) + +LINESTRING (2552879.3357571587 6673419.2100551445, 2552872.472142659 6673518.93294443) + +LINESTRING (2553270.223552655 6673799.537351251, 2553263.7229177677 6673904.271390739) + +LINESTRING (2552850.64386866 6672373.590055137, 2552844.266976823 6672450.797776541) + +LINESTRING (2548800.0058757598 6671883.607590001, 2548781.922891404 6671969.317262848, 2548788.6215151707 6672008.0761591345) + +LINESTRING (2548706.2746402444 6676511.199756138, 2548656.3484443864 6676539.556264776) + +LINESTRING (2551195.696070036 6673935.398535319, 2551162.9124113545 6674054.935972615) + +LINESTRING (2552610.153375988 6677178.372891653, 2552604.74167994 6677178.863004148) + +LINESTRING (2551966.153296732 6673989.120866146, 2551970.2203183044 6673991.151332197) + +LINESTRING (2547830.4048341243 6672948.171938284, 2547704.0054334407 6672921.665854372, 2547693.1655422715 6672917.094805184, 2547663.98693111 6672867.21335595, 2547663.1949755903 6672854.8905275045, 2547673.2016635574 6672803.978841801) + +LINESTRING (2548357.2614928274 6676661.654289802, 2548339.5249890117 6676671.62657873) + +LINESTRING (2553520.0360217514 6676177.143080477, 2553485.0002395622 6676211.250909209) + +LINESTRING (2551398.0159565886 6674494.136781894, 2551392.612510077 6674494.64689898) + +LINESTRING (2552795.8091984903 6676178.813463878, 2552847.575041023 6676242.638113479) + +LINESTRING (2553534.563455807 6676611.812849751, 2553530.5459314547 6676630.687181955) + +LINESTRING (2547022.8411915377 6673003.024528539, 2546955.747709893 6673031.54107391) + +LINESTRING (2550389.617344048 6675636.388961779, 2550483.3898272463 6675641.560148716) + +LINESTRING (2547970.531463808 6673861.74162893, 2548011.927638761 6673860.351309812, 2548018.947994457 6673856.340389189, 2548029.944626823 6673775.231772418, 2548028.641200031 6673763.4490679465, 2548021.8105836776 6673747.835484178, 2548010.978942045 6673736.6229105685, 2547982.2870535464 6673722.389643622) + +LINESTRING (2551452.718634172 6675067.47838036, 2551447.7276644935 6675063.277416117) + +LINESTRING (2548554.5491620186 6677173.441759816, 2548546.208880457 6677206.839425545, 2548543.758768069 6677234.355741335) + +LINESTRING (2551825.407951799 6673124.782475507, 2551804.2396407328 6673136.3051202865, 2551655.096267482 6673173.833734188) + +LINESTRING (2550230.508530513 6675872.463147627, 2550230.904508272 6675950.681100908, 2550235.746986291 6675967.93506119, 2550244.639986809 6675983.418615113, 2550267.94492787 6676025.558287386, 2550280.863702277 6676053.714750107, 2550285.7969251988 6676104.186334795, 2550294.6239294237 6676116.669199973) + +LINESTRING (2550967.0766606154 6675000.773069562, 2550929.1040433757 6674996.93218797) + +LINESTRING (2549001.8637882597 6670970.698050879, 2548996.798572751 6670927.438121475, 2548988.252052773 6670889.139330796) + +LINESTRING (2553521.553936497 6676745.293487415, 2553521.9581637927 6676760.566993125) + +LINESTRING (2553878.9733617683 6675535.2157396, 2553897.2378359307 6675544.497870117) + +LINESTRING (2551482.5324596562 6674683.330207252, 2551479.6698704357 6674688.431378118) + +LINESTRING (2549140.975724934 6672910.24323255, 2549125.219109916 6672924.776568371, 2549022.5783748096 6672918.4951265985, 2548894.050593668 6672927.007080338, 2548872.9647779684 6672919.015245981) + +LINESTRING (2548687.185212416 6675823.651944045, 2548658.146843378 6675785.453176324, 2548635.1966323936 6675724.639217763, 2548628.8857368496 6675685.640266377, 2548636.6155526987 6675562.331963558) + +LINESTRING (2551467.757539501 6675888.4568186365, 2551592.2760458263 6675941.008880854, 2551745.329699454 6676011.725112272) + +LINESTRING (2553875.335316102 6676875.273321543, 2553906.485566525 6676867.321496368, 2554291.912168753 6676437.282790058, 2554510.19490874 6676193.726886939) + +LINESTRING (2550580.9900954547 6672513.142086362, 2550611.983604681 6672531.376271633) + +LINESTRING (2553317.5263958555 6676505.718498031, 2553243.536301564 6676573.534063662) + +LINESTRING (2552978.882916019 6673298.132264293, 2552888.7732270965 6673293.051098018) + +LINESTRING (2550947.8057429804 6675665.505644899, 2550905.0566440155 6675637.209150036, 2550870.713822906 6675609.952893937, 2550832.5184681765 6675572.254241007) + +LINESTRING (2549773.979171824 6677189.7354997005, 2549756.9108804776 6677171.781378711, 2549758.032817463 6677156.327831675, 2549819.5166141796 6677095.683912143) + +LINESTRING (2550885.983715261 6672158.480681319, 2550859.799685906 6672193.228656984) + +LINESTRING (2551032.5862312214 6672510.751537661, 2551064.701677433 6672466.021270772, 2551073.9576575644 6672453.1283114655, 2551108.061242111 6672405.627408636) + +LINESTRING (2549854.4699010025 6676293.439773928, 2549836.40341572 6676274.085331525) + +LINESTRING (2553117.0709045874 6675047.643827756, 2553143.370427455 6675083.712106469) + +LINESTRING (2552963.6212732 6673523.774055605, 2552956.9143998967 6673618.665836011) + +LINESTRING (2548928.781143001 6671341.783225651, 2548923.5509367594 6671364.108349912, 2548904.4780080044 6671446.957366155, 2548899.0168147366 6671469.6525753625) + +LINESTRING (2551768.7088863445 6672875.395233927, 2551725.456565643 6672934.608825157) + +LINESTRING (2547628.4479271844 6674898.609620099, 2547618.3422447774 6674886.046736554) + +LINESTRING (2552837.8075896194 6672534.056886912, 2552821.9107324784 6672739.764102663) + +LINESTRING (2553932.7438417096 6677359.32442526, 2553875.4425600786 6677416.427532073, 2553865.2708813786 6677426.5598577345, 2553797.1709562615 6677443.4337307755, 2553820.1294167824 6677524.132253419) + +LINESTRING (2548826.3961435305 6676796.665278725, 2548822.997334427 6676901.8294169335, 2548791.005631265 6676900.409090928, 2548780.256484999 6676907.05061535, 2548654.855278251 6677031.539189075) + +LINESTRING (2553636.857710374 6677136.563295143, 2553601.5909411586 6677123.940397823, 2553575.456409024 6677123.720347315, 2553552.7619336764 6677113.357968849, 2553538.242749157 6677080.780491377, 2553519.7555375053 6677022.507115954, 2553570.820169422 6677006.193371478, 2553701.558826388 6676964.403779559, 2553684.4162892113 6676981.82777887, 2553659.279951012 6676995.380889701, + 2553649.0092778723 6677005.473206178, 2553633.293910538 6677032.589430136, 2553627.568732097 6677051.813842694, 2553626.4962923313 6677070.998246069, 2553628.2286950294 6677094.623668786, 2553630.315827804 6677124.7905929675) + +LINESTRING (2549184.987003008 6672841.267400604, 2549145.2159867766 6672828.484466551) + +LINESTRING (2552896.948517925 6675897.6289238995, 2552949.778550687 6675961.593605643) + +LINESTRING (2548349.498678832 6671792.986789908, 2548361.87298382 6671705.256653307, 2548274.774375778 6671697.8249475155, 2548255.46221046 6671701.405769418) + +LINESTRING (2552001.873790464 6672212.112991484, 2551966.2852893183 6672312.3359955605) + +LINESTRING (2553207.4693272924 6675690.261327044, 2553209.2099795276 6675696.742814733) + +LINESTRING (2552942.890187577 6674846.207592319, 2552869.494059925 6674900.820127474) + +LINESTRING (2552973.6609593136 6675416.438476786, 2552968.777233612 6675494.2663405305, 2553057.575246205 6675500.387745569) + +LINESTRING (2551115.9395496203 6672778.863077007, 2551121.9534618445 6672693.903576347) + +LINESTRING (2552515.5064419033 6675173.012603514, 2552433.3163081734 6675233.786552891) + +LINESTRING (2553462.404758654 6675946.380113707, 2553452.7775493735 6675965.714551519) + +LINESTRING (2553651.9296138496 6677408.825787253, 2553672.239973103 6677388.731174959) + +LINESTRING (2553769.3782672584 6675563.292183956, 2553789.5813825354 6675557.130769733) + +LINESTRING (2553240.327231804 6672440.575430216, 2553137.735993917 6672468.141757485) + +LINESTRING (2550653.817005077 6675339.81088854, 2550628.1856946787 6675291.009687254) + +LINESTRING (2551257.212864899 6675722.818799925, 2551122.7041696804 6675711.97631126) + +LINESTRING (2552905.7342744665 6674299.052004299, 2552838.467552552 6674293.070631401, 2552834.1117971963 6674327.438519824, 2552733.706686524 6674363.156718183) + +LINESTRING (2552888.7732270965 6673293.051098018, 2552879.3357571587 6673419.2100551445) + +LINESTRING (2553070.4445233927 6674102.01677902, 2553025.905274973 6674099.6162280245, 2553022.6054603094 6674161.260377139, 2553017.0947698215 6674169.642301032, 2552992.205917722 6674154.008712672, 2552984.0471259668 6674152.608391258) + +LINESTRING (2553315.5877547404 6673324.248258668, 2553328.457031928 6673316.036373803) + +LINESTRING (2551039.7138308943 6675190.116529359, 2551019.4859670075 6675223.744247892) + +LINESTRING (2552713.016848584 6676244.208473923, 2552762.827550929 6676310.513692887) + +LINESTRING (2550514.3503383263 6674728.170499395, 2550507.346481703 6674724.719707338) + +LINESTRING (2553373.021028958 6675488.214951562, 2553379.010192572 6675456.007559034, 2553363.2040803344 6675432.822237332, 2553328.0115569485 6675425.510559091, 2553315.167028371 6675433.792460027) + +LINESTRING (2550165.947656622 6676333.578987038, 2550163.3078048914 6676323.626702702, 2550165.221697396 6676312.714197966, 2550176.4988140087 6676300.621422324, 2550187.2809584215 6676297.890795567) + +LINESTRING (2553105.2658176287 6673629.888411916, 2552956.9143998967 6673618.665836011) + +LINESTRING (2553084.064508416 6676100.765549626, 2553105.1255755057 6676116.769222932) + +LINESTRING (2552590.024506541 6675868.522243075, 2552606.5565780047 6675885.096047242) + +LINESTRING (2548776.5689421124 6672470.202230424, 2548598.576939166 6672504.560116551) + +LINESTRING (2551465.6374085797 6673661.9857791895, 2551457.841596437 6673570.304735741) + +LINESTRING (2551584.183250364 6677169.180781798, 2551616.562681749 6677182.5638536, 2551603.363423095 6677252.729958749, 2551590.774630154 6677326.5469018705) + +LINESTRING (2552035.4659037376 6676994.45067619, 2552034.0222348226 6677000.342028425) + +LINESTRING (2547162.2006143117 6677254.1602870505, 2547175.515366479 6677256.300778355) + +LINESTRING (2554326.5684722555 6675869.682509391, 2554395.4933510385 6675847.697463186) + +LINESTRING (2551374.3892835984 6672043.314247294, 2551364.5310872914 6671947.522260265) + +LINESTRING (2553096.81829209 6676021.077258861, 2553171.336356728 6675959.843203875, 2553183.3311830293 6675952.131433801, 2553201.7441488514 6675946.3501068195) + +LINESTRING (2551800.230365917 6672605.523290517, 2551785.174961515 6672603.022716563, 2551761.795774624 6672609.224139969, 2551737.7731238743 6672604.973164247, 2551675.596366078 6672560.723007558, 2551609.583573736 6672512.792006007, 2551592.7710180255 6672511.671748877, 2551562.9076953214 6672521.093911535, 2551507.050082606 6672544.609308998, 2551487.9111575577 6672562.0333083095, + 2551420.1329643703 6672640.221254703, 2551414.6140243458 6672657.84529993, 2551395.013125245 6672698.214565843, 2551382.737814697 6672714.818376898, 2551364.7703238544 6672731.342169586, 2551332.7043748624 6672762.019210854, 2551326.104745535 6672791.0058641285, 2551317.2612422374 6672889.818544494) + +LINESTRING (2551519.869862573 6672942.42061819, 2551428.9187209117 6672931.848191513) + +LINESTRING (2551774.252574979 6674172.703003552, 2551844.6623703605 6674216.3330179015) + +LINESTRING (2551458.163328367 6673872.90419106, 2551492.902127236 6673776.792130565) + +LINESTRING (2551082.3969335663 6675956.682478397, 2551050.380481794 6676014.395725255) + +LINESTRING (2547013.139736427 6677294.529552964, 2547063.527906338 6677265.18281704, 2547094.636909078 6677249.819290667, 2547114.6915326947 6677243.657876444, 2547137.9634756087 6677244.258014193, 2547162.2006143117 6677254.1602870505) + +LINESTRING (2551612.3884162 6672988.061093998, 2551655.096267482 6673173.833734188) + +LINESTRING (2553820.1294167824 6677524.132253419, 2553834.4588619582 6677520.791486616, 2553855.783914221 6677521.091555491, 2553884.566547623 6677532.484170426, 2553902.781524565 6677548.137763377, 2553937.437828068 6677596.8189371135) + +LINESTRING (2553098.567193862 6673709.276633807, 2552952.212164001 6673697.553943111) + +LINESTRING (2549999.9999771975 6675316.555550768, 2549983.888632103 6675286.308608221, 2549972.3722789274 6675285.618449809) + +LINESTRING (2553447.770080622 6676247.48922695, 2553412.2310766964 6676283.58751255) + +LINESTRING (2553499.816407401 6672266.725526639, 2553477.25392464 6672208.932261415, 2553439.60303933 6672204.061143353, 2553432.656929463 6672199.62012401) + +LINESTRING (2551344.7569479207 6674104.177274917, 2551321.955228596 6674108.958372317, 2551288.7425940083 6674110.538735055, 2551160.388053137 6674084.392733793) + +LINESTRING (2554443.794388175 6673363.117180209, 2554419.5654990086 6673407.567382815, 2554372.741128934 6673408.547607805) + +LINESTRING (2546894.247414103 6672981.289539731, 2546900.5830582567 6672983.37001726, 2546952.1096642264 6672967.336337067) + +LINESTRING (2552568.922191768 6672052.846435207, 2552530.1906171557 6672202.120697964) + +LINESTRING (2552733.706686524 6674363.156718183, 2552729.771657538 6674428.26166165) + +LINESTRING (2553722.1084222044 6676732.620578615, 2553879.567328408 6676716.386852507, 2553891.8261398827 6676716.9269764805, 2553915.7250475828 6676736.621496942) + +LINESTRING (2551469.6466833954 6673988.37069396, 2551375.3132317043 6673964.885303384) + +LINESTRING (2550187.2809584215 6676297.890795567, 2550200.2822281956 6676301.631654202, 2550202.946828536 6676304.2822625935) + +LINESTRING (2551813.8668500134 6673803.158182336, 2551795.5776272416 6673793.976074777, 2551731.78396026 6673845.057799509) + +LINESTRING (2553270.223552655 6673799.537351251, 2553092.8007677374 6673789.244988856) + +LINESTRING (2549148.9200287363 6676040.821790801, 2549151.5103832474 6676045.732918046, 2549227.925841316 6676190.726198195) + +LINESTRING (2553923.430114822 6672945.05122199, 2553923.570356945 6672935.098937653, 2553934.6494846777 6672924.7465614835, 2553958.6721354276 6672914.244150877, 2553978.083295185 6672908.722883586, 2554043.2711338615 6672907.632633342, 2554059.4897229327 6672917.074800593, 2554066.1141008693 6672926.416944885, 2554065.3551434968 6672955.5536325965) + +LINESTRING (2553238.7845684486 6676995.460908067, 2553233.5956098903 6676956.431949793) + +LINESTRING (2553071.0549891056 6675017.826983929, 2552987.3881883137 6675082.56184245, 2552968.340008169 6675103.746704988) + +LINESTRING (2553372.7487942483 6676171.031677733, 2553447.770080622 6676247.48922695) + +LINESTRING (2551374.3892835984 6672043.314247294, 2551380.0649648197 6672051.496125272, 2551417.1466321 6672056.937374196, 2551426.072630765 6672063.0687815305, 2551429.9004157744 6672071.310673283, 2551382.6965670134 6672509.321209359, 2551355.9928168496 6672543.769116149) + +LINESTRING (2552715.260722555 6675284.768254665, 2552842.6418181015 6675292.620056881) + +LINESTRING (2551960.758099757 6676974.956201645, 2551959.4134252816 6676980.72752633) + +LINESTRING (2553052.246045524 6675578.855756246, 2553018.50544059 6675578.375646046, 2552866.8294595843 6675678.07853074, 2552850.0086543374 6675677.598420541) + +LINESTRING (2551366.3872330394 6674304.313211898, 2551307.7165283235 6674304.733308323) + +LINESTRING (2553504.419648857 6675758.016878901, 2553353.255139124 6675804.357515416) + +LINESTRING (2550661.109595483 6675351.45356087, 2550612.7755602 6675371.6882053055, 2550578.9689589734 6675364.496554614, 2550567.6340956045 6675338.260532688, 2550574.2914716876 6675320.2864071075, 2550653.817005077 6675339.81088854) + +LINESTRING (2549078.518482892 6671515.843177441, 2548899.0168147366 6671469.6525753625) + +LINESTRING (2549957.399369892 6676568.973016771, 2549903.752633001 6676653.942519727) + +LINESTRING (2552938.220949828 6673883.426606258, 2552935.6140962443 6673927.976831823, 2552921.309399678 6673955.193078739) + +LINESTRING (2552256.454491749 6673534.296470803, 2552181.4084567656 6673476.683246903) + +LINESTRING (2552590.024506541 6675868.522243075, 2552573.698673493 6675872.113067273, 2552411.248797612 6675882.315409006) + +LINESTRING (2550232.8843970704 6677124.780590671, 2550311.5932263304 6677127.911309262) + +LINESTRING (2552587.524896933 6673579.326806567, 2552510.0452486356 6673575.045823957) + +LINESTRING (2550234.880784942 6676700.8732916955, 2550305.4720701296 6676712.665998463) + +LINESTRING (2551485.098065557 6674678.779162656, 2551482.5324596562 6674683.330207252) + +LINESTRING (2547474.643565721 6677223.763310066, 2547399.944011277 6677255.330555662, 2547230.6222713585 6677319.825359083, 2547208.0350399874 6677318.315012414, 2547200.2309783082 6677308.102668386) + +LINESTRING (2552655.97130259 6672798.9676915975, 2552599.255738062 6672877.725768852) + +LINESTRING (2551370.503751832 6673963.615011815, 2551365.6117765936 6673962.324715655) + +LINESTRING (2550993.1864441396 6675199.478678242, 2550960.6832697047 6675199.428666763, 2550900.989622443 6675190.876703841) + +LINESTRING (2552912.630887113 6676335.909521963, 2552959.414009504 6676398.26383408) + +LINESTRING (2552633.0953374356 6673626.467626747, 2552622.8329138323 6673749.445853804) + +LINESTRING (2551435.485352092 6673768.170151572, 2551398.321189445 6673860.751401644) + +LINESTRING (2553672.239973103 6677388.731174959, 2553628.212195956 6677344.641055002) + +LINESTRING (2548200.495547704 6671992.0024697585, 2548151.377806438 6672015.597885588, 2548108.4802158135 6672048.515441119, 2548090.727212924 6672066.879656237, 2548058.941748178 6672108.509211423) + +LINESTRING (2551022.645539548 6672570.415232203, 2551026.6383152907 6672522.404212287, 2551032.5862312214 6672510.751537661) + +LINESTRING (2553785.2338767163 6673218.283936794, 2553780.1521621346 6673315.01613963) + +LINESTRING (2551269.785158767 6673683.120630248, 2551263.5815071994 6673683.270664685) + +LINESTRING (2547888.7043096907 6672669.0778781315, 2547882.871887273 6672694.0436084885, 2547876.132015823 6672722.87022503) + +LINESTRING (2551826.9588646907 6672789.355485318, 2551768.7088863445 6672875.395233927) + +LINESTRING (2549965.4591672076 6676688.620479321, 2549926.9255814753 6676671.406528221, 2549903.752633001 6676653.942519727) + +LINESTRING (2552908.753604884 6674299.502107611, 2552905.7342744665 6674299.052004299) + +LINESTRING (2553805.0740123806 6673063.04830573, 2553824.567667505 6673093.225232207) + +LINESTRING (2551964.618882913 6676958.282374519, 2551961.9542825725 6676969.775012411) + +LINESTRING (2553841.6277093147 6673119.391238062, 2553978.339030822 6673032.391269054) + +LINESTRING (2553041.0431747413 6676562.551542857, 2553109.8113123276 6676658.843644677, 2553114.3320584167 6676665.175097928) + +LINESTRING (2548241.652486094 6672848.799129353, 2548236.3727826322 6672840.697269741, 2548234.120659124 6672824.61357807, 2548236.042801166 6672815.441472807, 2548243.285894352 6672806.419401981) + +LINESTRING (2553143.370427455 6675083.712106469, 2553170.527902135 6675122.29096143, 2553180.0973646594 6675129.492614418) + +LINESTRING (2553020.4605807783 6676178.553404187, 2553055.9253388736 6676203.589150614) + +LINESTRING (2552932.009048724 6672051.656162005, 2552689.9841422336 6671988.821739689) + +LINESTRING (2554239.172880894 6675133.953638352, 2554257.7920851326 6675124.461459623) + +LINESTRING (2553023.9996320046 6672035.852534615, 2552985.4247985887 6671987.861519291, 2552951.6016982887 6671978.96947831) + +LINESTRING (2551596.433812302 6671064.409560379, 2551481.427021744 6671124.963459249) + +LINESTRING (2551868.6767715737 6676065.037348972, 2551856.8881836883 6676082.841435524, 2551844.6458712867 6676093.863965513, 2551776.083972117 6676132.332795221) + +LINESTRING (2554008.458089162 6675550.689291228, 2554011.683657996 6675583.416803137, 2554014.3977555563 6675594.989459396, 2554017.0046091406 6675600.560738166) + +LINESTRING (2553310.629783209 6676647.3510067845, 2553286.912365315 6676669.9361907365, 2553208.731506401 6676720.377768537, 2553149.5245818025 6676714.866503542, 2553114.3320584167 6676665.175097928) + +LINESTRING (2551895.075288881 6673445.706136761, 2551832.4695551787 6673402.116131595) + +LINESTRING (2550219.7346356367 6676905.580277865, 2550248.4430232085 6676902.809641924, 2550270.3867907207 6676906.280438572, 2550285.260705316 6676914.342289, 2550307.055981168 6676937.517608405, 2550312.541923046 6676953.311233498, 2550311.5932263304 6677127.911309262) + +LINESTRING (2552795.8091984903 6676178.813463878, 2552713.016848584 6676244.208473923) + +LINESTRING (2553523.0058549484 6675833.664242157, 2553532.6825614492 6675844.096636693, 2553564.418528975 6675862.490858698) + +LINESTRING (2551469.6466833954 6673988.37069396, 2551435.5678474586 6674092.2645406) + +LINESTRING (2554459.1302768234 6675014.6662584515, 2554244.320591769 6674631.058209318) + +LINESTRING (2552966.162130491 6673509.980889674, 2552963.6212732 6673523.774055605) + +LINESTRING (2549000.560361468 6672094.435981209, 2548812.1409441847 6672129.604053299) + +LINESTRING (2551820.4664793406 6674029.830210117, 2551708.858497886 6674048.154416052) + +LINESTRING (2548442.6524467813 6676602.390687092, 2548465.899641085 6676630.277087826, 2548482.283220889 6676658.733619423) + +LINESTRING (2552487.458017264 6672030.541315537, 2552443.66947668 6672192.648523826) + +LINESTRING (2549309.6705000666 6670983.260934425, 2549279.015221843 6671116.551528468, 2549270.600694451 6671125.503583223) + +LINESTRING (2554358.0404546084 6673304.683768053, 2554354.955127898 6673311.345297066, 2554358.2549425615 6673315.616277379) + +LINESTRING (2551115.9395496203 6672778.863077007, 2551005.1565218316 6672769.690971744) + +LINESTRING (2553352.6364238746 6673359.166273362, 2553373.384008571 6673347.723646948) + +LINESTRING (2553070.3290298795 6675956.22237279, 2553056.8162888326 6675976.8971182415, 2553042.33010246 6675991.860552782, 2553001.9073728328 6676024.287995817) + +LINESTRING (2549318.1510237516 6672494.647841398, 2549307.3771288753 6672502.729696416, 2549254.2088651103 6672523.984575026, 2549151.9146105433 6672527.495380857) + +LINESTRING (2551565.597044272 6672958.694353483, 2551519.869862573 6672942.42061819) + +LINESTRING (2549907.3411814477 6676348.252355, 2549950.8244891753 6676393.332702243) + +LINESTRING (2552844.266976823 6672450.797776541, 2552837.8075896194 6672534.056886912) + +LINESTRING (2552800.2309501395 6673040.093036833, 2552796.015436907 6673098.0563410865) + +LINESTRING (2551398.321189445 6673860.751401644, 2551383.892749829 6673906.171826945, 2551370.503751832 6673963.615011815) + +LINESTRING (2551683.6644129306 6674375.029443317, 2551528.069902012 6674337.650863852) + +LINESTRING (2553578.599482491 6672290.310940173, 2553540.833103668 6672381.091776999, 2553523.071851242 6672407.917934378, 2553505.426092329 6672426.992312498, 2553482.7316169813 6672438.925051407, 2553418.1459944807 6672454.128541047, 2553388.769394439 6672466.181307505) + +LINESTRING (2552115.643150523 6676678.328116926, 2552038.6089772047 6676658.383539069) + +LINESTRING (2551196.801507948 6675400.394794297, 2551120.806776249 6675346.8525047945) + +LINESTRING (2554336.4761657827 6675725.299369287, 2554395.4933510385 6675847.697463186) + +LINESTRING (2554126.7481953106 6677564.881606573, 2554102.1645760676 6677587.346762976, 2554055.67018746 6677619.424125657) + +LINESTRING (2552039.310187821 6672058.027624439, 2552011.946474724 6672145.087607222) + +LINESTRING (2550544.1476647374 6675483.043764625, 2550514.375086936 6675480.83325725, 2550513.294397634 6675580.226070773, 2550543.355709218 6675639.919772202, 2550510.1348250937 6675681.119228668) + +LINESTRING (2552036.455848137 6676990.389744088, 2552035.4659037376 6676994.45067619) + +LINESTRING (2553272.3601826495 6674925.315749927, 2553279.925007765 6674932.947501635) + +LINESTRING (2549088.203438929 6676042.572192569, 2549032.073591504 6676133.443050057, 2549026.769139432 6676151.847274358, 2549004.2066566707 6676188.2156219445, 2548995.0001737596 6676208.860360509) + +LINESTRING (2547609.4657433326 6674874.924183606, 2547585.5750851696 6674849.688391263, 2547548.881146112 6674822.56216501, 2547509.2091243207 6674800.907194569, 2547414.2652069163 6674770.770277275, 2547371.3676162916 6674760.517924064) + +LINESTRING (2547876.132015823 6672722.87022503, 2547881.403469748 6672694.513716391) + +LINESTRING (2551281.2190165757 6674505.089295812, 2551281.821232752 6674512.040891404, 2551258.524541228 6674562.652508233, 2551166.9711833904 6674761.498149053) + +LINESTRING (2551918.421477625 6673645.842073742, 2551913.018031114 6673659.905301659, 2551875.9528629063 6673714.607857477, 2551840.6200973974 6673766.099676338) + +LINESTRING (2549179.0968338335 6676455.867055684, 2549156.856083002 6676403.154956734, 2549158.66273153 6676391.662318842, 2549179.492811593 6676363.095761991) + +LINESTRING (2549155.024685864 6672944.45108424, 2549050.552553619 6672969.036727357, 2549016.572712122 6672958.524314454) + +LINESTRING (2550838.3096429105 6671750.977147481, 2550779.399701631 6671848.84961204) + +LINESTRING (2550386.4577715076 6676872.182612135, 2550604.0145522687 6676889.226524206) + +LINESTRING (2552342.0186859723 6675795.485479027, 2552319.9016781906 6675755.536309538, 2552302.6766456473 6675735.471704132) + +LINESTRING (2553744.1181860096 6677247.3487236, 2553727.5943640824 6677300.7809878485) + +LINESTRING (2552629.432543159 6674742.873874244, 2552573.50893415 6674798.426625206, 2552562.924778617 6674807.318666186, 2552545.1882748012 6674815.120456923, 2552518.270036684 6674811.499625837, 2552506.9021751685 6674803.67783051, 2552444.3624377595 6674745.6045010025) + +LINESTRING (2552833.2043481637 6675821.75150784, 2552839.267757608 6675828.933156236) + +LINESTRING (2553239.238292965 6674886.036734258, 2553322.8968442203 6674814.300268666, 2553410.886402221 6674736.8424898675) + +LINESTRING (2552713.016848584 6676244.208473923, 2552561.233623602 6676367.206705571, 2552526.4948247327 6676386.961239808) + +LINESTRING (2551385.080683108 6674421.690153298, 2551392.612510077 6674494.64689898) + +LINESTRING (2553785.118383203 6675669.196492055, 2553795.603544296 6675666.425856114) + +LINESTRING (2548621.320911734 6675563.552243647, 2548605.9107772554 6675559.371283996) + +LINESTRING (2552766.482095669 6673692.762843415, 2552769.3446848895 6673764.979419206) + +LINESTRING (2547618.3422447774 6674886.046736554, 2547609.4657433326 6674874.924183606) + +LINESTRING (2551770.499035799 6674351.273990754, 2551765.8792952704 6674350.123726735) + +LINESTRING (2550729.4157590168 6675166.941209953, 2550721.677693631 6675219.033166562) + +LINESTRING (2553289.4367235326 6675126.671966998, 2553270.3472957048 6675135.784058486) + +LINESTRING (2548600.4413344506 6676332.238679399, 2548613.9788241074 6676344.651528507, 2548642.7614575094 6676395.353165997) + +LINESTRING (2547767.007144903 6673898.2700132495, 2547849.4447647324 6673884.136769262) + +LINESTRING (2553358.3863509255 6674072.089909939, 2553284.6107445876 6674067.3188148355, 2553277.4088990847 6674161.500432238) + +LINESTRING (2547741.219093308 6673902.38095683, 2547767.007144903 6673898.2700132495) + +LINESTRING (2552885.8281425093 6675295.880805316, 2552883.279035682 6675339.250759974, 2552880.9444168075 6675375.529086899) + +LINESTRING (2552585.050035936 6677084.691389041, 2552527.3940242287 6677090.69276653, 2552505.202770617 6677101.255190913, 2552473.9617752903 6677100.154938373, 2552447.6457533496 6677076.079412344) + +LINESTRING (2551603.297426802 6677433.98156123, 2551631.4200972714 6677502.687331189, 2551638.3827062114 6677533.894494135, 2551666.3816336305 6677622.074734049) + +LINESTRING (2552762.6213125126 6673869.363378341, 2552638.878262633 6673862.84188147) + +LINESTRING (2554104.1774630123 6677538.065451491, 2554288.274123086 6677394.042394036) + +LINESTRING (2553024.99782594 6676248.229396841, 2552912.630887113 6676335.909521963) + +LINESTRING (2552994.8622685266 6673053.926211947, 2552983.1231778613 6673226.425805588) + +LINESTRING (2550668.0144576663 6675971.205811922, 2550671.0337880836 6675975.426780757) + +LINESTRING (2549038.92070693 6671689.052934085, 2548856.308963455 6671647.263342166) + +LINESTRING (2552264.671030261 6672803.6187591525, 2552125.790080613 6672703.615805584) + +LINESTRING (2551653.759842543 6676648.441257029, 2551635.99034058 6676720.5178006785) + +LINESTRING (2553645.173243326 6673111.869511608, 2553670.9777939944 6673151.3385708975) + +LINESTRING (2552350.5899545606 6672084.733754268, 2552337.415444517 6672086.264105528, 2552268.3998208307 6672073.281125559) + +LINESTRING (2551439.808109301 6673769.050353603, 2551435.485352092 6673768.170151572) + +LINESTRING (2553197.1326578595 6675362.035989843, 2553160.983188221 6675355.064389659, 2553131.986066866 6675319.296179822) + +LINESTRING (2552249.4588846625 6672531.896391016, 2552178.768605035 6672482.044948669) + +LINESTRING (2553344.139401116 6673364.037391424, 2553346.457520917 6673362.567053939) + +LINESTRING (2551893.7883611624 6673596.390723228, 2551887.972437818 6673592.839908214) + +LINESTRING (2552035.4659037376 6676994.45067619, 2551960.758099757 6676974.956201645) + +LINESTRING (2548204.9172993526 6672577.186786471, 2548203.1024012878 6672564.973983279, 2548209.1823098054 6672553.081253555, 2548275.376591954 6672464.21085523, 2548287.8168932353 6672458.179470852, 2548324.791316539 6672456.579103522) + +LINESTRING (2553388.9756328557 6672231.9875532705, 2553347.7114504892 6672197.249579902, 2553290.179181832 6672173.0340217315) + +LINESTRING (2552437.820555189 6672563.973753698, 2552299.6078180103 6672464.140839159) + +LINESTRING (2551944.9354884457 6673645.44198191, 2551925.8295615446 6673646.592245929, 2551925.4665819313 6673646.552236745) + +LINESTRING (2547974.804723797 6677400.693920755, 2547939.8184388275 6677412.386604563, 2547759.2113327603 6677485.943487993) + +LINESTRING (2553378.6637120326 6675701.753964936, 2553378.8781999857 6675704.80466516) + +LINESTRING (2552790.8677260317 6676479.262425598, 2552742.8141749953 6676471.2505866485) + +LINESTRING (2550369.2079903544 6675868.362206343, 2550373.0935221203 6676022.147504513, 2550391.8694675555 6676050.253955755) + +LINESTRING (2548768.484396187 6676625.876077668, 2548768.3524036007 6676634.418038295) + +LINESTRING (2551658.899303881 6673651.903465007, 2551645.3123170044 6673652.453591277) + +LINESTRING (2548587.390567457 6675960.003240609, 2548586.606861474 6675983.158555422, 2548594.9883907195 6676006.493911561) + +LINESTRING (2551179.4774809647 6677181.763669935, 2551135.086724205 6677249.159139142) + +LINESTRING (2552288.5451893513 6673519.573091362, 2552275.9398973365 6673509.820852942) + +LINESTRING (2552970.3528951136 6676142.775192053, 2553020.4605807783 6676178.553404187) + +LINESTRING (2552509.789512999 6675412.50757453, 2552507.603385784 6675416.78855714) + +LINESTRING (2553284.569496904 6677555.169377336, 2553384.306395107 6677653.441933728) + +LINESTRING (2552766.267607716 6673511.301192722, 2552662.2162018404 6673501.088848694) + +LINESTRING (2547791.145289166 6675062.09714521, 2547777.3108161893 6675000.362975434, 2547757.9079059684 6674907.281610571) + +LINESTRING (2552599.255738062 6672877.725768852, 2552521.487355981 6672986.790802429) + +LINESTRING (2553579.878160673 6676443.8843052965, 2553592.2112179776 6676440.853609664, 2553672.726695766 6676456.377172771) + +LINESTRING (2549044.6953825913 6677254.21029853, 2549009.032635616 6677388.471115267) + +LINESTRING (2548860.705966494 6672161.711422868, 2548880.463606791 6672266.825549598, 2548896.2449704194 6672351.384958426) + +LINESTRING (2551445.2198053496 6672682.380931567, 2551414.6140243458 6672657.84529993) + +LINESTRING (2549129.1046416825 6671709.017516534, 2549123.552703511 6671732.572923181, 2549097.913143576 6671757.208577774) + +LINESTRING (2550324.074775295 6676211.360934463, 2550320.692465265 6676206.41980033) + +LINESTRING (2553015.3458680497 6672745.815491632, 2553064.8595870747 6672720.689724542, 2553141.8855108563 6672701.855401521, 2553171.039373408 6672675.199283171, 2553186.8619847195 6672618.366238344, 2553176.9955388755 6672590.149761848, 2553149.5493304124 6672557.952371617) + +LINESTRING (2549413.3176786457 6671230.407661741, 2549399.4007103024 6671227.076897234, 2549384.66703783 6671217.424681772, 2549287.2895071115 6671136.266053521, 2549270.600694451 6671125.503583223) + +LINESTRING (2551326.8967010546 6673752.106464491, 2551301.966601272 6673840.286704404) + +LINESTRING (2549999.9999771975 6676444.304401721, 2549995.050255202 6676439.183226263) + +LINESTRING (2552610.153375988 6677178.372891653, 2552667.0339312493 6677171.111224891, 2552726.1831090916 6677163.55949155, 2552804.8341915947 6677153.51718655, 2552859.495621495 6677146.545586367, 2552865.080557813 6677154.937512556, 2552871.8039301895 6677202.028321258, 2552918.3973132377 6677227.804237575) + +LINESTRING (2551032.5862312214 6672510.751537661, 2550968.429584627 6672463.97080013) + +LINESTRING (2551327.3586751074 6672469.292021504, 2551302.5853165216 6672478.3741061045) + +LINESTRING (2547589.7988479384 6671804.979542592, 2547600.448999765 6671807.180047671, 2547612.996545023 6671799.388259231, 2547625.8328240635 6671797.7878919, 2547695.7641463187 6671807.050017825, 2547765.695468574 6671861.002401457, 2547781.815063205 6671864.313161372) + +LINESTRING (2552841.9571065586 6673043.233757719, 2552800.2309501395 6673040.093036833) + +LINESTRING (2552582.5586758647 6673055.516576981, 2552576.7427525204 6673055.246514994) + +LINESTRING (2549517.5423247907 6671512.252353243, 2549594.494002742 6671527.5658681365, 2549597.0266104965 6671528.065982928) + +LINESTRING (2549685.8081240165 6675916.403233146, 2549677.5420882846 6675906.200891415, 2549658.44441092 6675896.308620852, 2549456.7679882264 6675900.989695294) + +LINESTRING (2551435.5678474586 6674092.2645406, 2551354.903878011 6674102.476884628) + +LINESTRING (2551028.2799730855 6674580.806675139, 2550937.4113267907 6674556.25103891, 2550839.7863099724 6674532.4455748685) + +LINESTRING (2549568.351221071 6676074.7895873925, 2549588.8348205946 6676110.737838554, 2549596.754375787 6676136.793819156, 2549605.7958679646 6676198.618009593) + +LINESTRING (2551592.0780569464 6676894.527740988, 2551523.4666605564 6677169.820928731) + +LINESTRING (2550327.4653348615 6676216.322073188, 2550324.074775295 6676211.360934463) + +LINESTRING (2551347.5947885313 6674889.117441369, 2551245.6800126503 6674810.619423806) + +LINESTRING (2552805.8406350673 6676650.841808024, 2552848.3504974693 6676699.5529886475) + +LINESTRING (2552426.8404218964 6675906.450948809, 2552470.90119719 6675959.90321765) + +LINESTRING (2551697.0286623174 6673975.887828781, 2551624.8452165546 6673987.740549323, 2551623.3190522725 6673977.108108871, 2551500.805183355 6673995.512333172, 2551469.6466833954 6673988.37069396) + +LINESTRING (2553376.452836208 6673806.188877968, 2553270.223552655 6673799.537351251) + +LINESTRING (2547920.50627351 6672635.070072358, 2547892.4331002603 6672653.104211714) + +LINESTRING (2548909.716463783 6676167.730920114, 2548866.084664395 6676276.585905479, 2548863.6180529343 6676294.670056314, 2548866.5796365947 6676319.20568795) + +LINESTRING (2552098.2201290997 6676377.8591506155, 2552097.370426824 6676416.738074452, 2552089.5251174616 6676457.277379394) + +LINESTRING (2552923.314037086 6674179.344527974, 2552918.3478160175 6674178.664371858) + +LINESTRING (2553285.9141713795 6674257.772529467, 2553190.731017412 6674254.171702973, 2553163.4662987553 6674260.113066687) + +LINESTRING (2549174.402847475 6671097.657191671, 2549125.4665960157 6671310.466037451) + +LINESTRING (2548598.576939166 6672504.560116551, 2548615.777223099 6672593.840609004, 2548678.613943828 6672581.437762192, 2548782.1291298205 6672561.273133827, 2548793.9754644623 6672558.962603494) + +LINESTRING (2553352.5456789713 6675010.225239109, 2553453.15702806 6675162.200121736) + +LINESTRING (2551295.399970092 6677111.777606111, 2551324.520834497 6677004.983093684, 2551302.164590152 6677000.882152399, 2551293.1890942673 6677011.784654839, 2551278.3481778186 6677010.024250775, 2551271.765047565 6677000.902156991, 2551273.9264261695 6676981.847783461) + +LINESTRING (2552915.658467067 6674300.512339488, 2552908.753604884 6674299.502107611) + +LINESTRING (2552695.668072991 6675661.664763306, 2552715.433962825 6675686.590484479, 2552742.599687042 6675712.626460488, 2552755.2627258133 6675724.529192509) + +LINESTRING (2550815.9781471756 6672914.404187609, 2550828.5009438237 6672934.278749396, 2550852.053370984 6672955.323579793) + +LINESTRING (2551686.840484544 6673785.184056754, 2551606.0610215827 6673728.901138199) + +LINESTRING (2553683.9790637684 6675997.65188206, 2553613.321782287 6675997.141764973, 2553524.4742724737 6675996.581636407, 2553513.964362771 6675992.810770884) + +LINESTRING (2552411.215799465 6671838.257180772, 2552442.0608170317 6671888.928811375, 2552450.0546180536 6671923.526752602, 2552452.265493878 6671946.271973288, 2552450.1371134203 6671958.454769592) + +LINESTRING (2551513.327980003 6674483.304295525, 2551518.9211658575 6674539.787259997) + +LINESTRING (2551969.535606762 6673214.333029946, 2551953.028283908 6673208.571707557, 2551871.4321168177 6673231.22690758) + +LINESTRING (2549484.469932326 6671130.134646186, 2549497.231965537 6671140.727077454, 2549499.772822828 6671397.626043191, 2549493.272187941 6671418.080738135, 2549495.722300329 6671447.877577371) + +LINESTRING (2553209.2099795276 6675696.742814733, 2553130.9878729302 6675697.412968552, 2553080.269721553 6675702.394111868, 2553044.136750988 6675713.786726803) + +LINESTRING (2548616.8661619383 6672245.690698538, 2548556.8672818197 6672330.980274961, 2548546.0686383336 6672346.333799038) + +LINESTRING (2550424.3313943073 6672768.740753642, 2550421.0645777904 6672772.481612277) + +LINESTRING (2551631.1726111714 6674317.166162021, 2551431.1625948832 6674269.815293629, 2551369.464310213 6674242.12893881) + +LINESTRING (2550443.4868184286 6676129.602168463, 2550440.8057190147 6676125.491224883) + +LINESTRING (2552199.210956875 6672085.163852988, 2552158.169511998 6672075.951738542, 2552146.0756912567 6672080.212716559, 2552135.6565264566 6672092.005423326) + +LINESTRING (2553290.806146618 6673314.916116672, 2553302.9907122627 6673328.169158628, 2553302.866969213 6673339.621787338, 2553299.34441706 6673391.583714101) + +LINESTRING (2552643.258766599 6673756.567488425, 2552645.4943910334 6673763.759139117, 2552639.3567357594 6673853.58975784) + +LINESTRING (2552803.943241636 6675439.963876545, 2552705.7820049347 6675432.572179938) + +LINESTRING (2551082.545425226 6675357.174874077, 2551043.657109417 6675369.397679564, 2551027.050792123 6675395.103579811) + +LINESTRING (2551455.746214126 6673563.933273306, 2551427.202817287 6673567.884180153, 2551286.2512339377 6673585.218158802) + +LINESTRING (2552390.534211062 6675006.754442461, 2552312.8730729576 6675064.587716868, 2552309.0287888744 6675070.719124204) + +LINESTRING (2553565.094990981 6674021.468290815, 2553561.6796828043 6674022.26847448) + +LINESTRING (2549063.7600618093 6676756.946162039, 2549032.9232937796 6676911.541646171) + +LINESTRING (2551983.931048231 6672903.211618591, 2551923.44544545 6672987.520970024) + +LINESTRING (2552658.1574298046 6675140.395116857, 2552552.216880034 6675219.863357116) + +LINESTRING (2550089.9611744597 6676277.016004199, 2550075.6564778937 6676303.832159282, 2550063.785394642 6676340.120488502, 2550059.8008684358 6676375.318567478, 2550066.944967182 6676406.875810778, 2550088.5422541546 6676439.833375491, 2550110.8984984993 6676456.087106192, 2550136.4308144576 6676464.619064523, 2550173.9249585713 6676467.729778522) + +LINESTRING (2552885.225926333 6673938.009134526, 2552889.0537113426 6673977.008085913, 2552897.798220201 6673998.282969113) + +LINESTRING (2548409.3490672903 6672539.118048595, 2548261.4018768542 6672575.436384703, 2548204.9172993526 6672577.186786471) + +LINESTRING (2552868.842346529 6677328.447338075, 2552851.666811206 6677363.325343586, 2552710.9049671995 6677653.501947503) + +LINESTRING (2549225.8717066883 6676391.872367053, 2549223.3555980073 6676408.646217137, 2549230.012974091 6676428.090680203) + +LINESTRING (2551251.314446188 6676921.94403382, 2551248.8478347273 6676931.406205662, 2551229.6264143125 6677007.5336791165, 2551212.219891963 6677082.820959724, 2551212.929352116 6677090.332683881, 2551230.294626782 6677103.4156868085) + +LINESTRING (2549827.799148985 6676060.336269938, 2549806.721582822 6676037.010916095, 2549795.757948603 6676017.0063244635) + +LINESTRING (2548275.4590873206 6676549.548558296, 2548318.8434006083 6676596.559348631) + +LINESTRING (2554280.189577161 6673075.421145655, 2554266.635588431 6673100.146820912) + +LINESTRING (2551912.597304744 6677299.730746788, 2551917.1592985163 6677415.157240504, 2551924.130156993 6677482.70274415, 2551938.0141271893 6677573.793652145, 2551941.0829548263 6677586.416549465, 2551947.6495860065 6677613.392741281, 2551956.550836061 6677631.126811762, 2551968.199181823 6677649.330990147, 2551983.5680686184 6677661.813855326, 2551999.8279053723 6677670.175774627, + 2552016.566215253 6677675.446984523, 2552033.717001966 6677679.347879891, 2552054.5470820293 6677678.557698522, 2552090.440816031 6677666.6749710925, 2552102.732625652 6677655.452395187, 2552123.009986759 6677628.6462424, 2552136.176247266 6677605.070831162) + +LINESTRING (2546952.1096642264 6672967.336337067, 2547052.3002869454 6672935.599052443) + +LINESTRING (2553542.9862327357 6675506.95925392, 2553533.6147590918 6675507.999492685) + +LINESTRING (2548948.6130291284 6671255.803490818, 2548909.0235027033 6671246.531362596, 2548889.6453410923 6671241.990320295) + +LINESTRING (2552360.4316517944 6672117.5012753615, 2552338.5868787225 6672125.783176296, 2552308.7895523114 6672129.944131357, 2552261.4207128175 6672125.6131372675) + +LINESTRING (2552387.3498899117 6672630.489020874, 2552341.7794494093 6672696.104081427) + +LINESTRING (2548587.390567457 6675960.003240609, 2548597.6859892067 6675971.405857839, 2548602.1407390023 6675985.929191363, 2548594.9883907195 6676006.493911561) + +LINESTRING (2549605.7958679646 6676198.618009593, 2549607.280784563 6676221.383234871) + +LINESTRING (2551390.7481147926 6674544.158263269, 2551342.1005971166 6674633.5187740885, 2551245.6800126503 6674810.619423806) + +LINESTRING (2552769.3446848895 6673764.979419206, 2552643.258766599 6673756.567488425) + +LINESTRING (2552325.9403390246 6671965.876473087, 2552343.3468613746 6671989.031787901, 2552348.7420583493 6672011.997059095, 2552350.5899545606 6672084.733754268) + +LINESTRING (2553113.0533802346 6676122.790605012, 2553132.0438136226 6676137.233920171) + +LINESTRING (2553448.322799578 6675165.300833439, 2553381.2045693235 6675208.450737589) + +LINESTRING (2554045.5892536626 6673323.128001537, 2554066.3533374327 6673328.469227502, 2554097.445841099 6673345.293089065, 2554166.857442545 6673382.771691487, 2554229.4796753204 6673415.939304413) + +LINESTRING (2551849.595593282 6672448.047145191, 2551839.7703951215 6672466.191309801, 2551799.9003844503 6672520.0636750655, 2551797.2440336463 6672528.165534677, 2551800.230365917 6672605.523290517) + +LINESTRING (2552710.1872575106 6672835.416057551, 2552706.5574613805 6672882.976974156) + +LINESTRING (2552495.9550400223 6671994.583062079, 2552487.458017264 6672030.541315537) + +LINESTRING (2550829.325897489 6675864.911414286, 2550810.5499520544 6675880.254936067, 2550671.0337880836 6675975.426780757, 2550568.9540214697 6676046.99320732, 2550443.4868184286 6676129.602168463, 2550324.074775295 6676211.360934463, 2550235.021027065 6676278.466337092, 2550202.946828536 6676304.2822625935) + +LINESTRING (2552063.959803357 6673790.795344708, 2552037.8417702955 6673754.316971866) + +LINESTRING (2551206.618456572 6675407.336387593, 2551200.670540641 6675403.125421056) + +LINESTRING (2547915.3833112447 6673845.657937258, 2547935.652422815 6673857.020545305, 2547970.531463808 6673861.74162893) + +LINESTRING (2552122.746001586 6673002.154328803, 2552061.534439579 6673087.613944255) + +LINESTRING (2552672.198141197 6675830.973624582, 2552606.5565780047 6675885.096047242) + +LINESTRING (2549151.9146105433 6672527.495380857, 2549107.6888445164 6672515.902720006, 2549050.767041572 6672511.47170296, 2548935.2405302045 6672531.896391016) + +LINESTRING (2551655.096267482 6673173.833734188, 2551573.186617998 6673194.328438315) + +LINESTRING (2553279.4795327857 6672551.920987239, 2553283.6702974085 6672585.738749393) + +LINESTRING (2553357.8171328963 6675007.504614647, 2553352.5456789713 6675010.225239109) + +LINESTRING (2548817.0659175697 6676739.162080079, 2548827.5593281994 6676760.847057408, 2548826.3961435305 6676796.665278725) + +LINESTRING (2553169.719447543 6674624.686746883, 2553181.112057668 6674618.595348732, 2553213.37599554 6674595.089953564, 2553231.4012331394 6674563.35266894) + +LINESTRING (2547781.815063205 6671864.313161372, 2547821.635576656 6671910.9838736495, 2547861.076611421 6671954.783927027, 2547876.3630028493 6671967.746902404, 2547895.0977006014 6671978.22930842) + +LINESTRING (2554656.3272011112 6675864.1412375085, 2554612.423167014 6675880.555004942) + +LINESTRING (2552498.9166236827 6672416.219839904, 2552487.8622445604 6672410.318485373) + +LINESTRING (2549256.0485117855 6676792.624351216, 2549190.6544346926 6676779.691382726) + +LINESTRING (2552317.179331093 6673633.669279735, 2552315.545922835 6673650.46313441, 2552320.32240456 6673658.92507667, 2552358.7569958526 6673661.565682765, 2552359.0127314893 6673658.444966471) + +LINESTRING (2550929.1040433757 6674996.93218797, 2550900.989622443 6675190.876703841) + +LINESTRING (2548977.4369102134 6671973.518227091, 2548788.6215151707 6672008.0761591345) + +LINESTRING (2553115.338501889 6674468.290849505, 2553136.8615430314 6674489.455707451, 2553161.263672468 6674509.460299083) + +LINESTRING (2552847.962769246 6673878.025366519, 2552762.6213125126 6673869.363378341) + +LINESTRING (2552188.3380675586 6673180.105173664, 2552061.534439579 6673087.613944255) + +LINESTRING (2553080.822440509 6672916.394644477, 2553069.644318337 6672961.244938916) + +LINESTRING (2553941.0511251246 6673227.276000733, 2553933.329558812 6673324.638348205) + +LINESTRING (2553654.69320863 6675521.5926127, 2553743.8212026902 6675464.299462265) + +LINESTRING (2551497.6291117417 6674081.552081781, 2551512.4040318974 6674180.384766739) + +LINESTRING (2549957.399369892 6676568.973016771, 2549848.2744989716 6676564.922086965, 2549847.160811523 6676590.908051495) + +LINESTRING (2548155.8325562337 6676774.85027155, 2548147.929500115 6676753.445358505) + +LINESTRING (2549961.2849016585 6677138.453729052, 2549900.155835018 6677138.173664769) + +LINESTRING (2550917.7691800063 6674209.481445267, 2550921.547467796 6674198.3989015035, 2550926.0847129584 6674192.2975010555, 2550948.762689233 6674188.726681449, 2550977.471076805 6674174.703462715, 2550997.6824416188 6674154.628855012, 2551010.510471123 6674129.593108585) + +LINESTRING (2549004.124161304 6672112.680168778, 2548857.076170364 6672141.0166728245) + +LINESTRING (2553377.5747731933 6675988.449769909, 2553273.7626038813 6675945.189840505, 2553248.609766609 6675941.959098957, 2553201.7441488514 6675946.3501068195) + +LINESTRING (2547626.294798116 6674630.097988919, 2547640.104522483 6674650.722722892, 2547656.4221059936 6674664.395861273, 2547739.907416979 6674658.604531995, 2547757.6356712584 6674652.723182055, 2547775.5866630278 6674641.390580895, 2547786.4100551237 6674627.257336908, 2547773.0045580533 6674599.16088796) + +LINESTRING (2551417.0146395136 6676405.98560645, 2551403.8153808597 6676457.767491889) + +LINESTRING (2553291.6228507473 6674559.161706992, 2553261.041818354 6674561.242184523) + +LINESTRING (2549805.7481374964 6676012.335252318, 2549819.005142907 6676016.836285435, 2549829.5233021467 6676016.386182123, 2549894.001680671 6675981.878261558, 2549939.365882756 6675948.670639449) + +LINESTRING (2549130.2678263513 6672089.474842485, 2549004.124161304 6672112.680168778) + +LINESTRING (2552097.857149487 6671828.464933168, 2552100.1092729946 6671880.116788762, 2552039.310187821 6672058.027624439) + +LINESTRING (2552039.8464077036 6676652.9322878495, 2552038.6089772047 6676658.383539069) + +LINESTRING (2549147.600102871 6671811.280988956, 2549354.2509961696 6672050.675937015) + +LINESTRING (2548873.171016385 6675909.131564088, 2548851.3427423863 6675891.12743162, 2548834.546685749 6675883.735735011, 2548756.0853425893 6675861.6306612585, 2548715.728609255 6675846.057086673, 2548702.034378402 6675837.93522247, 2548687.185212416 6675823.651944045) + +LINESTRING (2551754.717672171 6674389.842843421, 2551683.6644129306 6674375.029443317) + +LINESTRING (2553413.179773412 6676420.128852733, 2553480.3310018135 6676496.446369809) + +LINESTRING (2548714.095200997 6676795.715060622, 2548615.364746266 6676844.806328488, 2548604.4588588034 6676848.5471871225) + +LINESTRING (2552093.8891223543 6676457.64746434, 2552089.5251174616 6676457.277379394) + +LINESTRING (2553112.030437689 6673518.282795202, 2553112.269674252 6673535.126661356) + +LINESTRING (2552428.7213162547 6676613.913331872, 2552396.135646453 6676748.2741715675, 2552382.3754193066 6676805.027198027) + +LINESTRING (2551826.9588646907 6672789.355485318, 2551814.8402953395 6672778.893083896) + +LINESTRING (2550343.865413739 6672709.737210624, 2550337.3730283887 6672735.0830282215, 2550326.7971223923 6672754.117397159, 2550231.5479721315 6672874.485025008) + +LINESTRING (2552885.225926333 6673938.009134526, 2552897.3527452215 6673947.931411976, 2552921.309399678 6673955.193078739) + +LINESTRING (2553057.575246205 6675500.387745569, 2553056.9400318824 6675511.130211276) + +LINESTRING (2551301.966601272 6673840.286704404, 2551289.4438046245 6673900.360493075, 2551331.69793139 6673952.922557588, 2551365.6117765936 6673962.324715655) + +LINESTRING (2552657.6542080683 6675811.769216616, 2552672.198141197 6675830.973624582) + +LINESTRING (2553180.0973646594 6675129.492614418, 2553063.374670476 6675121.190708891) + +LINESTRING (2553394.2553363172 6675336.7501860205, 2553403.5113164485 6675346.842502499, 2553414.920425647 6675381.700503417) + +LINESTRING (2550611.1504014786 6673856.980536122, 2550576.172366046 6673875.77484996, 2550569.952215405 6673874.444544616, 2550469.8028403698 6673808.719458809, 2550358.3021028917 6673752.836632086, 2550326.417643706 6673757.687745556, 2550254.9189094855 6673758.087837389) + +LINESTRING (2550999.72832671 6675440.514002815, 2550972.4306099066 6675484.664136547, 2550964.453307958 6675509.989949552) + +LINESTRING (2549125.4665960157 6671310.466037451, 2548945.4699556613 6671269.13655114) + +LINESTRING (2552856.402045248 6674760.487917176, 2552873.899312501 6674769.630015552) + +LINESTRING (2551120.270556366 6671890.589192481, 2551045.859735705 6671915.754968753, 2551024.7326723225 6671931.338545634, 2550978.2795313974 6672002.13479542, 2550945.1988893966 6672062.238590978) + +LINESTRING (2553075.270502338 6674767.719577051, 2553150.877505814 6674825.012727485) + +LINESTRING (2547371.3676162916 6674760.517924064, 2547371.384115365 6674744.094154334, 2547383.263448153 6674673.017840265, 2547389.6320904535 6674622.506246395) + +LINESTRING (2548873.171016385 6675909.131564088, 2548880.1418748614 6675927.455770023, 2548900.048006819 6675955.962313099, 2548929.581348057 6675978.607510826, 2548946.2949093273 6675985.529099531) + +LINESTRING (2552529.26666905 6671861.652550685, 2552411.215799465 6671838.257180772) + +LINESTRING (2547971.0181864705 6672303.113878818, 2547827.9547217367 6672273.6971268235) + +LINESTRING (2548379.9147204924 6675369.337665789, 2548270.1051380294 6675336.150048272) + +LINESTRING (2553036.877158729 6675914.892886478, 2552975.046881472 6675965.034395403) + +LINESTRING (2552411.248797612 6675882.315409006, 2552426.8404218964 6675906.450948809) + +LINESTRING (2553933.329558812 6673324.638348205, 2553929.6667645355 6673370.90896865, 2553844.209814289 6673408.267543522, 2553775.755159096 6673404.646712436) + +LINESTRING (2550386.4577715076 6676872.182612135, 2550396.0602321783 6677002.332485292, 2550396.332466888 6677132.652397479) + +LINESTRING (2549732.6407436277 6672352.875300502, 2549727.5425299727 6672409.788363695, 2549713.955543096 6672500.559198225, 2549711.7116691247 6672521.834081425) + +LINESTRING (2554115.636069431 6673175.21405101, 2554061.725347367 6673270.4559117695) + +LINESTRING (2550674.9523179964 6674116.500103362, 2550674.0861166473 6674139.545392922, 2550653.6437648074 6674194.578024501, 2550637.09519427 6674216.643089072) + +LINESTRING (2552588.985064922 6673860.221279966, 2552540.7087763953 6673856.620453472) + +LINESTRING (2549381.598210193 6676613.453226265, 2549380.228787108 6676628.726731976, 2549385.879719719 6676658.773628606, 2549385.5084905694 6676692.791436676, 2549373.8766438807 6676726.019063377, 2549353.0300647444 6676750.8047524085, 2549344.673284109 6676770.929371591, 2549345.9932099744 6676800.186086852, 2549356.1978868213 6676839.5251162965, 2549356.519618751 6676887.556140805) + +LINESTRING (2552168.737168458 6673636.910023579, 2552172.432960881 6673639.590638857) + +LINESTRING (2552261.4207128175 6672125.6131372675, 2552225.056755226 6672122.252365874, 2552210.686062367 6672116.801114654, 2552205.5466010286 6672110.759727981, 2552199.210956875 6672085.163852988) + +LINESTRING (2547933.1528132074 6674984.289286058, 2547920.885752196 6674999.992890489) + +LINESTRING (2549346.0179585842 6675556.560638872, 2549342.5366541143 6675552.099614938, 2549281.407587474 6675541.397158415) + +LINESTRING (2548856.308963455 6671647.263342166, 2548833.7134825466 6671745.735944474, 2548826.6848773137 6671777.543245168) + +LINESTRING (2551323.192659095 6676814.979482364, 2551273.0354762105 6676879.604315631) + +LINESTRING (2549641.392618647 6677444.533983315, 2549624.728554596 6677449.885211578, 2549639.354983092 6677485.693430598, 2549642.6547977556 6677502.937388585, 2549639.6272178018 6677527.393001855, 2549628.0778664798 6677551.338498038, 2549614.0784027698 6677565.70179483, 2549594.5599990357 6677577.114414356) + +LINESTRING (2551428.9187209117 6672931.848191513, 2551321.592248983 6672912.583769771, 2551303.7237525806 6672909.38303511) + +LINESTRING (2553442.6636174303 6674102.896981052, 2553437.3179176752 6674178.624362675, 2553369.1437467285 6674168.962144917) + +LINESTRING (2552502.199939273 6676110.617811005, 2552436.0221561976 6676165.820481613) + +LINESTRING (2547987.030537125 6671903.372126534, 2547895.0977006014 6671978.22930842) + +LINESTRING (2551314.926623363 6673157.730037924, 2551319.1091384487 6673194.168401582, 2551312.9137364184 6673244.529961015) + +LINESTRING (2550721.677693631 6675219.033166562, 2550697.3498100247 6675261.432898526) + +LINESTRING (2548873.171016385 6675909.131564088, 2548824.7627352723 6675670.196721637, 2548810.433290096 6675625.306418015, 2548782.211625187 6675579.535912361, 2548722.080752482 6675502.718280494, 2548681.3692890718 6675476.232201174) + +LINESTRING (2552052.253710838 6672642.651812586, 2552049.0941382977 6672646.4926941795) + +LINESTRING (2548947.969565269 6676316.775130067, 2548995.231160786 6676343.3312254585, 2549006.3185380553 6676357.754536025) + +LINESTRING (2554348.165759228 6673156.739810638, 2554413.601084004 6673201.910178543) + +LINESTRING (2551898.243110958 6672671.248376324, 2551869.584220606 6672709.9872680195, 2551852.7964135054 6672722.820213551, 2551814.8402953395 6672778.893083896) + +LINESTRING (2552328.299706509 6676252.960482761, 2552238.9902226427 6676326.42734553) + +LINESTRING (2549227.925841316 6676190.726198195, 2549124.6828900333 6676320.435970336) + +LINESTRING (2552971.7305677356 6673425.081402789, 2552977.2000105404 6673466.290861551, 2552974.8076449092 6673488.175884795, 2552966.162130491 6673509.980889674) + +LINESTRING (2550177.2330227713 6672701.135236222, 2550192.3956711497 6672662.466360598, 2550198.6735685472 6672642.421759782, 2550210.569400409 6672635.2201067945, 2550222.366237831 6672634.639973638, 2550253.879467867 6672593.780595229) + +LINESTRING (2551683.6644129306 6674375.029443317, 2551667.602565056 6674403.045873897, 2551633.1360008963 6674446.5158515135) + +LINESTRING (2551188.7252115593 6672244.900517169, 2551176.2931598146 6672228.556765806, 2551150.6535998797 6672205.1814004835, 2551035.061092219 6672120.672003135, 2550945.1988893966 6672062.238590978) + +LINESTRING (2552237.274319018 6677050.573558013, 2552220.610254967 6677124.070427668, 2552214.8933260627 6677146.535584071, 2552211.8574965727 6677157.938201302, 2552209.5063786246 6677168.29057747) + +LINESTRING (2553231.4012331394 6674563.35266894, 2553261.041818354 6674561.242184523) + +LINESTRING (2553476.230982094 6676802.706665398, 2553454.559449292 6676780.601591645, 2553439.1575643504 6676774.570207268, 2553336.2528440706 6676782.191956679, 2553319.0030629174 6676784.622514563, 2553313.451124746 6676788.76346503) + +LINESTRING (2553500.468120797 6675986.279271716, 2553452.7775493735 6675965.714551519) + +LINESTRING (2553495.114171506 6674905.331162887, 2553508.379426453 6674894.768738505) + +LINESTRING (2552362.5765313255 6675300.39184073, 2552349.6825055284 6675299.091542274) + +LINESTRING (2551649.1483515506 6673666.116727361, 2551645.3123170044 6673652.453591277) + +LINESTRING (2551175.3114649523 6671566.634835593, 2551111.3693063115 6671441.356080499) + +LINESTRING (2552168.737168458 6673636.910023579, 2551899.2743030405 6673441.985282717) + +LINESTRING (2551949.291243802 6673645.181922219, 2551944.9354884457 6673645.44198191) + +LINESTRING (2552249.4588846625 6672531.896391016, 2552203.3439747407 6672596.1711439295) + +LINESTRING (2552890.282892305 6674615.774701311, 2552889.8539163987 6674627.117304767) + +LINESTRING (2549059.3878073804 6676493.845772897, 2549063.232091463 6676502.957864385) + +LINESTRING (2551307.7165283235 6674304.733308323, 2551281.2190165757 6674505.089295812) + +LINESTRING (2552267.0221482087 6672090.435062883, 2552223.563589091 6672089.834925135, 2552199.210956875 6672085.163852988) + +LINESTRING (2554656.3272011112 6675864.1412375085, 2554739.6557708997 6675836.414873506) + +LINESTRING (2553113.0533802346 6676122.790605012, 2553077.761862409 6676172.722065726) + +LINESTRING (2553213.2687515635 6671834.346283107, 2553194.0885788323 6671842.618181747, 2553180.641834079 6671843.99849857, 2553166.5351263923 6671840.257639934) + +LINESTRING (2550208.8039995637 6675386.541614592, 2550191.347979994 6675362.526102338, 2550153.705344221 6675327.848142744, 2550135.3748737653 6675288.829186766, 2550121.7878868887 6675284.388167424, 2550107.540937079 6675285.958527867, 2550092.279294261 6675293.270206109, 2550079.055286997 6675306.313199853) + +LINESTRING (2553020.485329388 6674618.795394648, 2553066.311505527 6674620.17571147) + +LINESTRING (2552868.842346529 6677328.447338075, 2552886.0838781456 6677327.807191144, 2552907.318185505 6677315.674406319, 2552903.1521694926 6677290.118540509, 2552894.242669901 6677276.845493961) + +LINESTRING (2547175.515366479 6677256.300778355, 2547211.5080949203 6677225.343672805, 2547219.881374629 6677213.620982109, 2547233.8808383388 6677177.9227883415) + +LINESTRING (2554346.812835216 6675966.984843087, 2554186.4170939624 6676034.840417903, 2554177.557091591 6676015.015867596, 2554170.553234968 6676018.396643582, 2554137.8685707264 6676034.210273267, 2554115.4380805516 6676040.741772435, 2554089.608781273 6676041.121859675, 2554083.108146386 6676037.010916095, 2554075.4360772935 6676018.516671131) + +LINESTRING (2550534.8834350696 6675717.747635946, 2550510.1348250937 6675681.119228668) + +LINESTRING (2551194.4091423173 6675230.625827413, 2551114.611374218 6675220.503504047) + +LINESTRING (2551863.776546798 6673999.603272161, 2551850.932018221 6673967.375875042) + +LINESTRING (2554314.8953778837 6673219.284166375, 2554289.3300637784 6673267.365202363) + +LINESTRING (2548905.8061834066 6677564.9516226435, 2548911.3581215777 6677552.868849298) + +LINESTRING (2553517.874643147 6675334.66970849, 2553513.0239155916 6675335.189827873) + +LINESTRING (2549950.8244891753 6676393.332702243, 2549989.1023392715 6676433.011809745) + +LINESTRING (2551743.5972967553 6673653.503832337, 2551743.440555559 6673647.422436481) + +LINESTRING (2550636.89720539 6671631.9498272715, 2550611.5133810914 6671615.7461080495, 2550609.335503414 6671596.181617434, 2550675.5792827825 6671482.095431358) + +LINESTRING (2552606.457583565 6675546.97843948, 2552609.3944186154 6675551.299431273) + +LINESTRING (2551672.841020834 6676567.80274816, 2551717.042038251 6676584.5265867645) + +LINESTRING (2548243.285894352 6672806.419401981, 2548218.3557945695 6672801.918368864, 2548203.4818799742 6672795.32685592, 2548169.4937889404 6672768.730751346, 2548094.2580146138 6672804.498961184, 2548001.0135017615 6672871.764400546, 2547980.3979096515 6672890.68874423, 2547959.947308275 6672919.4253401095, 2547927.3038917165 6672968.396580424) + +LINESTRING (2550396.332466888 6677132.652397479, 2550392.4056874383 6677305.872156419, 2550397.6853909 6677360.904787999, 2550435.3280266733 6677486.393591305) + +LINESTRING (2553284.1240219246 6676080.130813357, 2553319.63827724 6676115.9590369705) + +LINESTRING (2552892.741254229 6673220.99455896, 2552888.7732270965 6673293.051098018) + +LINESTRING (2552548.2323538284 6673736.992995514, 2552503.1238873787 6673733.622221824, 2552510.1359935384 6673580.497075177) + +LINESTRING (2554366.9252055897 6675022.638088216, 2554056.9076179583 6674483.824414907, 2554142.290322375 6674448.276255577) + +LINESTRING (2552526.3050853894 6672709.167079763, 2552398.7095018905 6672619.206431193) + +LINESTRING (2548966.861004217 6677556.069583959, 2548947.895319439 6677648.530806482, 2548947.4168463126 6677650.461249574, 2548936.68419912 6677749.223918461, 2548939.126061971 6677798.465220763, 2548944.339769139 6677829.712392892) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553180.9635660085 6672364.467961353) + +LINESTRING (2554104.1774630123 6677538.065451491, 2554126.7481953106 6677564.881606573) + +LINESTRING (2551107.195040762 6674255.151927963, 2551035.0445931456 6674552.090083851, 2551028.2799730855 6674580.806675139) + +LINESTRING (2553213.62348164 6676806.227473525, 2553309.557343443 6676796.075143272) + +LINESTRING (2549607.280784563 6676221.383234871, 2549607.8087549093 6676229.3850715235, 2549607.06629661 6676254.200767443) + +LINESTRING (2553522.774867922 6676791.444080309, 2553523.146097072 6676805.30726231) + +LINESTRING (2551061.5256058197 6675212.5716834655, 2551060.2469276376 6675205.620087873, 2551039.7138308943 6675190.116529359) + +LINESTRING (2552225.469232059 6671927.747721436, 2552204.4164145063 6671940.430632532, 2552173.0434265938 6671965.96649375, 2552159.8771660863 6671979.909694117, 2552129.898349869 6672026.35035359, 2552126.2355555925 6672046.625007209, 2552129.923098479 6672065.879426655, 2552135.961759313 6672077.812165564, 2552135.6565264566 6672092.005423326) + +LINESTRING (2553309.557343443 6676796.075143272, 2553438.1181227313 6676782.472020962, 2553446.7141399295 6676834.023853597) + +LINESTRING (2552343.1571220313 6672403.776983909, 2552299.6078180103 6672464.140839159) + +LINESTRING (2548526.8142197724 6675418.729002528, 2548394.1946684485 6675373.758680539) + +LINESTRING (2549456.7679882264 6675900.989695294, 2549465.1247688616 6675918.343678535, 2549568.351221071 6676074.7895873925) + +LINESTRING (2550900.989622443 6675190.876703841, 2550826.0508314357 6675180.984433278) + +LINESTRING (2551628.912238127 6676351.483096548, 2551621.669144941 6676342.901126739, 2551539.9657338737 6676322.26639047) + +LINESTRING (2551523.4666605564 6677169.820928731, 2551521.569267125 6677212.550736456, 2551524.811335032 6677220.862644279, 2551535.271747515 6677230.074758726, 2551552.6535212547 6677235.265950254) + +LINESTRING (2552821.9107324784 6672739.764102663, 2552820.5495589296 6672756.447932084) + +LINESTRING (2552810.485124206 6672890.968808513, 2552706.5574613805 6672882.976974156) + +LINESTRING (2552530.1906171557 6672202.120697964, 2552487.98598761 6672197.139554648, 2552443.66947668 6672192.648523826) + +LINESTRING (2554164.2258403506 6673085.173384075, 2554199.1873767097 6673104.997934382, 2554179.3967382656 6673142.466534509, 2554229.141444317 6673170.67300871) + +LINESTRING (2553381.666543376 6673728.240986674, 2553376.452836208 6673806.188877968) + +LINESTRING (2553119.9004956614 6673301.242978292, 2553112.4016668387 6673434.35353101) + +LINESTRING (2547945.8323510517 6672417.580152135, 2547927.510130133 6672506.360529798) + +LINESTRING (2553377.5747731933 6675988.449769909, 2553284.1240219246 6676080.130813357) + +LINESTRING (2553010.6683807643 6672823.043217626, 2552920.7484311853 6672816.4917138675) + +LINESTRING (2548826.6848773137 6671777.543245168, 2548821.3804252422 6671791.406427169, 2548820.439978063 6671793.86699194, 2548776.08221945 6671875.74578549, 2548775.7192398366 6671876.385932422, 2548722.039504799 6671974.878539322, 2548706.348886074 6672025.30011253, 2548709.2609725147 6672091.895398072, 2548721.940510359 6672165.17221722) + +LINESTRING (2553044.136750988 6675713.786726803, 2552998.36007207 6675727.009761872, 2552953.64758338 6675747.974573902, 2552906.1055036164 6675781.722319985, 2552861.3930149265 6675815.029965051, 2552841.833363509 6675831.963851868) + +LINESTRING (2552411.248797612 6675882.315409006, 2552399.5592041663 6675863.2110239975, 2552380.428528655 6675843.006386449) + +LINESTRING (2549849.701668814 6677531.543954618, 2549793.8358065616 6677516.940602727, 2549757.9255734864 6677481.262413552) + +LINESTRING (2553587.4264867157 6676880.294474042, 2553572.42882907 6676771.799571327, 2553584.1679197354 6676747.223930507) + +LINESTRING (2552318.9612310114 6673271.776214818, 2552188.3380675586 6673180.105173664) + +LINESTRING (2548138.4177843477 6671814.501728209, 2548081.801214259 6671838.827311633, 2548061.004132343 6671850.830066612, 2548016.4318857766 6671880.016765803, 2547987.030537125 6671903.372126534) + +LINESTRING (2550834.0116343116 6672229.256926513, 2550859.799685906 6672193.228656984) + +LINESTRING (2551590.560142201 6673751.856407096, 2551590.659136641 6673766.419749804, 2551567.4531900203 6673802.518035403) + +LINESTRING (2554280.189577161 6673075.421145655, 2554361.727997495 6673132.004133086) + +LINESTRING (2551107.195040762 6674255.151927963, 2551105.107907987 6674254.621806284) + +LINESTRING (2550509.837841774 6675965.304457391, 2550519.811531594 6675973.136255015, 2550565.035491557 6676041.211880337) + +LINESTRING (2551691.2787352665 6676490.985116294, 2551618.6828126702 6676472.390848372) + +LINESTRING (2552225.469232059 6671927.747721436, 2552280.015168446 6671938.780253721, 2552298.1806481685 6671947.172179911, 2552325.9403390246 6671965.876473087) + +LINESTRING (2547866.3563148826 6671640.20172132, 2547875.9505260168 6671671.538914111, 2547916.323758424 6671737.954158329) + +LINESTRING (2550060.518578125 6676537.765853825, 2549982.6759502143 6676534.105013556) + +LINESTRING (2548337.0088803307 6671880.666915031, 2548323.8426198238 6671981.420040785) + +LINESTRING (2551923.008220007 6677196.5270585595, 2551917.8770082057 6677195.676863415) + +LINESTRING (2549421.1959861545 6671189.488269557, 2549413.3176786457 6671230.407661741) + +LINESTRING (2552274.289990005 6672061.3383843545, 2552229.775490195 6672054.426797946, 2552217.9044069434 6672044.524525088, 2552217.137200034 6672017.598344752) + +LINESTRING (2553341.0788230156 6674602.941755779, 2553324.785988115 6674559.971892954, 2553336.62407322 6674492.626435225, 2553335.518635308 6674474.212208628, 2553330.8906452423 6674463.919846233, 2553320.273491563 6674457.528379207) + +LINESTRING (2552963.6212732 6673523.774055605, 2552872.472142659 6673518.93294443) + +LINESTRING (2549545.178272597 6672487.866284834, 2549538.3806543904 6672527.685424478) + +LINESTRING (2551050.322735037 6675236.387149803, 2551082.545425226 6675357.174874077) + +LINESTRING (2549907.8031555004 6676812.688956622, 2550052.7640136657 6676852.027986066) + +LINESTRING (2552918.3478160175 6674178.664371858, 2552913.356846339 6674178.394309871) + +LINESTRING (2551419.8442305876 6674530.035021577, 2551421.4116425524 6674539.957299026, 2551421.2878995026 6674540.157344943) + +LINESTRING (2553675.9275159896 6675738.582418131, 2553679.953289879 6675760.077351839) + +LINESTRING (2548349.498678832 6671792.986789908, 2548295.7446979643 6671789.025880765, 2548239.0621315828 6671790.946321562, 2548182.2970698345 6671800.918610491, 2548138.4177843477 6671814.501728209) + +LINESTRING (2551421.2878995026 6674540.157344943, 2551416.4124233373 6674548.089165525, 2551406.422234444 6674551.429932327) + +LINESTRING (2553174.5866741715 6676358.924804635, 2553317.5263958555 6676505.718498031) + +LINESTRING (2551633.1360008963 6674446.5158515135, 2551585.6021706695 6674501.628501459, 2551557.9002265697 6674544.118254086) + +LINESTRING (2553348.371413422 6676346.65198767, 2553345.1045969054 6676349.882729218) + +LINESTRING (2553556.903201079 6676140.89476044, 2553520.0360217514 6676177.143080477) + +LINESTRING (2552708.001130296 6672220.484913082, 2552630.0925060916 6672212.543090205) + +LINESTRING (2549818.6834109775 6676321.926312412, 2549737.2604841567 6676245.558783858) + +LINESTRING (2553136.6388055417 6671827.364680628, 2553237.8936184896 6671761.569578751, 2553258.6824508696 6671752.257441346) + +LINESTRING (2550968.429584627 6672463.97080013, 2550841.0979863014 6672371.139492662) + +LINESTRING (2551503.1398022296 6675145.046184412, 2551476.8980261185 6675196.317952764, 2551416.2309335307 6675277.816659073) + +LINESTRING (2552918.3973132377 6677227.804237575, 2552894.242669901 6677276.845493961) + +LINESTRING (2551259.7454726533 6672681.020619336, 2551264.447708549 6672628.208497427, 2551127.200167159 6672617.045935297) + +LINESTRING (2553221.9472641284 6675203.719651668, 2553183.413678396 6675229.635600127) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553224.133391343 6672354.1956035495, 2553237.8936184896 6672345.463599303, 2553271.7909646197 6672331.730447147) + +LINESTRING (2554326.5684722555 6675869.682509391, 2554357.7187226787 6675935.927714579) + +LINESTRING (2551059.8921975615 6672896.0199679, 2550992.7162205502 6672922.8861344615, 2550967.9676105743 6672935.599052443, 2550937.0813453244 6672957.334041252) + +LINESTRING (2553299.34441706 6673391.583714101, 2553296.217842666 6673446.466311243) + +LINESTRING (2552786.1159929163 6675098.67554101, 2552685.7521299277 6675175.6432073135) + +LINESTRING (2549854.4699010025 6676293.439773928, 2549890.388383614 6676330.678321252, 2549907.3411814477 6676348.252355) + +LINESTRING (2553675.9275159896 6675738.582418131, 2553804.1335652014 6675701.3238662165, 2553907.5497567537 6675674.807780008, 2554035.524818939 6675640.069806639, 2554023.6289870776 6675614.693982154, 2554021.5006066198 6675608.172485282, 2554017.0046091406 6675600.560738166, 2554020.7251501735 6675608.492558748, 2554023.6289870776 6675614.693982154) + +LINESTRING (2553042.4950931934 6672305.494425222, 2552883.7245106613 6672239.799346303) + +LINESTRING (2552867.3904280774 6673610.51396492, 2552854.5046518166 6673780.332943284, 2552851.1718390062 6673786.784424085, 2552848.061763686 6673823.792918604, 2552833.5590782403 6673841.386956944) + +LINESTRING (2549063.058851193 6672410.918623122, 2548914.6744353147 6672439.865267213) + +LINESTRING (2553769.3782672584 6675563.292183956, 2553790.076354735 6675645.090959139) + +LINESTRING (2552805.8406350673 6676650.841808024, 2552800.0082126497 6676643.68016422) + +LINESTRING (2551280.3115675435 6672498.72877809, 2551302.5853165216 6672478.3741061045) + +LINESTRING (2551015.2374556283 6675697.262934115, 2550947.8057429804 6675665.505644899) + +LINESTRING (2550917.7691800063 6674209.481445267, 2550888.227589232 6674330.749279739, 2550869.96311507 6674403.3559450675, 2550852.1111177406 6674441.834777072, 2550840.8505002013 6674482.714160072, 2550839.7863099724 6674532.4455748685) + +LINESTRING (2553313.451124746 6676788.76346503, 2553309.557343443 6676796.075143272) + +LINESTRING (2553174.5866741715 6676358.924804635, 2553169.5132091264 6676352.803399596) + +LINESTRING (2552149.2847610167 6673657.954853976, 2552116.047377819 6673649.562927786, 2551949.291243802 6673645.181922219) + +LINESTRING (2551573.186617998 6673194.328438315, 2551502.2900999538 6673211.672419259) + +LINESTRING (2553239.238292965 6674886.036734258, 2553236.9036740907 6674889.257473511) + +LINESTRING (2553672.726695766 6676456.377172771, 2553746.3785590543 6676467.58974638) + +LINESTRING (2553151.1827386706 6674957.58315623, 2553086.96834532 6675006.344348332) + +LINESTRING (2553153.5008584717 6677426.869928905, 2553079.6097586206 6677500.29678249, 2553064.570853292 6677519.3911652025, 2553017.7712318273 6677599.049449081, 2552981.2505330397 6677651.461479156, 2552899.2336395797 6677765.667692782) + +LINESTRING (2549995.050255202 6676439.183226263, 2549989.1023392715 6676433.011809745) + +LINESTRING (2547838.2336444133 6671608.824519346, 2547849.4447647324 6671625.538355654, 2547866.3563148826 6671640.20172132) + +LINESTRING (2551028.2799730855 6674580.806675139, 2551006.8394273096 6674670.747319115) + +LINESTRING (2551961.9542825725 6676969.775012411, 2551960.758099757 6676974.956201645) + +LINESTRING (2551745.329699454 6676011.725112272, 2551759.16417243 6676018.126581594) + +LINESTRING (2551774.252574979 6674172.703003552, 2551758.8424405004 6674218.34347936) + +LINESTRING (2547785.263369528 6677662.604036695, 2547799.0070976014 6677546.967494767) + +LINESTRING (2552443.66947668 6672192.648523826, 2552400.565647639 6672187.877428723) + +LINESTRING (2549155.041184937 6676773.579979982, 2549063.7600618093 6676756.946162039) + +LINESTRING (2549256.3784932517 6676421.319125935, 2549258.9688477623 6676424.309812385) + +LINESTRING (2550253.879467867 6672593.780595229, 2550350.6960300924 6672625.367845416, 2550359.91076254 6672651.313800762, 2550343.865413739 6672709.737210624) + +LINESTRING (2551528.9278538246 6671397.786079925, 2551436.2773076114 6671444.056700369) + +LINESTRING (2554347.439800002 6675597.4800310545, 2554378.4085606188 6675673.437465481, 2554376.5524148704 6675696.03265173, 2554333.258846486 6675718.607833386) + +LINESTRING (2553383.2587039513 6673452.957801227, 2553296.217842666 6673446.466311243) + +LINESTRING (2553507.9339514733 6675335.729951847, 2553396.4332139953 6675319.626255584) + +LINESTRING (2551540.584449123 6676790.563878277, 2551520.8268088256 6676869.451985378) + +LINESTRING (2551764.122143962 6673339.771821775, 2551760.599591809 6673343.492675818, 2551755.715866107 6673348.653860459) + +LINESTRING (2552089.5251174616 6676457.277379394, 2552060.3300072267 6676568.23284688, 2552039.8464077036 6676652.9322878495) + +LINESTRING (2552609.3944186154 6675551.299431273, 2552627.8981293407 6675578.555687371, 2552679.7877149233 6675641.640167083) + +LINESTRING (2549044.6953825913 6677254.21029853, 2549022.611372956 6677239.146841031, 2549005.5925788293 6677219.95243536, 2548989.3492411487 6677203.238599052, 2548967.37247549 6677184.804367863, 2548950.23818785 6677173.841851649, 2548923.212705756 6677162.749305589, 2548895.25502602 6677159.888648985, 2548853.2071376713 6677163.419459408, 2548816.1007217807 6677167.030288198, + 2548774.3415672146 6677162.519252785, 2548855.731495889 6677158.098238034, 2548923.121960853 6677157.91819671, 2548967.8179504694 6677161.789085191, 2549061.2027054452 6677165.359904797, 2549078.5514810383 6677099.384761594, 2549060.1137666064 6677088.8123349175, 2549031.2816359843 6677090.07262419, 2548983.393075681 6677098.46455038, 2548942.013399801 6677113.54801247, + 2548906.3671518993 6677130.371874033, 2548854.2465792904 6677147.775868752, 2548774.3415672146 6677162.519252785, 2548621.5271501504 6677157.598123243, 2548561.2972830054 6677146.435561113, 2548245.7607553494 6677087.942135181, 2548227.554027944 6677086.711852795, 2548071.703781389 6677086.111715047, 2547917.338451433 6677110.957417854, 2547839.223588812 6677132.572379112, + 2547608.5335456906 6677220.122474389, 2547152.6888985443 6677394.032391741, 2547130.3904009564 6677402.35430186, 2547035.0257571824 6677437.392344103, 2546989.15833336 6677455.196430655, 2546745.0545436316 6677547.607641699) + +LINESTRING (2551018.1247934587 6672888.988353942, 2551072.6047335523 6672871.274288051, 2551102.270067377 6672869.903973524, 2551317.2612422374 6672889.818544494, 2551321.592248983 6672912.583769771, 2551325.197296503 6672931.528118047, 2551241.192264708 6672922.67608625, 2551065.2048991695 6672911.10342999, 2551041.9824534757 6672913.1939098155, 2551011.1951826657 6672922.7561046155, + 2550961.2442381973 6672948.942115062, 2550937.0813453244 6672957.334041252, 2550914.815845883 6672972.847602062, 2550869.4433942605 6673004.914962448, 2550737.005332743 6673085.04335423, 2550585.098364711 6673131.2839677865, 2550450.465926442 6673161.500903447, 2550327.5230816184 6673173.463649243, 2550187.660437108 6673162.511135324, 2550058.967665233 6673135.564950396, + 2549996.1556931143 6673120.591513559, 2549774.5483898534 6673069.78985311, 2549472.961828687 6672995.92289851, 2549214.371852586 6672931.748168554, 2549163.067984106 6672916.744724831, 2549161.253086041 6672916.204600857, 2549140.975724934 6672910.24323255, 2548982.9063530182 6672863.72255471, 2548979.8127767714 6672862.812345791, 2548865.771182002 6672820.342597757, + 2548836.0316023477 6672809.280058584, 2548832.525549268 6672807.819723395, 2548831.1808747924 6672807.259594829, 2548738.0518554533 6672768.48069395, 2548584.362987503 6672703.2157137515, 2548574.620284709 6672699.644894145, 2548403.161914796 6672636.710448871, 2548393.798690689 6672633.859794564, 2548383.8002522583 6672630.819096636, 2548259.2982450062 6672612.834968759, + 2548147.4097793056 6672620.4867250575, 2548121.2587480973 6672625.987987757, 2548090.2074921145 6672629.168717826, 2547920.7125119264 6672681.830805297, 2547882.871887273 6672694.0436084885, 2547881.403469748 6672694.513716391, 2547833.382916858 6672710.027277202, 2547685.3779796655 6672758.648437164, 2547673.3171570706 6672763.109461098, 2547663.2857204936 6672766.830315141, + 2547607.287865655 6672785.594622091, 2547597.809148034 6672788.495287878, 2547570.4371854006 6672796.867209476, 2547532.654307504 6672810.190267503, 2547314.5613068603 6672884.447311641, 2547067.850663547 6672968.146523029, 2547062.1089860327 6672970.096970713, 2547022.6514521944 6672983.550058586, 2546848.379990281 6673049.56521097, 2546831.484939204 6673057.83710961, + 2546816.7595162685 6673065.048764894) + +LINESTRING (2550184.0718886615 6676346.001838442, 2550178.858181493 6676383.270392652, 2550180.2771017984 6676468.249897904, 2550177.3732648944 6676527.243438627, 2550175.8718492226 6676545.997743282, 2550174.3951821607 6676564.371960695, 2550164.2812502175 6676695.402035885, 2550143.2531812745 6676741.2425576085, 2550075.136757084 6676897.898514678, 2550071.4079665146 6676906.480484488, + 2550063.5791562255 6676933.906779615, 2550055.882338523 6676982.537941873, 2550043.483284925 6677192.91622977, 2550037.131141698 6677349.362138627, 2550035.6709737093 6677366.696117276, 2550031.117229474 6677442.883604506, 2550033.0971182715 6677584.066009948, 2550031.5049576964 6677619.0840476, 2550029.3765772386 6677630.906761254, 2550023.1976742814 6677665.124615241, + 2550019.0399078056 6677686.849601753, 2550021.143539653 6677692.1808254225, 2550022.8016965217 6677696.371787369, 2550035.6874727826 6677729.009278617, 2550035.695722319 6677810.307939009) + +LINESTRING (2553675.4737914735 6675736.161862543, 2553667.5707353544 6675743.563561447, 2553636.0575053184 6675773.070334104, 2553569.1702620904 6675865.6115749935, 2553545.0156187536 6675913.912661488, 2553506.539779778 6675989.219946686, 2553485.651952958 6676036.060697992, 2553474.5315775424 6676055.495158763, 2553471.5039975885 6676060.786373249, 2553457.2570477794 6676073.959396839, + 2553438.2088676346 6676092.903745115, 2553403.569063205 6676127.341649609, 2553366.2564088977 6676164.4401647905, 2553330.758652656 6676200.098349375, 2553295.4341366836 6676235.586494929, 2553280.9561998476 6676250.11983075, 2553266.857741698 6676263.442888777, 2553263.0299566886 6676267.053717567, 2553258.8721902124 6676270.974617526, 2553213.62348164 6676312.414129091, + 2553169.5132091264 6676352.803399596, 2553108.3923920225 6676400.944449359, 2553067.763423979 6676432.941793674, 2553014.4384190175 6676475.401539412, 2552967.5068049664 6676512.910148722, 2552964.231738913 6676515.460734155, 2552800.0082126497 6676643.68016422, 2552747.194678961 6676689.470674465, 2552732.5187532455 6676700.013094256, 2552601.0293884436 6676876.613629182, + 2552588.5065917955 6676903.429784264, 2552580.1250625504 6676934.786981648, 2552578.9866264914 6676950.380560825, 2552592.647859198 6677083.961221446, 2552604.74167994 6677178.863004148, 2552602.341064772 6677277.905737318, 2552604.881922063 6677633.767417857, 2552605.1294081626 6677756.13550487, 2552605.154156773 6677770.558815436, 2552599.9651982146 6677798.575246017, + 2552592.4416207816 6677831.402780885, 2552588.836573262 6677847.116387612, 2552561.2501226757 6677966.763850162) + +LINESTRING (2553644.7360178833 6677147.805875639, 2553666.4900460523 6677180.123293421, 2553675.4572924 6677195.976932289, 2553711.1447879854 6677259.091418888, 2553727.5943640824 6677300.7809878485, 2553750.1980945272 6677358.084140578, 2553789.837118172 6677473.050528687, 2553823.915954109 6677589.587277238, 2553855.2229457283 6677741.772208078, 2553875.120828149 6677877.7434174, + 2553886.628931788 6677968.024139435, 2553888.5098261456 6678057.214611226) + +LINESTRING (2554173.8860477777 6675504.448677671, 2554289.198071192 6675483.313826611, 2554368.5503643113 6675468.740481608, 2554388.472995342 6675467.460187743, 2554414.9292594064 6675465.779802047, 2554417.577360674 6675465.189666593, 2554451.491205877 6675457.627930956, 2554586.420627466 6675429.461465939, 2554623.0238216203 6675421.849718823, 2554651.063996723 6675416.008378066, + 2554673.997708634 6675411.237282962, 2554938.444855763 6675356.194649086, 2555013.4413935267 6675337.160280149, 2555039.9719034205 6675335.669938073) + +LINESTRING (2553224.356128833 6671841.2578695165, 2553245.0954639926 6671840.097603202, 2553284.3385098777 6671818.292598323, 2553364.416762223 6671759.249046122, 2553385.3128385795 6671743.845510565, 2553534.835690517 6671645.212871524) \ No newline at end of file diff --git a/data/Manhattan/bus.wkt b/data/Manhattan/bus.wkt new file mode 100644 index 000000000..08a4b117d --- /dev/null +++ b/data/Manhattan/bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2549691.4669673573 6673187.82779412, 2550453.412051166 6673207.361937253, 2551222.2931330632 6673212.614600562, 2551968.1713229036 6673212.614600562, 2552703.235282084 6673187.82779412, 2552708.4879453927 6673891.68467749, 2552735.650626272 6674643.226953467, 2552724.8363956125 6675327.549693705, 2552730.089058921 6676020.901250457, 2551995.025099741 6676045.688056899, + 2551249.1469099005 6676045.688056899, 2550480.265828003 6676040.4353935905, 2549718.3207441946 6676020.901250457, 2549713.068080886 6675327.549693705, 2549723.8823115453 6674643.226953467, 2549696.719630666 6673891.68467749, 2549691.4669673573 6673187.82779412) \ No newline at end of file diff --git a/data/Manhattan/roads.wkt b/data/Manhattan/roads.wkt new file mode 100644 index 000000000..0cee4380e --- /dev/null +++ b/data/Manhattan/roads.wkt @@ -0,0 +1,2559 @@ +LINESTRING (2548233.6149715823 6675852.649101299, 2548417.5184834544 6675852.235489515, 2548417.518483455 6676020.901250458, 2548237.378595174 6676045.688056899, 2548233.6149715823 6675852.649101299) + +LINESTRING (2548604.5879469537 6676020.901250458, 2548417.518483455 6676020.901250458) + +LINESTRING (2548417.5184834544 6675852.235489515, 2548601.9966594866 6675852.649101298) + +LINESTRING (2548417.5184834544 6675683.983340356, 2548417.5184834544 6675852.235489515) + +LINESTRING (2548233.5673879255 6675683.456259852, 2548233.6149715823 6675852.649101299) + +LINESTRING (2548788.4914588258 6675683.983340356, 2548788.4914588258 6675852.235489515) + +LINESTRING (2548788.4914588258 6675852.235489515, 2548972.969634858 6675852.649101298) + +LINESTRING (2548601.9966594866 6675852.649101298, 2548788.4914588258 6675852.235489515, 2548788.491458826 6676020.901250458, 2548604.5879469537 6676020.901250458, 2548601.9966594866 6675852.649101298) + +LINESTRING (2548983.256785014 6676045.688056899, 2548788.491458826 6676020.901250458) + +LINESTRING (2548603.1464908933 6675679.276164135, 2548601.9966594866 6675852.649101298) + +LINESTRING (2548787.0500027654 6675510.610403191, 2548971.5281787976 6675511.024014975) + +LINESTRING (2548416.077027394 6675342.358254032, 2548416.077027394 6675510.610403191) + +LINESTRING (2548416.077027394 6675510.610403191, 2548600.555203426 6675511.024014975) + +LINESTRING (2548232.173515522 6675511.024014976, 2548416.077027394 6675510.610403191, 2548417.5184834544 6675683.983340356, 2548233.5673879255 6675683.456259852, 2548232.173515522 6675511.024014976) + +LINESTRING (2548603.1464908933 6675679.276164135, 2548417.5184834544 6675683.983340356) + +LINESTRING (2548228.3623082736 6675327.5496937055, 2548232.173515522 6675511.024014976) + +LINESTRING (2548603.0989072365 6675341.831173529, 2548600.555203426 6675511.024014975) + +LINESTRING (2548783.2387955175 6675327.5496937055, 2548787.0500027654 6675510.610403191) + +LINESTRING (2548600.555203426 6675511.024014975, 2548787.0500027654 6675510.610403191, 2548788.4914588258 6675683.983340356, 2548603.1464908933 6675679.276164135, 2548600.555203426 6675511.024014975) + +LINESTRING (2548971.001098294 6675679.276164134, 2548788.4914588258 6675683.983340356) + +LINESTRING (2548971.5281787976 6675511.024014975, 2549161.9552172343 6675510.610403191, 2549163.3966732947 6675683.983340356, 2548971.001098294 6675679.276164134, 2548971.5281787976 6675511.024014975) + +LINESTRING (2549163.3966732947 6675683.983340356, 2549163.3966732947 6675852.235489515) + +LINESTRING (2548974.240498114 6675327.5496937055, 2548971.5281787976 6675511.024014975) + +LINESTRING (2549349.0246807337 6675679.276164135, 2549163.3966732947 6675683.983340356) + +LINESTRING (2549163.3966732947 6675852.235489515, 2549347.874849327 6675852.649101298) + +LINESTRING (2548972.969634858 6675852.649101298, 2549163.3966732947 6675852.235489515, 2549163.396673295 6676020.901250458, 2548983.256785014 6676045.688056899, 2548972.969634858 6675852.649101298) + +LINESTRING (2548971.001098294 6675679.276164134, 2548972.969634858 6675852.649101298) + +LINESTRING (2549158.1440099864 6675327.5496937055, 2549161.9552172343 6675510.610403191) + +LINESTRING (2549730.5764309145 6675678.2035965435, 2549534.369648666 6675683.983340356) + +LINESTRING (2549534.369648666 6675852.235489515, 2549718.8478246983 6675852.649101298) + +LINESTRING (2549161.9552172343 6675510.610403191, 2549346.4333932665 6675511.024014975) + +LINESTRING (2549529.116985358 6675327.5496937055, 2549532.9281926057 6675510.610403191) + +LINESTRING (2549532.9281926057 6675510.610403191, 2549729.182558511 6675505.771351667) + +LINESTRING (2549349.0246807337 6675679.276164135, 2549347.874849327 6675852.649101298) + +LINESTRING (2549350.466136794 6676020.901250458, 2549163.396673295 6676020.901250458) + +LINESTRING (2549345.2134734853 6675327.5496937055, 2549346.4333932665 6675511.024014975) + +LINESTRING (2549347.874849327 6675852.649101298, 2549534.369648666 6675852.235489515, 2549534.3696486666 6676020.901250458, 2549350.466136794 6676020.901250458, 2549347.874849327 6675852.649101298) + +LINESTRING (2549534.369648666 6675683.983340356, 2549534.369648666 6675852.235489515) + +LINESTRING (2549346.4333932665 6675511.024014975, 2549532.9281926057 6675510.610403191, 2549534.369648666 6675683.983340356, 2549349.0246807337 6675679.276164135, 2549346.4333932665 6675511.024014975) + +LINESTRING (2549718.3207441946 6676020.901250457, 2549534.3696486666 6676020.901250458) + +LINESTRING (2548966.275515489 6674817.672458222, 2549156.7025539256 6674817.2588464385, 2549158.144009986 6674990.631783603, 2548965.748434985 6674985.924607381, 2548966.275515489 6674817.672458222) + +LINESTRING (2548412.2658201456 6674990.631783603, 2548412.2658201456 6675158.883932762) + +LINESTRING (2548217.2665213626 6674585.036234244, 2548226.920852213 6674817.672458223) + +LINESTRING (2549343.772017425 6674985.924607382, 2549158.144009986 6674990.631783603) + +LINESTRING (2548412.2658201456 6675158.883932762, 2548596.743996178 6675159.2975445455) + +LINESTRING (2549725.3237676057 6674984.852039791, 2549529.1169853574 6674990.631783603) + +LINESTRING (2548228.3623082736 6675159.297544546, 2548412.2658201456 6675158.883932762, 2548416.077027394 6675342.358254032, 2548228.3623082736 6675327.5496937055, 2548228.3623082736 6675159.297544546) + +LINESTRING (2549527.675529297 6674817.2588464385, 2549723.929895202 6674812.419794914) + +LINESTRING (2548965.748434985 6674985.924607381, 2548783.238795517 6674990.631783603) + +LINESTRING (2549529.1169853574 6675158.883932762, 2549725.3713512626 6675154.044881238) + +LINESTRING (2548783.238795517 6675158.883932762, 2548967.716971549 6675159.2975445455) + +LINESTRING (2548410.824364085 6674817.2588464385, 2548595.3025401174 6674817.672458222) + +LINESTRING (2549529.1169853574 6674990.631783603, 2549529.1169853574 6675158.883932762) + +LINESTRING (2548781.7973394566 6674649.006697279, 2548781.7973394566 6674817.2588464385) + +LINESTRING (2549713.068080886 6675327.549693705, 2549529.116985358 6675327.5496937055) + +LINESTRING (2548597.8938275846 6674985.924607382, 2548596.743996178 6675159.2975445455) + +LINESTRING (2548603.0989072365 6675341.831173529, 2548416.077027394 6675342.358254032) + +LINESTRING (2548595.3025401174 6674817.672458222, 2548781.7973394566 6674817.2588464385, 2548783.238795517 6674990.631783603, 2548597.8938275846 6674985.924607382, 2548595.3025401174 6674817.672458222) + +LINESTRING (2549343.724433768 6674648.479616776, 2549341.1807299578 6674817.672458222) + +LINESTRING (2548965.748434985 6674985.924607381, 2548967.716971549 6675159.2975445455) + +LINESTRING (2548972.7514583967 6674648.479616776, 2548966.275515489 6674817.672458222) + +LINESTRING (2549343.772017425 6674985.924607382, 2549342.622186018 6675159.2975445455) + +LINESTRING (2548226.920852213 6674817.672458223, 2548410.824364085 6674817.2588464385, 2548412.2658201456 6674990.631783603, 2548228.3147246167 6674990.1047030995, 2548226.920852213 6674817.672458223) + +LINESTRING (2548967.716971549 6675159.2975445455, 2549158.144009986 6675158.883932762, 2549158.1440099864 6675327.5496937055, 2548974.240498114 6675327.5496937055, 2548967.716971549 6675159.2975445455) + +LINESTRING (2549158.144009986 6674990.631783603, 2549158.144009986 6675158.883932762) + +LINESTRING (2549341.1807299578 6674817.672458222, 2549527.675529297 6674817.2588464385, 2549529.1169853574 6674990.631783603, 2549343.772017425 6674985.924607382, 2549341.1807299578 6674817.672458222) + +LINESTRING (2548597.8938275846 6674985.924607382, 2548412.2658201456 6674990.631783603) + +LINESTRING (2548228.3147246167 6674990.1047030995, 2548228.3623082736 6675159.297544546) + +LINESTRING (2549156.7025539256 6674817.2588464385, 2549341.1807299578 6674817.672458222) + +LINESTRING (2548410.824364085 6674649.006697279, 2548410.824364085 6674817.2588464385) + +LINESTRING (2549156.7025539256 6674649.006697279, 2549156.7025539256 6674817.2588464385) + +LINESTRING (2549158.144009986 6675158.883932762, 2549342.622186018 6675159.2975445455) + +LINESTRING (2549527.675529297 6674649.006697279, 2549527.675529297 6674817.2588464385) + +LINESTRING (2549345.2134734853 6675327.5496937055, 2549158.1440099864 6675327.5496937055) + +LINESTRING (2548781.7973394566 6674817.2588464385, 2548966.275515489 6674817.672458222) + +LINESTRING (2548588.239496734 6674585.036234244, 2548595.3025401174 6674817.672458222) + +LINESTRING (2549342.622186018 6675159.2975445455, 2549529.1169853574 6675158.883932762, 2549529.116985358 6675327.5496937055, 2549345.2134734853 6675327.5496937055, 2549342.622186018 6675159.2975445455) + +LINESTRING (2548783.238795517 6674990.631783603, 2548783.238795517 6675158.883932762) + +LINESTRING (2548596.743996178 6675159.2975445455, 2548783.238795517 6675158.883932762, 2548783.2387955175 6675327.5496937055, 2548603.0989072365 6675341.831173529, 2548596.743996178 6675159.2975445455) + +LINESTRING (2548974.240498114 6675327.5496937055, 2548783.2387955175 6675327.5496937055) + +LINESTRING (2551240.0830393434 6674990.1047030995, 2551026.1260283464 6674985.379120294) + +LINESTRING (2550840.733476757 6674643.226953467, 2550838.1897729468 6674812.419794913) + +LINESTRING (2550846.0337237227 6675674.023500826, 2550660.4057162837 6675678.730677047) + +LINESTRING (2549914.5275264434 6675846.982826206, 2550099.0057024756 6675847.39643799) + +LINESTRING (2550653.7115969146 6674812.00618313, 2550838.1897729468 6674812.419794913) + +LINESTRING (2551029.9372355947 6675505.357739883, 2551243.9418302486 6675511.024014976) + +LINESTRING (2550093.753039167 6675154.044881237, 2550280.247838506 6675153.631269453, 2550280.2478385065 6675322.297030397, 2550100.1079502255 6675336.57851022, 2550093.753039167 6675154.044881237) + +LINESTRING (2550644.0572660645 6674579.783570935, 2550653.7115969146 6674812.00618313) + +LINESTRING (2550468.010141283 6675674.023500825, 2550285.5005018148 6675678.730677047) + +LINESTRING (2551031.378691655 6675846.982826206, 2551215.8568676873 6675847.39643799) + +LINESTRING (2550471.249541103 6675322.297030397, 2550280.2478385065 6675322.297030397) + +LINESTRING (2550285.5005018148 6675846.982826206, 2550469.978677847 6675847.39643799) + +LINESTRING (2551031.378691655 6675678.730677047, 2551031.378691655 6675846.982826206) + +LINESTRING (2551026.1260283464 6674985.379120294, 2551026.1260283464 6675153.631269453) + +LINESTRING (2550840.781060414 6674980.671944073, 2550839.631229007 6675154.044881237) + +LINESTRING (2550280.2478385065 6675322.297030397, 2550284.0590457544 6675505.357739883) + +LINESTRING (2550100.1555338823 6675674.023500826, 2550099.0057024756 6675847.39643799) + +LINESTRING (2550105.360613534 6676040.4353935905, 2549914.527526444 6676015.64858715) + +LINESTRING (2550278.8063824456 6674812.00618313, 2550463.284558478 6674812.419794913) + +LINESTRING (2550471.249541103 6675322.297030397, 2550468.5372217866 6675505.771351666) + +LINESTRING (2550846.0337237227 6675674.023500826, 2550844.883892316 6675847.39643799) + +LINESTRING (2550469.978677847 6675847.39643799, 2550660.4057162837 6675846.982826206, 2550660.405716284 6676015.64858715, 2550480.265828003 6676040.4353935905, 2550469.978677847 6675847.39643799) + +LINESTRING (2550660.4057162837 6675678.730677047, 2550660.4057162837 6675846.982826206) + +LINESTRING (2549725.3237676057 6674984.852039791, 2549725.3713512626 6675154.044881238) + +LINESTRING (2550100.1555338823 6675674.023500826, 2549914.5275264434 6675678.730677047) + +LINESTRING (2550280.247838506 6674985.379120294, 2550280.247838506 6675153.631269453) + +LINESTRING (2550839.631229007 6675154.044881237, 2551026.1260283464 6675153.631269453, 2551026.126028347 6675322.297030397, 2550842.2225164743 6675322.297030397, 2550839.631229007 6675154.044881237) + +LINESTRING (2550464.726014538 6675154.044881237, 2550655.153052975 6675153.631269453, 2550655.1530529754 6675322.297030397, 2550471.249541103 6675322.297030397, 2550464.726014538 6675154.044881237) + +LINESTRING (2550655.153052975 6674985.379120294, 2550655.153052975 6675153.631269453) + +LINESTRING (2549730.5764309145 6675678.2035965435, 2549718.8478246983 6675852.649101298) + +LINESTRING (2551024.684572286 6674812.00618313, 2551209.162748318 6674812.419794913) + +LINESTRING (2550658.9642602233 6675505.357739883, 2550843.4424362555 6675505.771351666) + +LINESTRING (2550462.757477974 6674980.6719440725, 2550280.247838506 6674985.379120294) + +LINESTRING (2550838.1897729468 6674812.419794913, 2551024.684572286 6674812.00618313, 2551026.1260283464 6674985.379120294, 2550840.781060414 6674980.671944073, 2550838.1897729468 6674812.419794913) + +LINESTRING (2550092.3115831064 6674812.419794913, 2550278.8063824456 6674812.00618313, 2550280.247838506 6674985.379120294, 2550094.9028705736 6674980.671944073, 2550092.3115831064 6674812.419794913) + +LINESTRING (2550655.1530529754 6675322.297030397, 2550658.9642602233 6675505.357739883) + +LINESTRING (2550094.9028705736 6674980.671944073, 2549909.2748631346 6674985.379120294) + +LINESTRING (2550660.4057162837 6675846.982826206, 2550844.883892316 6675847.39643799) + +LINESTRING (2549723.8823115453 6674643.226953467, 2549723.929895202 6674812.419794914) + +LINESTRING (2549723.929895202 6674812.419794914, 2549907.833407074 6674812.00618313, 2549909.2748631346 6674985.379120294, 2549725.3237676057 6674984.852039791, 2549723.929895202 6674812.419794914) + +LINESTRING (2551026.126028347 6675322.297030397, 2551029.9372355947 6675505.357739883) + +LINESTRING (2550851.2388033746 6676040.4353935905, 2550660.405716284 6676015.64858715) + +LINESTRING (2550278.8063824456 6674643.754033971, 2550278.8063824456 6674812.00618313) + +LINESTRING (2550844.883892316 6675847.39643799, 2551031.378691655 6675846.982826206, 2551035.1898989035 6676040.962474094, 2550851.2388033746 6676040.4353935905, 2550844.883892316 6675847.39643799) + +LINESTRING (2550480.265828003 6676040.4353935905, 2550285.500501815 6676015.64858715) + +LINESTRING (2550463.284558478 6674812.419794913, 2550653.7115969146 6674812.00618313, 2550655.153052975 6674985.379120294, 2550462.757477974 6674980.6719440725, 2550463.284558478 6674812.419794913) + +LINESTRING (2550655.153052975 6675153.631269453, 2550839.631229007 6675154.044881237) + +LINESTRING (2550468.5372217866 6675505.771351666, 2550658.9642602233 6675505.357739883, 2550660.4057162837 6675678.730677047, 2550468.010141283 6675674.023500825, 2550468.5372217866 6675505.771351666) + +LINESTRING (2549914.5275264434 6675678.730677047, 2549914.5275264434 6675846.982826206) + +LINESTRING (2549713.068080886 6675327.549693705, 2549729.182558511 6675505.771351667) + +LINESTRING (2551024.684572286 6674643.754033971, 2551024.684572286 6674812.00618313) + +LINESTRING (2549907.833407074 6674643.754033971, 2549907.833407074 6674812.00618313) + +LINESTRING (2549907.833407074 6674812.00618313, 2550092.3115831064 6674812.419794913) + +LINESTRING (2551245.335702652 6675683.456259852, 2551031.378691655 6675678.730677047) + +LINESTRING (2549718.8478246983 6675852.649101298, 2549914.5275264434 6675846.982826206, 2549914.527526444 6676015.64858715, 2549718.3207441946 6676020.901250457, 2549718.8478246983 6675852.649101298) + +LINESTRING (2551026.1260283464 6675153.631269453, 2551240.130623 6675159.297544546) + +LINESTRING (2550280.247838506 6675153.631269453, 2550464.726014538 6675154.044881237) + +LINESTRING (2551240.130623 6675327.5496937055, 2551026.126028347 6675322.297030397) + +LINESTRING (2549909.2748631346 6674985.379120294, 2549909.2748631346 6675153.631269453) + +LINESTRING (2549913.086070383 6675505.357739883, 2550097.564246415 6675505.771351666) + +LINESTRING (2551249.1469099005 6676045.688056899, 2551035.1898989035 6676040.962474094) + +LINESTRING (2550097.564246415 6675505.771351666, 2550284.0590457544 6675505.357739883, 2550285.5005018148 6675678.730677047, 2550100.1555338823 6675674.023500826, 2550097.564246415 6675505.771351666) + +LINESTRING (2550842.2225164743 6675322.297030397, 2550843.4424362555 6675505.771351666) + +LINESTRING (2550468.010141283 6675674.023500825, 2550469.978677847 6675847.39643799) + +LINESTRING (2549729.182558511 6675505.771351667, 2549913.086070383 6675505.357739883, 2549914.5275264434 6675678.730677047, 2549730.5764309145 6675678.2035965435, 2549729.182558511 6675505.771351667) + +LINESTRING (2550094.9028705736 6674980.671944073, 2550093.753039167 6675154.044881237) + +LINESTRING (2550460.153754192 6674579.783570935, 2550463.284558478 6674812.419794913) + +LINESTRING (2550843.4424362555 6675505.771351666, 2551029.9372355947 6675505.357739883, 2551031.378691655 6675678.730677047, 2550846.0337237227 6675674.023500826, 2550843.4424362555 6675505.771351666) + +LINESTRING (2550462.757477974 6674980.6719440725, 2550464.726014538 6675154.044881237) + +LINESTRING (2549913.086070383 6675337.105590723, 2549913.086070383 6675505.357739883) + +LINESTRING (2550842.2225164743 6675322.297030397, 2550655.1530529754 6675322.297030397) + +LINESTRING (2550840.781060414 6674980.671944073, 2550655.153052975 6674985.379120294) + +LINESTRING (2549725.3713512626 6675154.044881238, 2549909.2748631346 6675153.631269453, 2549913.086070383 6675337.105590723, 2549713.068080886 6675327.549693705, 2549725.3713512626 6675154.044881238) + +LINESTRING (2549909.2748631346 6675153.631269453, 2550093.753039167 6675154.044881237) + +LINESTRING (2550100.1079502255 6675336.57851022, 2549913.086070383 6675337.105590723) + +LINESTRING (2550094.8552869167 6674643.226953467, 2550092.3115831064 6674812.419794913) + +LINESTRING (2550284.0590457544 6675505.357739883, 2550468.5372217866 6675505.771351666) + +LINESTRING (2550100.1079502255 6675336.57851022, 2550097.564246415 6675505.771351666) + +LINESTRING (2550099.0057024756 6675847.39643799, 2550285.5005018148 6675846.982826206, 2550285.500501815 6676015.64858715, 2550105.360613534 6676040.4353935905, 2550099.0057024756 6675847.39643799) + +LINESTRING (2550285.5005018148 6675678.730677047, 2550285.5005018148 6675846.982826206) + +LINESTRING (2549735.829094223 6676382.060479914, 2549539.622311975 6676387.840223726) + +LINESTRING (2549350.466136794 6676020.901250458, 2549351.6860565753 6676214.880898345) + +LINESTRING (2551035.1898989035 6676040.962474094, 2551035.1898989035 6676209.214623253) + +LINESTRING (2549359.530007351 6677076.484604258, 2549173.901999912 6677081.191780479) + +LINESTRING (2548428.023810072 6677249.443929638, 2548612.501986104 6677249.857541421) + +LINESTRING (2549167.207880543 6676214.467286562, 2549351.6860565753 6676214.880898345) + +LINESTRING (2549543.4335192232 6676907.818843314, 2549739.6878851284 6676902.97979179) + +LINESTRING (2550856.53905034 6677071.231940949, 2550670.911042901 6677075.93911717) + +LINESTRING (2548607.2493227953 6676556.505984669, 2548793.7441221345 6676556.092372885, 2548793.744122135 6676724.758133829, 2548613.604233854 6676739.039613652, 2548607.2493227953 6676556.505984669) + +LINESTRING (2549544.8749752836 6677249.443929638, 2549729.353151316 6677249.857541421) + +LINESTRING (2550112.10231656 6677412.857027273, 2549925.0328530613 6677412.857027273) + +LINESTRING (2550105.408197191 6676377.8803841965, 2550104.2583657843 6676551.25332136) + +LINESTRING (2548984.7458247314 6676724.758133829, 2548793.744122135 6676724.758133829) + +LINESTRING (2549918.3387336917 6676209.214623253, 2550102.816909724 6676209.6282350365) + +LINESTRING (2550285.500501815 6676015.64858715, 2550289.311709063 6676209.214623253) + +LINESTRING (2550660.405716284 6676015.64858715, 2550664.216923532 6676209.214623253) + +LINESTRING (2549539.622311975 6676387.840223726, 2549539.622311975 6676556.092372885) + +LINESTRING (2549354.2773440424 6676383.133047505, 2549353.1275126357 6676556.505984669) + +LINESTRING (2548793.744122135 6676724.758133829, 2548797.555329383 6676907.818843314) + +LINESTRING (2551035.1898989035 6676209.214623253, 2551249.1944935573 6676214.880898346) + +LINESTRING (2548613.651817511 6677076.484604258, 2548612.501986104 6677249.857541421) + +LINESTRING (2548615.093273571 6677418.109690581, 2548428.0238100723 6677418.109690581) + +LINESTRING (2548792.302666074 6676214.467286562, 2548976.7808421063 6676214.880898345) + +LINESTRING (2549925.032853061 6677244.191266329, 2550109.511029093 6677244.604878113) + +LINESTRING (2549359.530007351 6677076.484604258, 2549358.3801759444 6677249.857541421) + +LINESTRING (2550487.007531029 6677412.857027273, 2550296.0058284327 6677412.857027273) + +LINESTRING (2550851.2388033746 6676040.4353935905, 2550848.6950995643 6676209.6282350365) + +LINESTRING (2550481.7548677204 6676719.50547052, 2550479.042548404 6676902.979791789) + +LINESTRING (2549173.901999912 6677081.191780479, 2549173.901999912 6677249.443929638) + +LINESTRING (2548978.2222981667 6676556.505984669, 2549168.6493366035 6676556.092372885, 2549168.649336604 6676724.758133829, 2548984.7458247314 6676724.758133829, 2548978.2222981667 6676556.505984669) + +LINESTRING (2548244.072714543 6677080.664699975, 2548244.1202982 6677249.857541422) + +LINESTRING (2550110.6608605 6677071.231940949, 2549925.032853061 6677075.93911717) + +LINESTRING (2550665.6583795925 6676382.587560417, 2550665.6583795925 6676550.839709576) + +LINESTRING (2548605.807866735 6676214.880898345, 2548792.302666074 6676214.467286562, 2548793.7441221345 6676387.840223726, 2548608.399154202 6676383.133047505, 2548605.807866735 6676214.880898345) + +LINESTRING (2550848.6950995643 6676209.6282350365, 2551035.1898989035 6676209.214623253, 2551036.631354964 6676382.587560417, 2550851.2863870314 6676377.8803841965, 2550848.6950995643 6676209.6282350365) + +LINESTRING (2550669.469586841 6676902.566180006, 2550853.947762873 6676902.979791789) + +LINESTRING (2549173.901999912 6677249.443929638, 2549358.3801759444 6677249.857541421) + +LINESTRING (2550289.311709063 6676209.214623253, 2550473.7898850953 6676209.6282350365) + +LINESTRING (2550104.2583657843 6676551.25332136, 2550290.7531651235 6676550.839709576, 2550290.753165124 6676719.50547052, 2550110.613276843 6676733.786950343, 2550104.2583657843 6676551.25332136) + +LINESTRING (2548237.4261788307 6676214.880898346, 2548421.3296907027 6676214.467286562, 2548422.771146763 6676387.840223726, 2548238.820051234 6676387.313143223, 2548237.4261788307 6676214.880898346) + +LINESTRING (2549539.6223119753 6676724.758133829, 2549543.4335192232 6676907.818843314) + +LINESTRING (2549360.9714634116 6677418.109690581, 2549173.9019999127 6677418.109690581) + +LINESTRING (2548788.491458826 6676020.901250458, 2548792.302666074 6676214.467286562) + +LINESTRING (2548976.7808421063 6676214.880898345, 2549167.207880543 6676214.467286562, 2549168.6493366035 6676387.840223726, 2548976.2537616026 6676383.133047504, 2548976.7808421063 6676214.880898345) + +LINESTRING (2550850.1365556247 6676551.25332136, 2551036.631354964 6676550.839709576, 2551036.6313549643 6676719.50547052, 2550852.727843092 6676719.50547052, 2550850.1365556247 6676551.25332136) + +LINESTRING (2548238.867634891 6676724.758133829, 2548242.6788421394 6676908.232455099) + +LINESTRING (2549741.081757532 6677075.412036667, 2549544.8749752836 6677081.191780479) + +LINESTRING (2550481.7548677204 6676719.50547052, 2550290.753165124 6676719.50547052) + +LINESTRING (2549539.622311975 6676556.092372885, 2549735.87667788 6676551.253321361) + +LINESTRING (2549723.5734075033 6676724.758133828, 2549539.6223119753 6676724.758133829) + +LINESTRING (2551225.835113801 6677412.857027272, 2551041.884018273 6677412.857027273) + +LINESTRING (2548422.771146763 6676387.840223726, 2548422.771146763 6676556.092372885) + +LINESTRING (2548426.5823540115 6676907.818843314, 2548611.0605300437 6676908.232455098) + +LINESTRING (2548611.0605300437 6676908.232455098, 2548797.555329383 6676907.818843314, 2548798.9967854433 6677081.191780479, 2548613.651817511 6677076.484604258, 2548611.0605300437 6676908.232455098) + +LINESTRING (2549923.5913970005 6676902.566180006, 2550108.0695730327 6676902.979791789) + +LINESTRING (2549355.718800103 6676724.758133829, 2549356.938719884 6676908.232455098) + +LINESTRING (2548983.256785014 6676045.688056899, 2548976.7808421063 6676214.880898345) + +LINESTRING (2551250.588365961 6676387.313143223, 2551036.631354964 6676382.587560417) + +LINESTRING (2551040.4425622122 6676902.566180006, 2551254.447156866 6676908.232455099) + +LINESTRING (2550290.7531651235 6676382.587560417, 2550290.7531651235 6676550.839709576) + +LINESTRING (2551250.6359496177 6676724.758133829, 2551036.6313549643 6676719.50547052) + +LINESTRING (2550110.6608605 6677071.231940949, 2550109.511029093 6677244.604878113) + +LINESTRING (2550856.53905034 6677071.231940949, 2550855.3892189334 6677244.604878113) + +LINESTRING (2548976.2537616026 6676383.133047504, 2548978.2222981667 6676556.505984669) + +LINESTRING (2550290.753165124 6676719.50547052, 2550294.564372372 6676902.566180006) + +LINESTRING (2550105.408197191 6676377.8803841965, 2549919.780189752 6676382.587560417) + +LINESTRING (2548426.5823540115 6676739.566694155, 2548426.5823540115 6676907.818843314) + +LINESTRING (2549355.718800103 6676724.758133829, 2549168.649336604 6676724.758133829) + +LINESTRING (2551041.8840182726 6677244.191266329, 2551255.8886129265 6677249.857541422) + +LINESTRING (2550296.0058284323 6677075.93911717, 2550296.0058284323 6677244.191266329) + +LINESTRING (2548238.867634891 6676556.50598467, 2548422.771146763 6676556.092372885, 2548426.5823540115 6676739.566694155, 2548238.867634891 6676724.758133829, 2548238.867634891 6676556.50598467) + +LINESTRING (2548422.771146763 6676556.092372885, 2548607.2493227953 6676556.505984669) + +LINESTRING (2549914.527526444 6676015.64858715, 2549918.3387336917 6676209.214623253) + +LINESTRING (2548613.604233854 6676739.039613652, 2548426.5823540115 6676739.566694155) + +LINESTRING (2549919.780189752 6676550.839709576, 2550104.2583657843 6676551.25332136) + +LINESTRING (2550105.360613534 6676040.4353935905, 2550102.816909724 6676209.6282350365) + +LINESTRING (2550852.727843092 6676719.50547052, 2550665.658379593 6676719.50547052) + +LINESTRING (2548798.9967854433 6677081.191780479, 2548798.9967854433 6677249.443929638) + +LINESTRING (2551036.631354964 6676550.839709576, 2551250.6359496177 6676556.50598467) + +LINESTRING (2550473.2628045916 6676377.880384196, 2550290.7531651235 6676382.587560417) + +LINESTRING (2550478.5154679003 6677071.231940948, 2550296.0058284323 6677075.93911717) + +LINESTRING (2550108.0695730327 6676902.979791789, 2550294.564372372 6676902.566180006, 2550296.0058284323 6677075.93911717, 2550110.6608605 6677071.231940949, 2550108.0695730327 6676902.979791789) + +LINESTRING (2549923.5913970005 6676734.314030847, 2549923.5913970005 6676902.566180006) + +LINESTRING (2550665.658379593 6676719.50547052, 2550669.469586841 6676902.566180006) + +LINESTRING (2550852.727843092 6676719.50547052, 2550853.947762873 6676902.979791789) + +LINESTRING (2548981.5064249113 6677076.484604257, 2548798.9967854433 6677081.191780479) + +LINESTRING (2549163.396673295 6676020.901250458, 2549167.207880543 6676214.467286562) + +LINESTRING (2550475.2313411557 6676551.25332136, 2550665.6583795925 6676550.839709576, 2550665.658379593 6676719.50547052, 2550481.7548677204 6676719.50547052, 2550475.2313411557 6676551.25332136) + +LINESTRING (2548798.9967854433 6677249.443929638, 2548983.4749614755 6677249.857541421) + +LINESTRING (2550855.3892189334 6677244.604878113, 2551041.8840182726 6677244.191266329, 2551041.884018273 6677412.857027273, 2550857.9805064006 6677412.857027273, 2550855.3892189334 6677244.604878113) + +LINESTRING (2549735.87667788 6676551.253321361, 2549919.780189752 6676550.839709576, 2549923.5913970005 6676734.314030847, 2549723.5734075033 6676724.758133828, 2549735.87667788 6676551.253321361) + +LINESTRING (2549735.829094223 6676382.060479914, 2549735.87667788 6676551.253321361) + +LINESTRING (2549544.8749752836 6677081.191780479, 2549544.8749752836 6677249.443929638) + +LINESTRING (2549718.3207441946 6676020.901250457, 2549734.4352218197 6676209.628235037) + +LINESTRING (2548984.7458247314 6676724.758133829, 2548982.033505415 6676908.232455098) + +LINESTRING (2550109.511029093 6677244.604878113, 2550296.0058284323 6677244.191266329, 2550296.0058284327 6677412.857027273, 2550112.10231656 6677412.857027273, 2550109.511029093 6677244.604878113) + +LINESTRING (2551036.631354964 6676382.587560417, 2551036.631354964 6676550.839709576) + +LINESTRING (2548983.4749614755 6677249.857541421, 2549173.901999912 6677249.443929638, 2549173.9019999127 6677418.109690581, 2548989.99848804 6677418.109690581, 2548983.4749614755 6677249.857541421) + +LINESTRING (2548238.820051234 6676387.313143223, 2548238.867634891 6676556.50598467) + +LINESTRING (2548613.651817511 6677076.484604258, 2548428.023810072 6677081.191780479) + +LINESTRING (2550296.0058284323 6677244.191266329, 2550480.4840044645 6677244.604878113) + +LINESTRING (2548793.7441221345 6676387.840223726, 2548793.7441221345 6676556.092372885) + +LINESTRING (2549353.1275126357 6676556.505984669, 2549539.622311975 6676556.092372885, 2549539.6223119753 6676724.758133829, 2549355.718800103 6676724.758133829, 2549353.1275126357 6676556.505984669) + +LINESTRING (2549723.5734075033 6676724.758133828, 2549739.6878851284 6676902.97979179) + +LINESTRING (2549168.6493366035 6676387.840223726, 2549168.6493366035 6676556.092372885) + +LINESTRING (2549538.1808559145 6676214.467286562, 2549734.4352218197 6676209.628235037) + +LINESTRING (2549172.460543852 6676907.818843314, 2549356.938719884 6676908.232455098) + +LINESTRING (2548976.2537616026 6676383.133047504, 2548793.7441221345 6676387.840223726) + +LINESTRING (2549729.353151316 6677249.857541421, 2549925.032853061 6677244.191266329, 2549925.0328530613 6677412.857027273, 2549728.826070812 6677418.1096905805, 2549729.353151316 6677249.857541421) + +LINESTRING (2549351.6860565753 6676214.880898345, 2549538.1808559145 6676214.467286562, 2549539.622311975 6676387.840223726, 2549354.2773440424 6676383.133047505, 2549351.6860565753 6676214.880898345) + +LINESTRING (2551255.8410292696 6677080.664699975, 2551041.8840182726 6677075.93911717) + +LINESTRING (2549168.649336604 6676724.758133829, 2549172.460543852 6676907.818843314) + +LINESTRING (2548608.399154202 6676383.133047505, 2548422.771146763 6676387.840223726) + +LINESTRING (2550480.265828003 6676040.4353935905, 2550473.7898850953 6676209.6282350365) + +LINESTRING (2548237.378595174 6676045.688056899, 2548237.4261788307 6676214.880898346) + +LINESTRING (2550851.2863870314 6676377.8803841965, 2550850.1365556247 6676551.25332136) + +LINESTRING (2550478.5154679003 6677071.231940948, 2550480.4840044645 6677244.604878113) + +LINESTRING (2550851.2863870314 6676377.8803841965, 2550665.6583795925 6676382.587560417) + +LINESTRING (2549358.3801759444 6677249.857541421, 2549544.8749752836 6677249.443929638, 2549544.874975284 6677418.109690581, 2549360.9714634116 6677418.109690581, 2549358.3801759444 6677249.857541421) + +LINESTRING (2548989.99848804 6677418.109690581, 2548798.9967854437 6677418.109690581) + +LINESTRING (2550857.9805064006 6677412.857027273, 2550670.9110429017 6677412.857027273) + +LINESTRING (2549168.6493366035 6676556.092372885, 2549353.1275126357 6676556.505984669) + +LINESTRING (2548982.033505415 6676908.232455098, 2549172.460543852 6676907.818843314, 2549173.901999912 6677081.191780479, 2548981.5064249113 6677076.484604257, 2548982.033505415 6676908.232455098) + +LINESTRING (2548428.023810072 6677081.191780479, 2548428.023810072 6677249.443929638) + +LINESTRING (2549534.3696486666 6676020.901250458, 2549538.1808559145 6676214.467286562) + +LINESTRING (2548417.518483455 6676020.901250458, 2548421.3296907027 6676214.467286562) + +LINESTRING (2548421.3296907027 6676214.467286562, 2548605.807866735 6676214.880898345) + +LINESTRING (2550670.911042901 6677075.93911717, 2550670.911042901 6677244.191266329) + +LINESTRING (2549919.780189752 6676382.587560417, 2549919.780189752 6676550.839709576) + +LINESTRING (2548244.1202982 6677249.857541422, 2548428.023810072 6677249.443929638, 2548428.0238100723 6677418.109690581, 2548244.1202982 6677418.109690581, 2548244.1202982 6677249.857541422) + +LINESTRING (2550473.7898850953 6676209.6282350365, 2550664.216923532 6676209.214623253, 2550665.6583795925 6676382.587560417, 2550473.2628045916 6676377.880384196, 2550473.7898850953 6676209.6282350365) + +LINESTRING (2549741.081757532 6677075.412036667, 2549729.353151316 6677249.857541421) + +LINESTRING (2548793.7441221345 6676556.092372885, 2548978.2222981667 6676556.505984669) + +LINESTRING (2551041.8840182726 6677075.93911717, 2551041.8840182726 6677244.191266329) + +LINESTRING (2550473.2628045916 6676377.880384196, 2550475.2313411557 6676551.25332136) + +LINESTRING (2550665.6583795925 6676550.839709576, 2550850.1365556247 6676551.25332136) + +LINESTRING (2550102.816909724 6676209.6282350365, 2550289.311709063 6676209.214623253, 2550290.7531651235 6676382.587560417, 2550105.408197191 6676377.8803841965, 2550102.816909724 6676209.6282350365) + +LINESTRING (2549728.826070812 6677418.1096905805, 2549544.874975284 6677418.109690581) + +LINESTRING (2549925.032853061 6677075.93911717, 2549925.032853061 6677244.191266329) + +LINESTRING (2548981.5064249113 6677076.484604257, 2548983.4749614755 6677249.857541421) + +LINESTRING (2550480.4840044645 6677244.604878113, 2550670.911042901 6677244.191266329, 2550670.9110429017 6677412.857027273, 2550487.007531029 6677412.857027273, 2550480.4840044645 6677244.604878113) + +LINESTRING (2548242.6788421394 6676908.232455099, 2548426.5823540115 6676907.818843314, 2548428.023810072 6677081.191780479, 2548244.072714543 6677080.664699975, 2548242.6788421394 6676908.232455099) + +LINESTRING (2548608.399154202 6676383.133047505, 2548607.2493227953 6676556.505984669) + +LINESTRING (2551036.6313549643 6676719.50547052, 2551040.4425622122 6676902.566180006) + +LINESTRING (2550664.216923532 6676209.214623253, 2550848.6950995643 6676209.6282350365) + +LINESTRING (2550294.564372372 6676902.566180006, 2550479.042548404 6676902.979791789) + +LINESTRING (2550110.613276843 6676733.786950343, 2550108.0695730327 6676902.979791789) + +LINESTRING (2549356.938719884 6676908.232455098, 2549543.4335192232 6676907.818843314, 2549544.8749752836 6677081.191780479, 2549359.530007351 6677076.484604258, 2549356.938719884 6676908.232455098) + +LINESTRING (2550853.947762873 6676902.979791789, 2551040.4425622122 6676902.566180006, 2551041.8840182726 6677075.93911717, 2550856.53905034 6677071.231940949, 2550853.947762873 6676902.979791789) + +LINESTRING (2549734.4352218197 6676209.628235037, 2549918.3387336917 6676209.214623253, 2549919.780189752 6676382.587560417, 2549735.829094223 6676382.060479914, 2549734.4352218197 6676209.628235037) + +LINESTRING (2550290.7531651235 6676550.839709576, 2550475.2313411557 6676551.25332136) + +LINESTRING (2549739.6878851284 6676902.97979179, 2549923.5913970005 6676902.566180006, 2549925.032853061 6677075.93911717, 2549741.081757532 6677075.412036667, 2549739.6878851284 6676902.97979179) + +LINESTRING (2550110.613276843 6676733.786950343, 2549923.5913970005 6676734.314030847) + +LINESTRING (2549354.2773440424 6676383.133047505, 2549168.6493366035 6676387.840223726) + +LINESTRING (2548604.5879469537 6676020.901250458, 2548605.807866735 6676214.880898345) + +LINESTRING (2548797.555329383 6676907.818843314, 2548982.033505415 6676908.232455098) + +LINESTRING (2550479.042548404 6676902.979791789, 2550669.469586841 6676902.566180006, 2550670.911042901 6677075.93911717, 2550478.5154679003 6677071.231940948, 2550479.042548404 6676902.979791789) + +LINESTRING (2548613.604233854 6676739.039613652, 2548611.0605300437 6676908.232455098) + +LINESTRING (2548612.501986104 6677249.857541421, 2548798.9967854433 6677249.443929638, 2548798.9967854437 6677418.109690581, 2548615.093273571 6677418.109690581, 2548612.501986104 6677249.857541421) + +LINESTRING (2550670.911042901 6677244.191266329, 2550855.3892189334 6677244.604878113) + +LINESTRING (2552737.0920823324 6674984.852039791, 2552540.885300084 6674990.631783603) + +LINESTRING (2552355.4927484947 6674648.479616776, 2552352.9490446844 6674817.672458222) + +LINESTRING (2551429.286798181 6675852.235489515, 2551613.764974213 6675852.649101298) + +LINESTRING (2552168.470868652 6674817.2588464385, 2552352.9490446844 6674817.672458222) + +LINESTRING (2553857.8020384493 6675674.023500826, 2553672.1740310104 6675678.730677047) + +LINESTRING (2551608.5123109045 6675159.2975445455, 2551795.0071102437 6675158.883932762, 2551795.007110244 6675327.5496937055, 2551614.867221963 6675341.831173529, 2551608.5123109045 6675159.2975445455) + +LINESTRING (2551434.5394614898 6676387.840223726, 2551434.5394614898 6676556.092372885) + +LINESTRING (2553493.523182447 6676719.50547052, 2553490.8108631307 6676902.979791789) + +LINESTRING (2552546.137963393 6675852.235489515, 2552730.616139425 6675852.649101298) + +LINESTRING (2553117.128928261 6676040.4353935905, 2552926.2958411705 6676015.64858715) + +LINESTRING (2553106.6711853 6674980.671944073, 2553105.5213538934 6675154.044881237) + +LINESTRING (2552735.34172223 6676724.758133828, 2552751.456199855 6676902.97979179) + +LINESTRING (2553486.9996558824 6676551.25332136, 2553677.426694319 6676550.839709576, 2553677.4266943196 6676719.50547052, 2553493.523182447 6676719.50547052, 2553486.9996558824 6676551.25332136) + +LINESTRING (2552919.601721801 6674812.00618313, 2553104.079897833 6674812.419794913) + +LINESTRING (2552747.59740895 6676382.060479914, 2552551.3906267015 6676387.840223726) + +LINESTRING (2553490.283782627 6677071.231940948, 2553307.774143159 6677075.93911717) + +LINESTRING (2552931.5485044788 6676550.839709576, 2553116.026680511 6676551.25332136) + +LINESTRING (2551433.0980054294 6676214.467286562, 2551617.5761814616 6676214.880898345) + +LINESTRING (2551810.76510017 6677081.191780479, 2551810.76510017 6677249.443929638) + +LINESTRING (2553655.825580791 6674579.783570935, 2553665.479911641 6674812.00618313) + +LINESTRING (2551250.588365961 6676387.313143223, 2551250.6359496177 6676556.50598467) + +LINESTRING (2551795.007110244 6675327.5496937055, 2551798.818317492 6675510.610403191) + +LINESTRING (2553865.7160775997 6676902.979791789, 2554052.210876939 6676902.566180006, 2554053.6523329993 6677075.93911717, 2553868.307365067 6677071.231940949, 2553865.7160775997 6676902.979791789) + +LINESTRING (2551793.5656541833 6674817.2588464385, 2551978.0438302155 6674817.672458222) + +LINESTRING (2552926.2958411705 6676015.64858715, 2552930.1070484184 6676209.214623253) + +LINESTRING (2551616.3562616804 6676020.901250458, 2551429.2867981815 6676020.901250458) + +LINESTRING (2554036.4528870126 6674812.00618313, 2554220.931063045 6674812.419794913) + +LINESTRING (2553114.5852244506 6676209.6282350365, 2553301.08002379 6676209.214623253, 2553302.52147985 6676382.587560417, 2553117.1765119177 6676377.8803841965, 2553114.5852244506 6676209.6282350365) + +LINESTRING (2552926.29584117 6675846.982826206, 2553110.774017202 6675847.39643799) + +LINESTRING (2552360.7929954603 6675679.276164135, 2552359.6431640536 6675852.649101298) + +LINESTRING (2553492.03414273 6676040.4353935905, 2553297.268816542 6676015.64858715) + +LINESTRING (2553119.8378877593 6676902.979791789, 2553306.3326870985 6676902.566180006, 2553307.774143159 6677075.93911717, 2553122.4291752265 6677071.231940949, 2553119.8378877593 6676902.979791789) + +LINESTRING (2552180.4176513306 6676724.758133829, 2552184.2288585785 6676907.818843314) + +LINESTRING (2554230.9093091586 6676377.880384196, 2554048.3996696905 6676382.587560417) + +LINESTRING (2551979.485286276 6675159.2975445455, 2552169.9123247126 6675158.883932762, 2552169.912324713 6675327.5496937055, 2551986.0088128406 6675327.5496937055, 2551979.485286276 6675159.2975445455) + +LINESTRING (2553111.923848609 6675674.023500826, 2552926.29584117 6675678.730677047) + +LINESTRING (2551607.070854844 6674817.672458222, 2551793.5656541833 6674817.2588464385, 2551795.0071102437 6674990.631783603, 2551609.662142311 6674985.924607382, 2551607.070854844 6674817.672458222) + +LINESTRING (2552367.4871148295 6676724.758133829, 2552180.4176513306 6676724.758133829) + +LINESTRING (2553493.523182447 6676719.50547052, 2553302.5214798506 6676719.50547052) + +LINESTRING (2552175.1649880214 6675852.235489515, 2552359.6431640536 6675852.649101298) + +LINESTRING (2553290.5746971723 6674812.00618313, 2553475.0528732045 6674812.419794913) + +LINESTRING (2554048.3996696905 6676550.839709576, 2554232.8778457227 6676551.25332136) + +LINESTRING (2553117.1765119177 6676377.8803841965, 2553116.026680511 6676551.25332136) + +LINESTRING (2551625.4201322375 6677076.484604258, 2551439.7921247985 6677081.191780479) + +LINESTRING (2552540.8853000845 6675327.5496937055, 2552544.6965073324 6675510.610403191) + +LINESTRING (2552362.2344515207 6676020.901250458, 2552175.164988022 6676020.901250458) + +LINESTRING (2551793.5656541833 6674649.006697279, 2551793.5656541833 6674817.2588464385) + +LINESTRING (2552178.9761952697 6676214.467286562, 2552363.454371302 6676214.880898345) + +LINESTRING (2551978.0438302155 6674817.672458222, 2552168.470868652 6674817.2588464385, 2552169.9123247126 6674990.631783603, 2551977.5167497117 6674985.924607381, 2551978.0438302155 6674817.672458222) + +LINESTRING (2551800.259773553 6676020.901250458, 2551804.070980801 6676214.467286562) + +LINESTRING (2552364.8958273623 6676556.505984669, 2552551.3906267015 6676556.092372885, 2552551.390626702 6676724.758133829, 2552367.4871148295 6676724.758133829, 2552364.8958273623 6676556.505984669) + +LINESTRING (2551625.4201322375 6677076.484604258, 2551624.2703008307 6677249.857541421) + +LINESTRING (2553490.283782627 6677071.231940948, 2553492.252319191 6677244.604878113) + +LINESTRING (2551616.3562616804 6676020.901250458, 2551617.5761814616 6676214.880898345) + +LINESTRING (2553123.870631287 6677412.857027273, 2552936.801167788 6677412.857027273) + +LINESTRING (2551240.130623 6675327.5496937055, 2551243.9418302486 6675511.024014976) + +LINESTRING (2553863.054701758 6676377.8803841965, 2553677.426694319 6676382.587560417) + +LINESTRING (2552742.344745641 6675678.2035965435, 2552546.137963393 6675683.983340356) + +LINESTRING (2552931.5485044788 6676382.587560417, 2552931.5485044788 6676550.839709576) + +LINESTRING (2552746.2035365463 6676209.628235037, 2552930.1070484184 6676209.214623253, 2552931.5485044788 6676382.587560417, 2552747.59740895 6676382.060479914, 2552746.2035365463 6676209.628235037) + +LINESTRING (2551424.0341348723 6674990.631783603, 2551424.0341348723 6675158.883932762) + +LINESTRING (2553863.054701758 6676377.8803841965, 2553861.9048703513 6676551.25332136) + +LINESTRING (2551993.274739638 6677076.484604257, 2551810.76510017 6677081.191780479) + +LINESTRING (2552924.8543851096 6675505.357739883, 2553109.332561142 6675505.771351666) + +LINESTRING (2552936.8011677875 6677075.93911717, 2552936.8011677875 6677244.191266329) + +LINESTRING (2551984.5197731233 6674648.479616776, 2551978.0438302155 6674817.672458222) + +LINESTRING (2554041.7055503214 6675505.357739883, 2554226.1837263536 6675505.771351666) + +LINESTRING (2553292.0161532327 6674985.379120294, 2553292.0161532327 6675153.631269453) + +LINESTRING (2552551.390626702 6676724.758133829, 2552555.20183395 6676907.818843314) + +LINESTRING (2553111.923848609 6675674.023500826, 2553110.774017202 6675847.39643799) + +LINESTRING (2552184.2288585785 6676907.818843314, 2552368.7070346107 6676908.232455098) + +LINESTRING (2554053.6523329993 6677075.93911717, 2554053.6523329993 6677244.191266329) + +LINESTRING (2551977.5167497117 6674985.924607381, 2551979.485286276 6675159.2975445455) + +LINESTRING (2551438.350668738 6676739.566694155, 2551438.350668738 6676907.818843314) + +LINESTRING (2553106.6711853 6674980.671944073, 2552921.0431778613 6674985.379120294) + +LINESTRING (2551427.8453421206 6675342.358254032, 2551427.8453421206 6675510.610403191) + +LINESTRING (2552356.981788212 6675327.5496937055, 2552169.912324713 6675327.5496937055) + +LINESTRING (2554043.147006382 6675846.982826206, 2554227.625182414 6675847.39643799) + +LINESTRING (2552930.1070484184 6676209.214623253, 2553114.5852244506 6676209.6282350365) + +LINESTRING (2553297.2688165414 6675678.730677047, 2553297.2688165414 6675846.982826206) + +LINESTRING (2551988.022076329 6676383.133047504, 2551805.512436861 6676387.840223726) + +LINESTRING (2551424.0341348723 6675158.883932762, 2551608.5123109045 6675159.2975445455) + +LINESTRING (2553117.1765119177 6676377.8803841965, 2552931.5485044788 6676382.587560417) + +LINESTRING (2551439.7921247985 6677081.191780479, 2551439.7921247985 6677249.443929638) + +LINESTRING (2552546.1379633932 6676020.901250458, 2552549.949170641 6676214.467286562) + +LINESTRING (2551614.867221963 6675341.831173529, 2551427.8453421206 6675342.358254032) + +LINESTRING (2552747.6449926067 6676551.253321361, 2552931.5485044788 6676550.839709576, 2552935.359711727 6676734.314030847, 2552735.34172223 6676724.758133828, 2552747.6449926067 6676551.253321361) + +LINESTRING (2552921.0431778613 6675153.631269453, 2553105.5213538934 6675154.044881237) + +LINESTRING (2551800.2597735524 6675683.983340356, 2551800.2597735524 6675852.235489515) + +LINESTRING (2552370.148490671 6677249.857541421, 2552556.6432900103 6677249.443929638, 2552556.6432900107 6677418.109690581, 2552372.739778138 6677418.109690581, 2552370.148490671 6677249.857541421) + +LINESTRING (2551988.549156833 6676214.880898345, 2552178.9761952697 6676214.467286562, 2552180.41765133 6676387.840223726, 2551988.022076329 6676383.133047504, 2551988.549156833 6676214.880898345) + +LINESTRING (2553306.3326870985 6676902.566180006, 2553490.8108631307 6676902.979791789) + +LINESTRING (2551249.1944935573 6676214.880898346, 2551433.0980054294 6676214.467286562, 2551434.5394614898 6676387.840223726, 2551250.588365961 6676387.313143223, 2551249.1944935573 6676214.880898346) + +LINESTRING (2551620.1674689287 6676383.133047505, 2551619.017637522 6676556.505984669) + +LINESTRING (2553474.5257927007 6674980.6719440725, 2553292.0161532327 6674985.379120294) + +LINESTRING (2552551.3906267015 6676556.092372885, 2552747.6449926067 6676551.253321361) + +LINESTRING (2551620.1674689287 6676383.133047505, 2551434.5394614898 6676387.840223726) + +LINESTRING (2551249.1469099005 6676045.688056899, 2551249.1944935573 6676214.880898346) + +LINESTRING (2553666.921367702 6675322.297030397, 2553670.73257495 6675505.357739883) + +LINESTRING (2551624.2703008307 6677249.857541421, 2551810.76510017 6677249.443929638, 2551810.7651001704 6677418.109690581, 2551626.861588298 6677418.109690581, 2551624.2703008307 6677249.857541421) + +LINESTRING (2553682.679357628 6677244.191266329, 2553867.15753366 6677244.604878113) + +LINESTRING (2553853.990831201 6675322.297030397, 2553855.210750982 6675505.771351666) + +LINESTRING (2552168.470868652 6674649.006697279, 2552168.470868652 6674817.2588464385) + +LINESTRING (2551982.7694130205 6675679.276164134, 2551800.2597735524 6675683.983340356) + +LINESTRING (2553498.775845756 6677412.857027273, 2553307.7741431594 6677412.857027273) + +LINESTRING (2554048.399669691 6676719.50547052, 2554052.210876939 6676902.566180006) + +LINESTRING (2553869.748821127 6677412.857027273, 2553682.6793576283 6677412.857027273) + +LINESTRING (2553476.494329265 6675154.044881237, 2553666.9213677016 6675153.631269453, 2553666.921367702 6675322.297030397, 2553483.0178558296 6675322.297030397, 2553476.494329265 6675154.044881237) + +LINESTRING (2553856.6522070426 6675847.39643799, 2554043.147006382 6675846.982826206, 2554046.95821363 6676040.962474094, 2553863.007118101 6676040.4353935905, 2553856.6522070426 6675847.39643799) + +LINESTRING (2551250.6359496177 6676724.758133829, 2551254.447156866 6676908.232455099) + +LINESTRING (2551439.7921247985 6677249.443929638, 2551624.2703008307 6677249.857541421) + +LINESTRING (2552737.0920823324 6674984.852039791, 2552737.139665989 6675154.044881238) + +LINESTRING (2552747.59740895 6676382.060479914, 2552747.6449926067 6676551.253321361) + +LINESTRING (2551255.8886129265 6677249.857541422, 2551439.7921247985 6677249.443929638, 2551439.792124799 6677418.109690581, 2551225.835113801 6677412.857027272, 2551255.8886129265 6677249.857541422) + +LINESTRING (2553122.3815915696 6676733.786950343, 2552935.359711727 6676734.314030847) + +LINESTRING (2552371.298322078 6677076.484604258, 2552370.148490671 6677249.857541421) + +LINESTRING (2551986.0088128406 6675327.5496937055, 2551983.296493524 6675511.024014975) + +LINESTRING (2552730.089058921 6676020.901250457, 2552746.2035365463 6676209.628235037) + +LINESTRING (2551984.7379495846 6675852.649101298, 2552175.1649880214 6675852.235489515, 2552175.164988022 6676020.901250458, 2551995.025099741 6676045.688056899, 2551984.7379495846 6675852.649101298) + +LINESTRING (2551240.0830393434 6674990.1047030995, 2551240.130623 6675159.297544546) + +LINESTRING (2552724.8363956125 6675327.549693705, 2552740.9508732376 6675505.771351667) + +LINESTRING (2552539.4438440236 6674817.2588464385, 2552735.698209929 6674812.419794914) + +LINESTRING (2554236.1619724673 6677071.231940948, 2554053.6523329993 6677075.93911717) + +LINESTRING (2551977.5167497117 6674985.924607381, 2551795.0071102437 6674990.631783603) + +LINESTRING (2552730.616139425 6675852.649101298, 2552926.29584117 6675846.982826206, 2552926.2958411705 6676015.64858715, 2552730.089058921 6676020.901250457, 2552730.616139425 6675852.649101298) + +LINESTRING (2552372.739778138 6677418.109690581, 2552185.6703146393 6677418.109690581) + +LINESTRING (2551609.662142311 6674985.924607382, 2551424.0341348723 6674990.631783603) + +LINESTRING (2551198.981336964 6674579.783570934, 2551209.162748318 6674812.419794913) + +LINESTRING (2553852.5493751406 6674980.671944073, 2553851.399543734 6675154.044881237) + +LINESTRING (2553479.7784560095 6675674.023500825, 2553481.7469925736 6675847.39643799) + +LINESTRING (2553852.5493751406 6674980.671944073, 2553666.9213677016 6674985.379120294) + +LINESTRING (2552359.6431640536 6675852.649101298, 2552546.137963393 6675852.235489515, 2552546.1379633932 6676020.901250458, 2552362.2344515207 6676020.901250458, 2552359.6431640536 6675852.649101298) + +LINESTRING (2552001.766802767 6677418.109690581, 2551810.7651001704 6677418.109690581) + +LINESTRING (2552169.9123247126 6675158.883932762, 2552354.390500745 6675159.2975445455) + +LINESTRING (2551626.861588298 6677418.109690581, 2551439.792124799 6677418.109690581) + +LINESTRING (2551429.286798181 6675683.983340356, 2551429.286798181 6675852.235489515) + +LINESTRING (2554237.6034285277 6677412.857027272, 2554053.6523329997 6677412.857027273) + +LINESTRING (2551422.592678812 6674649.006697279, 2551422.592678812 6674817.2588464385) + +LINESTRING (2551805.512436861 6676387.840223726, 2551805.512436861 6676556.092372885) + +LINESTRING (2551422.592678812 6674817.2588464385, 2551607.070854844 6674817.672458222) + +LINESTRING (2552921.0431778613 6674985.379120294, 2552921.0431778613 6675153.631269453) + +LINESTRING (2553475.0528732045 6674812.419794913, 2553665.479911641 6674812.00618313, 2553666.9213677016 6674985.379120294, 2553474.5257927007 6674980.6719440725, 2553475.0528732045 6674812.419794913) + +LINESTRING (2551795.0071102437 6675158.883932762, 2551979.485286276 6675159.2975445455) + +LINESTRING (2554053.6523329993 6677244.191266329, 2554238.1305090315 6677244.604878113) + +LINESTRING (2553474.5257927007 6674980.6719440725, 2553476.494329265 6675154.044881237) + +LINESTRING (2553104.079897833 6674812.419794913, 2553290.5746971723 6674812.00618313, 2553292.0161532327 6674985.379120294, 2553106.6711853 6674980.671944073, 2553104.079897833 6674812.419794913) + +LINESTRING (2552371.298322078 6677076.484604258, 2552185.670314639 6677081.191780479) + +LINESTRING (2551622.8288447703 6676908.232455098, 2551809.3236441095 6676907.818843314, 2551810.76510017 6677081.191780479, 2551625.4201322375 6677076.484604258, 2551622.8288447703 6676908.232455098) + +LINESTRING (2552730.089058921 6676020.901250457, 2552546.1379633932 6676020.901250458) + +LINESTRING (2552926.29584117 6675678.730677047, 2552926.29584117 6675846.982826206) + +LINESTRING (2551805.512436861 6676556.092372885, 2551989.9906128934 6676556.505984669) + +LINESTRING (2553677.4266943196 6676719.50547052, 2553681.2379015675 6676902.566180006) + +LINESTRING (2553868.307365067 6677071.231940949, 2553682.679357628 6677075.93911717) + +LINESTRING (2551982.7694130205 6675679.276164134, 2551984.7379495846 6675852.649101298) + +LINESTRING (2551243.9418302486 6675511.024014976, 2551427.8453421206 6675510.610403191, 2551429.286798181 6675683.983340356, 2551245.335702652 6675683.456259852, 2551243.9418302486 6675511.024014976) + +LINESTRING (2553677.426694319 6676382.587560417, 2553677.426694319 6676550.839709576) + +LINESTRING (2551609.662142311 6674985.924607382, 2551608.5123109045 6675159.2975445455) + +LINESTRING (2554046.95821363 6676209.214623253, 2554231.4363896623 6676209.6282350365) + +LINESTRING (2553855.210750982 6675505.771351666, 2554041.7055503214 6675505.357739883, 2554043.147006382 6675678.730677047, 2553857.8020384493 6675674.023500826, 2553855.210750982 6675505.771351666) + +LINESTRING (2551617.5761814616 6676214.880898345, 2551804.070980801 6676214.467286562, 2551805.512436861 6676387.840223726, 2551620.1674689287 6676383.133047505, 2551617.5761814616 6676214.880898345) + +LINESTRING (2553681.2379015675 6676902.566180006, 2553865.7160775997 6676902.979791789) + +LINESTRING (2552556.6432900103 6677081.191780479, 2552556.6432900103 6677249.443929638) + +LINESTRING (2552355.5403321516 6674985.924607382, 2552169.9123247126 6674990.631783603) + +LINESTRING (2551619.017637522 6676556.505984669, 2551805.512436861 6676556.092372885, 2551805.5124368616 6676724.758133829, 2551625.3725485806 6676739.039613652, 2551619.017637522 6676556.505984669) + +LINESTRING (2553864.4961578185 6676719.50547052, 2553865.7160775997 6676902.979791789) + +LINESTRING (2552366.045658769 6676383.133047505, 2552364.8958273623 6676556.505984669) + +LINESTRING (2551798.818317492 6675510.610403191, 2551983.296493524 6675511.024014975) + +LINESTRING (2552556.6432900103 6677249.443929638, 2552741.1214660425 6677249.857541421) + +LINESTRING (2551614.867221963 6675341.831173529, 2551612.323518153 6675511.024014975) + +LINESTRING (2553672.1740310104 6675846.982826206, 2553856.6522070426 6675847.39643799) + +LINESTRING (2551988.022076329 6676383.133047504, 2551989.9906128934 6676556.505984669) + +LINESTRING (2554036.4528870126 6674643.754033971, 2554036.4528870126 6674812.00618313) + +LINESTRING (2552735.34172223 6676724.758133828, 2552551.390626702 6676724.758133829) + +LINESTRING (2552360.7929954603 6675679.276164135, 2552175.1649880214 6675683.983340356) + +LINESTRING (2552936.8011677875 6677244.191266329, 2553121.2793438197 6677244.604878113) + +LINESTRING (2552544.6965073324 6675510.610403191, 2552740.9508732376 6675505.771351667) + +LINESTRING (2551986.0088128406 6675327.5496937055, 2551795.007110244 6675327.5496937055) + +LINESTRING (2553490.8108631307 6676902.979791789, 2553681.2379015675 6676902.566180006, 2553682.679357628 6677075.93911717, 2553490.283782627 6677071.231940948, 2553490.8108631307 6676902.979791789) + +LINESTRING (2553290.5746971723 6674643.754033971, 2553290.5746971723 6674812.00618313) + +LINESTRING (2552185.670314639 6677081.191780479, 2552185.670314639 6677249.443929638) + +LINESTRING (2552362.2344515207 6676020.901250458, 2552363.454371302 6676214.880898345) + +LINESTRING (2552355.5403321516 6674985.924607382, 2552354.390500745 6675159.2975445455) + +LINESTRING (2552540.885300084 6674990.631783603, 2552540.885300084 6675158.883932762) + +LINESTRING (2551993.274739638 6677076.484604257, 2551995.243276202 6677249.857541421) + +LINESTRING (2553117.128928261 6676040.4353935905, 2553114.5852244506 6676209.6282350365) + +LINESTRING (2553297.268816542 6676015.64858715, 2553301.08002379 6676209.214623253) + +LINESTRING (2551614.91480562 6675679.276164135, 2551613.764974213 6675852.649101298) + +LINESTRING (2551996.514139458 6676724.758133829, 2551993.8018201417 6676908.232455098) + +LINESTRING (2553852.5017914837 6674643.226953467, 2553849.9580876734 6674812.419794913) + +LINESTRING (2552367.4871148295 6676724.758133829, 2552368.7070346107 6676908.232455098) + +LINESTRING (2553483.0178558296 6675322.297030397, 2553480.305536513 6675505.771351666) + +LINESTRING (2552363.454371302 6676214.880898345, 2552549.949170641 6676214.467286562, 2552551.3906267015 6676387.840223726, 2552366.045658769 6676383.133047505, 2552363.454371302 6676214.880898345) + +LINESTRING (2552175.1649880214 6675683.983340356, 2552175.1649880214 6675852.235489515) + +LINESTRING (2553868.307365067 6677071.231940949, 2553867.15753366 6677244.604878113) + +LINESTRING (2551434.5394614898 6676556.092372885, 2551619.017637522 6676556.505984669) + +LINESTRING (2553666.9213677016 6674985.379120294, 2553666.9213677016 6675153.631269453) + +LINESTRING (2551245.335702652 6675683.456259852, 2551215.8568676873 6675847.39643799) + +LINESTRING (2553849.9580876734 6674812.419794913, 2554036.4528870126 6674812.00618313, 2554037.894343073 6674985.379120294, 2553852.5493751406 6674980.671944073, 2553849.9580876734 6674812.419794913) + +LINESTRING (2552549.949170641 6676214.467286562, 2552746.2035365463 6676209.628235037) + +LINESTRING (2553122.4291752265 6677071.231940949, 2552936.8011677875 6677075.93911717) + +LINESTRING (2553670.73257495 6675505.357739883, 2553855.210750982 6675505.771351666) + +LINESTRING (2552185.670314639 6677249.443929638, 2552370.148490671 6677249.857541421) + +LINESTRING (2553307.774143159 6677075.93911717, 2553307.774143159 6677244.191266329) + +LINESTRING (2552741.1214660425 6677249.857541421, 2552936.8011677875 6677244.191266329, 2552936.801167788 6677412.857027273, 2552740.5943855387 6677418.1096905805, 2552741.1214660425 6677249.857541421) + +LINESTRING (2551209.162748318 6674812.419794913, 2551422.592678812 6674817.2588464385, 2551424.0341348723 6674990.631783603, 2551240.0830393434 6674990.1047030995, 2551209.162748318 6674812.419794913) + +LINESTRING (2553105.5213538934 6675154.044881237, 2553292.0161532327 6675153.631269453, 2553292.016153233 6675322.297030397, 2553111.876264952 6675336.57851022, 2553105.5213538934 6675154.044881237) + +LINESTRING (2553302.5214798506 6676719.50547052, 2553306.3326870985 6676902.566180006) + +LINESTRING (2553864.4961578185 6676719.50547052, 2553677.4266943196 6676719.50547052) + +LINESTRING (2553867.15753366 6677244.604878113, 2554053.6523329993 6677244.191266329, 2554053.6523329997 6677412.857027273, 2553869.748821127 6677412.857027273, 2553867.15753366 6677244.604878113) + +LINESTRING (2554232.350765219 6676719.505470519, 2554048.399669691 6676719.50547052) + +LINESTRING (2552366.045658769 6676383.133047505, 2552180.41765133 6676387.840223726) + +LINESTRING (2553302.52147985 6676382.587560417, 2553302.52147985 6676550.839709576) + +LINESTRING (2553116.026680511 6676551.25332136, 2553302.52147985 6676550.839709576, 2553302.5214798506 6676719.50547052, 2553122.3815915696 6676733.786950343, 2553116.026680511 6676551.25332136) + +LINESTRING (2553851.399543734 6675154.044881237, 2554037.894343073 6675153.631269453, 2554037.8943430735 6675322.297030397, 2553853.990831201 6675322.297030397, 2553851.399543734 6675154.044881237) + +LINESTRING (2551993.8018201417 6676908.232455098, 2552184.2288585785 6676907.818843314, 2552185.670314639 6677081.191780479, 2551993.274739638 6677076.484604257, 2551993.8018201417 6676908.232455098) + +LINESTRING (2551438.350668738 6676907.818843314, 2551622.8288447703 6676908.232455098) + +LINESTRING (2554052.210876939 6676902.566180006, 2554236.689052971 6676902.979791789) + +LINESTRING (2553483.0178558296 6675322.297030397, 2553292.016153233 6675322.297030397) + +LINESTRING (2552540.885300084 6675158.883932762, 2552737.139665989 6675154.044881238) + +LINESTRING (2551255.8410292696 6677080.664699975, 2551255.8886129265 6677249.857541422) + +LINESTRING (2552724.8363956125 6675327.549693705, 2552540.8853000845 6675327.5496937055) + +LINESTRING (2554227.09810191 6676015.648587149, 2554046.95821363 6676040.962474094) + +LINESTRING (2551427.8453421206 6675510.610403191, 2551612.323518153 6675511.024014975) + +LINESTRING (2551612.323518153 6675511.024014975, 2551798.818317492 6675510.610403191, 2551800.2597735524 6675683.983340356, 2551614.91480562 6675679.276164135, 2551612.323518153 6675511.024014975) + +LINESTRING (2552356.981788212 6675327.5496937055, 2552358.201707993 6675511.024014975) + +LINESTRING (2552935.359711727 6676734.314030847, 2552935.359711727 6676902.566180006) + +LINESTRING (2554220.403982541 6674980.6719440725, 2554037.894343073 6674985.379120294) + +LINESTRING (2553860.463414291 6676209.6282350365, 2554046.95821363 6676209.214623253, 2554048.3996696905 6676382.587560417, 2553863.054701758 6676377.8803841965, 2553860.463414291 6676209.6282350365) + +LINESTRING (2552752.8500722586 6677075.412036667, 2552556.6432900103 6677081.191780479) + +LINESTRING (2553302.52147985 6676550.839709576, 2553486.9996558824 6676551.25332136) + +LINESTRING (2553122.3815915696 6676733.786950343, 2553119.8378877593 6676902.979791789) + +LINESTRING (2554221.8454386014 6675322.297030396, 2554037.8943430735 6675322.297030397) + +LINESTRING (2551805.5124368616 6676724.758133829, 2551809.3236441095 6676907.818843314) + +LINESTRING (2553863.007118101 6676040.4353935905, 2553860.463414291 6676209.6282350365) + +LINESTRING (2553857.8020384493 6675674.023500826, 2553856.6522070426 6675847.39643799) + +LINESTRING (2553292.016153233 6675322.297030397, 2553295.827360481 6675505.357739883) + +LINESTRING (2551250.6359496177 6676556.50598467, 2551434.5394614898 6676556.092372885, 2551438.350668738 6676739.566694155, 2551250.6359496177 6676724.758133829, 2551250.6359496177 6676556.50598467) + +LINESTRING (2554046.95821363 6676040.962474094, 2554046.95821363 6676209.214623253) + +LINESTRING (2551254.447156866 6676908.232455099, 2551438.350668738 6676907.818843314, 2551439.7921247985 6677081.191780479, 2551255.8410292696 6677080.664699975, 2551254.447156866 6676908.232455099) + +LINESTRING (2551996.514139458 6676724.758133829, 2551805.5124368616 6676724.758133829) + +LINESTRING (2552175.164988022 6676020.901250458, 2552178.9761952697 6676214.467286562) + +LINESTRING (2551240.130623 6675159.297544546, 2551424.0341348723 6675158.883932762, 2551427.8453421206 6675342.358254032, 2551240.130623 6675327.5496937055, 2551240.130623 6675159.297544546) + +LINESTRING (2553492.252319191 6677244.604878113, 2553682.679357628 6677244.191266329, 2553682.6793576283 6677412.857027273, 2553498.775845756 6677412.857027273, 2553492.252319191 6677244.604878113) + +LINESTRING (2551625.3725485806 6676739.039613652, 2551438.350668738 6676739.566694155) + +LINESTRING (2552909.9473909508 6674579.783570935, 2552919.601721801 6674812.00618313) + +LINESTRING (2553485.031119318 6676377.880384196, 2553486.9996558824 6676551.25332136) + +LINESTRING (2553097.0168544496 6674579.783570935, 2553104.079897833 6674812.419794913) + +LINESTRING (2553853.990831201 6675322.297030397, 2553666.921367702 6675322.297030397) + +LINESTRING (2553677.426694319 6676550.839709576, 2553861.9048703513 6676551.25332136) + +LINESTRING (2553122.4291752265 6677071.231940949, 2553121.2793438197 6677244.604878113) + +LINESTRING (2554037.894343073 6675153.631269453, 2554222.372519105 6675154.044881237) + +LINESTRING (2553682.679357628 6677075.93911717, 2553682.679357628 6677244.191266329) + +LINESTRING (2553479.7784560095 6675674.023500825, 2553297.2688165414 6675678.730677047) + +LINESTRING (2553109.332561142 6675505.771351666, 2553295.827360481 6675505.357739883, 2553297.2688165414 6675678.730677047, 2553111.923848609 6675674.023500826, 2553109.332561142 6675505.771351666) + +LINESTRING (2553672.174031011 6676015.64858715, 2553675.9852382587 6676209.214623253) + +LINESTRING (2552751.456199855 6676902.97979179, 2552935.359711727 6676902.566180006, 2552936.8011677875 6677075.93911717, 2552752.8500722586 6677075.412036667, 2552751.456199855 6676902.97979179) + +LINESTRING (2551989.9906128934 6676556.505984669, 2552180.41765133 6676556.092372885, 2552180.4176513306 6676724.758133829, 2551996.514139458 6676724.758133829, 2551989.9906128934 6676556.505984669) + +LINESTRING (2552924.8543851096 6675337.105590723, 2552924.8543851096 6675505.357739883) + +LINESTRING (2551800.2597735524 6675852.235489515, 2551984.7379495846 6675852.649101298) + +LINESTRING (2552737.139665989 6675154.044881238, 2552921.0431778613 6675153.631269453, 2552924.8543851096 6675337.105590723, 2552724.8363956125 6675327.549693705, 2552737.139665989 6675154.044881238) + +LINESTRING (2553307.774143159 6677244.191266329, 2553492.252319191 6677244.604878113) + +LINESTRING (2551429.2867981815 6676020.901250458, 2551433.0980054294 6676214.467286562) + +LINESTRING (2552546.137963393 6675683.983340356, 2552546.137963393 6675852.235489515) + +LINESTRING (2552735.650626272 6674643.226953467, 2552735.698209929 6674812.419794914) + +LINESTRING (2553110.774017202 6675847.39643799, 2553297.2688165414 6675846.982826206, 2553297.268816542 6676015.64858715, 2553117.128928261 6676040.4353935905, 2553110.774017202 6675847.39643799) + +LINESTRING (2551995.025099741 6676045.688056899, 2551988.549156833 6676214.880898345) + +LINESTRING (2554037.894343073 6674985.379120294, 2554037.894343073 6675153.631269453) + +LINESTRING (2551614.91480562 6675679.276164135, 2551429.286798181 6675683.983340356) + +LINESTRING (2553861.9048703513 6676551.25332136, 2554048.3996696905 6676550.839709576, 2554048.399669691 6676719.50547052, 2553864.4961578185 6676719.50547052, 2553861.9048703513 6676551.25332136) + +LINESTRING (2553485.031119318 6676377.880384196, 2553302.52147985 6676382.587560417) + +LINESTRING (2551795.0071102437 6674990.631783603, 2551795.0071102437 6675158.883932762) + +LINESTRING (2553297.2688165414 6675846.982826206, 2553481.7469925736 6675847.39643799) + +LINESTRING (2552354.390500745 6675159.2975445455, 2552540.885300084 6675158.883932762, 2552540.8853000845 6675327.5496937055, 2552356.981788212 6675327.5496937055, 2552354.390500745 6675159.2975445455) + +LINESTRING (2552169.9123247126 6674990.631783603, 2552169.9123247126 6675158.883932762) + +LINESTRING (2552173.723531961 6675510.610403191, 2552358.201707993 6675511.024014975) + +LINESTRING (2552352.9490446844 6674817.672458222, 2552539.4438440236 6674817.2588464385, 2552540.885300084 6674990.631783603, 2552355.5403321516 6674985.924607382, 2552352.9490446844 6674817.672458222) + +LINESTRING (2554225.65664585 6675674.023500825, 2554043.147006382 6675678.730677047) + +LINESTRING (2552169.912324713 6675327.5496937055, 2552173.723531961 6675510.610403191) + +LINESTRING (2552551.3906267015 6676387.840223726, 2552551.3906267015 6676556.092372885) + +LINESTRING (2553481.5288161123 6674643.226953467, 2553475.0528732045 6674812.419794913) + +LINESTRING (2553492.03414273 6676040.4353935905, 2553485.558199822 6676209.6282350365) + +LINESTRING (2551804.070980801 6676214.467286562, 2551988.549156833 6676214.880898345) + +LINESTRING (2553301.08002379 6676209.214623253, 2553485.558199822 6676209.6282350365) + +LINESTRING (2551995.025099741 6676045.688056899, 2551800.259773553 6676020.901250458) + +LINESTRING (2553863.007118101 6676040.4353935905, 2553672.174031011 6676015.64858715) + +LINESTRING (2551983.296493524 6675511.024014975, 2552173.723531961 6675510.610403191, 2552175.1649880214 6675683.983340356, 2551982.7694130205 6675679.276164134, 2551983.296493524 6675511.024014975) + +LINESTRING (2553121.2793438197 6677244.604878113, 2553307.774143159 6677244.191266329, 2553307.7741431594 6677412.857027273, 2553123.870631287 6677412.857027273, 2553121.2793438197 6677244.604878113) + +LINESTRING (2552529.7895131735 6674585.036234244, 2552539.4438440236 6674817.2588464385) + +LINESTRING (2552740.5943855387 6677418.1096905805, 2552556.6432900107 6677418.109690581) + +LINESTRING (2553672.1740310104 6675678.730677047, 2553672.1740310104 6675846.982826206) + +LINESTRING (2552752.8500722586 6677075.412036667, 2552741.1214660425 6677249.857541421) + +LINESTRING (2551215.8568676873 6675847.39643799, 2551429.286798181 6675852.235489515, 2551429.2867981815 6676020.901250458, 2551249.1469099005 6676045.688056899, 2551215.8568676873 6675847.39643799) + +LINESTRING (2552742.344745641 6675678.2035965435, 2552730.616139425 6675852.649101298) + +LINESTRING (2552555.20183395 6676907.818843314, 2552751.456199855 6676902.97979179) + +LINESTRING (2552180.41765133 6676387.840223726, 2552180.41765133 6676556.092372885) + +LINESTRING (2552180.41765133 6676556.092372885, 2552364.8958273623 6676556.505984669) + +LINESTRING (2554043.147006382 6675678.730677047, 2554043.147006382 6675846.982826206) + +LINESTRING (2553666.9213677016 6675153.631269453, 2553851.399543734 6675154.044881237) + +LINESTRING (2552368.7070346107 6676908.232455098, 2552555.20183395 6676907.818843314, 2552556.6432900103 6677081.191780479, 2552371.298322078 6677076.484604258, 2552368.7070346107 6676908.232455098) + +LINESTRING (2553675.9852382587 6676209.214623253, 2553860.463414291 6676209.6282350365) + +LINESTRING (2553481.7469925736 6675847.39643799, 2553672.1740310104 6675846.982826206, 2553672.174031011 6676015.64858715, 2553492.03414273 6676040.4353935905, 2553481.7469925736 6675847.39643799) + +LINESTRING (2554037.8943430735 6675322.297030397, 2554041.7055503214 6675505.357739883) + +LINESTRING (2553665.479911641 6674812.00618313, 2553849.9580876734 6674812.419794913) + +LINESTRING (2553485.558199822 6676209.6282350365, 2553675.9852382587 6676209.214623253, 2553677.426694319 6676382.587560417, 2553485.031119318 6676377.880384196, 2553485.558199822 6676209.6282350365) + +LINESTRING (2553111.876264952 6675336.57851022, 2553109.332561142 6675505.771351666) + +LINESTRING (2553295.827360481 6675505.357739883, 2553480.305536513 6675505.771351666) + +LINESTRING (2552358.201707993 6675511.024014975, 2552544.6965073324 6675510.610403191, 2552546.137963393 6675683.983340356, 2552360.7929954603 6675679.276164135, 2552358.201707993 6675511.024014975) + +LINESTRING (2553292.0161532327 6675153.631269453, 2553476.494329265 6675154.044881237) + +LINESTRING (2552735.698209929 6674812.419794914, 2552919.601721801 6674812.00618313, 2552921.0431778613 6674985.379120294, 2552737.0920823324 6674984.852039791, 2552735.698209929 6674812.419794914) + +LINESTRING (2552740.9508732376 6675505.771351667, 2552924.8543851096 6675505.357739883, 2552926.29584117 6675678.730677047, 2552742.344745641 6675678.2035965435, 2552740.9508732376 6675505.771351667) + +LINESTRING (2552935.359711727 6676902.566180006, 2553119.8378877593 6676902.979791789) + +LINESTRING (2553111.876264952 6675336.57851022, 2552924.8543851096 6675337.105590723) + +LINESTRING (2551810.76510017 6677249.443929638, 2551995.243276202 6677249.857541421) + +LINESTRING (2551995.243276202 6677249.857541421, 2552185.670314639 6677249.443929638, 2552185.6703146393 6677418.109690581, 2552001.766802767 6677418.109690581, 2551995.243276202 6677249.857541421) + +LINESTRING (2551809.3236441095 6676907.818843314, 2551993.8018201417 6676908.232455098) + +LINESTRING (2551609.6145586544 6674648.479616776, 2551607.070854844 6674817.672458222) + +LINESTRING (2554048.3996696905 6676382.587560417, 2554048.3996696905 6676550.839709576) + +LINESTRING (2553480.305536513 6675505.771351666, 2553670.73257495 6675505.357739883, 2553672.1740310104 6675678.730677047, 2553479.7784560095 6675674.023500825, 2553480.305536513 6675505.771351666) + +LINESTRING (2551625.3725485806 6676739.039613652, 2551622.8288447703 6676908.232455098) + +LINESTRING (2551613.764974213 6675852.649101298, 2551800.2597735524 6675852.235489515, 2551800.259773553 6676020.901250458, 2551616.3562616804 6676020.901250458, 2551613.764974213 6675852.649101298) + +LINESTRING (2551223.7345891236 6673554.239686885, 2551223.7821727805 6673723.432528332) + +LINESTRING (2553655.8255807906 6674242.865660832, 2553655.8255807906 6674411.117809991) + +LINESTRING (2553649.1314614215 6673376.141166915, 2553833.6096374537 6673376.554778699) + +LINESTRING (2551213.229262506 6672157.031246762, 2551213.276846163 6672326.224088209) + +LINESTRING (2551969.660362621 6673891.684677491, 2551966.9480433045 6674075.15899876) + +LINESTRING (2549129.8487770883 6671984.185390101, 2549314.3269531205 6671984.599001884) + +LINESTRING (2553280.9203663217 6674411.117809991, 2553465.398542354 6674411.531421775) + +LINESTRING (2550819.1799468854 6672840.9500444885, 2550633.5519394465 6672845.657220709) + +LINESTRING (2548395.917369926 6673554.766767388, 2548395.917369926 6673723.018916547) + +LINESTRING (2550454.901090883 6673886.432014182, 2550452.188771567 6674069.906335452) + +LINESTRING (2551588.0610287827 6672846.202707797, 2551402.433021344 6672850.909884018) + +LINESTRING (2550078.506836697 6673207.361937253, 2549887.6737496066 6673182.575130812) + +LINESTRING (2553077.226120996 6671979.346338576, 2553263.720920335 6671978.932726792, 2553265.1623763954 6672152.305663956, 2553079.817408463 6672147.598487736, 2553077.226120996 6671979.346338576) + +LINESTRING (2550448.3775643185 6673718.179865022, 2550638.8046027552 6673717.766253239, 2550638.8046027557 6673886.432014182, 2550454.901090883 6673886.432014182, 2550448.3775643185 6673718.179865022) + +LINESTRING (2551598.5663554003 6674243.41114792, 2551412.9383479613 6674248.118324141) + +LINESTRING (2549708.975317386 6673548.987023576, 2549512.7685351376 6673554.766767388) + +LINESTRING (2550451.661691063 6674238.158484611, 2550269.152051595 6674242.865660832) + +LINESTRING (2548772.143008606 6674248.118324141, 2548772.143008606 6674416.3704733) + +LINESTRING (2550626.8578200773 6671810.680577633, 2550626.8578200773 6671978.932726792) + +LINESTRING (2548211.966274397 6673554.239686885, 2548212.013858054 6673723.432528332) + +LINESTRING (2548756.3850186802 6672494.476237368, 2548760.196225928 6672677.536946854) + +LINESTRING (2551598.5187717434 6673905.966157314, 2551411.496891901 6673906.493237818) + +LINESTRING (2548754.9435626194 6671984.185390101, 2548939.4217386516 6671984.599001884) + +LINESTRING (2549887.6737496066 6673182.575130812, 2549891.4849568545 6673376.141166915) + +LINESTRING (2552141.617091815 6671984.185390101, 2552326.095267847 6671984.599001884) + +LINESTRING (2550997.8307954487 6671978.932726792, 2551182.308971481 6671979.346338576) + +LINESTRING (2549887.673749606 6673013.909369868, 2550072.1519256383 6673014.322981652) + +LINESTRING (2554209.30819563 6674238.158484611, 2554026.798556162 6674242.865660832) + +LINESTRING (2552153.5638744934 6673891.684677491, 2552157.3750817413 6674074.745386977) + +LINESTRING (2553452.924679172 6672840.950044488, 2553454.8932157364 6673014.322981652) + +LINESTRING (2551407.6856846525 6673554.766767388, 2551407.6856846525 6673723.018916547) + +LINESTRING (2550081.2157961954 6674069.906335452, 2550267.7105955346 6674069.492723668, 2550269.152051595 6674242.865660832, 2550083.8070836626 6674238.158484612, 2550081.2157961954 6674069.906335452) + +LINESTRING (2549141.7955597667 6673891.684677491, 2549145.6067670146 6674074.745386977) + +LINESTRING (2553458.177342481 6673544.806927858, 2553275.667703013 6673549.514104079) + +LINESTRING (2552903.253271581 6673376.141166915, 2553087.7314476133 6673376.554778699) + +LINESTRING (2553645.320254173 6673013.909369868, 2553829.7984302053 6673014.322981652) + +LINESTRING (2549136.5428964575 6673019.162033177, 2549321.0210724897 6673019.575644961) + +LINESTRING (2551009.7775781266 6673717.766253239, 2551223.7821727805 6673723.432528332) + +LINESTRING (2550078.554420354 6673544.806927859, 2550077.404588947 6673718.179865022) + +LINESTRING (2553830.948261612 6672840.9500444885, 2553645.320254173 6672845.657220709) + +LINESTRING (2552355.4927484947 6674648.479616776, 2552168.470868652 6674649.006697279) + +LINESTRING (2552899.4420643332 6673182.575130812, 2552903.253271581 6673376.141166915) + +LINESTRING (2548939.4217386516 6671984.599001884, 2549129.8487770883 6671984.185390101, 2549131.2902331487 6672157.558327265, 2548938.894658148 6672152.851151044, 2548939.4217386516 6671984.599001884) + +LINESTRING (2550451.661691063 6674238.158484611, 2550453.630227627 6674411.531421775) + +LINESTRING (2548586.7980406736 6674243.41114792, 2548585.648209267 6674416.784085084) + +LINESTRING (2551961.6953799957 6673381.807442008, 2552152.1224184325 6673381.393830224, 2552153.563874493 6673554.766767388, 2551961.168299492 6673550.059591167, 2551961.6953799957 6673381.807442008) + +LINESTRING (2551766.711877346 6671984.185390101, 2551951.190053378 6671984.599001884) + +LINESTRING (2551593.3136920915 6673550.059591168, 2551407.6856846525 6673554.766767388) + +LINESTRING (2552148.311211184 6672850.909884018, 2552148.311211184 6673019.162033177) + +LINESTRING (2551957.665996286 6671815.406160438, 2551951.190053378 6671984.599001884) + +LINESTRING (2552143.058547876 6672494.476237368, 2552146.8697551237 6672677.536946854) + +LINESTRING (2549892.926412915 6673549.514104079, 2549892.926412915 6673717.766253239) + +LINESTRING (2552143.0585478754 6672157.558327265, 2552143.0585478754 6672325.810476424) + +LINESTRING (2553082.4787843046 6672672.6978953285, 2553268.973583644 6672672.284283545, 2553270.415039704 6672845.657220709, 2553085.0700717717 6672840.9500444885, 2553082.4787843046 6672672.6978953285) + +LINESTRING (2554194.991661764 6672489.223574058, 2554011.0405662362 6672489.223574059) + +LINESTRING (2549886.2322935457 6672672.284283545, 2550070.710469578 6672672.6978953285) + +LINESTRING (2549898.1790762236 6674242.865660832, 2549898.1790762236 6674411.117809991) + +LINESTRING (2552703.235282084 6673187.82779412, 2552719.349759709 6673376.5547787) + +LINESTRING (2553465.1803658926 6673207.361937253, 2553458.7044229847 6673376.554778699) + +LINESTRING (2551589.502484843 6673187.827794121, 2551590.7224046243 6673381.807442008) + +LINESTRING (2553830.948261612 6672840.9500444885, 2553829.7984302053 6673014.322981652) + +LINESTRING (2552328.6389716575 6671815.406160438, 2552326.095267847 6671984.599001884) + +LINESTRING (2552529.789513173 6674248.118324141, 2552529.789513173 6674416.3704733) + +LINESTRING (2549512.768535138 6673891.684677491, 2549516.579742386 6674074.745386977) + +LINESTRING (2551229.0348360892 6674416.784085085, 2551412.9383479613 6674416.3704733, 2551422.592678812 6674649.006697279, 2551198.981336964 6674579.783570934, 2551229.0348360892 6674416.784085085) + +LINESTRING (2548399.7285771742 6673906.493237818, 2548399.7285771742 6674074.745386977) + +LINESTRING (2550068.0490937363 6672147.598487736, 2549882.4210862974 6672152.305663956) + +LINESTRING (2548389.2232505567 6672509.2847976945, 2548389.2232505567 6672677.536946854) + +LINESTRING (2552336.6005944647 6673381.807442008, 2552523.095393804 6673381.393830224, 2552524.5368498643 6673554.766767388, 2552339.191881932 6673550.059591168, 2552336.6005944647 6673381.807442008) + +LINESTRING (2549891.4849568545 6673376.141166915, 2550075.9631328867 6673376.554778699) + +LINESTRING (2553823.104310836 6671979.346338576, 2554009.5991101754 6671978.932726792, 2554011.040566236 6672152.305663956, 2553825.6955983033 6672147.598487736, 2553823.104310836 6671979.346338576) + +LINESTRING (2550078.554420354 6673544.806927859, 2549892.926412915 6673549.514104079) + +LINESTRING (2549507.5158718294 6673187.827794121, 2549511.3270790773 6673381.393830224) + +LINESTRING (2554198.8028690126 6672840.950044488, 2554016.2932295445 6672845.657220709) + +LINESTRING (2552892.7479449636 6671810.680577633, 2552892.7479449636 6671978.932726792) + +LINESTRING (2548576.2451303992 6672508.757717191, 2548389.2232505567 6672509.2847976945) + +LINESTRING (2553078.667577056 6672320.971424899, 2553265.1623763954 6672320.557813115, 2553265.162376396 6672489.223574059, 2553085.022488115 6672503.5050538825, 2553078.667577056 6672320.971424899) + +LINESTRING (2553270.415039704 6673013.909369868, 2553454.8932157364 6673014.322981652) + +LINESTRING (2550267.7105955346 6674069.492723668, 2550452.188771567 6674069.906335452) + +LINESTRING (2548210.5724019934 6673381.8074420085, 2548394.4759138655 6673381.393830224, 2548395.917369926 6673554.766767388, 2548211.966274397 6673554.239686885, 2548210.5724019934 6673381.8074420085) + +LINESTRING (2549512.7685351376 6673723.018916547, 2549709.022901043 6673718.179865023) + +LINESTRING (2552340.6333379922 6673891.684677491, 2552341.8532577734 6674075.15899876) + +LINESTRING (2551406.244228592 6673381.393830224, 2551590.7224046243 6673381.807442008) + +LINESTRING (2548210.5248183366 6673212.614600562, 2548210.5724019934 6673381.8074420085) + +LINESTRING (2550628.299276138 6672489.223574059, 2550632.110483386 6672672.284283545) + +LINESTRING (2551968.1713229036 6673212.614600562, 2551773.4059967156 6673187.827794121) + +LINESTRING (2550437.872237701 6672320.971424899, 2550628.2992761377 6672320.557813115, 2550628.299276138 6672489.223574059, 2550444.3957642657 6672489.223574059, 2550437.872237701 6672320.971424899) + +LINESTRING (2550840.733476757 6674643.226953467, 2550644.0572660645 6674579.783570935) + +LINESTRING (2552335.3806746835 6673187.827794121, 2552336.6005944647 6673381.807442008) + +LINESTRING (2553280.9203663217 6674242.865660832, 2553280.9203663217 6674411.117809991) + +LINESTRING (2551588.013445126 6672508.757717191, 2551400.9915652834 6672509.2847976945) + +LINESTRING (2551217.0880534113 6672677.950558638, 2551400.9915652834 6672677.536946854, 2551402.433021344 6672850.909884018, 2551218.481925815 6672850.382803515, 2551217.0880534113 6672677.950558638) + +LINESTRING (2548401.1700332346 6674416.3704733, 2548585.648209267 6674416.784085084) + +LINESTRING (2548212.013858054 6673891.684677491, 2548215.825065302 6674075.158998761) + +LINESTRING (2551412.9383479613 6674416.3704733, 2551597.4165239935 6674416.784085084) + +LINESTRING (2549698.4699907685 6672151.778583453, 2549698.5175744253 6672320.9714249) + +LINESTRING (2553460.145879045 6673718.179865022, 2553650.572917482 6673717.766253239, 2553650.5729174824 6673886.432014182, 2553466.66940561 6673886.432014182, 2553460.145879045 6673718.179865022) + +LINESTRING (2549708.975317386 6673548.987023576, 2549709.022901043 6673718.179865023) + +LINESTRING (2549691.4669673573 6673187.82779412, 2549707.5814449824 6673376.5547787) + +LINESTRING (2552152.1224184325 6673381.393830224, 2552336.6005944647 6673381.807442008) + +LINESTRING (2553828.356974145 6672672.6978953285, 2554014.851773484 6672672.284283545, 2554016.2932295445 6672845.657220709, 2553830.948261612 6672840.9500444885, 2553828.356974145 6672672.6978953285) + +LINESTRING (2552333.939218623 6672846.202707797, 2552332.7893872163 6673019.575644961) + +LINESTRING (2551959.1550360033 6672494.476237368, 2551956.442716687 6672677.950558637) + +LINESTRING (2553838.8623007624 6674069.906335452, 2554025.3571001017 6674069.492723668, 2554026.798556162 6674242.865660832, 2553841.4535882296 6674238.158484612, 2553838.8623007624 6674069.906335452) + +LINESTRING (2549500.8217524597 6671984.185390101, 2549697.076118365 6671979.346338577) + +LINESTRING (2551228.9872524324 6674247.591243638, 2551015.0302414354 6674242.865660832) + +LINESTRING (2551400.9915652834 6672677.536946854, 2551585.4697413156 6672677.950558637) + +LINESTRING (2553638.626134804 6671978.932726792, 2553823.104310836 6671979.346338576) + +LINESTRING (2549343.724433768 6674648.479616776, 2549156.7025539256 6674649.006697279) + +LINESTRING (2548200.019491719 6671815.406160438, 2548200.067075376 6671984.599001885) + +LINESTRING (2553836.153341264 6673207.361937253, 2553645.3202541736 6673182.575130812) + +LINESTRING (2552899.442064333 6673013.909369868, 2553083.920240365 6673014.322981652) + +LINESTRING (2549321.0210724897 6673019.575644961, 2549507.515871829 6673019.162033177, 2549507.5158718294 6673187.827794121, 2549323.612359957 6673187.827794121, 2549321.0210724897 6673019.575644961) + +LINESTRING (2552725.9962954214 6674242.338580329, 2552529.789513173 6674248.118324141) + +LINESTRING (2548972.7514583967 6674648.479616776, 2548781.7973394566 6674649.006697279) + +LINESTRING (2549131.2902331487 6672325.810476424, 2549315.768409181 6672326.224088208) + +LINESTRING (2553481.5288161123 6674643.226953467, 2553290.5746971723 6674643.754033971) + +LINESTRING (2548390.664706617 6672850.909884018, 2548390.664706617 6673019.162033177) + +LINESTRING (2553841.4535882296 6674238.158484612, 2553655.8255807906 6674242.865660832) + +LINESTRING (2551590.7224046243 6673381.807442008, 2551777.2172039635 6673381.393830224, 2551778.658660024 6673554.766767388, 2551593.3136920915 6673550.059591168, 2551590.7224046243 6673381.807442008) + +LINESTRING (2548383.970587248 6671815.933240942, 2548383.970587248 6671984.185390101) + +LINESTRING (2554021.5458928533 6673549.514104079, 2554021.5458928533 6673717.766253239) + +LINESTRING (2548766.8903452973 6673554.766767388, 2548766.8903452973 6673723.018916547) + +LINESTRING (2553275.667703013 6673549.514104079, 2553275.667703013 6673717.766253239) + +LINESTRING (2553449.6405524276 6672320.971424899, 2553640.0675908644 6672320.557813115, 2553640.067590865 6672489.223574059, 2553456.1640789923 6672489.223574059, 2553449.6405524276 6672320.971424899) + +LINESTRING (2551597.4165239935 6674416.784085084, 2551783.9113233327 6674416.3704733, 2551793.5656541833 6674649.006697279, 2551609.6145586544 6674648.479616776, 2551597.4165239935 6674416.784085084) + +LINESTRING (2552909.9473909503 6674411.117809991, 2553094.4255669825 6674411.531421775) + +LINESTRING (2550065.457806269 6671979.346338576, 2550251.9526056084 6671978.932726792, 2550253.394061669 6672152.305663956, 2550068.0490937363 6672147.598487736, 2550065.457806269 6671979.346338576) + +LINESTRING (2548584.2067532064 6674075.15899876, 2548770.7015525457 6674074.745386977, 2548772.143008606 6674248.118324141, 2548586.7980406736 6674243.41114792, 2548584.2067532064 6674075.15899876) + +LINESTRING (2553452.924679172 6672840.950044488, 2553270.415039704 6672845.657220709) + +LINESTRING (2552703.235282084 6673187.82779412, 2552519.284186556 6673187.827794121) + +LINESTRING (2551782.4698672723 6674074.745386977, 2551966.9480433045 6674075.15899876) + +LINESTRING (2548766.8903452973 6673723.018916547, 2548951.3685213295 6673723.432528331) + +LINESTRING (2550638.8046027557 6673886.432014182, 2550642.6158100036 6674069.492723668) + +LINESTRING (2550829.685273503 6674238.158484612, 2550644.057266064 6674242.865660832) + +LINESTRING (2548944.1473214566 6672846.202707796, 2548946.1158580207 6673019.575644961) + +LINESTRING (2550638.8046027552 6673549.514104079, 2550638.8046027552 6673717.766253239) + +LINESTRING (2548571.0400507473 6672152.8511510445, 2548569.8902193406 6672326.224088208) + +LINESTRING (2551008.3361220662 6673376.141166915, 2551222.34071672 6673381.8074420085) + +LINESTRING (2552143.0585478754 6672325.810476424, 2552327.5367239076 6672326.224088208) + +LINESTRING (2553268.973583644 6672672.284283545, 2553453.451759676 6672672.6978953285) + +LINESTRING (2552519.2841865555 6673019.162033177, 2552703.7623625877 6673019.575644961) + +LINESTRING (2551955.915636183 6672846.202707796, 2551773.405996715 6672850.909884018) + +LINESTRING (2551228.9872524324 6674247.591243638, 2551229.0348360892 6674416.784085085) + +LINESTRING (2551961.168299492 6673550.059591167, 2551963.136836056 6673723.432528331) + +LINESTRING (2548578.9540898977 6673381.807442008, 2548765.448889237 6673381.393830224, 2548766.8903452973 6673554.766767388, 2548581.545377365 6673550.059591168, 2548578.9540898977 6673381.807442008) + +LINESTRING (2550642.6158100036 6674069.492723668, 2550827.093986036 6674069.906335452) + +LINESTRING (2552708.4879453927 6673891.68467749, 2552524.5368498648 6673891.684677491) + +LINESTRING (2549518.0211984464 6674248.118324141, 2549518.0211984464 6674416.3704733) + +LINESTRING (2551609.6145586544 6674648.479616776, 2551422.592678812 6674649.006697279) + +LINESTRING (2551412.9383479613 6674248.118324141, 2551412.9383479613 6674416.3704733) + +LINESTRING (2548760.196225928 6672677.536946854, 2548944.6744019603 6672677.950558637) + +LINESTRING (2551582.808365474 6672152.8511510445, 2551581.658534067 6672326.224088208) + +LINESTRING (2553089.1729036737 6673718.179865022, 2553275.667703013 6673717.766253239, 2553275.6677030134 6673886.432014182, 2553095.5278147324 6673900.713494006, 2553089.1729036737 6673718.179865022) + +LINESTRING (2553458.177342481 6673544.806927858, 2553460.145879045 6673718.179865022) + +LINESTRING (2549518.0211984464 6674416.3704733, 2549702.4993744786 6674416.784085084) + +LINESTRING (2552327.5367239076 6672326.224088208, 2552514.031523247 6672325.810476424, 2552514.0315232472 6672494.476237368, 2552330.1280113747 6672494.476237368, 2552327.5367239076 6672326.224088208) + +LINESTRING (2548576.2451303992 6672508.757717191, 2548573.701426589 6672677.950558637) + +LINESTRING (2552338.042050525 6673723.432528331, 2552524.5368498643 6673723.018916547, 2552524.5368498648 6673891.684677491, 2552340.6333379922 6673891.684677491, 2552338.042050525 6673723.432528331) + +LINESTRING (2548949.3999847653 6673550.059591167, 2548951.3685213295 6673723.432528331) + +LINESTRING (2554011.040566236 6672320.557813115, 2554195.518742268 6672320.971424899) + +LINESTRING (2551213.276846163 6672494.476237368, 2551217.0880534113 6672677.950558638) + +LINESTRING (2549696.719630666 6673891.68467749, 2549512.768535138 6673891.684677491) + +LINESTRING (2549322.1709038964 6672846.202707797, 2549136.5428964575 6672850.909884018) + +LINESTRING (2549898.1790762236 6674411.117809991, 2550082.657252256 6674411.531421775) + +LINESTRING (2551966.4209628007 6674243.4111479195, 2551968.389499365 6674416.784085084) + +LINESTRING (2552703.7623625877 6673019.575644961, 2552899.442064333 6673013.909369868, 2552899.4420643332 6673182.575130812, 2552703.235282084 6673187.82779412, 2552703.7623625877 6673019.575644961) + +LINESTRING (2553638.626134804 6671810.680577633, 2553638.626134804 6671978.932726792) + +LINESTRING (2548947.3867212767 6672494.476237368, 2548756.3850186802 6672494.476237368) + +LINESTRING (2550452.188771567 6674069.906335452, 2550642.6158100036 6674069.492723668, 2550644.057266064 6674242.865660832, 2550451.661691063 6674238.158484611, 2550452.188771567 6674069.906335452) + +LINESTRING (2551768.1533334064 6672157.558327265, 2551768.1533334064 6672325.810476424) + +LINESTRING (2548954.652648074 6674243.4111479195, 2548956.6211846382 6674416.784085084) + +LINESTRING (2550078.506836697 6673207.361937253, 2550075.9631328867 6673376.554778699) + +LINESTRING (2548957.892047894 6673891.684677491, 2548955.179728578 6674075.15899876) + +LINESTRING (2551213.276846163 6672326.224088209, 2551397.180358035 6672325.810476424, 2551400.9915652834 6672509.2847976945, 2551213.276846163 6672494.476237368, 2551213.276846163 6672326.224088209) + +LINESTRING (2551402.4330213442 6673187.827794121, 2551406.244228592 6673381.393830224) + +LINESTRING (2554009.5991101754 6671978.932726792, 2554194.0772862076 6671979.346338576) + +LINESTRING (2549328.8650232656 6673891.684677491, 2549330.084943047 6674075.15899876) + +LINESTRING (2551950.6629728745 6672152.851151044, 2551768.1533334064 6672157.558327265) + +LINESTRING (2552339.191881932 6673550.059591168, 2552153.563874493 6673554.766767388) + +LINESTRING (2553090.2751514236 6673207.361937253, 2552899.4420643332 6673182.575130812) + +LINESTRING (2553825.6955983033 6672147.598487736, 2553824.5457668966 6672320.971424899) + +LINESTRING (2552326.095267847 6671984.599001884, 2552512.5900671864 6671984.185390101, 2552514.031523247 6672157.558327265, 2552328.6865553143 6672152.8511510445, 2552326.095267847 6671984.599001884) + +LINESTRING (2551395.7389019746 6671815.933240942, 2551395.7389019746 6671984.185390101) + +LINESTRING (2551588.0610287827 6672846.202707797, 2551586.911197376 6673019.575644961) + +LINESTRING (2552892.7479449636 6671978.932726792, 2553077.226120996 6671979.346338576) + +LINESTRING (2548395.917369926 6673723.018916547, 2548580.395545958 6673723.432528331) + +LINESTRING (2551182.308971481 6671979.346338576, 2551395.7389019746 6671984.185390101, 2551397.180358035 6672157.558327265, 2551213.229262506 6672157.031246762, 2551182.308971481 6671979.346338576) + +LINESTRING (2549511.3270790773 6673381.393830224, 2549707.5814449824 6673376.5547787) + +LINESTRING (2550632.110483386 6672672.284283545, 2550816.5886594183 6672672.6978953285) + +LINESTRING (2552724.602423018 6674069.906335453, 2552908.50593489 6674069.492723668, 2552909.9473909503 6674242.865660832, 2552725.9962954214 6674242.338580329, 2552724.602423018 6674069.906335453) + +LINESTRING (2551984.5197731233 6674648.479616776, 2551793.5656541833 6674649.006697279) + +LINESTRING (2552894.189401024 6672152.305663956, 2552894.189401024 6672320.557813115) + +LINESTRING (2550269.152051595 6674242.865660832, 2550269.152051595 6674411.117809991) + +LINESTRING (2553829.7984302053 6673014.322981652, 2554016.2932295445 6673013.909369868, 2554020.104436793 6673207.889017756, 2553836.153341264 6673207.361937253, 2553829.7984302053 6673014.322981652) + +LINESTRING (2552524.5368498643 6673723.018916547, 2552720.7912157695 6673718.179865023) + +LINESTRING (2548200.067075376 6671984.599001885, 2548383.970587248 6671984.185390101, 2548385.4120433084 6672157.558327265, 2548201.4609477795 6672157.031246762, 2548200.067075376 6671984.599001885) + +LINESTRING (2550066.8992623296 6672320.971424899, 2550253.394061669 6672320.557813115, 2550253.3940616692 6672489.223574059, 2550073.2541733882 6672503.5050538825, 2550066.8992623296 6672320.971424899) + +LINESTRING (2553085.0700717717 6672840.9500444885, 2552899.442064333 6672845.657220709) + +LINESTRING (2550828.535442096 6674411.531421775, 2551015.0302414354 6674411.117809991, 2551024.684572286 6674643.754033971, 2550840.733476757 6674643.226953467, 2550828.535442096 6674411.531421775) + +LINESTRING (2554011.0405662362 6672489.223574059, 2554014.851773484 6672672.284283545) + +LINESTRING (2551223.7821727805 6673891.684677491, 2551009.777578127 6673886.432014182) + +LINESTRING (2552517.842730495 6672677.536946854, 2552714.0970964003 6672672.697895329) + +LINESTRING (2549327.423567205 6673550.059591168, 2549141.7955597662 6673554.766767388) + +LINESTRING (2550263.8993882863 6673549.514104079, 2550263.8993882863 6673717.766253239) + +LINESTRING (2553840.303756823 6674411.531421775, 2554026.798556162 6674411.117809991, 2554036.4528870126 6674643.754033971, 2553852.5017914837 6674643.226953467, 2553840.303756823 6674411.531421775) + +LINESTRING (2554200.244325073 6673182.575130811, 2554020.104436793 6673207.889017756) + +LINESTRING (2553837.6423809812 6673886.432014182, 2553650.5729174824 6673886.432014182) + +LINESTRING (2553079.817408463 6672147.598487736, 2553078.667577056 6672320.971424899) + +LINESTRING (2554021.5458928533 6673717.766253239, 2554206.0240688855 6673718.179865022) + +LINESTRING (2552519.2841865555 6672850.909884018, 2552519.2841865555 6673019.162033177) + +LINESTRING (2551397.180358035 6672157.558327265, 2551397.180358035 6672325.810476424) + +LINESTRING (2550444.3957642657 6672489.223574059, 2550253.3940616692 6672489.223574059) + +LINESTRING (2549502.26320852 6672325.810476424, 2549698.5175744253 6672320.9714249) + +LINESTRING (2551189.00309085 6673014.322981652, 2551402.433021344 6673019.162033177, 2551402.4330213442 6673187.827794121, 2551222.2931330632 6673212.614600562, 2551189.00309085 6673014.322981652) + +LINESTRING (2551411.496891901 6673906.493237818, 2551411.496891901 6674074.745386977) + +LINESTRING (2553090.3227350805 6673544.806927859, 2553089.1729036737 6673718.179865022) + +LINESTRING (2552158.8165378016 6674416.3704733, 2552343.294713834 6674416.784085084) + +LINESTRING (2552332.7893872163 6673019.575644961, 2552519.2841865555 6673019.162033177, 2552519.284186556 6673187.827794121, 2552335.3806746835 6673187.827794121, 2552332.7893872163 6673019.575644961) + +LINESTRING (2548217.2189377057 6674247.591243638, 2548217.2665213626 6674416.784085085) + +LINESTRING (2549686.2143040486 6672494.476237367, 2549502.2632085206 6672494.476237368) + +LINESTRING (2553825.6955983033 6672147.598487736, 2553640.0675908644 6672152.305663956) + +LINESTRING (2548389.2232505567 6672677.536946854, 2548573.701426589 6672677.950558637) + +LINESTRING (2552715.490968804 6672845.130140206, 2552519.2841865555 6672850.909884018) + +LINESTRING (2551588.013445126 6672508.757717191, 2551585.4697413156 6672677.950558637) + +LINESTRING (2548573.701426589 6672677.950558637, 2548760.196225928 6672677.536946854, 2548761.6376819885 6672850.909884018, 2548576.292714056 6672846.202707797, 2548573.701426589 6672677.950558637) + +LINESTRING (2549318.359696648 6672494.476237368, 2549319.5796164293 6672677.950558637) + +LINESTRING (2549896.7376201632 6673901.240574509, 2549896.7376201632 6674069.492723668) + +LINESTRING (2553825.6480146465 6671810.15349713, 2553823.104310836 6671979.346338576) + +LINESTRING (2551213.229262506 6672157.031246762, 2550999.272251509 6672152.305663956) + +LINESTRING (2553654.3841247302 6674069.492723668, 2553838.8623007624 6674069.906335452) + +LINESTRING (2552904.6947276415 6673549.514104079, 2552904.6947276415 6673717.766253239) + +LINESTRING (2552710.238305495 6672151.778583453, 2552710.285889152 6672320.9714249) + +LINESTRING (2548766.8903452978 6673891.684677491, 2548770.7015525457 6674074.745386977) + +LINESTRING (2550824.3850265373 6673207.361937253, 2550821.841322727 6673376.554778699) + +LINESTRING (2550819.1799468854 6672840.9500444885, 2550818.0301154787 6673014.322981652) + +LINESTRING (2550253.3940616692 6672489.223574059, 2550257.205268917 6672672.284283545) + +LINESTRING (2548212.013858054 6673723.432528332, 2548395.917369926 6673723.018916547, 2548399.7285771742 6673906.493237818, 2548212.013858054 6673891.684677491, 2548212.013858054 6673723.432528332) + +LINESTRING (2553640.067590865 6672489.223574059, 2553643.8787981127 6672672.284283545) + +LINESTRING (2552514.031523247 6672157.558327265, 2552514.031523247 6672325.810476424) + +LINESTRING (2552524.5368498648 6673891.684677491, 2552528.3480571127 6674074.745386977) + +LINESTRING (2548215.825065302 6674075.158998761, 2548399.7285771742 6674074.745386977, 2548401.1700332346 6674248.118324141, 2548217.2189377057 6674247.591243638, 2548215.825065302 6674075.158998761) + +LINESTRING (2548201.5085314363 6672326.224088209, 2548385.4120433084 6672325.810476424, 2548389.2232505567 6672509.2847976945, 2548201.5085314363 6672494.476237368, 2548201.5085314363 6672326.224088209) + +LINESTRING (2550453.630227627 6674411.531421775, 2550644.057266064 6674411.117809991, 2550644.0572660645 6674579.783570935, 2550460.153754192 6674579.783570935, 2550453.630227627 6674411.531421775) + +LINESTRING (2548586.7504570168 6673905.966157314, 2548399.7285771742 6673906.493237818) + +LINESTRING (2550446.4090277543 6673544.806927858, 2550448.3775643185 6673718.179865022) + +LINESTRING (2554016.2932295445 6672845.657220709, 2554016.2932295445 6673013.909369868) + +LINESTRING (2554025.3571001017 6674069.492723668, 2554209.835276134 6674069.906335452) + +LINESTRING (2554016.2932295445 6673013.909369868, 2554200.7714055767 6673014.322981652) + +LINESTRING (2552157.3750817413 6674074.745386977, 2552341.8532577734 6674075.15899876) + +LINESTRING (2550068.0015100795 6671810.15349713, 2550065.457806269 6671979.346338576) + +LINESTRING (2552904.6947276415 6673717.766253239, 2553089.1729036737 6673718.179865022) + +LINESTRING (2550083.8070836626 6674238.158484612, 2550082.657252256 6674411.531421775) + +LINESTRING (2550644.057266064 6674242.865660832, 2550644.057266064 6674411.117809991) + +LINESTRING (2551586.911197376 6673019.575644961, 2551773.405996715 6673019.162033177, 2551773.4059967156 6673187.827794121, 2551589.502484843 6673187.827794121, 2551586.911197376 6673019.575644961) + +LINESTRING (2551966.4209628007 6674243.4111479195, 2551783.9113233327 6674248.118324141) + +LINESTRING (2550441.1563644456 6672840.950044488, 2550258.6467249775 6672845.657220709) + +LINESTRING (2551968.389499365 6674416.784085084, 2552158.8165378016 6674416.3704733, 2552168.470868652 6674649.006697279, 2551984.5197731233 6674648.479616776, 2551968.389499365 6674416.784085084) + +LINESTRING (2551956.442716687 6672677.950558637, 2552146.8697551237 6672677.536946854, 2552148.311211184 6672850.909884018, 2551955.915636183 6672846.202707796, 2551956.442716687 6672677.950558637) + +LINESTRING (2550633.551939447 6673182.575130812, 2550637.363146695 6673376.141166915) + +LINESTRING (2548951.3685213295 6673723.432528331, 2549141.7955597662 6673723.018916547, 2549141.7955597667 6673891.684677491, 2548957.892047894 6673891.684677491, 2548951.3685213295 6673723.432528331) + +LINESTRING (2549886.2322935457 6672504.032134386, 2549886.2322935457 6672672.284283545) + +LINESTRING (2551963.136836056 6673723.432528331, 2552153.563874493 6673723.018916547, 2552153.5638744934 6673891.684677491, 2551969.660362621 6673891.684677491, 2551963.136836056 6673723.432528331) + +LINESTRING (2548761.6376819885 6673019.162033177, 2548946.1158580207 6673019.575644961) + +LINESTRING (2553835.051093514 6673718.179865022, 2554021.5458928533 6673717.766253239, 2554021.5458928538 6673886.432014182, 2553837.6423809812 6673886.432014182, 2553835.051093514 6673718.179865022) + +LINESTRING (2554026.798556162 6674242.865660832, 2554026.798556162 6674411.117809991) + +LINESTRING (2549698.5175744253 6672320.9714249, 2549882.4210862974 6672320.557813115, 2549886.2322935457 6672504.032134386, 2549686.2143040486 6672494.476237367, 2549698.5175744253 6672320.9714249) + +LINESTRING (2551400.9915652834 6672509.2847976945, 2551400.9915652834 6672677.536946854) + +LINESTRING (2550269.152051595 6674411.117809991, 2550453.630227627 6674411.531421775) + +LINESTRING (2552333.939218623 6672846.202707797, 2552148.311211184 6672850.909884018) + +LINESTRING (2549507.515871829 6672850.909884018, 2549507.515871829 6673019.162033177) + +LINESTRING (2552708.4879453927 6673891.68467749, 2552724.602423018 6674069.906335453) + +LINESTRING (2553275.667703013 6673717.766253239, 2553460.145879045 6673718.179865022) + +LINESTRING (2551778.6586600244 6673891.684677491, 2551782.4698672723 6674074.745386977) + +LINESTRING (2550072.1519256383 6673014.322981652, 2550258.6467249775 6673013.909369868, 2550258.646724978 6673182.575130812, 2550078.506836697 6673207.361937253, 2550072.1519256383 6673014.322981652) + +LINESTRING (2552720.7436321126 6673548.987023576, 2552524.5368498643 6673554.766767388) + +LINESTRING (2548956.403008177 6673212.614600562, 2548949.927065269 6673381.807442008) + +LINESTRING (2553095.5753983893 6674238.158484612, 2553094.4255669825 6674411.531421775) + +LINESTRING (2552894.189401024 6672320.557813115, 2553078.667577056 6672320.971424899) + +LINESTRING (2554009.5991101754 6671810.680577633, 2554009.5991101754 6671978.932726792) + +LINESTRING (2551580.217078007 6671984.599001884, 2551766.711877346 6671984.185390101, 2551768.1533334064 6672157.558327265, 2551582.808365474 6672152.8511510445, 2551580.217078007 6671984.599001884) + +LINESTRING (2552720.7912157695 6673718.179865023, 2552904.6947276415 6673717.766253239, 2552908.50593489 6673901.240574509, 2552708.4879453927 6673891.68467749, 2552720.7912157695 6673718.179865023) + +LINESTRING (2550823.2827787874 6673718.179865022, 2551009.7775781266 6673717.766253239, 2551009.777578127 6673886.432014182, 2550825.8740662546 6673886.432014182, 2550823.2827787874 6673718.179865022) + +LINESTRING (2553454.8932157364 6673014.322981652, 2553645.320254173 6673013.909369868, 2553645.3202541736 6673182.575130812, 2553465.1803658926 6673207.361937253, 2553454.8932157364 6673014.322981652) + +LINESTRING (2550258.6467249775 6673013.909369868, 2550443.1249010097 6673014.322981652) + +LINESTRING (2553265.1623763954 6672152.305663956, 2553265.1623763954 6672320.557813115) + +LINESTRING (2551218.481925815 6672850.382803515, 2551004.524914818 6672845.657220709) + +LINESTRING (2553640.0675908644 6672320.557813115, 2553824.5457668966 6672320.971424899) + +LINESTRING (2551966.9480433045 6674075.15899876, 2552157.3750817413 6674074.745386977, 2552158.8165378016 6674248.118324141, 2551966.4209628007 6674243.4111479195, 2551966.9480433045 6674075.15899876) + +LINESTRING (2551593.3136920915 6673550.059591168, 2551592.1638606847 6673723.432528331) + +LINESTRING (2552340.6333379922 6673891.684677491, 2552153.5638744934 6673891.684677491) + +LINESTRING (2550262.457932226 6673376.141166915, 2550446.936108258 6673376.554778699) + +LINESTRING (2548956.403008177 6673212.614600562, 2548761.637681989 6673187.827794121) + +LINESTRING (2548944.6744019603 6672677.950558637, 2549135.101440397 6672677.536946854, 2549136.5428964575 6672850.909884018, 2548944.1473214566 6672846.202707796, 2548944.6744019603 6672677.950558637) + +LINESTRING (2550082.657252256 6674411.531421775, 2550269.152051595 6674411.117809991, 2550278.8063824456 6674643.754033971, 2550094.8552869167 6674643.226953467, 2550082.657252256 6674411.531421775) + +LINESTRING (2553827.1370543637 6672489.223574059, 2553640.067590865 6672489.223574059) + +LINESTRING (2549500.8217524597 6671815.933240942, 2549500.8217524597 6671984.185390101) + +LINESTRING (2549723.8823115453 6674643.226953467, 2549527.675529297 6674649.006697279) + +LINESTRING (2552148.311211184 6673019.162033177, 2552332.7893872163 6673019.575644961) + +LINESTRING (2553263.720920335 6671810.680577633, 2553263.720920335 6671978.932726792) + +LINESTRING (2548206.761194745 6673019.575644962, 2548390.664706617 6673019.162033177, 2548390.6647066176 6673187.827794121, 2548210.5248183366 6673212.614600562, 2548206.761194745 6673019.575644962) + +LINESTRING (2554210.7496516905 6674579.783570934, 2554036.4528870126 6674643.754033971) + +LINESTRING (2549703.722654077 6672845.130140206, 2549691.994047861 6673019.575644961) + +LINESTRING (2549141.7955597662 6673723.018916547, 2549326.2737357984 6673723.432528331) + +LINESTRING (2551598.5187717434 6673905.966157314, 2551595.975067933 6674075.15899876) + +LINESTRING (2551004.524914818 6672845.657220709, 2551004.524914818 6673013.909369868) + +LINESTRING (2550628.2992761377 6672320.557813115, 2550812.77745217 6672320.971424899) + +LINESTRING (2549330.084943047 6674075.15899876, 2549516.579742386 6674074.745386977, 2549518.0211984464 6674248.118324141, 2549332.676230514 6674243.41114792, 2549330.084943047 6674075.15899876) + +LINESTRING (2553655.8255807906 6674411.117809991, 2553840.303756823 6674411.531421775) + +LINESTRING (2552330.1280113747 6672494.476237368, 2552331.347931156 6672677.950558637) + +LINESTRING (2553085.022488115 6672503.5050538825, 2552898.0006082724 6672504.032134386) + +LINESTRING (2550443.1249010097 6673014.322981652, 2550633.5519394465 6673013.909369868, 2550633.551939447 6673182.575130812, 2550453.412051166 6673207.361937253, 2550443.1249010097 6673014.322981652) + +LINESTRING (2550999.2722515096 6672489.223574059, 2551003.0834587575 6672672.284283545) + +LINESTRING (2552898.0006082724 6672504.032134386, 2552898.0006082724 6672672.284283545) + +LINESTRING (2553640.0675908644 6672152.305663956, 2553640.0675908644 6672320.557813115) + +LINESTRING (2550257.205268917 6672672.284283545, 2550441.6834449493 6672672.6978953285) + +LINESTRING (2549697.076118365 6671979.346338577, 2549880.979630237 6671978.932726792, 2549882.4210862974 6672152.305663956, 2549698.4699907685 6672151.778583453, 2549697.076118365 6671979.346338577) + +LINESTRING (2549896.7376201632 6674069.492723668, 2550081.2157961954 6674069.906335452) + +LINESTRING (2552344.4445452406 6674243.41114792, 2552158.8165378016 6674248.118324141) + +LINESTRING (2553466.66940561 6673886.432014182, 2553275.6677030134 6673886.432014182) + +LINESTRING (2551581.658534067 6672326.224088208, 2551768.1533334064 6672325.810476424, 2551768.153333407 6672494.476237368, 2551588.013445126 6672508.757717191, 2551581.658534067 6672326.224088208) + +LINESTRING (2553833.6096374537 6673376.554778699, 2554020.104436793 6673376.141166915, 2554021.5458928533 6673549.514104079, 2553836.200924921 6673544.806927859, 2553833.6096374537 6673376.554778699) + +LINESTRING (2550073.2541733882 6672503.5050538825, 2549886.2322935457 6672504.032134386) + +LINESTRING (2548772.143008606 6674416.3704733, 2548956.6211846382 6674416.784085084) + +LINESTRING (2554014.851773484 6672672.284283545, 2554199.3299495163 6672672.6978953285) + +LINESTRING (2548956.6211846382 6674416.784085084, 2549147.048223075 6674416.3704733, 2549156.7025539256 6674649.006697279, 2548972.7514583967 6674648.479616776, 2548956.6211846382 6674416.784085084) + +LINESTRING (2551222.34071672 6673381.8074420085, 2551406.244228592 6673381.393830224, 2551407.6856846525 6673554.766767388, 2551223.7345891236 6673554.239686885, 2551222.34071672 6673381.8074420085) + +LINESTRING (2551589.502484843 6673187.827794121, 2551402.4330213442 6673187.827794121) + +LINESTRING (2552710.285889152 6672320.9714249, 2552894.189401024 6672320.557813115, 2552898.0006082724 6672504.032134386, 2552697.982618775 6672494.476237367, 2552710.285889152 6672320.9714249) + +LINESTRING (2548770.7015525457 6674074.745386977, 2548955.179728578 6674075.15899876) + +LINESTRING (2548570.9924670905 6671815.406160438, 2548568.44876328 6671984.599001884) + +LINESTRING (2551009.7775781266 6673549.514104079, 2551009.7775781266 6673717.766253239) + +LINESTRING (2552158.8165378016 6674248.118324141, 2552158.8165378016 6674416.3704733) + +LINESTRING (2550441.6834449493 6672672.6978953285, 2550632.110483386 6672672.284283545, 2550633.5519394465 6672845.657220709, 2550441.1563644456 6672840.950044488, 2550441.6834449493 6672672.6978953285) + +LINESTRING (2548586.7504570168 6673905.966157314, 2548584.2067532064 6674075.15899876) + +LINESTRING (2554205.4969883817 6673886.432014181, 2554021.5458928538 6673886.432014182) + +LINESTRING (2552514.031523247 6672325.810476424, 2552710.285889152 6672320.9714249) + +LINESTRING (2549698.4699907685 6672151.778583453, 2549502.26320852 6672157.558327265) + +LINESTRING (2549316.870656931 6671815.406160438, 2549314.3269531205 6671984.599001884) + +LINESTRING (2548390.664706617 6673019.162033177, 2548575.1428826493 6673019.575644961) + +LINESTRING (2548569.8902193406 6672326.224088208, 2548756.38501868 6672325.810476424, 2548756.3850186802 6672494.476237368, 2548576.2451303992 6672508.757717191, 2548569.8902193406 6672326.224088208) + +LINESTRING (2550068.0490937363 6672147.598487736, 2550066.8992623296 6672320.971424899) + +LINESTRING (2549507.515871829 6673019.162033177, 2549691.994047861 6673019.575644961) + +LINESTRING (2549696.719630666 6673891.68467749, 2549712.834108291 6674069.906335453) + +LINESTRING (2552344.4445452406 6674243.41114792, 2552343.294713834 6674416.784085084) + +LINESTRING (2549880.979630237 6671978.932726792, 2550065.457806269 6671979.346338576) + +LINESTRING (2554193.550205704 6672147.598487735, 2554011.040566236 6672152.305663956) + +LINESTRING (2554021.5458928538 6673886.432014182, 2554025.3571001017 6674069.492723668) + +LINESTRING (2549892.926412915 6673717.766253239, 2550077.404588947 6673718.179865022) + +LINESTRING (2548394.4759138655 6673381.393830224, 2548578.9540898977 6673381.807442008) + +LINESTRING (2552519.284186556 6673187.827794121, 2552523.095393804 6673381.393830224) + +LINESTRING (2551778.658660024 6673723.018916547, 2551963.136836056 6673723.432528331) + +LINESTRING (2550827.093986036 6674069.906335452, 2551013.588785375 6674069.492723668, 2551015.0302414354 6674242.865660832, 2550829.685273503 6674238.158484612, 2550827.093986036 6674069.906335452) + +LINESTRING (2548577.7341701165 6673187.827794121, 2548390.6647066176 6673187.827794121) + +LINESTRING (2550075.9631328867 6673376.554778699, 2550262.457932226 6673376.141166915, 2550263.8993882863 6673549.514104079, 2550078.554420354 6673544.806927859, 2550075.9631328867 6673376.554778699) + +LINESTRING (2550453.412051166 6673207.361937253, 2550258.646724978 6673182.575130812) + +LINESTRING (2549322.1709038964 6672846.202707797, 2549321.0210724897 6673019.575644961) + +LINESTRING (2551223.7345891236 6673554.239686885, 2551009.7775781266 6673549.514104079) + +LINESTRING (2551783.9113233327 6674248.118324141, 2551783.9113233327 6674416.3704733) + +LINESTRING (2553466.66940561 6673886.432014182, 2553463.9570862935 6674069.906335452) + +LINESTRING (2548940.863194712 6672326.224088208, 2549131.2902331487 6672325.810476424, 2549131.290233149 6672494.476237368, 2548947.3867212767 6672494.476237368, 2548940.863194712 6672326.224088208) + +LINESTRING (2551395.7389019746 6671984.185390101, 2551580.217078007 6671984.599001884) + +LINESTRING (2550073.301757045 6672840.9500444885, 2549887.673749606 6672845.657220709) + +LINESTRING (2548568.44876328 6671984.599001884, 2548754.9435626194 6671984.185390101, 2548756.38501868 6672157.558327265, 2548571.0400507473 6672152.8511510445, 2548568.44876328 6671984.599001884) + +LINESTRING (2549328.8650232656 6673891.684677491, 2549141.7955597667 6673891.684677491) + +LINESTRING (2552341.8532577734 6674075.15899876, 2552528.3480571127 6674074.745386977, 2552529.789513173 6674248.118324141, 2552344.4445452406 6674243.41114792, 2552341.8532577734 6674075.15899876) + +LINESTRING (2550454.901090883 6673886.432014182, 2550263.8993882868 6673886.432014182) + +LINESTRING (2550251.9526056084 6671978.932726792, 2550436.4307816406 6671979.346338576) + +LINESTRING (2551957.8841727474 6673019.575644961, 2552148.311211184 6673019.162033177, 2552148.3112111846 6673187.827794121, 2551968.1713229036 6673212.614600562, 2551957.8841727474 6673019.575644961) + +LINESTRING (2549323.612359957 6673187.827794121, 2549136.542896458 6673187.827794121) + +LINESTRING (2549502.2632085206 6672494.476237368, 2549506.0744157685 6672677.536946854) + +LINESTRING (2548586.7980406736 6674243.41114792, 2548401.1700332346 6674248.118324141) + +LINESTRING (2552523.095393804 6673381.393830224, 2552719.349759709 6673376.5547787) + +LINESTRING (2548754.9435626194 6671815.933240942, 2548754.9435626194 6671984.185390101) + +LINESTRING (2552908.50593489 6673901.240574509, 2552908.50593489 6674069.492723668) + +LINESTRING (2553458.7044229847 6673376.554778699, 2553649.1314614215 6673376.141166915, 2553650.572917482 6673549.514104079, 2553458.177342481 6673544.806927858, 2553458.7044229847 6673376.554778699) + +LINESTRING (2549140.354103706 6673381.393830224, 2549324.832279738 6673381.807442008) + +LINESTRING (2551223.7821727805 6673723.432528332, 2551407.6856846525 6673723.018916547, 2551411.496891901 6673906.493237818, 2551223.7821727805 6673891.684677491, 2551223.7821727805 6673723.432528332) + +LINESTRING (2548761.637681989 6673187.827794121, 2548765.448889237 6673381.393830224) + +LINESTRING (2549326.2737357984 6673723.432528331, 2549512.7685351376 6673723.018916547, 2549512.768535138 6673891.684677491, 2549328.8650232656 6673891.684677491, 2549326.2737357984 6673723.432528331) + +LINESTRING (2551582.760781817 6671815.406160438, 2551580.217078007 6671984.599001884) + +LINESTRING (2553090.3227350805 6673544.806927859, 2552904.6947276415 6673549.514104079) + +LINESTRING (2548577.7341701165 6673187.827794121, 2548578.9540898977 6673381.807442008) + +LINESTRING (2550094.8552869167 6674643.226953467, 2549907.833407074 6674643.754033971) + +LINESTRING (2550824.432610194 6673544.806927859, 2550638.8046027552 6673549.514104079) + +LINESTRING (2548201.5085314363 6672494.476237368, 2548205.3197386847 6672677.950558638) + +LINESTRING (2553650.5729174824 6673886.432014182, 2553654.3841247302 6674069.492723668) + +LINESTRING (2553453.451759676 6672672.6978953285, 2553643.8787981127 6672672.284283545, 2553645.320254173 6672845.657220709, 2553452.924679172 6672840.950044488, 2553453.451759676 6672672.6978953285) + +LINESTRING (2553465.1803658926 6673207.361937253, 2553270.4150397046 6673182.575130812) + +LINESTRING (2553085.0700717717 6672840.9500444885, 2553083.920240365 6673014.322981652) + +LINESTRING (2551582.808365474 6672152.8511510445, 2551397.180358035 6672157.558327265) + +LINESTRING (2549703.722654077 6672845.130140206, 2549507.515871829 6672850.909884018) + +LINESTRING (2552697.982618775 6672494.476237367, 2552714.0970964003 6672672.697895329) + +LINESTRING (2554011.040566236 6672152.305663956, 2554011.040566236 6672320.557813115) + +LINESTRING (2552714.2676892052 6674416.784085084, 2552909.9473909503 6674411.117809991, 2552909.9473909508 6674579.783570935, 2552735.650626272 6674643.226953467, 2552714.2676892052 6674416.784085084) + +LINESTRING (2551783.9113233327 6674416.3704733, 2551968.389499365 6674416.784085084) + +LINESTRING (2549707.5814449824 6673376.5547787, 2549891.4849568545 6673376.141166915, 2549892.926412915 6673549.514104079, 2549708.975317386 6673548.987023576, 2549707.5814449824 6673376.5547787) + +LINESTRING (2548385.4120433084 6672157.558327265, 2548385.4120433084 6672325.810476424) + +LINESTRING (2552146.8697551237 6672677.536946854, 2552331.347931156 6672677.950558637) + +LINESTRING (2551766.711877346 6671815.933240942, 2551766.711877346 6671984.185390101) + +LINESTRING (2551211.7878064457 6671815.406160438, 2551182.308971481 6671979.346338576) + +LINESTRING (2550824.432610194 6673544.806927859, 2550823.2827787874 6673718.179865022) + +LINESTRING (2552708.8444330916 6671979.346338577, 2552892.7479449636 6671978.932726792, 2552894.189401024 6672152.305663956, 2552710.238305495 6672151.778583453, 2552708.8444330916 6671979.346338577) + +LINESTRING (2553097.0168544496 6674579.783570935, 2552909.9473909508 6674579.783570935) + +LINESTRING (2548954.652648074 6674243.4111479195, 2548772.143008606 6674248.118324141) + +LINESTRING (2553447.6720158635 6672147.598487735, 2553449.6405524276 6672320.971424899) + +LINESTRING (2548945.8976815594 6671815.406160438, 2548939.4217386516 6671984.599001884) + +LINESTRING (2552899.442064333 6672845.657220709, 2552899.442064333 6673013.909369868) + +LINESTRING (2551003.0834587575 6672672.284283545, 2551217.0880534113 6672677.950558638) + +LINESTRING (2550253.394061669 6672152.305663956, 2550253.394061669 6672320.557813115) + +LINESTRING (2550073.301757045 6672840.9500444885, 2550072.1519256383 6673014.322981652) + +LINESTRING (2551015.0302414354 6674242.865660832, 2551015.0302414354 6674411.117809991) + +LINESTRING (2549145.6067670146 6674074.745386977, 2549330.084943047 6674075.15899876) + +LINESTRING (2548938.894658148 6672152.851151044, 2548940.863194712 6672326.224088208) + +LINESTRING (2549318.359696648 6672494.476237368, 2549131.290233149 6672494.476237368) + +LINESTRING (2551004.524914818 6673013.909369868, 2551189.00309085 6673014.322981652) + +LINESTRING (2548949.3999847653 6673550.059591167, 2548766.8903452973 6673554.766767388) + +LINESTRING (2550258.6467249775 6672845.657220709, 2550258.6467249775 6673013.909369868) + +LINESTRING (2551397.180358035 6672325.810476424, 2551581.658534067 6672326.224088208) + +LINESTRING (2548385.4120433084 6672325.810476424, 2548569.8902193406 6672326.224088208) + +LINESTRING (2548401.1700332346 6674248.118324141, 2548401.1700332346 6674416.3704733) + +LINESTRING (2549709.022901043 6673718.179865023, 2549892.926412915 6673717.766253239, 2549896.7376201632 6673901.240574509, 2549696.719630666 6673891.68467749, 2549709.022901043 6673718.179865023) + +LINESTRING (2549882.4210862974 6672320.557813115, 2550066.8992623296 6672320.971424899) + +LINESTRING (2549331.526399107 6674416.784085084, 2549518.0211984464 6674416.3704733, 2549527.675529297 6674649.006697279, 2549343.724433768 6674648.479616776, 2549331.526399107 6674416.784085084) + +LINESTRING (2548761.6376819885 6672850.909884018, 2548761.6376819885 6673019.162033177) + +LINESTRING (2548949.927065269 6673381.807442008, 2549140.354103706 6673381.393830224, 2549141.7955597662 6673554.766767388, 2548949.3999847653 6673550.059591167, 2548949.927065269 6673381.807442008) + +LINESTRING (2553274.2262469525 6673376.141166915, 2553458.7044229847 6673376.554778699) + +LINESTRING (2552909.9473909503 6674242.865660832, 2552909.9473909503 6674411.117809991) + +LINESTRING (2548581.545377365 6673550.059591168, 2548580.395545958 6673723.432528331) + +LINESTRING (2550435.903701137 6672147.598487735, 2550253.394061669 6672152.305663956) + +LINESTRING (2548581.545377365 6673550.059591168, 2548395.917369926 6673554.766767388) + +LINESTRING (2553094.4255669825 6674411.531421775, 2553280.9203663217 6674411.117809991, 2553290.5746971723 6674643.754033971, 2553097.0168544496 6674579.783570935, 2553094.4255669825 6674411.531421775) + +LINESTRING (2548585.648209267 6674416.784085084, 2548772.143008606 6674416.3704733, 2548781.7973394566 6674649.006697279, 2548588.239496734 6674585.036234244, 2548585.648209267 6674416.784085084) + +LINESTRING (2550644.057266064 6674411.117809991, 2550828.535442096 6674411.531421775) + +LINESTRING (2550815.368739637 6672489.223574059, 2550816.5886594183 6672672.6978953285) + +LINESTRING (2549129.8487770883 6671815.933240942, 2549129.8487770883 6671984.185390101) + +LINESTRING (2548944.1473214566 6672846.202707796, 2548761.6376819885 6672850.909884018) + +LINESTRING (2550460.153754192 6674579.783570935, 2550278.8063824456 6674643.754033971) + +LINESTRING (2551009.777578127 6673886.432014182, 2551013.588785375 6674069.492723668) + +LINESTRING (2551768.1533334064 6672325.810476424, 2551952.6315094386 6672326.224088208) + +LINESTRING (2551773.405996715 6672850.909884018, 2551773.405996715 6673019.162033177) + +LINESTRING (2553270.4150397046 6673182.575130812, 2553274.2262469525 6673376.141166915) + +LINESTRING (2550818.0301154787 6673014.322981652, 2551004.524914818 6673013.909369868, 2551008.3361220662 6673207.889017756, 2550824.3850265373 6673207.361937253, 2550818.0301154787 6673014.322981652) + +LINESTRING (2548217.2665213626 6674416.784085085, 2548401.1700332346 6674416.3704733, 2548410.824364085 6674649.006697279, 2548217.2665213626 6674585.036234244, 2548217.2665213626 6674416.784085085) + +LINESTRING (2553827.1370543637 6672489.223574059, 2553828.356974145 6672672.6978953285) + +LINESTRING (2551218.481925815 6672850.382803515, 2551189.00309085 6673014.322981652) + +LINESTRING (2550083.7595000057 6673900.713494006, 2549896.7376201632 6673901.240574509) + +LINESTRING (2549332.676230514 6674243.41114792, 2549331.526399107 6674416.784085084) + +LINESTRING (2548947.3867212767 6672494.476237368, 2548944.6744019603 6672677.950558637) + +LINESTRING (2553263.720920335 6671978.932726792, 2553448.199096367 6671979.346338576) + +LINESTRING (2548946.1158580207 6673019.575644961, 2549136.5428964575 6673019.162033177, 2549136.542896458 6673187.827794121, 2548956.403008177 6673212.614600562, 2548946.1158580207 6673019.575644961) + +LINESTRING (2553279.4789102613 6674069.492723668, 2553463.9570862935 6674069.906335452) + +LINESTRING (2548201.4609477795 6672157.031246762, 2548201.5085314363 6672326.224088209) + +LINESTRING (2552715.490968804 6672845.130140206, 2552703.7623625877 6673019.575644961) + +LINESTRING (2553836.200924921 6673544.806927859, 2553650.572917482 6673549.514104079) + +LINESTRING (2551768.153333407 6672494.476237368, 2551771.964540655 6672677.536946854) + +LINESTRING (2552529.789513173 6674416.3704733, 2552714.2676892052 6674416.784085084) + +LINESTRING (2549686.2143040486 6672494.476237367, 2549702.3287816737 6672672.697895329) + +LINESTRING (2548938.894658148 6672152.851151044, 2548756.38501868 6672157.558327265) + +LINESTRING (2549691.994047861 6673019.575644961, 2549887.673749606 6673013.909369868, 2549887.6737496066 6673182.575130812, 2549691.4669673573 6673187.82779412, 2549691.994047861 6673019.575644961) + +LINESTRING (2551955.915636183 6672846.202707796, 2551957.8841727474 6673019.575644961) + +LINESTRING (2548571.0400507473 6672152.8511510445, 2548385.4120433084 6672157.558327265) + +LINESTRING (2550813.9272835767 6672147.598487736, 2550812.77745217 6672320.971424899) + +LINESTRING (2550441.1563644456 6672840.950044488, 2550443.1249010097 6673014.322981652) + +LINESTRING (2552330.1280113747 6672494.476237368, 2552143.058547876 6672494.476237368) + +LINESTRING (2553454.675039275 6671810.15349713, 2553448.199096367 6671979.346338576) + +LINESTRING (2553083.920240365 6673014.322981652, 2553270.415039704 6673013.909369868, 2553270.4150397046 6673182.575130812, 2553090.2751514236 6673207.361937253, 2553083.920240365 6673014.322981652) + +LINESTRING (2550813.9272835767 6672147.598487736, 2550628.2992761377 6672152.305663956) + +LINESTRING (2551222.2931330632 6673212.614600562, 2551222.34071672 6673381.8074420085) + +LINESTRING (2553463.9570862935 6674069.906335452, 2553654.3841247302 6674069.492723668, 2553655.8255807906 6674242.865660832, 2553463.4300057897 6674238.158484611, 2553463.9570862935 6674069.906335452) + +LINESTRING (2552328.6865553143 6672152.8511510445, 2552327.5367239076 6672326.224088208) + +LINESTRING (2552735.650626272 6674643.226953467, 2552529.7895131735 6674585.036234244) + +LINESTRING (2553836.153341264 6673207.361937253, 2553833.6096374537 6673376.554778699) + +LINESTRING (2548588.239496734 6674585.036234244, 2548410.824364085 6674649.006697279) + +LINESTRING (2551198.981336964 6674579.783570934, 2551024.684572286 6674643.754033971) + +LINESTRING (2552153.563874493 6673554.766767388, 2552153.563874493 6673723.018916547) + +LINESTRING (2548383.970587248 6671984.185390101, 2548568.44876328 6671984.599001884) + +LINESTRING (2549882.4210862974 6672152.305663956, 2549882.4210862974 6672320.557813115) + +LINESTRING (2550436.4307816406 6671979.346338576, 2550626.8578200773 6671978.932726792, 2550628.2992761377 6672152.305663956, 2550435.903701137 6672147.598487735, 2550436.4307816406 6671979.346338576) + +LINESTRING (2548756.38501868 6672325.810476424, 2548940.863194712 6672326.224088208) + +LINESTRING (2551015.0302414354 6674411.117809991, 2551229.0348360892 6674416.784085085) + +LINESTRING (2550435.903701137 6672147.598487735, 2550437.872237701 6672320.971424899) + +LINESTRING (2551773.405996715 6673019.162033177, 2551957.8841727474 6673019.575644961) + +LINESTRING (2552153.563874493 6673723.018916547, 2552338.042050525 6673723.432528331) + +LINESTRING (2549332.676230514 6674243.41114792, 2549147.048223075 6674248.118324141) + +LINESTRING (2549691.4669673573 6673187.82779412, 2549507.5158718294 6673187.827794121) + +LINESTRING (2549887.673749606 6672845.657220709, 2549887.673749606 6673013.909369868) + +LINESTRING (2551778.658660024 6673554.766767388, 2551778.658660024 6673723.018916547) + +LINESTRING (2553837.6423809812 6673886.432014182, 2553838.8623007624 6674069.906335452) + +LINESTRING (2548205.3197386847 6672677.950558638, 2548389.2232505567 6672677.536946854, 2548390.664706617 6672850.909884018, 2548206.713611088 6672850.382803515, 2548205.3197386847 6672677.950558638) + +LINESTRING (2551402.433021344 6673019.162033177, 2551586.911197376 6673019.575644961) + +LINESTRING (2551950.6629728745 6672152.851151044, 2551952.6315094386 6672326.224088208) + +LINESTRING (2550816.5886594183 6672672.6978953285, 2551003.0834587575 6672672.284283545, 2551004.524914818 6672845.657220709, 2550819.1799468854 6672840.9500444885, 2550816.5886594183 6672672.6978953285) + +LINESTRING (2553456.1640789923 6672489.223574059, 2553265.162376396 6672489.223574059) + +LINESTRING (2553092.984110922 6674069.906335452, 2553279.4789102613 6674069.492723668, 2553280.9203663217 6674242.865660832, 2553095.5753983893 6674238.158484612, 2553092.984110922 6674069.906335452) + +LINESTRING (2549316.9182405877 6672152.8511510445, 2549131.2902331487 6672157.558327265) + +LINESTRING (2548580.395545958 6673723.432528331, 2548766.8903452973 6673723.018916547, 2548766.8903452978 6673891.684677491, 2548586.7504570168 6673905.966157314, 2548580.395545958 6673723.432528331) + +LINESTRING (2550825.8740662546 6673886.432014182, 2550827.093986036 6674069.906335452) + +LINESTRING (2549327.423567205 6673550.059591168, 2549326.2737357984 6673723.432528331) + +LINESTRING (2550633.5519394465 6673013.909369868, 2550818.0301154787 6673014.322981652) + +LINESTRING (2551227.593380029 6674075.158998761, 2551411.496891901 6674074.745386977, 2551412.9383479613 6674248.118324141, 2551228.9872524324 6674247.591243638, 2551227.593380029 6674075.158998761) + +LINESTRING (2550997.8307954487 6671810.680577633, 2550997.8307954487 6671978.932726792) + +LINESTRING (2553852.5017914837 6674643.226953467, 2553655.825580791 6674579.783570935) + +LINESTRING (2549506.0744157685 6672677.536946854, 2549702.3287816737 6672672.697895329) + +LINESTRING (2551952.6315094386 6672326.224088208, 2552143.0585478754 6672325.810476424, 2552143.058547876 6672494.476237368, 2551959.1550360033 6672494.476237368, 2551952.6315094386 6672326.224088208) + +LINESTRING (2553463.4300057897 6674238.158484611, 2553280.9203663217 6674242.865660832) + +LINESTRING (2550251.9526056084 6671810.680577633, 2550251.9526056084 6671978.932726792) + +LINESTRING (2549147.048223075 6674248.118324141, 2549147.048223075 6674416.3704733) + +LINESTRING (2549323.612359957 6673187.827794121, 2549324.832279738 6673381.807442008) + +LINESTRING (2552328.6865553143 6672152.8511510445, 2552143.0585478754 6672157.558327265) + +LINESTRING (2553095.5278147324 6673900.713494006, 2552908.50593489 6673901.240574509) + +LINESTRING (2549316.9182405877 6672152.8511510445, 2549315.768409181 6672326.224088208) + +LINESTRING (2549502.26320852 6672157.558327265, 2549502.26320852 6672325.810476424) + +LINESTRING (2552141.617091815 6671815.933240942, 2552141.617091815 6671984.185390101) + +LINESTRING (2550258.646724978 6673182.575130812, 2550262.457932226 6673376.141166915) + +LINESTRING (2552898.0006082724 6672672.284283545, 2553082.4787843046 6672672.6978953285) + +LINESTRING (2548576.292714056 6672846.202707797, 2548575.1428826493 6673019.575644961) + +LINESTRING (2550813.87969992 6671810.15349713, 2550811.3359961095 6671979.346338576) + +LINESTRING (2553265.1623763954 6672320.557813115, 2553449.6405524276 6672320.971424899) + +LINESTRING (2550444.3957642657 6672489.223574059, 2550441.6834449493 6672672.6978953285) + +LINESTRING (2549324.832279738 6673381.807442008, 2549511.3270790773 6673381.393830224, 2549512.7685351376 6673554.766767388, 2549327.423567205 6673550.059591168, 2549324.832279738 6673381.807442008) + +LINESTRING (2552512.5900671864 6671984.185390101, 2552708.8444330916 6671979.346338577) + +LINESTRING (2549136.5428964575 6672850.909884018, 2549136.5428964575 6673019.162033177) + +LINESTRING (2550829.685273503 6674238.158484612, 2550828.535442096 6674411.531421775) + +LINESTRING (2548206.713611088 6672850.382803515, 2548206.761194745 6673019.575644962) + +LINESTRING (2550628.2992761377 6672152.305663956, 2550628.2992761377 6672320.557813115) + +LINESTRING (2550811.3359961095 6671979.346338576, 2550997.8307954487 6671978.932726792, 2550999.272251509 6672152.305663956, 2550813.9272835767 6672147.598487736, 2550811.3359961095 6671979.346338576) + +LINESTRING (2552719.349759709 6673376.5547787, 2552903.253271581 6673376.141166915, 2552904.6947276415 6673549.514104079, 2552720.7436321126 6673548.987023576, 2552719.349759709 6673376.5547787) + +LINESTRING (2549147.048223075 6674416.3704733, 2549331.526399107 6674416.784085084) + +LINESTRING (2550083.8070836626 6674238.158484612, 2549898.1790762236 6674242.865660832) + +LINESTRING (2552708.7968494347 6671810.15349713, 2552708.8444330916 6671979.346338577) + +LINESTRING (2549702.4993744786 6674416.784085084, 2549898.1790762236 6674411.117809991, 2549907.833407074 6674643.754033971, 2549723.8823115453 6674643.226953467, 2549702.4993744786 6674416.784085084) + +LINESTRING (2550825.8740662546 6673886.432014182, 2550638.8046027557 6673886.432014182) + +LINESTRING (2550263.8993882868 6673886.432014182, 2550267.7105955346 6674069.492723668) + +LINESTRING (2553095.5753983893 6674238.158484612, 2552909.9473909503 6674242.865660832) + +LINESTRING (2552528.3480571127 6674074.745386977, 2552724.602423018 6674069.906335453) + +LINESTRING (2553841.4535882296 6674238.158484612, 2553840.303756823 6674411.531421775) + +LINESTRING (2550077.404588947 6673718.179865022, 2550263.8993882863 6673717.766253239, 2550263.8993882868 6673886.432014182, 2550083.7595000057 6673900.713494006, 2550077.404588947 6673718.179865022) + +LINESTRING (2553650.572917482 6673549.514104079, 2553650.572917482 6673717.766253239) + +LINESTRING (2548955.179728578 6674075.15899876, 2549145.6067670146 6674074.745386977, 2549147.048223075 6674248.118324141, 2548954.652648074 6674243.4111479195, 2548955.179728578 6674075.15899876) + +LINESTRING (2550812.77745217 6672320.971424899, 2550999.272251509 6672320.557813115, 2550999.2722515096 6672489.223574059, 2550815.368739637 6672489.223574059, 2550812.77745217 6672320.971424899) + +LINESTRING (2552512.5900671864 6671815.933240942, 2552512.5900671864 6671984.185390101) + +LINESTRING (2553448.199096367 6671979.346338576, 2553638.626134804 6671978.932726792, 2553640.0675908644 6672152.305663956, 2553447.6720158635 6672147.598487735, 2553448.199096367 6671979.346338576) + +LINESTRING (2552908.50593489 6674069.492723668, 2553092.984110922 6674069.906335452) + +LINESTRING (2548399.7285771742 6674074.745386977, 2548584.2067532064 6674075.15899876) + +LINESTRING (2551013.588785375 6674069.492723668, 2551227.593380029 6674075.158998761) + +LINESTRING (2553079.817408463 6672147.598487736, 2552894.189401024 6672152.305663956) + +LINESTRING (2553456.1640789923 6672489.223574059, 2553453.451759676 6672672.6978953285) + +LINESTRING (2551961.168299492 6673550.059591167, 2551778.658660024 6673554.766767388) + +LINESTRING (2551222.2931330632 6673212.614600562, 2551008.3361220662 6673207.889017756) + +LINESTRING (2553645.320254173 6672845.657220709, 2553645.320254173 6673013.909369868) + +LINESTRING (2552514.0315232472 6672494.476237368, 2552517.842730495 6672677.536946854) + +LINESTRING (2551777.2172039635 6673381.393830224, 2551961.6953799957 6673381.807442008) + +LINESTRING (2552725.9962954214 6674242.338580329, 2552714.2676892052 6674416.784085084) + +LINESTRING (2553095.5278147324 6673900.713494006, 2553092.984110922 6674069.906335452) + +LINESTRING (2549714.2279806947 6674242.338580329, 2549518.0211984464 6674248.118324141) + +LINESTRING (2550821.841322727 6673376.554778699, 2551008.3361220662 6673376.141166915, 2551009.7775781266 6673549.514104079, 2550824.432610194 6673544.806927859, 2550821.841322727 6673376.554778699) + +LINESTRING (2552710.238305495 6672151.778583453, 2552514.031523247 6672157.558327265) + +LINESTRING (2550263.8993882863 6673717.766253239, 2550448.3775643185 6673718.179865022) + +LINESTRING (2551592.1638606847 6673723.432528331, 2551778.658660024 6673723.018916547, 2551778.6586600244 6673891.684677491, 2551598.5187717434 6673905.966157314, 2551592.1638606847 6673723.432528331) + +LINESTRING (2550083.7595000057 6673900.713494006, 2550081.2157961954 6674069.906335452) + +LINESTRING (2551213.276846163 6672494.476237368, 2550999.2722515096 6672489.223574059) + +LINESTRING (2551407.6856846525 6673723.018916547, 2551592.1638606847 6673723.432528331) + +LINESTRING (2551008.3361220662 6673207.889017756, 2551008.3361220662 6673376.141166915) + +LINESTRING (2551969.660362621 6673891.684677491, 2551778.6586600244 6673891.684677491) + +LINESTRING (2548957.892047894 6673891.684677491, 2548766.8903452978 6673891.684677491) + +LINESTRING (2551585.4697413156 6672677.950558637, 2551771.964540655 6672677.536946854, 2551773.405996715 6672850.909884018, 2551588.0610287827 6672846.202707797, 2551585.4697413156 6672677.950558637) + +LINESTRING (2549136.542896458 6673187.827794121, 2549140.354103706 6673381.393830224) + +LINESTRING (2549880.979630237 6671810.680577633, 2549880.979630237 6671978.932726792) + +LINESTRING (2552339.191881932 6673550.059591168, 2552338.042050525 6673723.432528331) + +LINESTRING (2552524.5368498643 6673554.766767388, 2552524.5368498643 6673723.018916547) + +LINESTRING (2550638.8046027552 6673717.766253239, 2550823.2827787874 6673718.179865022) + +LINESTRING (2550815.368739637 6672489.223574059, 2550628.299276138 6672489.223574059) + +LINESTRING (2551595.975067933 6674075.15899876, 2551782.4698672723 6674074.745386977, 2551783.9113233327 6674248.118324141, 2551598.5663554003 6674243.41114792, 2551595.975067933 6674075.15899876) + +LINESTRING (2550999.272251509 6672320.557813115, 2551213.276846163 6672326.224088209) + +LINESTRING (2550070.710469578 6672672.6978953285, 2550257.205268917 6672672.284283545, 2550258.6467249775 6672845.657220709, 2550073.301757045 6672840.9500444885, 2550070.710469578 6672672.6978953285) + +LINESTRING (2553079.769824806 6671810.15349713, 2553077.226120996 6671979.346338576) + +LINESTRING (2552331.347931156 6672677.950558637, 2552517.842730495 6672677.536946854, 2552519.2841865555 6672850.909884018, 2552333.939218623 6672846.202707797, 2552331.347931156 6672677.950558637) + +LINESTRING (2551959.1550360033 6672494.476237368, 2551768.153333407 6672494.476237368) + +LINESTRING (2551968.1713229036 6673212.614600562, 2551961.6953799957 6673381.807442008) + +LINESTRING (2549712.834108291 6674069.906335453, 2549896.7376201632 6674069.492723668, 2549898.1790762236 6674242.865660832, 2549714.2279806947 6674242.338580329, 2549712.834108291 6674069.906335453) + +LINESTRING (2554020.104436793 6673376.141166915, 2554204.582612825 6673376.554778699) + +LINESTRING (2554204.0555323213 6673544.806927858, 2554021.5458928533 6673549.514104079) + +LINESTRING (2553645.3202541736 6673182.575130812, 2553649.1314614215 6673376.141166915) + +LINESTRING (2553270.415039704 6672845.657220709, 2553270.415039704 6673013.909369868) + +LINESTRING (2552148.3112111846 6673187.827794121, 2552152.1224184325 6673381.393830224) + +LINESTRING (2548390.6647066176 6673187.827794121, 2548394.4759138655 6673381.393830224) + +LINESTRING (2553643.8787981127 6672672.284283545, 2553828.356974145 6672672.6978953285) + +LINESTRING (2549697.028534708 6671810.15349713, 2549697.076118365 6671979.346338577) + +LINESTRING (2553447.6720158635 6672147.598487735, 2553265.1623763954 6672152.305663956) + +LINESTRING (2551771.964540655 6672677.536946854, 2551956.442716687 6672677.950558637) + +LINESTRING (2550999.272251509 6672152.305663956, 2550999.272251509 6672320.557813115) + +LINESTRING (2551773.4059967156 6673187.827794121, 2551777.2172039635 6673381.393830224) + +LINESTRING (2551951.190053378 6671984.599001884, 2552141.617091815 6671984.185390101, 2552143.0585478754 6672157.558327265, 2551950.6629728745 6672152.851151044, 2551951.190053378 6671984.599001884) + +LINESTRING (2550446.4090277543 6673544.806927858, 2550263.8993882863 6673549.514104079) + +LINESTRING (2548576.292714056 6672846.202707797, 2548390.664706617 6672850.909884018) + +LINESTRING (2548756.38501868 6672157.558327265, 2548756.38501868 6672325.810476424) + +LINESTRING (2549315.768409181 6672326.224088208, 2549502.26320852 6672325.810476424, 2549502.2632085206 6672494.476237368, 2549318.359696648 6672494.476237368, 2549315.768409181 6672326.224088208) + +LINESTRING (2549131.2902331487 6672157.558327265, 2549131.2902331487 6672325.810476424) + +LINESTRING (2549135.101440397 6672677.536946854, 2549319.5796164293 6672677.950558637) + +LINESTRING (2549314.3269531205 6671984.599001884, 2549500.8217524597 6671984.185390101, 2549502.26320852 6672157.558327265, 2549316.9182405877 6672152.8511510445, 2549314.3269531205 6671984.599001884) + +LINESTRING (2549131.290233149 6672494.476237368, 2549135.101440397 6672677.536946854) + +LINESTRING (2549512.7685351376 6673554.766767388, 2549512.7685351376 6673723.018916547) + +LINESTRING (2550442.9067245484 6671810.15349713, 2550436.4307816406 6671979.346338576) + +LINESTRING (2551402.433021344 6672850.909884018, 2551402.433021344 6673019.162033177) + +LINESTRING (2554026.798556162 6674411.117809991, 2554211.2767321942 6674411.531421775) + +LINESTRING (2551411.496891901 6674074.745386977, 2551595.975067933 6674075.15899876) + +LINESTRING (2550453.412051166 6673207.361937253, 2550446.936108258 6673376.554778699) + +LINESTRING (2548765.448889237 6673381.393830224, 2548949.927065269 6673381.807442008) + +LINESTRING (2552720.7436321126 6673548.987023576, 2552720.7912157695 6673718.179865023) + +LINESTRING (2552697.982618775 6672494.476237367, 2552514.0315232472 6672494.476237368) + +LINESTRING (2552714.0970964003 6672672.697895329, 2552898.0006082724 6672672.284283545, 2552899.442064333 6672845.657220709, 2552715.490968804 6672845.130140206, 2552714.0970964003 6672672.697895329) + +LINESTRING (2553090.2751514236 6673207.361937253, 2553087.7314476133 6673376.554778699) + +LINESTRING (2550824.3850265373 6673207.361937253, 2550633.551939447 6673182.575130812) + +LINESTRING (2552335.3806746835 6673187.827794121, 2552148.3112111846 6673187.827794121) + +LINESTRING (2553465.398542354 6674411.531421775, 2553655.8255807906 6674411.117809991, 2553655.825580791 6674579.783570935, 2553481.5288161123 6674643.226953467, 2553465.398542354 6674411.531421775) + +LINESTRING (2554020.104436793 6673207.889017756, 2554020.104436793 6673376.141166915) + +LINESTRING (2550633.5519394465 6672845.657220709, 2550633.5519394465 6673013.909369868) + +LINESTRING (2549714.2279806947 6674242.338580329, 2549702.4993744786 6674416.784085084) + +LINESTRING (2553265.162376396 6672489.223574059, 2553268.973583644 6672672.284283545) + +LINESTRING (2549141.7955597662 6673554.766767388, 2549141.7955597662 6673723.018916547) + +LINESTRING (2549516.579742386 6674074.745386977, 2549712.834108291 6674069.906335453) + +LINESTRING (2553836.200924921 6673544.806927859, 2553835.051093514 6673718.179865022) + +LINESTRING (2551223.7821727805 6673891.684677491, 2551227.593380029 6674075.158998761) + +LINESTRING (2553087.7314476133 6673376.554778699, 2553274.2262469525 6673376.141166915, 2553275.667703013 6673549.514104079, 2553090.3227350805 6673544.806927859, 2553087.7314476133 6673376.554778699) + +LINESTRING (2550637.363146695 6673376.141166915, 2550821.841322727 6673376.554778699) + +LINESTRING (2552343.294713834 6674416.784085084, 2552529.789513173 6674416.3704733, 2552529.7895131735 6674585.036234244, 2552355.4927484947 6674648.479616776, 2552343.294713834 6674416.784085084) + +LINESTRING (2550626.8578200773 6671978.932726792, 2550811.3359961095 6671979.346338576) + +LINESTRING (2550446.936108258 6673376.554778699, 2550637.363146695 6673376.141166915, 2550638.8046027552 6673549.514104079, 2550446.4090277543 6673544.806927858, 2550446.936108258 6673376.554778699) + +LINESTRING (2553275.6677030134 6673886.432014182, 2553279.4789102613 6674069.492723668) + +LINESTRING (2553085.022488115 6672503.5050538825, 2553082.4787843046 6672672.6978953285) + +LINESTRING (2550073.2541733882 6672503.5050538825, 2550070.710469578 6672672.6978953285) + +LINESTRING (2549319.5796164293 6672677.950558637, 2549506.0744157685 6672677.536946854, 2549507.515871829 6672850.909884018, 2549322.1709038964 6672846.202707797, 2549319.5796164293 6672677.950558637) + +LINESTRING (2550253.394061669 6672320.557813115, 2550437.872237701 6672320.971424899) + +LINESTRING (2549702.3287816737 6672672.697895329, 2549886.2322935457 6672672.284283545, 2549887.673749606 6672845.657220709, 2549703.722654077 6672845.130140206, 2549702.3287816737 6672672.697895329) + +LINESTRING (2553463.4300057897 6674238.158484611, 2553465.398542354 6674411.531421775) + +LINESTRING (2551598.5663554003 6674243.41114792, 2551597.4165239935 6674416.784085084) + +LINESTRING (2553824.5457668966 6672320.971424899, 2554011.040566236 6672320.557813115, 2554011.0405662362 6672489.223574059, 2553827.1370543637 6672489.223574059, 2553824.5457668966 6672320.971424899) + +LINESTRING (2553650.572917482 6673717.766253239, 2553835.051093514 6673718.179865022) + +LINESTRING (2548575.1428826493 6673019.575644961, 2548761.6376819885 6673019.162033177, 2548761.637681989 6673187.827794121, 2548577.7341701165 6673187.827794121, 2548575.1428826493 6673019.575644961) \ No newline at end of file diff --git a/data/ParkPOIs.wkt b/data/ParkPOIs.wkt new file mode 100644 index 000000000..32d6a09c0 --- /dev/null +++ b/data/ParkPOIs.wkt @@ -0,0 +1,21 @@ +POINT (2553143.9097474786 6672121.598159393) + +POINT (2553290.179181832 6672173.0340217315) + +POINT (2553205.4575377535 6672050.908441204) + +POINT (2553015.3458680497 6672745.815491632) + +POINT (2553072.3655058085 6672628.625246054) + +POINT (2552990.331251769 6672620.934534737) + +POINT (2553248.9572028136 6671937.993476591) + +POINT (2553249.4343082923 6672094.541162056) + +POINT (2552785.543273026 6673249.298489128) + +POINT (2552729.0506920097 6673245.719605062) + +POINT (2552841.676618883 6673253.251878758) \ No newline at end of file diff --git a/data/WestPOIs.wkt b/data/WestPOIs.wkt new file mode 100644 index 000000000..692cdf74e --- /dev/null +++ b/data/WestPOIs.wkt @@ -0,0 +1,5 @@ +POINT (2550854.3137440286 6672591.750129179) + +POINT (2551121.9534618445 6672693.903576347) + +POINT (2550700.913609861 6672866.723243455) \ No newline at end of file diff --git a/data/cluster/ferryroute.wkt b/data/cluster/ferryroute.wkt new file mode 100644 index 000000000..cae1f0c3b --- /dev/null +++ b/data/cluster/ferryroute.wkt @@ -0,0 +1 @@ +LINESTRING (100 -100, 600 -100, 350 -533, 100 -100) \ No newline at end of file diff --git a/data/cluster/origin.wkt b/data/cluster/origin.wkt new file mode 100644 index 000000000..a6612600b --- /dev/null +++ b/data/cluster/origin.wkt @@ -0,0 +1 @@ +LINESTRING (0 0, 100 -100) \ No newline at end of file diff --git a/data/demo_bus.wkt b/data/demo_bus.wkt new file mode 100644 index 000000000..c306066a4 --- /dev/null +++ b/data/demo_bus.wkt @@ -0,0 +1,2 @@ +LINESTRING (2550592.003226894 6672735.4731177585, 2551115.9395496203 6672778.863077007, 2551733.574109715 6672719.2894031275, 2552056.98894488 6672339.2921827845, 2552443.66947668 6672192.648523826, 2552707.5061580963 6671918.555611582, 2553198.6258239946 6672295.572147773, 2553076.243947664 6672827.414220898, 2552788.4341127174 6673214.002954185, 2553299.34441706 6673391.583714101, + 2553901.791580166 6673127.503099969, 2553449.865462933 6674015.21685593, 2552643.258766599 6673756.567488425, 2552068.1670670523 6673793.766026565, 2551642.8869532268 6674154.408804504, 2551301.966601272 6673840.286704404, 2551573.186617998 6673194.328438315, 2551303.7237525806 6672909.38303511, 2550592.003226894 6672735.4731177585) \ No newline at end of file diff --git a/data/helsinki_underlay.png b/data/helsinki_underlay.png new file mode 100644 index 000000000..23fe60e41 Binary files /dev/null and b/data/helsinki_underlay.png differ diff --git a/data/main_roads.wkt b/data/main_roads.wkt new file mode 100644 index 000000000..c06fc8a9f --- /dev/null +++ b/data/main_roads.wkt @@ -0,0 +1,21 @@ +MULTILINESTRING ((2551018.1247934587 6672888.988353942, 2551072.6047335523 6672871.274288051, 2551102.270067377 6672869.903973524, 2551317.2612422374 6672889.818544494), + (2551317.2612422374 6672889.818544494, 2551321.592248983 6672912.583769771, 2551325.197296503 6672931.528118047, 2551241.192264708 6672922.67608625, 2551065.2048991695 6672911.10342999, 2551041.9824534757 6672913.1939098155, 2551011.1951826657 6672922.7561046155, 2550961.2442381973 6672948.942115062, 2550937.0813453244 6672957.334041252, 2550914.815845883 6672972.847602062, + 2550869.4433942605 6673004.914962448, 2550737.005332743 6673085.04335423, 2550585.098364711 6673131.2839677865), + (2550585.098364711 6673131.2839677865, 2550450.465926442 6673161.500903447, 2550327.5230816184 6673173.463649243, 2550187.660437108 6673162.511135324, 2550186.3236131626 6673162.231226012), + (2552554.469003542 6673143.706819191, 2552508.7708714856 6673110.496865532, 2552459.211603745 6673074.480929848, 2552330.7745675067 6672982.3197762, 2552261.900555275 6672932.613958296, 2552203.5997103774 6672890.538709792, 2552065.320976905 6672790.54575852, 2551986.7936374517 6672734.5429042475, 2551898.243110958 6672671.248376324, 2551824.970726356 6672617.436024834, + 2551800.230365917 6672605.523290517), + (2551800.230365917 6672605.523290517, 2551795.8003647313 6672629.388768334, 2551790.0999349 6672641.201479693, 2551733.574109715 6672719.2894031275, 2551619.8624964124 6672639.221025121, 2551531.089232429 6672581.677817292, 2551522.3364740345 6672575.816471944, 2551503.8905100655 6672563.463636612, 2551487.9111575577 6672562.0333083095), + (2551006.2619597437 6672888.91833787, 2550832.7989524226 6672878.625975476, 2550815.9781471756 6672914.404187609, 2550792.821697775 6672954.823465002, 2550728.731047474 6673032.95139762, 2550585.098364711 6673131.2839677865), + (2551800.230365917 6672605.523290517, 2551785.174961515 6672603.022716563, 2551761.795774624 6672609.224139969, 2551737.7731238743 6672604.973164247, 2551675.596366078 6672560.723007558, 2551609.583573736 6672512.792006007, 2551592.7710180255 6672511.671748877, 2551562.9076953214 6672521.093911535, 2551507.050082606 6672544.609308998, 2551487.9111575577 6672562.0333083095), + (2551487.9111575577 6672562.0333083095, 2551420.1329643703 6672640.221254703, 2551414.6140243458 6672657.84529993, 2551395.013125245 6672698.214565843, 2551382.737814697 6672714.818376898, 2551364.7703238544 6672731.342169586, 2551332.7043748624 6672762.019210854, 2551326.104745535 6672791.0058641285, 2551317.2612422374 6672889.818544494)) + +LINESTRING (2552559.517719977 6673146.45745054, 2552473.318311431 6673253.912114491, 2552440.104393391 6673297.548247428, 2552408.7574375407 6673338.7315830095, 2552398.0412894213 6673352.814815518, 2552387.0611561285 6673365.997841404, 2552275.9398973365 6673509.820852942, 2552256.454491749 6673534.296470803, 2552195.9111422114 6673612.1843483215, 2552172.432960881 6673639.590638857, + 2552153.657015446 6673654.484057328, 2552149.2847610167 6673657.954853976, 2552146.0756912567 6673660.495437113, 2552144.1535492153 6673662.015786077, 2552140.721741965 6673665.156506963, 2552137.4466759115 6673668.147193412, 2552124.4206575276 6673683.880804731, 2552092.0164775327 6673747.715456628, 2552068.1670670523 6673793.766026565, 2552022.431635817 6673885.937182508, + 2551970.2203183044 6673991.151332197, 2551943.3598269443 6674056.316289438, 2551910.081196063 6674119.950895418, 2551906.723634643 6674125.11208006, 2551861.5739205102 6674198.388899207, 2551849.810081235 6674219.603768633, 2551800.86558024 6674295.731242088, 2551770.499035799 6674351.273990754, 2551761.5729668215 6674388.38925647) + +LINESTRING (2552565.003661855 6673149.448136989, 2552576.849996497 6673154.089202248, 2552643.456755479 6673204.110683623, 2552681.874847698 6673207.531468792, 2552788.4341127174 6673214.002954185, 2552892.741254229 6673220.99455896, 2552983.1231778613 6673226.425805588, 2552993.2701079515 6673230.756799676, 2553050.2414081157 6673236.108027938, 2553055.265375941 6673247.010530378, + 2553055.669603237 6673293.861283979, 2553119.9004956614 6673301.242978292, 2553205.6544292276 6673309.334835607, 2553290.806146618 6673314.916116672, 2553304.1373978583 6673315.44623835, 2553311.495984558 6673318.586959236, 2553315.5877547404 6673324.248258668, 2553324.134274719 6673336.040965435, 2553344.139401116 6673364.037391424, 2553379.109187012 6673412.298468736, + 2553382.615240092 6673431.512878998, 2553383.2587039513 6673452.957801227, 2553384.355892327 6673489.416169477, 2553390.7657823106 6673499.708531871, 2553398.388354183 6673503.7994708605, 2553399.287553679 6673503.929500706, 2553433.0446576863 6673508.920646318, 2553438.126372268 6673509.670818504, 2553443.909297466 6673513.061596786, 2553451.424625362 6673526.524686954, + 2553479.8277800772 6673656.594541744, 2553493.3322715876 6673718.438736775, 2553545.51884049 6673950.411981339, 2553561.6796828043 6674022.26847448, 2553559.7905389094 6674043.833424259, 2553548.8516533 6674160.680243981, 2553547.647220948 6674163.500891401, 2553538.020011667 6674185.976050099, 2553503.4132053843 6674218.46350691, 2553481.741672582 6674232.366698094, + 2553470.2088203332 6674233.837035579, 2553446.1614209735 6674233.516962113, 2553433.2838942492 6674233.7470149165, 2553381.4190572766 6674234.637219245, 2553366.974118587 6674236.167570504, 2553355.1937802387 6674240.948667904, 2553331.1958780987 6674260.173080462, 2553328.6632703445 6674268.35495844, 2553317.6418893686 6674303.933124657, 2553310.6380327456 6674361.746394473, + 2553308.7473131865 6674388.38925647) \ No newline at end of file diff --git a/data/pedestrian_paths.wkt b/data/pedestrian_paths.wkt new file mode 100644 index 000000000..9295e86c0 --- /dev/null +++ b/data/pedestrian_paths.wkt @@ -0,0 +1,31 @@ +LINESTRING (2553224.356128833 6671841.2578695165, 2553256.2648518803 6671877.70537179, 2553248.9572028136 6671937.993476591, 2553205.4575377535 6672050.908441204, 2553143.9097474786 6672121.598159393, 2553104.2841227665 6672154.279717077) + +LINESTRING (2553290.179181832 6672173.0340217315, 2553370.4468685486 6672045.781300326, 2553439.4132999866 6671885.367994064) + +LINESTRING (2553477.5591574963 6672131.244429813, 2553417.9465874825 6672096.934843793, 2553388.7159912153 6672067.704247526, 2553370.4468685486 6672045.781300326) + +LINESTRING (2553248.9572028136 6671937.993476591, 2553307.4206877006 6671957.858982022, 2553345.5260227406 6672000.106201305, 2553370.4468685486 6672045.781300326) + +LINESTRING (2553205.4575377535 6672050.908441204, 2553249.4343082923 6672094.541162056, 2553249.4343082923 6672159.982933102, 2553290.179181832 6672173.0340217315) + +LINESTRING (2552980.989947268 6673262.500561615, 2552890.7744802726 6673256.709769484, 2552841.676618883 6673253.251878758, 2552785.543273026 6673249.298489128, 2552729.0506920097 6673245.719605062, 2552680.1661104076 6673242.622698407, 2552642.234078203 6673239.357966944) + +LINESTRING (2552640.585861742 6673275.677317152, 2552642.234078203 6673239.357966944, 2552643.456755479 6673204.110683623) + +LINESTRING (2552782.3212060533 6673285.5993876355, 2552785.543273026 6673249.298489128, 2552788.4341127174 6673214.002954185) + +LINESTRING (2552459.211603745 6673074.480929848, 2552424.328013667 6673073.345559651, 2552383.7805014118 6673072.025843509, 2552327.450875701 6673090.250134179, 2552250.077599912 6673094.855606426) + +LINESTRING (2552378.5476342966 6673187.666909302, 2552383.7805014118 6673130.012222917, 2552346.503543221 6673096.04877212, 2552327.450875701 6673090.250134179) + +LINESTRING (2552327.450875701 6673090.250134179, 2552318.3387303655 6673043.861030653, 2552325.418393619 6673008.825885631, 2552330.7745675067 6672982.3197762) + +LINESTRING (2552424.328013667 6673073.345559651, 2552383.7805014118 6673038.890769561, 2552325.418393619 6673008.825885631) + +LINESTRING (2552830.964236457 6672622.610688017, 2552894.624622056 6672562.826938125, 2552950.823014919 6672488.199116582, 2552949.314124749 6672565.390508564, 2552990.331251769 6672620.934534737, 2553072.3655058085 6672628.625246054, 2553149.5493304124 6672557.952371617) + +LINESTRING (2553171.039373408 6672675.199283171, 2553072.3655058085 6672628.625246054) + +LINESTRING (2552924.1307412153 6672763.979660833, 2552946.75055431 6672726.8954462055, 2552980.076970014 6672720.913781848, 2553015.3458680497 6672745.815491632) + +LINESTRING (2552990.331251769 6672620.934534737, 2552980.076970014 6672720.913781848) \ No newline at end of file diff --git a/data/roads.wkt b/data/roads.wkt new file mode 100644 index 000000000..f1da873fc --- /dev/null +++ b/data/roads.wkt @@ -0,0 +1,2149 @@ +LINESTRING (2551175.3114649523 6671566.634835593, 2551111.3693063115 6671441.356080499) + +LINESTRING (2550636.89720539 6671631.9498272715, 2550611.5133810914 6671615.7461080495, 2550609.335503414 6671596.181617434, 2550675.5792827825 6671482.095431358) + +LINESTRING (2550955.7665458564 6671748.946681431, 2550991.9407641045 6671685.38209152, 2551028.362468452 6671646.51316998, 2551045.8267375585 6671634.44039893, 2551175.3114649523 6671566.634835593) + +LINESTRING (2550636.89720539 6671631.9498272715, 2550578.80396824 6671730.592468609) + +LINESTRING (2550838.3096429105 6671750.977147481, 2550636.89720539 6671631.9498272715) + +LINESTRING (2550955.7665458564 6671748.946681431, 2550924.7647870933 6671798.608080157, 2550838.3096429105 6671750.977147481) + +LINESTRING (2551086.298964406 6671839.64749989, 2551235.038110361 6671764.340214692, 2551250.3904980826 6671753.617753577, 2551259.217502307 6671729.32217704) + +LINESTRING (2550779.399701631 6671848.84961204, 2550578.80396824 6671730.592468609) + +LINESTRING (2551086.298964406 6671839.64749989, 2551006.228961597 6671778.523470159, 2550955.7665458564 6671748.946681431) + +LINESTRING (2551596.433812302 6671064.409560379, 2551481.427021744 6671124.963459249) + +LINESTRING (2551481.427021744 6671124.963459249, 2551445.178557666 6671054.67732655, 2551435.180119236 6671046.105359036, 2551419.3410088513 6671039.603866755, 2551404.846572942 6671040.844151436, 2551386.400608973 6671047.835756212, 2551312.4600119023 6671088.845169057, 2551297.338611207 6671100.237783992, 2551288.8415884483 6671108.17960687, 2551285.1210474153 6671126.433796734, + 2551335.657708986 6671225.196465621, 2551491.2522199047 6671144.017832778) + +LINESTRING (2551491.2522199047 6671144.017832778, 2551481.427021744 6671124.963459249) + +LINESTRING (2551618.7735575736 6671352.915780894, 2551528.9278538246 6671397.786079925) + +LINESTRING (2551528.9278538246 6671397.786079925, 2551436.2773076114 6671444.056700369) + +LINESTRING (2551906.43490086 6671776.923102828, 2551921.572800629 6671722.220547011, 2551916.697324463 6671708.97750735, 2551897.690392002 6671693.523960315, 2551873.7749852287 6671666.857839669, 2551855.8652411425 6671639.501560613, 2551795.7261189013 6671523.915030164, 2551805.782304088 6671476.494145701, 2551804.5366240526 6671466.011739685, 2551679.473648308 6671222.705893962, + 2551671.422100529 6671215.784305258, 2551660.813196386 6671215.63427082, 2551571.1077347603 6671261.264744333, 2551561.926000459 6671263.085162171, 2551553.84970407 6671260.544579034, 2551547.093333547 6671252.882820439, 2551491.2522199047 6671144.017832778) + +LINESTRING (2551626.5116229593 6671587.909718794, 2551528.9278538246 6671397.786079925) + +LINESTRING (2551721.8515181234 6671541.018956009, 2551626.5116229593 6671587.909718794) + +LINESTRING (2551259.217502307 6671729.32217704, 2551175.3114649523 6671566.634835593) + +LINESTRING (2551906.43490086 6671776.923102828, 2551795.3878878984 6671740.494741467, 2551728.9956168695 6671713.738600159, 2551700.7657024236 6671694.3841577545, 2551668.7245020415 6671661.246551717, 2551626.5116229593 6671587.909718794) + +LINESTRING (2552393.5865396257 6671805.229599987, 2552305.316497378 6671800.688557687, 2552220.1730295243 6671809.450568821, 2552097.857149487 6671828.464933168) + +LINESTRING (2552393.5865396257 6671805.229599987, 2552394.7992215143 6671836.756836399) + +LINESTRING (2552411.215799465 6671838.257180772, 2552394.7992215143 6671836.756836399) + +LINESTRING (2552965.9063948547 6671923.686789336, 2552898.4829317434 6671882.237275475, 2552730.662607497 6671826.484478597, 2552542.1771939206 6671766.670749617, 2552501.8287101234 6671761.049459368, 2552459.665328261 6671765.190409836, 2552434.7929752353 6671777.543245168, 2552393.5865396257 6671805.229599987) + +LINESTRING (2552529.26666905 6671861.652550685, 2552411.215799465 6671838.257180772) + +LINESTRING (2552394.7992215143 6671836.756836399, 2552326.2620709543 6671842.438140423, 2552268.0945879743 6671857.091503793, 2552210.3148332173 6671883.367534901, 2552192.6443256945 6671895.100227893) + +LINESTRING (2552608.387975143 6671893.399837605, 2552538.3164107646 6671874.825574275, 2552529.26666905 6671861.652550685) + +LINESTRING (2552411.215799465 6671838.257180772, 2552442.0608170317 6671888.928811375, 2552450.0546180536 6671923.526752602, 2552452.265493878 6671946.271973288, 2552450.1371134203 6671958.454769592) + +LINESTRING (2552707.5061580963 6671918.555611582, 2552608.387975143 6671893.399837605) + +LINESTRING (2552192.6443256945 6671895.100227893, 2552225.469232059 6671927.747721436) + +LINESTRING (2553136.6388055417 6671827.364680628, 2553237.8936184896 6671761.569578751, 2553258.6824508696 6671752.257441346) + +LINESTRING (2553258.6824508696 6671752.257441346, 2553257.8327485938 6671759.619131067, 2553231.310488236 6671810.2207456, 2553213.2687515635 6671834.346283107) + +LINESTRING (2553166.5351263923 6671840.257639934, 2553136.6388055417 6671827.364680628) + +LINESTRING (2553213.2687515635 6671834.346283107, 2553224.356128833 6671841.2578695165) + +LINESTRING (2553213.2687515635 6671834.346283107, 2553194.0885788323 6671842.618181747, 2553180.641834079 6671843.99849857, 2553166.5351263923 6671840.257639934) + +LINESTRING (2552965.9063948547 6671923.686789336, 2552984.8143328764 6671922.006403638, 2553000.430705771 6671913.354417758, 2553136.6388055417 6671827.364680628) + +LINESTRING (2553166.5351263923 6671840.257639934, 2553133.875210761 6671847.919398529, 2553100.52233405 6671879.85672907, 2553073.7360885195 6671972.968100821, 2553033.420602869 6672024.900020697) + +LINESTRING (2552951.6016982887 6671978.96947831, 2552890.6046242346 6671963.876013924, 2552707.5061580963 6671918.555611582) + +LINESTRING (2552965.9063948547 6671923.686789336, 2552951.6016982887 6671978.96947831) + +LINESTRING (2553023.9996320046 6672035.852534615, 2552985.4247985887 6671987.861519291, 2552951.6016982887 6671978.96947831) + +LINESTRING (2552097.857149487 6671828.464933168, 2552023.157595043 6671823.333755414, 2551985.721197686 6671814.581746575, 2551951.163888623 6671802.518977821, 2551906.43490086 6671776.923102828) + +LINESTRING (2551364.5310872914 6671947.522260265, 2551259.217502307 6671729.32217704) + +LINESTRING (2551906.43490086 6671776.923102828, 2551837.279035051 6671991.542364151) + +LINESTRING (2551374.3892835984 6672043.314247294, 2551364.5310872914 6671947.522260265) + +LINESTRING (2552039.310187821 6672058.027624439, 2551837.279035051 6671991.542364151) + +LINESTRING (2551376.443418226 6672068.390002904, 2551364.993061344 6672039.063271573, 2551189.7811522516 6672020.549022017) + +LINESTRING (2551376.443418226 6672068.390002904, 2551374.3892835984 6672043.314247294) + +LINESTRING (2551837.279035051 6671991.542364151, 2551808.9418766284 6672073.831251829, 2552011.946474724 6672145.087607222) + +LINESTRING (2552039.310187821 6672058.027624439, 2552011.946474724 6672145.087607222) + +LINESTRING (2552022.74511821 6672148.888479631, 2552011.946474724 6672145.087607222) + +LINESTRING (2550838.3096429105 6671750.977147481, 2550779.399701631 6671848.84961204) + +LINESTRING (2550578.80396824 6671730.592468609, 2550450.4741759785 6671955.414071664) + +LINESTRING (2551120.270556366 6671890.589192481, 2551105.64412787 6671861.78258053, 2551086.298964406 6671839.64749989) + +LINESTRING (2550692.136102856 6672000.934519922, 2550779.399701631 6671848.84961204) + +LINESTRING (2551189.7811522516 6672020.549022017, 2551164.661313126 6671899.611263307, 2551154.4318876695 6671886.578271858, 2551139.9539508335 6671884.217730046, 2551120.270556366 6671890.589192481) + +LINESTRING (2551136.70363339 6672030.9214027785, 2551110.0823785923 6671906.722895632, 2551120.270556366 6671890.589192481) + +LINESTRING (2551120.270556366 6671890.589192481, 2551045.859735705 6671915.754968753, 2551024.7326723225 6671931.338545634, 2550978.2795313974 6672002.13479542, 2550945.1988893966 6672062.238590978) + +LINESTRING (2550905.988841658 6672124.8129536025, 2550884.144068586 6672115.780880481, 2550692.136102856 6672000.934519922) + +LINESTRING (2551136.70363339 6672030.9214027785, 2551093.929785815 6672039.913466717, 2551041.6359729357 6672111.649932309) + +LINESTRING (2550885.983715261 6672158.480681319, 2550679.3163228887 6672035.902546095, 2550677.328184554 6672029.341040039, 2550692.136102856 6672000.934519922) + +LINESTRING (2552529.26666905 6671861.652550685, 2552495.9550400223 6671994.583062079) + +LINESTRING (2552450.1371134203 6671958.454769592, 2552394.4774895846 6671930.768414773, 2552322.7560178745 6671906.8729300685, 2552302.775640087 6671904.872470906, 2552263.8130784486 6671910.0536601385, 2552225.469232059 6671927.747721436) + +LINESTRING (2552097.857149487 6671828.464933168, 2552100.1092729946 6671880.116788762, 2552039.310187821 6672058.027624439) + +LINESTRING (2552225.469232059 6671927.747721436, 2552280.015168446 6671938.780253721, 2552298.1806481685 6671947.172179911, 2552325.9403390246 6671965.876473087) + +LINESTRING (2552707.5061580963 6671918.555611582, 2552699.033883948 6671952.633433427, 2552689.9841422336 6671988.821739689) + +LINESTRING (2552385.361751577 6671970.1474534, 2552345.508239979 6671956.984432107, 2552336.9369713906 6671956.874406853, 2552325.9403390246 6671965.876473087) + +LINESTRING (2552608.387975143 6671893.399837605, 2552600.121939411 6671928.927992343, 2552568.922191768 6672052.846435207) + +LINESTRING (2552495.9550400223 6671994.583062079, 2552450.1371134203 6671958.454769592) + +LINESTRING (2552192.6443256945 6671895.100227893, 2552162.4427719875 6671917.265315422, 2552112.112348833 6671967.386819756, 2552091.9999784594 6671994.202974838, 2552071.8133622557 6672026.100296195, 2552059.4473068044 6672054.976924215, 2552050.5543062864 6672064.16903407) + +LINESTRING (2552445.847354358 6672020.799079413, 2552448.3469639653 6672005.375539265, 2552444.9811530085 6672000.17434544, 2552421.1729902118 6671985.530984365, 2552385.361751577 6671970.1474534) + +LINESTRING (2552225.469232059 6671927.747721436, 2552204.4164145063 6671940.430632532, 2552173.0434265938 6671965.96649375, 2552159.8771660863 6671979.909694117, 2552129.898349869 6672026.35035359, 2552126.2355555925 6672046.625007209, 2552129.923098479 6672065.879426655, 2552135.961759313 6672077.812165564, 2552135.6565264566 6672092.005423326) + +LINESTRING (2552495.9550400223 6671994.583062079, 2552487.458017264 6672030.541315537) + +LINESTRING (2552385.361751577 6671970.1474534, 2552384.074823858 6671979.859682638, 2552397.7195574916 6672026.420369661, 2552394.4032437545 6672059.577980291) + +LINESTRING (2552325.9403390246 6671965.876473087, 2552343.3468613746 6671989.031787901, 2552348.7420583493 6672011.997059095, 2552350.5899545606 6672084.733754268) + +LINESTRING (2552487.458017264 6672030.541315537, 2552445.847354358 6672020.799079413) + +LINESTRING (2552689.9841422336 6671988.821739689, 2552665.84599797 6672078.382296425) + +LINESTRING (2552274.289990005 6672061.3383843545, 2552229.775490195 6672054.426797946, 2552217.9044069434 6672044.524525088, 2552217.137200034 6672017.598344752) + +LINESTRING (2552274.289990005 6672061.3383843545, 2552281.6980739245 6672052.986467348, 2552283.8017057725 6672035.132369317, 2552277.0370857124 6672028.170771429, 2552217.137200034 6672017.598344752) + +LINESTRING (2552445.847354358 6672020.799079413, 2552441.5823439052 6672039.053269276, 2552394.4032437545 6672059.577980291) + +LINESTRING (2552568.922191768 6672052.846435207, 2552528.078735771 6672041.643863893, 2552487.458017264 6672030.541315537) + +LINESTRING (2552050.5543062864 6672064.16903407, 2552039.310187821 6672058.027624439) + +LINESTRING (2552665.84599797 6672078.382296425, 2552615.251589643 6672065.289291202, 2552568.922191768 6672052.846435207) + +LINESTRING (2552268.3998208307 6672073.281125559, 2552274.289990005 6672061.3383843545) + +LINESTRING (2552394.4032437545 6672059.577980291, 2552350.5899545606 6672084.733754268) + +LINESTRING (2552135.6565264566 6672092.005423326, 2552050.5543062864 6672064.16903407) + +LINESTRING (2552350.5899545606 6672084.733754268, 2552337.415444517 6672086.264105528, 2552268.3998208307 6672073.281125559) + +LINESTRING (2552268.3998208307 6672073.281125559, 2552267.0221482087 6672090.435062883) + +LINESTRING (2552199.210956875 6672085.163852988, 2552158.169511998 6672075.951738542, 2552146.0756912567 6672080.212716559, 2552135.6565264566 6672092.005423326) + +LINESTRING (2552267.0221482087 6672090.435062883, 2552223.563589091 6672089.834925135, 2552199.210956875 6672085.163852988) + +LINESTRING (2552350.5899545606 6672084.733754268, 2552360.4316517944 6672117.5012753615) + +LINESTRING (2552951.6016982887 6671978.96947831, 2552932.009048724 6672051.656162005) + +LINESTRING (2552932.009048724 6672051.656162005, 2552689.9841422336 6671988.821739689) + +LINESTRING (2553033.420602869 6672024.900020697, 2553023.9996320046 6672035.852534615) + +LINESTRING (2553104.2841227665 6672154.279717077, 2553023.9996320046 6672035.852534615) + +LINESTRING (2552932.009048724 6672051.656162005, 2552909.710551136 6672140.6265832875) + +LINESTRING (2552909.710551136 6672140.6265832875, 2552665.84599797 6672078.382296425) + +LINESTRING (2553078.108342949 6672215.473762878, 2552909.710551136 6672140.6265832875) + +LINESTRING (2553104.2841227665 6672154.279717077, 2553078.108342949 6672215.473762878) + +LINESTRING (2552909.710551136 6672140.6265832875, 2552883.7245106613 6672239.799346303) + +LINESTRING (2552883.7245106613 6672239.799346303, 2552708.001130296 6672220.484913082) + +LINESTRING (2553258.6824508696 6671752.257441346, 2553307.899186575 6671743.005317716, 2553327.4588379925 6671743.275379703, 2553356.2414713944 6671753.047622715, 2553364.416762223 6671759.249046122, 2553372.229073439 6671765.190409836, 2553384.3393932534 6671781.114064775, 2553425.45508396 6671872.695085266, 2553439.4132999866 6671885.367994064, 2553475.3317825985 6671896.300503392, + 2553498.7274685623 6671899.161159995, 2553558.3551195306 6671918.175524341, 2553586.8572686864 6671931.4285662975) + +LINESTRING (2553477.5591574963 6672131.244429813, 2553501.581808246 6672095.446213087, 2553524.688760427 6672067.959904185, 2553578.236502878 6672029.551088251, 2553588.5484237014 6672013.887493004, 2553596.9794501667 6671997.5837508235, 2553598.4066200084 6671985.601000437, 2553597.391926999 6671967.896936842, 2553586.8572686864 6671931.4285662975) + +LINESTRING (2553586.8572686864 6671931.4285662975, 2553627.296497387 6671954.933961465, 2553641.700188393 6671969.757363864, 2553651.4263921133 6671986.521211651, 2553655.7656483958 6672008.526262446, 2553650.584939374 6672047.015096746, 2553639.505811642 6672079.432537486, 2553636.5689765913 6672147.208093935, 2553619.970908834 6672194.188877382) + +LINESTRING (2553619.970908834 6672194.188877382, 2553581.255833295 6672168.172905965, 2553554.2550998116 6672157.400433371, 2553503.8999280473 6672151.739133939, 2553477.5591574963 6672131.244429813) + +LINESTRING (2553432.656929463 6672199.62012401, 2553477.5591574963 6672131.244429813) + +LINESTRING (2553388.9756328557 6672231.9875532705, 2553347.7114504892 6672197.249579902, 2553290.179181832 6672173.0340217315) + +LINESTRING (2553388.9756328557 6672231.9875532705, 2553432.656929463 6672199.62012401) + +LINESTRING (2553499.816407401 6672266.725526639, 2553477.25392464 6672208.932261415, 2553439.60303933 6672204.061143353, 2553432.656929463 6672199.62012401) + +LINESTRING (2553619.970908834 6672194.188877382, 2553578.599482491 6672290.310940173) + +LINESTRING (2553923.430114822 6672945.05122199, 2553923.570356945 6672935.098937653, 2553934.6494846777 6672924.7465614835, 2553958.6721354276 6672914.244150877, 2553978.083295185 6672908.722883586, 2554043.2711338615 6672907.632633342, 2554059.4897229327 6672917.074800593, 2554066.1141008693 6672926.416944885, 2554065.3551434968 6672955.5536325965) + +LINESTRING (2553923.430114822 6672945.05122199, 2553943.575483342 6672977.868754562) + +LINESTRING (2554065.3551434968 6672955.5536325965, 2554105.736625441 6672962.695271809, 2554136.8043804974 6672976.648474473) + +LINESTRING (2553943.575483342 6672977.868754562, 2553993.171697734 6672961.66503534, 2554065.3551434968 6672955.5536325965) + +LINESTRING (2553207.576571269 6672316.246893224, 2553198.6258239946 6672295.572147773, 2553104.2841227665 6672154.279717077) + +LINESTRING (2553207.576571269 6672316.246893224, 2553290.179181832 6672173.0340217315) + +LINESTRING (2553078.108342949 6672215.473762878, 2553042.4950931934 6672305.494425222) + +LINESTRING (2553042.4950931934 6672305.494425222, 2552883.7245106613 6672239.799346303) + +LINESTRING (2552708.001130296 6672220.484913082, 2552727.4617872736 6672281.32887853, 2552747.310172474 6672343.373119477) + +LINESTRING (2552883.7245106613 6672239.799346303, 2552850.64386866 6672373.590055137) + +LINESTRING (2553180.9635660085 6672364.467961353, 2553042.4950931934 6672305.494425222) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553207.576571269 6672316.246893224) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553224.133391343 6672354.1956035495, 2553237.8936184896 6672345.463599303, 2553271.7909646197 6672331.730447147) + +LINESTRING (2552850.64386866 6672373.590055137, 2552747.310172474 6672343.373119477) + +LINESTRING (2553361.900653542 6672271.626651589, 2553373.746988184 6672246.000769708, 2553388.9756328557 6672231.9875532705) + +LINESTRING (2553578.599482491 6672290.310940173, 2553499.816407401 6672266.725526639) + +LINESTRING (2553361.900653542 6672271.626651589, 2553429.7530925595 6672314.686535077, 2553444.2970256885 6672322.428312038, 2553455.615389984 6672324.588807935, 2553476.354725144 6672321.208031949, 2553486.146925158 6672313.646296312, 2553500.154638404 6672290.120896553, 2553502.6377489385 6672279.798527271, 2553499.816407401 6672266.725526639) + +LINESTRING (2553271.7909646197 6672331.730447147, 2553309.2603601236 6672316.446939141, 2553351.654729012 6672284.369576459, 2553361.900653542 6672271.626651589) + +LINESTRING (2553271.7909646197 6672331.730447147, 2553277.6316365744 6672344.343342171, 2553285.59243945 6672351.434969905, 2553382.573992409 6672376.150642866) + +LINESTRING (2553578.599482491 6672290.310940173, 2553540.833103668 6672381.091776999, 2553523.071851242 6672407.917934378, 2553505.426092329 6672426.992312498, 2553482.7316169813 6672438.925051407, 2553418.1459944807 6672454.128541047, 2553388.769394439 6672466.181307505) + +LINESTRING (2553388.769394439 6672466.181307505, 2553364.771492299 6672479.764425224, 2553347.34022134 6672495.868121487, 2553314.4080709983 6672538.807977425, 2553314.078089532 6672538.948009566, 2553302.165758597 6672544.049180432) + +LINESTRING (2553309.4995966866 6672526.205084696, 2553300.3673596056 6672508.3609889615) + +LINESTRING (2553388.769394439 6672466.181307505, 2553389.990325865 6672501.109324494, 2553349.3036110643 6672558.85257824, 2553318.409096278 6672569.254965888, 2553299.9218846257 6672575.486396182) + +LINESTRING (2553265.8842963725 6672521.714053876, 2553279.570277689 6672525.154843636, 2553302.165758597 6672544.049180432) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553180.9635660085 6672364.467961353) + +LINESTRING (2553205.5554347876 6672358.11650351, 2553224.11689227 6672386.7130672475) + +LINESTRING (2553224.11689227 6672386.7130672475, 2553180.9635660085 6672364.467961353) + +LINESTRING (2552747.310172474 6672343.373119477, 2552739.555608015 6672439.63521441) + +LINESTRING (2552850.64386866 6672373.590055137, 2552844.266976823 6672450.797776541) + +LINESTRING (2553224.11689227 6672386.7130672475, 2553240.327231804 6672440.575430216) + +LINESTRING (2553180.9635660085 6672364.467961353, 2553140.9945608974 6672433.893896611, 2553137.735993917 6672468.141757485) + +LINESTRING (2553137.735993917 6672468.141757485, 2553122.548596929 6672469.622097266, 2552850.64386866 6672373.590055137) + +LINESTRING (2553240.327231804 6672440.575430216, 2553137.735993917 6672468.141757485) + +LINESTRING (2553240.327231804 6672440.575430216, 2553257.577012957 6672503.50987549, 2553265.8842963725 6672521.714053876) + +LINESTRING (2552739.555608015 6672439.63521441, 2552733.0467235916 6672525.654958427) + +LINESTRING (2552844.266976823 6672450.797776541, 2552837.8075896194 6672534.056886912) + +LINESTRING (2553265.8842963725 6672521.714053876, 2553156.4129449124 6672481.784888978, 2553137.735993917 6672468.141757485) + +LINESTRING (2553149.5493304124 6672557.952371617, 2553078.0671048965 6672532.861995969, 2552950.823014919 6672488.199116582, 2552844.266976823 6672450.797776541) + +LINESTRING (2552837.8075896194 6672534.056886912, 2552787.726166266 6672530.040305593, 2552733.0467235916 6672525.654958427) + +LINESTRING (2552733.0467235916 6672525.654958427, 2552728.443482136 6672593.18045748, 2552716.8776317406 6672731.242146628) + +LINESTRING (2552837.8075896194 6672534.056886912, 2552830.964236457 6672622.610688017, 2552821.9107324784 6672739.764102663) + +LINESTRING (2553015.3458680497 6672745.815491632, 2553064.8595870747 6672720.689724542, 2553141.8855108563 6672701.855401521, 2553171.039373408 6672675.199283171, 2553186.8619847195 6672618.366238344, 2553176.9955388755 6672590.149761848, 2553149.5493304124 6672557.952371617) + +LINESTRING (2552821.9107324784 6672739.764102663, 2552716.8776317406 6672731.242146628) + +LINESTRING (2552821.9107324784 6672739.764102663, 2552820.5495589296 6672756.447932084) + +LINESTRING (2552261.4207128175 6672125.6131372675, 2552225.056755226 6672122.252365874, 2552210.686062367 6672116.801114654, 2552205.5466010286 6672110.759727981, 2552199.210956875 6672085.163852988) + +LINESTRING (2552050.5543062864 6672064.16903407, 2552022.74511821 6672148.888479631) + +LINESTRING (2552267.0221482087 6672090.435062883, 2552261.4207128175 6672125.6131372675) + +LINESTRING (2552487.458017264 6672030.541315537, 2552443.66947668 6672192.648523826) + +LINESTRING (2552360.4316517944 6672117.5012753615, 2552338.5868787225 6672125.783176296, 2552308.7895523114 6672129.944131357, 2552261.4207128175 6672125.6131372675) + +LINESTRING (2552135.6565264566 6672092.005423326, 2552116.3031134554 6672159.020805294) + +LINESTRING (2552568.922191768 6672052.846435207, 2552530.1906171557 6672202.120697964) + +LINESTRING (2552135.6565264566 6672092.005423326, 2552150.8604225186 6672095.106135029, 2552159.3244471303 6672103.238001527, 2552186.6056648605 6672156.870311692, 2552186.1766889542 6672165.952396294) + +LINESTRING (2552665.84599797 6672078.382296425, 2552630.0925060916 6672212.543090205) + +LINESTRING (2552261.4207128175 6672125.6131372675, 2552253.088680792 6672172.793966631) + +LINESTRING (2550945.1988893966 6672062.238590978, 2550905.988841658 6672124.8129536025) + +LINESTRING (2551188.7252115593 6672244.900517169, 2551136.70363339 6672030.9214027785) + +LINESTRING (2550905.988841658 6672124.8129536025, 2550885.983715261 6672158.480681319) + +LINESTRING (2551188.7252115593 6672244.900517169, 2551176.2931598146 6672228.556765806, 2551150.6535998797 6672205.1814004835, 2551035.061092219 6672120.672003135, 2550945.1988893966 6672062.238590978) + +LINESTRING (2550885.983715261 6672158.480681319, 2550859.799685906 6672193.228656984) + +LINESTRING (2550834.0116343116 6672229.256926513, 2550722.7913810797 6672165.142210333, 2550709.979850649 6672163.261778719, 2550702.3490292397 6672166.552534043, 2550687.1781313247 6672187.567357552) + +LINESTRING (2551159.1588721746 6672286.410044805, 2551001.279239602 6672187.047238169, 2550905.988841658 6672124.8129536025) + +LINESTRING (2550834.0116343116 6672229.256926513, 2550859.799685906 6672193.228656984) + +LINESTRING (2550942.872520059 6672249.761632935, 2550859.799685906 6672193.228656984) + +LINESTRING (2550942.872520059 6672249.761632935, 2550926.0434652753 6672273.377053357) + +LINESTRING (2552665.84599797 6672078.382296425, 2552708.001130296 6672220.484913082) + +LINESTRING (2552360.4316517944 6672117.5012753615, 2552400.565647639 6672187.877428723) + +LINESTRING (2552116.3031134554 6672159.020805294, 2552022.74511821 6672148.888479631) + +LINESTRING (2552186.1766889542 6672165.952396294, 2552116.3031134554 6672159.020805294) + +LINESTRING (2552253.088680792 6672172.793966631, 2552186.1766889542 6672165.952396294) + +LINESTRING (2552400.565647639 6672187.877428723, 2552253.088680792 6672172.793966631) + +LINESTRING (2552443.66947668 6672192.648523826, 2552400.565647639 6672187.877428723) + +LINESTRING (2552530.1906171557 6672202.120697964, 2552487.98598761 6672197.139554648, 2552443.66947668 6672192.648523826) + +LINESTRING (2552116.3031134554 6672159.020805294, 2552089.277631362 6672241.849816945) + +LINESTRING (2552630.0925060916 6672212.543090205, 2552530.1906171557 6672202.120697964) + +LINESTRING (2552022.74511821 6672148.888479631, 2552001.873790464 6672212.112991484) + +LINESTRING (2551318.944147716 6672449.857560733, 2551241.8109799577 6672263.934886106, 2551189.7811522516 6672020.549022017) + +LINESTRING (2551318.944147716 6672449.857560733, 2551336.358919602 6672432.703623409, 2551376.443418226 6672068.390002904) + +LINESTRING (2552001.873790464 6672212.112991484, 2551966.2852893183 6672312.3359955605) + +LINESTRING (2551374.3892835984 6672043.314247294, 2551380.0649648197 6672051.496125272, 2551417.1466321 6672056.937374196, 2551426.072630765 6672063.0687815305, 2551429.9004157744 6672071.310673283, 2551382.6965670134 6672509.321209359, 2551355.9928168496 6672543.769116149) + +LINESTRING (2552056.98894488 6672339.2921827845, 2551966.2852893183 6672312.3359955605) + +LINESTRING (2551966.2852893183 6672312.3359955605, 2551946.3131610677 6672357.306317548, 2551931.958967282 6672378.671221412) + +LINESTRING (2552032.2815825874 6672414.099353191, 2551931.958967282 6672378.671221412) + +LINESTRING (2551302.5853165216 6672478.3741061045, 2551292.9663567776 6672469.262014616, 2551260.9499050057 6672387.213182039, 2551229.33768053 6672340.972568481) + +LINESTRING (2551931.958967282 6672378.671221412, 2551873.2635139558 6672421.351017659, 2551849.595593282 6672448.047145191) + +LINESTRING (2552270.379709629 6672251.59205307, 2552183.701827957 6672186.897203732, 2552186.1766889542 6672165.952396294) + +LINESTRING (2552708.001130296 6672220.484913082, 2552630.0925060916 6672212.543090205) + +LINESTRING (2552089.277631362 6672241.849816945, 2552001.873790464 6672212.112991484) + +LINESTRING (2552443.66947668 6672192.648523826, 2552440.7491407027 6672213.753367998, 2552505.9039812325 6672310.61560068, 2552507.9168681772 6672319.74769676) + +LINESTRING (2552222.5653951555 6672317.377152652, 2552144.277292265 6672259.273816257, 2552089.277631362 6672241.849816945) + +LINESTRING (2552270.379709629 6672251.59205307, 2552222.5653951555 6672317.377152652) + +LINESTRING (2552089.277631362 6672241.849816945, 2552056.98894488 6672339.2921827845) + +LINESTRING (2552389.9319948857 6672339.512233292, 2552270.379709629 6672251.59205307) + +LINESTRING (2552443.66947668 6672192.648523826, 2552434.603235892 6672210.672660887, 2552435.131206238 6672218.544467694, 2552484.5789289703 6672314.256436356, 2552493.257441535 6672339.082134572, 2552487.8622445604 6672410.318485373) + +LINESTRING (2552747.310172474 6672343.373119477, 2552507.9168681772 6672319.74769676) + +LINESTRING (2551229.33768053 6672340.972568481, 2551228.2487416905 6672315.8267968, 2551215.453710333 6672284.3195649795, 2551188.7252115593 6672244.900517169) + +LINESTRING (2550841.0979863014 6672371.139492662, 2550768.287575752 6672318.807480953, 2550834.0116343116 6672229.256926513) + +LINESTRING (2551229.33768053 6672340.972568481, 2551159.1588721746 6672286.410044805) + +LINESTRING (2551124.766553845 6672382.372070864, 2550942.872520059 6672249.761632935) + +LINESTRING (2550926.0434652753 6672273.377053357, 2550841.0979863014 6672371.139492662) + +LINESTRING (2551108.061242111 6672405.627408636, 2550926.0434652753 6672273.377053357) + +LINESTRING (2551108.061242111 6672405.627408636, 2551124.766553845 6672382.372070864) + +LINESTRING (2550968.429584627 6672463.97080013, 2550841.0979863014 6672371.139492662) + +LINESTRING (2551280.3115675435 6672498.72877809, 2551249.6480397834 6672471.852609233, 2551124.766553845 6672382.372070864) + +LINESTRING (2550968.429584627 6672463.97080013, 2550922.859144125 6672528.195541564, 2550794.1663722503 6672436.714544032, 2550841.0979863014 6672371.139492662) + +LINESTRING (2552222.5653951555 6672317.377152652, 2552179.7832980435 6672378.541191566) + +LINESTRING (2552179.7832980435 6672378.541191566, 2552056.98894488 6672339.2921827845) + +LINESTRING (2552343.1571220313 6672403.776983909, 2552222.5653951555 6672317.377152652) + +LINESTRING (2552507.9168681772 6672319.74769676, 2552498.9166236827 6672416.219839904) + +LINESTRING (2552389.9319948857 6672339.512233292, 2552343.1571220313 6672403.776983909) + +LINESTRING (2552487.8622445604 6672410.318485373, 2552389.9319948857 6672339.512233292) + +LINESTRING (2552056.98894488 6672339.2921827845, 2552032.2815825874 6672414.099353191) + +LINESTRING (2552498.9166236827 6672416.219839904, 2552487.8622445604 6672410.318485373) + +LINESTRING (2552299.6078180103 6672464.140839159, 2552179.7832980435 6672378.541191566) + +LINESTRING (2552739.555608015 6672439.63521441, 2552498.9166236827 6672416.219839904) + +LINESTRING (2552343.1571220313 6672403.776983909, 2552299.6078180103 6672464.140839159) + +LINESTRING (2552178.768605035 6672482.044948669, 2552135.4420385035 6672451.177863781, 2552032.2815825874 6672414.099353191) + +LINESTRING (2552483.811722061 6672500.92928317, 2552462.948643851 6672493.047474067, 2552343.1571220313 6672403.776983909) + +LINESTRING (2552487.8622445604 6672410.318485373, 2552481.39460782 6672484.615538694, 2552483.811722061 6672500.92928317) + +LINESTRING (2552498.9166236827 6672416.219839904, 2552493.422432268 6672477.253848974, 2552483.811722061 6672500.92928317) + +LINESTRING (2552299.6078180103 6672464.140839159, 2552249.4588846625 6672531.896391016) + +LINESTRING (2552249.4588846625 6672531.896391016, 2552178.768605035 6672482.044948669) + +LINESTRING (2552640.7756560645 6672516.932956476, 2552483.811722061 6672500.92928317) + +LINESTRING (2552437.820555189 6672563.973753698, 2552299.6078180103 6672464.140839159) + +LINESTRING (2552733.0467235916 6672525.654958427, 2552640.7756560645 6672516.932956476) + +LINESTRING (2551327.3586751074 6672469.292021504, 2551318.944147716 6672449.857560733) + +LINESTRING (2551327.3586751074 6672469.292021504, 2551302.5853165216 6672478.3741061045) + +LINESTRING (2551946.024427285 6672514.9625042, 2551849.595593282 6672448.047145191) + +LINESTRING (2551280.3115675435 6672498.72877809, 2551302.5853165216 6672478.3741061045) + +LINESTRING (2551355.9928168496 6672543.769116149, 2551327.3586751074 6672469.292021504) + +LINESTRING (2551849.595593282 6672448.047145191, 2551839.7703951215 6672466.191309801, 2551799.9003844503 6672520.0636750655, 2551797.2440336463 6672528.165534677, 2551800.230365917 6672605.523290517) + +LINESTRING (2552052.253710838 6672642.651812586, 2551976.613709215 6672545.169437564, 2551946.024427285 6672514.9625042) + +LINESTRING (2551562.9076953214 6672521.093911535, 2551522.3364740345 6672575.816471944, 2551463.3192887786 6672655.414742047) + +LINESTRING (2551675.596366078 6672560.723007558, 2551619.8624964124 6672639.221025121) + +LINESTRING (2551414.6140243458 6672657.84529993, 2551389.2219505105 6672629.378766038, 2551355.9928168496 6672543.769116149) + +LINESTRING (2552483.811722061 6672500.92928317, 2552510.4824740784 6672559.752784863) + +LINESTRING (2552483.811722061 6672500.92928317, 2552437.820555189 6672563.973753698) + +LINESTRING (2552178.768605035 6672482.044948669, 2552141.472449801 6672536.617474641, 2552153.3187844427 6672560.252899654, 2552203.3439747407 6672596.1711439295) + +LINESTRING (2552640.7756560645 6672516.932956476, 2552637.005617812 6672559.452715989, 2552630.043008872 6672569.124936043, 2552510.4824740784 6672559.752784863) + +LINESTRING (2552249.4588846625 6672531.896391016, 2552203.3439747407 6672596.1711439295) + +LINESTRING (2552387.3498899117 6672630.489020874, 2552249.4588846625 6672531.896391016) + +LINESTRING (2552510.4824740784 6672559.752784863, 2552518.484524637 6672622.867271462) + +LINESTRING (2552437.820555189 6672563.973753698, 2552398.7095018905 6672619.206431193) + +LINESTRING (2552518.484524637 6672622.867271462, 2552437.820555189 6672563.973753698) + +LINESTRING (2552398.7095018905 6672619.206431193, 2552387.3498899117 6672630.489020874) + +LINESTRING (2551032.5862312214 6672510.751537661, 2551064.701677433 6672466.021270772, 2551073.9576575644 6672453.1283114655, 2551108.061242111 6672405.627408636) + +LINESTRING (2550317.9948667777 6672508.10092927, 2550357.790631619 6672459.869858845, 2550399.5992834046 6672418.320322026, 2550580.9900954547 6672513.142086362) + +LINESTRING (2551032.5862312214 6672510.751537661, 2550968.429584627 6672463.97080013) + +LINESTRING (2550580.9900954547 6672513.142086362, 2550611.983604681 6672531.376271633) + +LINESTRING (2550317.9948667777 6672508.10092927, 2550408.599527899 6672561.513188927) + +LINESTRING (2551022.645539548 6672570.415232203, 2551026.6383152907 6672522.404212287, 2551032.5862312214 6672510.751537661) + +LINESTRING (2550253.879467867 6672593.780595229, 2550268.200663506 6672568.444779928, 2550317.9948667777 6672508.10092927) + +LINESTRING (2551020.7646451895 6672593.250473551, 2551022.645539548 6672570.415232203) + +LINESTRING (2550591.8217370873 6672639.351054966, 2550611.983604681 6672531.376271633) + +LINESTRING (2550848.6793104904 6672658.8755364, 2550854.3137440286 6672591.750129179, 2550611.983604681 6672531.376271633) + +LINESTRING (2550201.123680935 6672664.926925369, 2550192.3956711497 6672662.466360598, 2550186.3236131626 6672660.753192104) + +LINESTRING (2552716.8776317406 6672731.242146628, 2552714.930741089 6672774.342039299) + +LINESTRING (2552820.5495589296 6672756.447932084, 2552924.1307412153 6672763.979660833) + +LINESTRING (2553281.9791423935 6672606.85359586, 2553277.1036662282 6672627.408313762, 2553263.2774427882 6672652.123986724, 2553117.945355473 6672841.277402899, 2553103.302427904 6672864.422715417, 2553080.822440509 6672916.394644477) + +LINESTRING (2553099.4993915046 6672962.855308542, 2553107.575687893 6672931.678152484, 2553127.2673318973 6672894.5896395985, 2553233.8843436735 6672761.339054738, 2553267.4847064842 6672712.667883297, 2553291.820839627 6672670.948307449, 2553306.8844935657 6672626.918201268, 2553317.8811259316 6672579.957422412) + +LINESTRING (2552820.5495589296 6672756.447932084, 2552817.4477331457 6672794.546676847) + +LINESTRING (2552714.930741089 6672774.342039299, 2552714.666755916 6672784.95447516) + +LINESTRING (2553015.3458680497 6672745.815491632, 2553010.6683807643 6672823.043217626) + +LINESTRING (2552817.4477331457 6672794.546676847, 2552714.666755916 6672784.95447516) + +LINESTRING (2552924.1307412153 6672763.979660833, 2552920.7484311853 6672816.4917138675) + +LINESTRING (2552714.666755916 6672784.95447516, 2552710.1872575106 6672835.416057551) + +LINESTRING (2553265.8842963725 6672521.714053876, 2553279.4795327857 6672551.920987239) + +LINESTRING (2553302.165758597 6672544.049180432, 2553279.4795327857 6672551.920987239) + +LINESTRING (2553317.8811259316 6672579.957422412, 2553318.409096278 6672569.254965888, 2553319.2010517973 6672553.201281104, 2553314.078089532 6672538.948009566, 2553309.4995966866 6672526.205084696) + +LINESTRING (2553302.165758597 6672544.049180432, 2553306.0677894363 6672556.502038723, 2553299.9218846257 6672575.486396182) + +LINESTRING (2553279.4795327857 6672551.920987239, 2553283.6702974085 6672585.738749393) + +LINESTRING (2553299.9218846257 6672575.486396182, 2553283.6702974085 6672585.738749393) + +LINESTRING (2553299.9218846257 6672575.486396182, 2553290.7566493982 6672596.851300045, 2553281.9791423935 6672606.85359586) + +LINESTRING (2553283.6702974085 6672585.738749393, 2553281.9791423935 6672606.85359586) + +LINESTRING (2553766.004206765 6673008.675825675, 2553881.6792097925 6672937.079392225) + +LINESTRING (2553766.004206765 6673008.675825675, 2553777.2400756944 6673026.169841057) + +LINESTRING (2554121.295251579 6673000.804018868, 2554124.149591263 6672992.832189103, 2554136.8043804974 6672976.648474473) + +LINESTRING (2554136.8043804974 6672976.648474473, 2554199.8968368624 6673020.008426835) + +LINESTRING (2553943.575483342 6672977.868754562, 2553960.9655066184 6673004.774930307, 2553978.339030822 6673032.391269054) + +LINESTRING (2553805.0740123806 6673063.04830573, 2553911.3857913003 6672994.122485262, 2553943.575483342 6672977.868754562) + +LINESTRING (2554121.295251579 6673000.804018868, 2554186.6315819155 6673045.404255911) + +LINESTRING (2554049.235548866 6673047.824811499, 2554121.295251579 6673000.804018868) + +LINESTRING (2554199.8968368624 6673020.008426835, 2554186.6315819155 6673045.404255911) + +LINESTRING (2554199.8968368624 6673020.008426835, 2554280.189577161 6673075.421145655) + +LINESTRING (2554186.6315819155 6673045.404255911, 2554164.2258403506 6673085.173384075) + +LINESTRING (2554049.235548866 6673047.824811499, 2554070.6100983485 6673083.382973124, 2554139.3122396413 6673072.140392628, 2554164.2258403506 6673085.173384075) + +LINESTRING (2553777.2400756944 6673026.169841057, 2553796.700732672 6673056.456792788, 2553805.0740123806 6673063.04830573) + +LINESTRING (2553634.0281193005 6673094.815597242, 2553650.980917134 6673081.342504778, 2553766.004206765 6673008.675825675) + +LINESTRING (2553777.2400756944 6673026.169841057, 2553645.173243326 6673111.869511608) + +LINESTRING (2553805.0740123806 6673063.04830573, 2553824.567667505 6673093.225232207) + +LINESTRING (2553634.0281193005 6673094.815597242, 2553645.173243326 6673111.869511608) + +LINESTRING (2553824.567667505 6673093.225232207, 2553841.6277093147 6673119.391238062) + +LINESTRING (2553670.9777939944 6673151.3385708975, 2553805.0740123806 6673063.04830573) + +LINESTRING (2553645.173243326 6673111.869511608, 2553670.9777939944 6673151.3385708975) + +LINESTRING (2553690.9416727084 6673181.575511149, 2553824.567667505 6673093.225232207) + +LINESTRING (2553532.6743119126 6673185.456401926, 2553521.784923523 6673168.482505926, 2553634.0281193005 6673094.815597242) + +LINESTRING (2554186.6315819155 6673045.404255911, 2554266.635588431 6673100.146820912) + +LINESTRING (2553841.6277093147 6673119.391238062, 2553978.339030822 6673032.391269054) + +LINESTRING (2553933.3460578853 6673124.282360716, 2553953.829657409 6673110.059096065, 2554049.235548866 6673047.824811499) + +LINESTRING (2554280.189577161 6673075.421145655, 2554266.635588431 6673100.146820912) + +LINESTRING (2554280.189577161 6673075.421145655, 2554361.727997495 6673132.004133086) + +LINESTRING (2553841.6277093147 6673119.391238062, 2553846.4701873334 6673125.522645397, 2553901.791580166 6673127.503099969, 2553933.3460578853 6673124.282360716) + +LINESTRING (2554164.2258403506 6673085.173384075, 2554199.1873767097 6673104.997934382, 2554179.3967382656 6673142.466534509, 2554229.141444317 6673170.67300871) + +LINESTRING (2554164.2258403506 6673085.173384075, 2554117.6819545226 6673171.423180896) + +LINESTRING (2554266.635588431 6673100.146820912, 2554348.165759228 6673156.739810638) + +LINESTRING (2554266.635588431 6673100.146820912, 2554229.141444317 6673170.67300871) + +LINESTRING (2554361.727997495 6673132.004133086, 2554348.165759228 6673156.739810638) + +LINESTRING (2554361.727997495 6673132.004133086, 2554427.1468231976 6673177.164498694) + +LINESTRING (2554117.6819545226 6673171.423180896, 2554115.636069431 6673175.21405101) + +LINESTRING (2553933.3460578853 6673124.282360716, 2553929.732760829 6673152.818910679, 2553941.0511251246 6673227.276000733) + +LINESTRING (2554348.165759228 6673156.739810638, 2554413.601084004 6673201.910178543) + +LINESTRING (2554427.1468231976 6673177.164498694, 2554452.00267715 6673194.558491118) + +LINESTRING (2554348.165759228 6673156.739810638, 2554314.8953778837 6673219.284166375) + +LINESTRING (2554427.1468231976 6673177.164498694, 2554413.601084004 6673201.910178543) + +LINESTRING (2554229.141444317 6673170.67300871, 2554314.8953778837 6673219.284166375) + +LINESTRING (2554229.141444317 6673170.67300871, 2554201.9262228804 6673221.8547564) + +LINESTRING (2553645.173243326 6673111.869511608, 2553541.649807797 6673179.044930308) + +LINESTRING (2553707.4902432454 6673207.421443538, 2553841.6277093147 6673119.391238062) + +LINESTRING (2553670.9777939944 6673151.3385708975, 2553690.9416727084 6673181.575511149) + +LINESTRING (2553557.5136667914 6673231.256914468, 2553565.499218277 6673219.764276574, 2553670.9777939944 6673151.3385708975) + +LINESTRING (2553690.9416727084 6673181.575511149, 2553707.4902432454 6673207.421443538) + +LINESTRING (2553532.6743119126 6673185.456401926, 2553555.352288187 6673221.024565848, 2553557.5136667914 6673231.256914468) + +LINESTRING (2553707.4902432454 6673207.421443538, 2553711.3592759385 6673214.263013876, 2553785.2338767163 6673218.283936794) + +LINESTRING (2553785.2338767163 6673218.283936794, 2553941.0511251246 6673227.276000733) + +LINESTRING (2553350.22755917 6673302.153187211, 2553415.7866269965 6673260.363595292, 2553532.6743119126 6673185.456401926) + +LINESTRING (2553594.125110483 6673282.258620833, 2553707.4902432454 6673207.421443538) + +LINESTRING (2554115.636069431 6673175.21405101, 2554201.9262228804 6673221.8547564) + +LINESTRING (2554452.00267715 6673194.558491118, 2554459.6005004128 6673182.305678744, 2554569.0553527996 6673247.020532673) + +LINESTRING (2554115.636069431 6673175.21405101, 2554061.725347367 6673270.4559117695) + +LINESTRING (2554413.601084004 6673201.910178543, 2554383.251038637 6673258.043062663) + +LINESTRING (2554314.8953778837 6673219.284166375, 2554383.251038637 6673258.043062663) + +LINESTRING (2554314.8953778837 6673219.284166375, 2554289.3300637784 6673267.365202363) + +LINESTRING (2554201.9262228804 6673221.8547564, 2554289.3300637784 6673267.365202363) + +LINESTRING (2553941.0511251246 6673227.276000733, 2553933.329558812 6673324.638348205) + +LINESTRING (2554413.601084004 6673201.910178543, 2554438.489936103 6673219.214150305, 2554482.8311956436 6673273.916706122, 2554440.9317989545 6673360.586599368) + +LINESTRING (2554383.251038637 6673258.043062663, 2554358.0404546084 6673304.683768053) + +LINESTRING (2553557.5136667914 6673231.256914468, 2553594.125110483 6673282.258620833) + +LINESTRING (2553785.2338767163 6673218.283936794, 2553780.1521621346 6673315.01613963) + +LINESTRING (2553373.384008571 6673347.723646948, 2553377.95425188 6673345.213070698, 2553557.5136667914 6673231.256914468) + +LINESTRING (2553594.125110483 6673282.258620833, 2553609.6342394007 6673306.284135383) + +LINESTRING (2553328.457031928 6673316.036373803, 2553350.22755917 6673302.153187211) + +LINESTRING (2553609.6342394007 6673306.284135383, 2553780.1521621346 6673315.01613963) + +LINESTRING (2553780.1521621346 6673315.01613963, 2553933.329558812 6673324.638348205) + +LINESTRING (2553315.5877547404 6673324.248258668, 2553328.457031928 6673316.036373803) + +LINESTRING (2553609.6342394007 6673306.284135383, 2553635.9420118053 6673348.1437433725) + +LINESTRING (2553290.806146618 6673314.916116672, 2553302.9907122627 6673328.169158628, 2553302.866969213 6673339.621787338, 2553299.34441706 6673391.583714101) + +LINESTRING (2551364.7703238544 6672731.342169586, 2551354.7636358873 6672659.835756798, 2551338.1655681306 6672600.862220667, 2551303.789748874 6672527.155302799, 2551280.3115675435 6672498.72877809) + +LINESTRING (2551463.3192887786 6672655.414742047, 2551445.2198053496 6672682.380931567) + +LINESTRING (2551445.2198053496 6672682.380931567, 2551414.6140243458 6672657.84529993) + +LINESTRING (2551619.8624964124 6672639.221025121, 2551565.234064659 6672717.038886569, 2551560.8783093034 6672723.220305383) + +LINESTRING (2551560.8783093034 6672723.220305383, 2551463.3192887786 6672655.414742047) + +LINESTRING (2552049.0941382977 6672646.4926941795, 2551986.7936374517 6672734.5429042475) + +LINESTRING (2551223.793991895 6672702.8256242145, 2551257.5428463654 6672705.786303776, 2551259.7454726533 6672681.020619336) + +LINESTRING (2551898.243110958 6672671.248376324, 2551869.584220606 6672709.9872680195, 2551852.7964135054 6672722.820213551, 2551814.8402953395 6672778.893083896) + +LINESTRING (2551445.2198053496 6672682.380931567, 2551422.2695943653 6672714.018193233, 2551410.9264814593 6672738.213746811, 2551404.1536118626 6672792.616233755) + +LINESTRING (2551217.6480870843 6672787.2850100845, 2551223.793991895 6672702.8256242145) + +LINESTRING (2551019.5107156173 6672608.303928754, 2551020.7646451895 6672593.250473551) + +LINESTRING (2551127.200167159 6672617.045935297, 2551019.5107156173 6672608.303928754) + +LINESTRING (2550698.306756277 6672645.982577093, 2550602.612131037 6672640.021208786, 2550591.8217370873 6672639.351054966) + +LINESTRING (2551013.0513284137 6672686.051774131, 2551019.5107156173 6672608.303928754) + +LINESTRING (2551259.7454726533 6672681.020619336, 2551264.447708549 6672628.208497427, 2551127.200167159 6672617.045935297) + +LINESTRING (2550253.879467867 6672593.780595229, 2550350.6960300924 6672625.367845416, 2550359.91076254 6672651.313800762, 2550343.865413739 6672709.737210624) + +LINESTRING (2550848.6793104904 6672658.8755364, 2550759.0233460846 6672651.183770917, 2550698.306756277 6672645.982577093) + +LINESTRING (2551121.9534618445 6672693.903576347, 2551127.200167159 6672617.045935297) + +LINESTRING (2550330.047439836 6672702.395525495, 2550210.858134192 6672667.677556718) + +LINESTRING (2550574.0522351246 6672733.982775682, 2550591.8217370873 6672639.351054966) + +LINESTRING (2552518.484524637 6672622.867271462, 2552520.4974115817 6672638.460850639) + +LINESTRING (2552052.253710838 6672642.651812586, 2552049.0941382977 6672646.4926941795) + +LINESTRING (2552341.7794494093 6672696.104081427, 2552203.3439747407 6672596.1711439295) + +LINESTRING (2552203.3439747407 6672596.1711439295, 2552125.790080613 6672703.615805584) + +LINESTRING (2552387.3498899117 6672630.489020874, 2552341.7794494093 6672696.104081427) + +LINESTRING (2552526.3050853894 6672709.167079763, 2552398.7095018905 6672619.206431193) + +LINESTRING (2552125.790080613 6672703.615805584, 2552058.515109162 6672648.903247471, 2552052.253710838 6672642.651812586) + +LINESTRING (2552520.4974115817 6672638.460850639, 2552526.3050853894 6672709.167079763) + +LINESTRING (2552686.56058452 6672754.707532612, 2552520.4974115817 6672638.460850639) + +LINESTRING (2552471.2311786567 6672787.425042226, 2552341.7794494093 6672696.104081427) + +LINESTRING (2550591.8217370873 6672639.351054966, 2550599.9805288427 6672638.240800131, 2550602.612131037 6672640.021208786, 2550605.8789475537 6672642.231716162, 2550606.4316665097 6672647.732978861, 2550592.003226894 6672735.4731177585) + +LINESTRING (2551121.9534618445 6672693.903576347, 2551013.0513284137 6672686.051774131) + +LINESTRING (2550691.5338866804 6672743.7150095105, 2550698.306756277 6672645.982577093) + +LINESTRING (2551223.793991895 6672702.8256242145, 2551121.9534618445 6672693.903576347) + +LINESTRING (2550343.865413739 6672709.737210624, 2550330.047439836 6672702.395525495) + +LINESTRING (2550839.241840553 6672755.957819589, 2550848.6793104904 6672658.8755364) + +LINESTRING (2550348.5181524144 6672712.20777769, 2550343.865413739 6672709.737210624) + +LINESTRING (2551005.1565218316 6672769.690971744, 2551013.0513284137 6672686.051774131) + +LINESTRING (2550592.003226894 6672735.4731177585, 2550574.0522351246 6672733.982775682) + +LINESTRING (2551115.9395496203 6672778.863077007, 2551121.9534618445 6672693.903576347) + +LINESTRING (2552125.790080613 6672703.615805584, 2552065.320976905 6672790.54575852) + +LINESTRING (2552526.3050853894 6672709.167079763, 2552471.2311786567 6672787.425042226) + +LINESTRING (2552341.7794494093 6672696.104081427, 2552264.671030261 6672803.6187591525) + +LINESTRING (2552264.671030261 6672803.6187591525, 2552125.790080613 6672703.615805584) + +LINESTRING (2552655.97130259 6672798.9676915975, 2552526.3050853894 6672709.167079763) + +LINESTRING (2552714.930741089 6672774.342039299, 2552686.56058452 6672754.707532612) + +LINESTRING (2552686.56058452 6672754.707532612, 2552655.97130259 6672798.9676915975) + +LINESTRING (2552710.1872575106 6672835.416057551, 2552655.97130259 6672798.9676915975) + +LINESTRING (2552599.255738062 6672877.725768852, 2552471.2311786567 6672787.425042226) + +LINESTRING (2552655.97130259 6672798.9676915975, 2552599.255738062 6672877.725768852) + +LINESTRING (2550691.5338866804 6672743.7150095105, 2550592.003226894 6672735.4731177585) + +LINESTRING (2550420.9243356674 6672772.641649011, 2550362.7733517606 6672722.400117126, 2550348.5181524144 6672712.20777769) + +LINESTRING (2550574.0522351246 6672733.982775682, 2550466.775260416 6672725.760888521, 2550455.6218868536 6672731.802275194, 2550424.3313943073 6672768.740753642) + +LINESTRING (2550839.241840553 6672755.957819589, 2550691.5338866804 6672743.7150095105) + +LINESTRING (2551005.1565218316 6672769.690971744, 2550953.1679418087 6672765.389984543, 2550839.241840553 6672755.957819589) + +LINESTRING (2550424.3313943073 6672768.740753642, 2550421.0645777904 6672772.481612277) + +LINESTRING (2550421.0645777904 6672772.481612277, 2550420.9243356674 6672772.641649011) + +LINESTRING (2551115.9395496203 6672778.863077007, 2551005.1565218316 6672769.690971744) + +LINESTRING (2551217.6480870843 6672787.2850100845, 2551115.9395496203 6672778.863077007) + +LINESTRING (2550343.865413739 6672709.737210624, 2550337.3730283887 6672735.0830282215, 2550326.7971223923 6672754.117397159, 2550231.5479721315 6672874.485025008) + +LINESTRING (2551814.8402953395 6672778.893083896, 2551733.574109715 6672719.2894031275) + +LINESTRING (2551733.574109715 6672719.2894031275, 2551671.7025847756 6672805.259135666) + +LINESTRING (2551671.7025847756 6672805.259135666, 2551560.8783093034 6672723.220305383) + +LINESTRING (2551826.9588646907 6672789.355485318, 2551814.8402953395 6672778.893083896) + +LINESTRING (2551326.104745535 6672791.0058641285, 2551288.899335205 6672793.17636232, 2551217.6480870843 6672787.2850100845) + +LINESTRING (2551630.2239144556 6672865.68300469, 2551518.434443195 6672784.574387918, 2551458.0890825368 6672869.863964342) + +LINESTRING (2551404.1536118626 6672792.616233755, 2551406.587225177 6672821.662900805, 2551411.949424005 6672836.316264175, 2551458.0890825368 6672869.863964342) + +LINESTRING (2551826.9588646907 6672789.355485318, 2551768.7088863445 6672875.395233927) + +LINESTRING (2551671.7025847756 6672805.259135666, 2551630.2239144556 6672865.68300469) + +LINESTRING (2551768.7088863445 6672875.395233927, 2551671.7025847756 6672805.259135666) + +LINESTRING (2550488.116811752 6672823.123235993, 2550464.160157295 6672807.159571871, 2550420.9243356674 6672772.641649011) + +LINESTRING (2550583.902181895 6672856.730949935, 2550538.711220079 6672846.538610498, 2550506.7607646002 6672835.546087396, 2550488.116811752 6672823.123235993) + +LINESTRING (2550583.3164647925 6672862.86235727, 2550583.902181895 6672856.730949935) + +LINESTRING (2550700.913609861 6672866.723243455, 2550583.902181895 6672856.730949935) + +LINESTRING (2550700.913609861 6672866.723243455, 2550700.550630248 6672872.334531408) + +LINESTRING (2550488.116811752 6672823.123235993, 2550582.7142486162 6672922.015934725) + +LINESTRING (2550832.7989524226 6672878.625975476, 2550700.913609861 6672866.723243455) + +LINESTRING (2551018.1247934587 6672888.988353942, 2551006.2619597437 6672888.91833787) + +LINESTRING (2551073.289445095 6672891.4089095285, 2551050.693964187 6672889.168395266, 2551018.1247934587 6672888.988353942) + +LINESTRING (2550583.3164647925 6672862.86235727, 2550579.9589033723 6672898.080440838, 2550582.7142486162 6672922.015934725) + +LINESTRING (2553010.6683807643 6672823.043217626, 2552920.7484311853 6672816.4917138675) + +LINESTRING (2553076.243947664 6672827.414220898, 2553010.6683807643 6672823.043217626) + +LINESTRING (2552817.4477331457 6672794.546676847, 2552810.485124206 6672890.968808513) + +LINESTRING (2552710.1872575106 6672835.416057551, 2552706.5574613805 6672882.976974156) + +LINESTRING (2553076.243947664 6672827.414220898, 2553070.947745129 6672902.731508393, 2553080.822440509 6672916.394644477) + +LINESTRING (2552920.7484311853 6672816.4917138675, 2552911.063475148 6672951.98281299) + +LINESTRING (2552810.485124206 6672890.968808513, 2552706.5574613805 6672882.976974156) + +LINESTRING (2553010.6683807643 6672823.043217626, 2553001.2886575833 6672957.1539999265) + +LINESTRING (2552810.485124206 6672890.968808513, 2552808.521734481 6672946.281504375) + +LINESTRING (2553080.822440509 6672916.394644477, 2553069.644318337 6672961.244938916) + +LINESTRING (2551983.931048231 6672903.211618591, 2551826.9588646907 6672789.355485318) + +LINESTRING (2552065.320976905 6672790.54575852, 2551983.931048231 6672903.211618591) + +LINESTRING (2551725.456565643 6672934.608825157, 2551630.2239144556 6672865.68300469) + +LINESTRING (2551768.7088863445 6672875.395233927, 2551725.456565643 6672934.608825157) + +LINESTRING (2551519.869862573 6672942.42061819, 2551528.4658797714 6672922.285996713, 2551458.0890825368 6672869.863964342) + +LINESTRING (2551630.2239144556 6672865.68300469, 2551565.597044272 6672958.694353483) + +LINESTRING (2551428.9187209117 6672931.848191513, 2551321.592248983 6672912.583769771, 2551303.7237525806 6672909.38303511) + +LINESTRING (2551923.44544545 6672987.520970024, 2551768.7088863445 6672875.395233927) + +LINESTRING (2551519.869862573 6672942.42061819, 2551428.9187209117 6672931.848191513) + +LINESTRING (2551983.931048231 6672903.211618591, 2551923.44544545 6672987.520970024) + +LINESTRING (2552471.2311786567 6672787.425042226, 2552393.388550746 6672896.21001152) + +LINESTRING (2552264.671030261 6672803.6187591525, 2552203.5997103774 6672890.538709792) + +LINESTRING (2552393.388550746 6672896.21001152, 2552264.671030261 6672803.6187591525) + +LINESTRING (2552706.5574613805 6672882.976974156, 2552599.255738062 6672877.725768852) + +LINESTRING (2552599.255738062 6672877.725768852, 2552521.487355981 6672986.790802429) + +LINESTRING (2552393.388550746 6672896.21001152, 2552330.7745675067 6672982.3197762) + +LINESTRING (2552521.487355981 6672986.790802429, 2552393.388550746 6672896.21001152) + +LINESTRING (2552203.5997103774 6672890.538709792, 2552122.746001586 6673002.154328803) + +LINESTRING (2552122.746001586 6673002.154328803, 2551983.931048231 6672903.211618591) + +LINESTRING (2552599.255738062 6672877.725768852, 2552579.465099618 6673027.760206092) + +LINESTRING (2551073.289445095 6672891.4089095285, 2551059.8921975615 6672896.0199679) + +LINESTRING (2550700.550630248 6672872.334531408, 2550697.168320218 6672918.5151311895) + +LINESTRING (2551303.7237525806 6672909.38303511, 2551073.289445095 6672891.4089095285) + +LINESTRING (2551059.8921975615 6672896.0199679, 2550992.7162205502 6672922.8861344615, 2550967.9676105743 6672935.599052443, 2550937.0813453244 6672957.334041252) + +LINESTRING (2550815.9781471756 6672914.404187609, 2550828.5009438237 6672934.278749396, 2550852.053370984 6672955.323579793) + +LINESTRING (2550697.168320218 6672918.5151311895, 2550657.999520163 6672973.347716853) + +LINESTRING (2550582.7142486162 6672922.015934725, 2550589.2643807232 6672929.837730054, 2550647.398865557 6672972.077425284, 2550657.999520163 6672973.347716853) + +LINESTRING (2550792.821697775 6672954.823465002, 2550821.6620779335 6672950.57248928, 2550852.053370984 6672955.323579793) + +LINESTRING (2550852.053370984 6672955.323579793, 2550885.084515765 6672967.196304926, 2550914.815845883 6672972.847602062) + +LINESTRING (2550852.053370984 6672955.323579793, 2550859.1149743637 6672960.734821829, 2550867.2655165824 6672976.258384936, 2550869.4433942605 6673004.914962448) + +LINESTRING (2552706.5574613805 6672882.976974156, 2552692.5414985977 6673061.627979725) + +LINESTRING (2552579.465099618 6673027.760206092, 2552521.487355981 6672986.790802429) + +LINESTRING (2552521.487355981 6672986.790802429, 2552459.211603745 6673074.480929848) + +LINESTRING (2552330.7745675067 6672982.3197762, 2552250.077599912 6673094.855606426) + +LINESTRING (2552579.465099618 6673027.760206092, 2552578.499903829 6673039.14281873, 2552576.7427525204 6673055.246514994) + +LINESTRING (2552122.746001586 6673002.154328803, 2552061.534439579 6673087.613944255) + +LINESTRING (2552250.077599912 6673094.855606426, 2552122.746001586 6673002.154328803) + +LINESTRING (2552582.5586758647 6673055.516576981, 2552576.7427525204 6673055.246514994) + +LINESTRING (2552692.5414985977 6673061.627979725, 2552582.5586758647 6673055.516576981) + +LINESTRING (2552692.5414985977 6673061.627979725, 2552692.162019911 6673088.934247302) + +LINESTRING (2552849.2414474282 6672948.622041596, 2552808.521734481 6672946.281504375) + +LINESTRING (2552911.063475148 6672951.98281299, 2552849.2414474282 6672948.622041596) + +LINESTRING (2553001.2886575833 6672957.1539999265, 2552911.063475148 6672951.98281299) + +LINESTRING (2553069.644318337 6672961.244938916, 2553001.2886575833 6672957.1539999265) + +LINESTRING (2553099.4993915046 6672962.855308542, 2553069.644318337 6672961.244938916) + +LINESTRING (2552808.521734481 6672946.281504375, 2552800.2309501395 6673040.093036833) + +LINESTRING (2552849.2414474282 6672948.622041596, 2552841.9571065586 6673043.233757719) + +LINESTRING (2552911.063475148 6672951.98281299, 2552904.6453356277 6673047.974845936) + +LINESTRING (2553001.2886575833 6672957.1539999265, 2552994.8622685266 6673053.926211947) + +LINESTRING (2553069.644318337 6672961.244938916, 2553064.4636093155 6673023.979338273, 2553058.119715625 6673058.3372244015) + +LINESTRING (2551565.597044272 6672958.694353483, 2551519.869862573 6672942.42061819) + +LINESTRING (2551612.3884162 6672988.061093998, 2551565.597044272 6672958.694353483) + +LINESTRING (2551725.456565643 6672934.608825157, 2551661.514407002 6673021.638801052) + +LINESTRING (2551878.6422118573 6673047.834813794, 2551725.456565643 6672934.608825157) + +LINESTRING (2551661.514407002 6673021.638801052, 2551612.3884162 6672988.061093998) + +LINESTRING (2551923.44544545 6672987.520970024, 2551878.6422118573 6673047.834813794) + +LINESTRING (2552061.534439579 6673087.613944255, 2551923.44544545 6672987.520970024) + +LINESTRING (2551325.197296503 6672931.528118047, 2551327.4741686205 6672946.5315617705, 2551311.15658511 6673112.779720527, 2551314.926623363 6673157.730037924) + +LINESTRING (2551825.407951799 6673124.782475507, 2551801.1295654126 6673120.011380402, 2551661.514407002 6673021.638801052) + +LINESTRING (2551949.7779664644 6673099.606696938, 2551878.6422118573 6673047.834813794) + +LINESTRING (2551612.3884162 6672988.061093998, 2551655.096267482 6673173.833734188) + +LINESTRING (2551878.6422118573 6673047.834813794, 2551825.407951799 6673124.782475507) + +LINESTRING (2551949.7779664644 6673099.606696938, 2551845.421327733 6673126.922966811) + +LINESTRING (2552016.7147069126 6673148.767980873, 2551949.7779664644 6673099.606696938) + +LINESTRING (2551538.4973163484 6673054.476338216, 2551573.186617998 6673194.328438315) + +LINESTRING (2551845.421327733 6673126.922966811, 2551825.407951799 6673124.782475507) + +LINESTRING (2551538.4973163484 6673054.476338216, 2551467.823535794 6673072.66051201, 2551502.2900999538 6673211.672419259) + +LINESTRING (2551825.407951799 6673124.782475507, 2551804.2396407328 6673136.3051202865, 2551655.096267482 6673173.833734188) + +LINESTRING (2551845.421327733 6673126.922966811, 2551871.4321168177 6673231.22690758) + +LINESTRING (2552016.7147069126 6673148.767980873, 2551969.535606762 6673214.333029946) + +LINESTRING (2552576.7427525204 6673055.246514994, 2552568.979938525 6673125.642672947, 2552559.517719977 6673146.45745054) + +LINESTRING (2552289.78261985 6673123.612206896, 2552250.077599912 6673094.855606426) + +LINESTRING (2552061.534439579 6673087.613944255, 2552016.7147069126 6673148.767980873) + +LINESTRING (2552459.211603745 6673074.480929848, 2552378.5476342966 6673187.666909302) + +LINESTRING (2552188.3380675586 6673180.105173664, 2552061.534439579 6673087.613944255) + +LINESTRING (2552250.077599912 6673094.855606426, 2552188.3380675586 6673180.105173664) + +LINESTRING (2552338.562130112 6673159.190373113, 2552289.78261985 6673123.612206896) + +LINESTRING (2552559.517719977 6673146.45745054, 2552554.469003542 6673143.706819191) + +LINESTRING (2552565.003661855 6673149.448136989, 2552559.517719977 6673146.45745054) + +LINESTRING (2552692.162019911 6673088.934247302, 2552681.874847698 6673207.531468792) + +LINESTRING (2552841.9571065586 6673043.233757719, 2552800.2309501395 6673040.093036833) + +LINESTRING (2552904.6453356277 6673047.974845936, 2552841.9571065586 6673043.233757719) + +LINESTRING (2552994.8622685266 6673053.926211947, 2552904.6453356277 6673047.974845936) + +LINESTRING (2553058.119715625 6673058.3372244015, 2552994.8622685266 6673053.926211947) + +LINESTRING (2552800.2309501395 6673040.093036833, 2552796.015436907 6673098.0563410865) + +LINESTRING (2552796.015436907 6673098.0563410865, 2552692.162019911 6673088.934247302) + +LINESTRING (2552904.6453356277 6673047.974845936, 2552892.741254229 6673220.99455896) + +LINESTRING (2552994.8622685266 6673053.926211947, 2552983.1231778613 6673226.425805588) + +LINESTRING (2553058.119715625 6673058.3372244015, 2553059.7036266634 6673072.410454614, 2553050.2414081157 6673236.108027938) + +LINESTRING (2552796.015436907 6673098.0563410865, 2552788.4341127174 6673214.002954185) + +LINESTRING (2552338.562130112 6673159.190373113, 2552312.8235757374 6673194.928576063, 2552264.5060395277 6673160.330634836, 2552289.78261985 6673123.612206896) + +LINESTRING (2552378.5476342966 6673187.666909302, 2552338.562130112 6673159.190373113) + +LINESTRING (2552146.09219033 6673240.589056464, 2552016.7147069126 6673148.767980873) + +LINESTRING (2552188.3380675586 6673180.105173664, 2552146.09219033 6673240.589056464) + +LINESTRING (2552468.145851946 6673251.841639256, 2552378.5476342966 6673187.666909302) + +LINESTRING (2552318.9612310114 6673271.776214818, 2552188.3380675586 6673180.105173664) + +LINESTRING (2552378.5476342966 6673187.666909302, 2552318.9612310114 6673271.776214818) + +LINESTRING (2552681.874847698 6673207.531468792, 2552680.1661104076 6673242.622698407, 2552678.434790911 6673278.177684139) + +LINESTRING (2552473.318311431 6673253.912114491, 2552468.145851946 6673251.841639256) + +LINESTRING (2552478.6805102592 6673256.062608091, 2552473.318311431 6673253.912114491) + +LINESTRING (2551655.096267482 6673173.833734188, 2551573.186617998 6673194.328438315) + +LINESTRING (2551314.926623363 6673157.730037924, 2551319.1091384487 6673194.168401582, 2551312.9137364184 6673244.529961015) + +LINESTRING (2551573.186617998 6673194.328438315, 2551502.2900999538 6673211.672419259) + +LINESTRING (2551655.096267482 6673173.833734188, 2551675.6128651514 6673254.372220098) + +LINESTRING (2551502.2900999538 6673211.672419259, 2551448.1896385467 6673225.065493357) + +LINESTRING (2551969.535606762 6673214.333029946, 2551953.028283908 6673208.571707557, 2551871.4321168177 6673231.22690758) + +LINESTRING (2551448.1896385467 6673225.065493357, 2551444.196862804 6673225.965699981) + +LINESTRING (2551969.535606762 6673214.333029946, 2551949.8274636846 6673239.518810811) + +LINESTRING (2551444.196862804 6673225.965699981, 2551433.3982193177 6673228.386255568) + +LINESTRING (2551433.3982193177 6673228.386255568, 2551424.051494283 6673230.496739985) + +LINESTRING (2551871.4321168177 6673231.22690758, 2551832.205570006 6673236.458108292) + +LINESTRING (2551949.8274636846 6673239.518810811, 2551928.378668372 6673231.466962679, 2551871.4321168177 6673231.22690758) + +LINESTRING (2551871.4321168177 6673231.22690758, 2551880.2013742854 6673268.035356183) + +LINESTRING (2551424.051494283 6673230.496739985, 2551388.8424718245 6673240.47903121, 2551388.174259355 6673250.431315547, 2551397.3229955095 6673270.465914066) + +LINESTRING (2551424.051494283 6673230.496739985, 2551411.6689397586 6673254.942350959, 2551397.3229955095 6673270.465914066) + +LINESTRING (2551832.205570006 6673236.458108292, 2551686.7332405676 6673273.27655919) + +LINESTRING (2551949.8274636846 6673239.518810811, 2551919.6341595137 6673281.248388955) + +LINESTRING (2551379.2647597636 6673289.070184284, 2551346.2583635924 6673254.562263719, 2551328.051636187 6673245.920280133, 2551312.9137364184 6673244.529961015) + +LINESTRING (2551487.0284571354 6673323.158008425, 2551456.760907135 6673262.224022313, 2551448.1896385467 6673225.065493357) + +LINESTRING (2551686.7332405676 6673273.27655919, 2551680.8183227833 6673274.816912746, 2551676.5285637206 6673275.937169877) + +LINESTRING (2551919.6341595137 6673281.248388955, 2551890.1090678126 6673280.268163965, 2551880.2013742854 6673268.035356183) + +LINESTRING (2551397.3229955095 6673270.465914066, 2551379.2647597636 6673289.070184284) + +LINESTRING (2552080.145394281 6673330.999808344, 2552006.798763849 6673277.947631336, 2551949.8274636846 6673239.518810811) + +LINESTRING (2551871.4321168177 6673231.22690758, 2551844.225144917 6673251.511563495, 2551789.984441387 6673311.995446294, 2551764.122143962 6673339.771821775) + +LINESTRING (2551880.2013742854 6673268.035356183, 2551892.3364427104 6673318.977048773) + +LINESTRING (2551676.5285637206 6673275.937169877, 2551487.0284571354 6673323.158008425) + +LINESTRING (2551919.6341595137 6673281.248388955, 2551892.3364427104 6673318.977048773) + +LINESTRING (2551764.122143962 6673339.771821775, 2551699.338532582 6673290.820586051, 2551690.173297354 6673282.138593283, 2551686.7332405676 6673273.27655919) + +LINESTRING (2551422.005609192 6673330.089599425, 2551379.2647597636 6673289.070184284) + +LINESTRING (2551755.715866107 6673348.653860459, 2551695.9644720885 6673304.323685403, 2551680.042866337 6673285.9894771725, 2551676.5285637206 6673275.937169877) + +LINESTRING (2552892.741254229 6673220.99455896, 2552890.7744802726 6673256.709769484, 2552888.7732270965 6673293.051098018) + +LINESTRING (2552983.1231778613 6673226.425805588, 2552980.989947268 6673262.500561615, 2552978.882916019 6673298.132264293) + +LINESTRING (2552782.3212060533 6673285.5993876355, 2552678.434790911 6673278.177684139) + +LINESTRING (2552888.7732270965 6673293.051098018, 2552782.3212060533 6673285.5993876355) + +LINESTRING (2552978.882916019 6673298.132264293, 2552888.7732270965 6673293.051098018) + +LINESTRING (2553055.669603237 6673293.861283979, 2553039.1292822366 6673301.743093083) + +LINESTRING (2553039.1292822366 6673301.743093083, 2552978.882916019 6673298.132264293) + +LINESTRING (2552782.3212060533 6673285.5993876355, 2552777.0415025917 6673358.90621367) + +LINESTRING (2552888.7732270965 6673293.051098018, 2552879.3357571587 6673419.2100551445) + +LINESTRING (2552978.882916019 6673298.132264293, 2552971.7305677356 6673425.081402789) + +LINESTRING (2552531.1145652616 6673268.445450311, 2552514.153517891 6673262.224022313, 2552491.153809687 6673261.063755998, 2552478.6805102592 6673256.062608091) + +LINESTRING (2552227.2511319774 6673298.412328576, 2552146.09219033 6673240.589056464) + +LINESTRING (2552678.434790911 6673278.177684139, 2552640.585861742 6673275.677317152, 2552531.1145652616 6673268.445450311) + +LINESTRING (2552146.09219033 6673240.589056464, 2552080.145394281 6673330.999808344) + +LINESTRING (2552318.9612310114 6673271.776214818, 2552292.5049669473 6673307.024305273, 2552245.845587606 6673274.606864533, 2552227.2511319774 6673298.412328576) + +LINESTRING (2552408.7574375407 6673338.7315830095, 2552318.9612310114 6673271.776214818) + +LINESTRING (2552531.1145652616 6673268.445450311, 2552529.0486969245 6673296.548545875, 2552521.652346714 6673397.1649951665) + +LINESTRING (2552678.434790911 6673278.177684139, 2552677.906820565 6673285.539373861, 2552674.216004995 6673336.247571644, 2552669.1210640236 6673406.247079767) + +LINESTRING (2552080.145394281 6673330.999808344, 2552067.267867557 6673354.565217286) + +LINESTRING (2552227.2511319774 6673298.412328576, 2552147.7668462717 6673412.808585823) + +LINESTRING (2551675.6128651514 6673254.372220098, 2551680.8183227833 6673274.816912746, 2551682.5094777984 6673281.458437167, 2551699.751009415 6673299.7926453985, 2551760.599591809 6673343.492675818, 2551763.5364268594 6673345.603160235, 2551774.2773235887 6673347.453584962, 2551828.163297043 6673385.082221821, 2551837.3615304176 6673395.314570441, 2551844.0519046476 6673402.756278528) + +LINESTRING (2551764.122143962 6673339.771821775, 2551760.599591809 6673343.492675818, 2551755.715866107 6673348.653860459) + +LINESTRING (2551892.3364427104 6673318.977048773, 2551837.3615304176 6673395.314570441, 2551832.4695551787 6673402.116131595) + +LINESTRING (2551509.392951017 6673395.794680639, 2551422.005609192 6673330.089599425) + +LINESTRING (2552067.267867557 6673354.565217286, 2552027.958825378 6673407.947470056, 2551903.242330173 6673321.147546966, 2551892.3364427104 6673318.977048773) + +LINESTRING (2551312.9137364184 6673244.529961015, 2551308.689973649 6673268.8555444395, 2551291.341198056 6673494.177262286) + +LINESTRING (2551832.4695551787 6673402.116131595, 2551755.715866107 6673348.653860459) + +LINESTRING (2551422.005609192 6673330.089599425, 2551396.1680603772 6673358.336082809, 2551386.895581173 6673427.361926234) + +LINESTRING (2551655.7479808778 6673452.047592308, 2551656.8781673997 6673439.724763864, 2551487.0284571354 6673323.158008425) + +LINESTRING (2551755.715866107 6673348.653860459, 2551655.7479808778 6673452.047592308) + +LINESTRING (2553039.1292822366 6673301.743093083, 2553031.4242149973 6673429.042311932) + +LINESTRING (2553119.9004956614 6673301.242978292, 2553112.4016668387 6673434.35353101) + +LINESTRING (2553205.6544292276 6673309.334835607, 2553195.4827505276 6673439.704759272) + +LINESTRING (2552777.0415025917 6673358.90621367, 2552773.2384661925 6673412.668553681) + +LINESTRING (2552773.2384661925 6673412.668553681, 2552720.809051393 6673409.434952837, 2552669.1210640236 6673406.247079767) + +LINESTRING (2552879.3357571587 6673419.2100551445, 2552825.95680176 6673415.918938927, 2552773.2384661925 6673412.668553681) + +LINESTRING (2552971.7305677356 6673425.081402789, 2552930.1703346907 6673422.44040407, 2552879.3357571587 6673419.2100551445) + +LINESTRING (2553031.4242149973 6673429.042311932, 2552971.7305677356 6673425.081402789) + +LINESTRING (2553112.4016668387 6673434.35353101, 2553031.4242149973 6673429.042311932) + +LINESTRING (2553195.4827505276 6673439.704759272, 2553112.4016668387 6673434.35353101) + +LINESTRING (2552521.652346714 6673397.1649951665, 2552480.8583879373 6673392.573941387, 2552448.388211649 6673384.4020657055, 2552422.245429978 6673371.049000791, 2552398.0412894213 6673352.814815518) + +LINESTRING (2552147.7668462717 6673412.808585823, 2552067.267867557 6673354.565217286) + +LINESTRING (2552669.1210640236 6673406.247079767, 2552521.652346714 6673397.1649951665) + +LINESTRING (2552212.113232209 6673461.839839912, 2552147.7668462717 6673412.808585823) + +LINESTRING (2552521.652346714 6673397.1649951665, 2552514.763983604 6673499.378456109) + +LINESTRING (2552669.1210640236 6673406.247079767, 2552662.2162018404 6673501.088848694, 2552661.8614717643 6673506.009978236) + +LINESTRING (2552181.4084567656 6673476.683246903, 2552212.113232209 6673461.839839912) + +LINESTRING (2552271.1386670014 6673506.220026447, 2552212.113232209 6673461.839839912) + +LINESTRING (2552661.8614717643 6673506.009978236, 2552514.763983604 6673499.378456109) + +LINESTRING (2552256.454491749 6673534.296470803, 2552181.4084567656 6673476.683246903) + +LINESTRING (2551314.926623363 6673157.730037924, 2551055.066218616 6673137.355361347, 2551046.1402199515 6673142.6865850175) + +LINESTRING (2551046.1402199515 6673142.6865850175, 2551022.521796498 6673186.146560337, 2551003.4901154265 6673197.489163793, 2550911.12005346 6673225.3055484565, 2550899.7851900905 6673215.853378911, 2550904.9411505023 6673194.278426835, 2550915.3850639123 6673178.004691543, 2550966.045468533 6673150.9284767695, 2550989.6473929132 6673144.18692939, 2551046.1402199515 6673142.6865850175) + +LINESTRING (2551193.0974659882 6673547.3694714345, 2551034.7063621427 6673639.970726099) + +LINESTRING (2551193.0974659882 6673547.3694714345, 2551173.7605520603 6673670.577751296) + +LINESTRING (2551039.1363633284 6673648.872769374, 2551034.7063621427 6673639.970726099) + +LINESTRING (2551173.7605520603 6673670.577751296, 2551039.1363633284 6673648.872769374) + +LINESTRING (2551034.7063621427 6673639.970726099, 2550919.047858189 6673708.456445551) + +LINESTRING (2551257.600593122 6673682.420469541, 2551173.7605520603 6673670.577751296) + +LINESTRING (2550919.047858189 6673708.456445551, 2550933.6990352944 6673730.841583586) + +LINESTRING (2550254.9189094855 6673758.087837389, 2550235.6892395345 6673737.38308505, 2550212.96176604 6673702.565093315, 2550195.4232511036 6673691.96265975, 2550186.3236131626 6673691.759598104) + +LINESTRING (2551509.392951017 6673395.794680639, 2551482.5324596562 6673422.460801285) + +LINESTRING (2551482.5324596562 6673422.460801285, 2551456.6949108415 6673412.728567456, 2551395.8133303006 6673420.730404109, 2551386.895581173 6673427.361926234) + +LINESTRING (2551899.2743030405 6673441.985282717, 2551844.0519046476 6673402.756278528) + +LINESTRING (2551895.075288881 6673445.706136761, 2551832.4695551787 6673402.116131595) + +LINESTRING (2551639.6118871733 6673470.691871709, 2551567.55218446 6673434.563579222, 2551509.392951017 6673395.794680639) + +LINESTRING (2551899.2743030405 6673441.985282717, 2551895.075288881 6673445.706136761) + +LINESTRING (2551602.5879666493 6673488.706006474, 2551597.6629932644 6673472.942388268, 2551592.012060653 6673468.18129546, 2551482.5324596562 6673422.460801285) + +LINESTRING (2551832.4695551787 6673402.116131595, 2551753.9422157253 6673510.250951662) + +LINESTRING (2551386.895581173 6673427.361926234, 2551376.9053922794 6673436.063923595, 2551339.2215088224 6673456.338577214, 2551291.341198056 6673494.177262286) + +LINESTRING (2551655.7479808778 6673452.047592308, 2551639.6118871733 6673470.691871709) + +LINESTRING (2553241.3996715695 6673442.8554824535, 2553195.4827505276 6673439.704759272) + +LINESTRING (2552773.2384661925 6673412.668553681, 2552766.5315928888 6673507.540329495, 2552766.267607716 6673511.301192722) + +LINESTRING (2552971.7305677356 6673425.081402789, 2552977.2000105404 6673466.290861551, 2552974.8076449092 6673488.175884795, 2552966.162130491 6673509.980889674) + +LINESTRING (2552879.3357571587 6673419.2100551445, 2552872.472142659 6673518.93294443) + +LINESTRING (2553112.4016668387 6673434.35353101, 2553108.070660093 6673450.797305332, 2553106.907475424 6673495.867650278, 2553112.030437689 6673518.282795202) + +LINESTRING (2553241.3996715695 6673442.8554824535, 2553233.3316247175 6673542.7184038805) + +LINESTRING (2552766.267607716 6673511.301192722, 2552661.8614717643 6673506.009978236) + +LINESTRING (2552785.5962721067 6673513.141615152, 2552766.267607716 6673511.301192722) + +LINESTRING (2553112.030437689 6673518.282795202, 2552966.162130491 6673509.980889674) + +LINESTRING (2552872.472142659 6673518.93294443, 2552785.5962721067 6673513.141615152) + +LINESTRING (2551753.9422157253 6673510.250951662, 2551673.154503227 6673459.269249887, 2551655.7479808778 6673452.047592308) + +LINESTRING (2551639.6118871733 6673470.691871709, 2551617.6186224413 6673499.048380348) + +LINESTRING (2551602.5879666493 6673488.706006474, 2551527.558430739 6673498.808325248) + +LINESTRING (2551617.6186224413 6673499.048380348, 2551602.5879666493 6673488.706006474) + +LINESTRING (2551895.075288881 6673445.706136761, 2551893.5491245994 6673447.066448992, 2551818.5030896156 6673548.549742341) + +LINESTRING (2551737.756624801 6673535.516750893, 2551639.6118871733 6673470.691871709) + +LINESTRING (2551527.558430739 6673498.808325248, 2551445.1950567393 6673509.880866717) + +LINESTRING (2551291.341198056 6673494.177262286, 2551290.1450152406 6673526.754739758) + +LINESTRING (2551445.1950567393 6673509.880866717, 2551290.1450152406 6673526.754739758) + +LINESTRING (2551291.341198056 6673494.177262286, 2551265.536647388 6673504.27958106, 2551193.0974659882 6673547.3694714345) + +LINESTRING (2552275.651163554 6673509.600802434, 2552271.1386670014 6673506.220026447) + +LINESTRING (2552275.9398973365 6673509.820852942, 2552275.651163554 6673509.600802434) + +LINESTRING (2552288.5451893513 6673519.573091362, 2552275.9398973365 6673509.820852942) + +LINESTRING (2552514.763983604 6673499.378456109, 2552509.9710028055 6673570.4747747695) + +LINESTRING (2552168.737168458 6673636.910023579, 2551899.2743030405 6673441.985282717) + +LINESTRING (2552348.164590783 6673563.0530712735, 2552308.443071772 6673535.956851909, 2552288.5451893513 6673519.573091362) + +LINESTRING (2552661.8614717643 6673506.009978236, 2552658.8338918104 6673514.27187458, 2552654.6513767247 6673568.414301831, 2552644.8674262473 6673602.582144339) + +LINESTRING (2552345.054515463 6673566.843941389, 2552348.164590783 6673563.0530712735) + +LINESTRING (2552510.0452486356 6673575.045823957, 2552363.5334775783 6673567.544102095, 2552348.164590783 6673563.0530712735) + +LINESTRING (2552510.0452486356 6673575.045823957, 2552509.9710028055 6673570.4747747695) + +LINESTRING (2551753.9422157253 6673510.250951662, 2551737.756624801 6673535.516750893) + +LINESTRING (2551818.5030896156 6673548.549742341, 2551753.9422157253 6673510.250951662) + +LINESTRING (2551527.558430739 6673498.808325248, 2551528.9031052147 6673530.415580027, 2551499.6584977596 6673564.653438604, 2551457.841596437 6673570.304735741) + +LINESTRING (2551455.746214126 6673563.933273306, 2551448.5938658426 6673542.218289089, 2551445.1950567393 6673509.880866717) + +LINESTRING (2551952.4673154154 6673511.141155989, 2551893.7883611624 6673596.390723228) + +LINESTRING (2551799.743643254 6673574.965805591, 2551737.756624801 6673535.516750893) + +LINESTRING (2551290.1450152406 6673526.754739758, 2551286.4904705007 6673553.3408420365, 2551280.9302827925 6673584.327954475) + +LINESTRING (2551818.5030896156 6673548.549742341, 2551799.743643254 6673574.965805591) + +LINESTRING (2551457.841596437 6673570.304735741, 2551455.746214126 6673563.933273306) + +LINESTRING (2551887.972437818 6673592.839908214, 2551818.5030896156 6673548.549742341) + +LINESTRING (2551455.746214126 6673563.933273306, 2551427.202817287 6673567.884180153, 2551286.2512339377 6673585.218158802) + +LINESTRING (2551617.6186224413 6673499.048380348, 2551503.742018406 6673652.123515515) + +LINESTRING (2551286.2512339377 6673585.218158802, 2551280.9302827925 6673584.327954475) + +LINESTRING (2551737.756624801 6673535.516750893, 2551662.3888578876 6673646.772287253) + +LINESTRING (2551893.7883611624 6673596.390723228, 2551887.972437818 6673592.839908214) + +LINESTRING (2551869.00675304 6673620.5562699195, 2551799.743643254 6673574.965805591) + +LINESTRING (2551887.972437818 6673592.839908214, 2551869.00675304 6673620.5562699195) + +LINESTRING (2551465.6374085797 6673661.9857791895, 2551457.841596437 6673570.304735741) + +LINESTRING (2551944.9354884457 6673645.44198191, 2551933.69136998 6673623.536954073, 2551893.7883611624 6673596.390723228) + +LINESTRING (2551896.26322216 6673640.000732986, 2551869.00675304 6673620.5562699195) + +LINESTRING (2552587.524896933 6673579.326806567, 2552510.0452486356 6673575.045823957) + +LINESTRING (2552510.1359935384 6673580.497075177, 2552510.0452486356 6673575.045823957) + +LINESTRING (2552644.8674262473 6673602.582144339, 2552616.431273385 6673583.687807542, 2552591.657914799 6673579.55685937, 2552587.524896933 6673579.326806567) + +LINESTRING (2552345.054515463 6673566.843941389, 2552330.0568578173 6673585.108133548, 2552322.863261851 6673626.757693326) + +LINESTRING (2552633.0953374356 6673626.467626747, 2552631.82490879 6673613.684692694, 2552625.340772976 6673601.6919400105, 2552611.53104861 6673592.439816381, 2552587.524896933 6673579.326806567) + +LINESTRING (2552644.8674262473 6673602.582144339, 2552652.5477448767 6673607.583292247) + +LINESTRING (2552202.6262650513 6673614.574897022, 2552195.9111422114 6673612.1843483215) + +LINESTRING (2552217.0959523506 6673619.726079367, 2552202.6262650513 6673614.574897022) + +LINESTRING (2552317.179331093 6673633.669279735, 2552217.0959523506 6673619.726079367) + +LINESTRING (2552322.863261851 6673626.757693326, 2552317.179331093 6673633.669279735) + +LINESTRING (2551280.9302827925 6673584.327954475, 2551263.5815071994 6673683.270664685) + +LINESTRING (2551902.1451417976 6673644.191694933, 2551896.26322216 6673640.000732986) + +LINESTRING (2551918.421477625 6673645.842073742, 2551902.1451417976 6673644.191694933) + +LINESTRING (2551949.291243802 6673645.181922219, 2551944.9354884457 6673645.44198191) + +LINESTRING (2551902.1451417976 6673644.191694933, 2551743.440555559 6673647.422436481) + +LINESTRING (2551944.9354884457 6673645.44198191, 2551925.8295615446 6673646.592245929, 2551925.4665819313 6673646.552236745) + +LINESTRING (2551925.4665819313 6673646.552236745, 2551918.421477625 6673645.842073742) + +LINESTRING (2551662.3888578876 6673646.772287253, 2551658.899303881 6673651.903465007) + +LINESTRING (2551743.440555559 6673647.422436481, 2551658.899303881 6673651.903465007) + +LINESTRING (2551743.5972967553 6673653.503832337, 2551743.440555559 6673647.422436481) + +LINESTRING (2552956.9143998967 6673618.665836011, 2552867.3904280774 6673610.51396492) + +LINESTRING (2553105.2658176287 6673629.888411916, 2552956.9143998967 6673618.665836011) + +LINESTRING (2553226.0967810676 6673638.8804758545, 2553105.2658176287 6673629.888411916) + +LINESTRING (2553282.366870616 6673641.751134754, 2553226.0967810676 6673638.8804758545) + +LINESTRING (2552652.5477448767 6673607.583292247, 2552719.2287496882 6673650.273090789, 2552757.3251099777 6673680.650063182, 2552766.482095669 6673692.762843415) + +LINESTRING (2552956.9143998967 6673618.665836011, 2552952.212164001 6673697.553943111) + +LINESTRING (2552777.759212281 6673637.510161328, 2552766.482095669 6673692.762843415) + +LINESTRING (2553105.2658176287 6673629.888411916, 2553098.567193862 6673709.276633807) + +LINESTRING (2553226.0967810676 6673638.8804758545, 2553219.7776359874 6673717.488518672) + +LINESTRING (2553098.567193862 6673709.276633807, 2552952.212164001 6673697.553943111) + +LINESTRING (2551658.899303881 6673651.903465007, 2551645.3123170044 6673652.453591277) + +LINESTRING (2551645.3123170044 6673652.453591277, 2551507.2315724124 6673658.074881526) + +LINESTRING (2551503.742018406 6673652.123515515, 2551490.402517629 6673659.335170798) + +LINESTRING (2551507.2315724124 6673658.074881526, 2551498.759298264 6673658.705026162) + +LINESTRING (2551658.899303881 6673651.903465007, 2551649.1483515506 6673666.116727361) + +LINESTRING (2551498.759298264 6673658.705026162, 2551490.402517629 6673659.335170798) + +LINESTRING (2551649.1483515506 6673666.116727361, 2551645.3123170044 6673652.453591277) + +LINESTRING (2551490.402517629 6673659.335170798, 2551465.6374085797 6673661.9857791895) + +LINESTRING (2551465.6374085797 6673661.9857791895, 2551347.883522314 6673674.828727017) + +LINESTRING (2551347.883522314 6673674.828727017, 2551269.785158767 6673683.120630248) + +LINESTRING (2552168.737168458 6673636.910023579, 2552172.432960881 6673639.590638857) + +LINESTRING (2552322.863261851 6673626.757693326, 2552361.289603607 6673630.088457832, 2552359.0127314893 6673658.444966471) + +LINESTRING (2552317.179331093 6673633.669279735, 2552315.545922835 6673650.46313441, 2552320.32240456 6673658.92507667, 2552358.7569958526 6673661.565682765, 2552359.0127314893 6673658.444966471) + +LINESTRING (2552149.2847610167 6673657.954853976, 2552116.047377819 6673649.562927786, 2551949.291243802 6673645.181922219) + +LINESTRING (2552548.2323538284 6673736.992995514, 2552503.1238873787 6673733.622221824, 2552510.1359935384 6673580.497075177) + +LINESTRING (2552217.0959523506 6673619.726079367, 2552205.0351297557 6673700.734673181, 2552169.0589003875 6673672.218127809, 2552146.0756912567 6673660.495437113) + +LINESTRING (2552652.5477448767 6673607.583292247, 2552643.258766599 6673756.567488425) + +LINESTRING (2552633.0953374356 6673626.467626747, 2552622.8329138323 6673749.445853804) + +LINESTRING (2552140.721741965 6673665.156506963, 2552144.871258904 6673684.150866718, 2552118.0437656906 6673737.923209025) + +LINESTRING (2552599.197991305 6673743.634519935, 2552585.5862558186 6673738.883429423, 2552548.2323538284 6673736.992995514) + +LINESTRING (2551749.36372288 6673705.585786651, 2551745.2059564036 6673693.513015602, 2551743.5972967553 6673653.503832337) + +LINESTRING (2551263.5815071994 6673683.270664685, 2551257.600593122 6673682.420469541) + +LINESTRING (2551269.785158767 6673683.120630248, 2551263.5815071994 6673683.270664685) + +LINESTRING (2551649.1483515506 6673666.116727361, 2551606.0610215827 6673728.901138199) + +LINESTRING (2552037.8417702955 6673754.316971866, 2551963.950670444 6673689.02198478, 2551925.4665819313 6673646.552236745) + +LINESTRING (2551918.421477625 6673645.842073742, 2551913.018031114 6673659.905301659, 2551875.9528629063 6673714.607857477, 2551840.6200973974 6673766.099676338) + +LINESTRING (2551498.759298264 6673658.705026162, 2551463.7812628313 6673709.036578707, 2551435.485352092 6673768.170151572) + +LINESTRING (2551347.883522314 6673674.828727017, 2551326.8967010546 6673752.106464491) + +LINESTRING (2551840.6200973974 6673766.099676338, 2551749.36372288 6673705.585786651) + +LINESTRING (2551606.0610215827 6673728.901138199, 2551590.560142201 6673751.856407096) + +LINESTRING (2554452.00267715 6673194.558491118, 2554481.4617725583 6673226.675862984, 2554513.494723404 6673266.004890132, 2554514.872396026 6673280.898308602, 2554469.673184673 6673376.390226757) + +LINESTRING (2554289.3300637784 6673267.365202363, 2554358.0404546084 6673304.683768053) + +LINESTRING (2554383.251038637 6673258.043062663, 2554422.9148108917 6673280.538225953, 2554393.620706217 6673334.840689938) + +LINESTRING (2554061.725347367 6673270.4559117695, 2554040.408544641 6673309.844952693, 2554045.5892536626 6673323.128001537) + +LINESTRING (2554358.0404546084 6673304.683768053, 2554354.955127898 6673311.345297066, 2554358.2549425615 6673315.616277379) + +LINESTRING (2554358.2549425615 6673315.616277379, 2554393.620706217 6673334.840689938) + +LINESTRING (2554358.2549425615 6673315.616277379, 2554340.8071725285 6673346.863449508) + +LINESTRING (2554393.620706217 6673334.840689938, 2554440.9317989545 6673360.586599368) + +LINESTRING (2554229.4796753204 6673415.939304413, 2554253.1888436773 6673374.27974234, 2554099.54122341 6673290.140429935) + +LINESTRING (2554440.9317989545 6673360.586599368, 2554443.794388175 6673363.117180209) + +LINESTRING (2553352.6364238746 6673359.166273362, 2553373.384008571 6673347.723646948) + +LINESTRING (2553780.1521621346 6673315.01613963, 2553775.755159096 6673404.646712436) + +LINESTRING (2553346.457520917 6673362.567053939, 2553352.6364238746 6673359.166273362) + +LINESTRING (2553344.139401116 6673364.037391424, 2553346.457520917 6673362.567053939) + +LINESTRING (2553340.542603133 6673366.31791487, 2553344.139401116 6673364.037391424) + +LINESTRING (2553933.329558812 6673324.638348205, 2553929.6667645355 6673370.90896865, 2553844.209814289 6673408.267543522, 2553775.755159096 6673404.646712436) + +LINESTRING (2553671.6212578537 6673408.037490718, 2553774.7487156233 6673413.858826883, 2553846.5279340902 6673417.569678631, 2553929.122295116 6673383.371829236, 2553962.6731607066 6673372.999448475, 2554024.099210667 6673341.062117935, 2554045.5892536626 6673323.128001537) + +LINESTRING (2553635.9420118053 6673348.1437433725, 2553667.240753888 6673396.284793135) + +LINESTRING (2553299.34441706 6673391.583714101, 2553340.542603133 6673366.31791487) + +LINESTRING (2553671.6212578537 6673408.037490718, 2553616.0936266044 6673442.715450312, 2553602.605634168 6673420.700397221, 2553500.204135624 6673413.6287740795, 2553504.9971164227 6673339.791826366, 2553635.9420118053 6673348.1437433725) + +LINESTRING (2553667.240753888 6673396.284793135, 2553678.61686494 6673400.075663249, 2553775.755159096 6673404.646712436) + +LINESTRING (2553667.240753888 6673396.284793135, 2553671.6212578537 6673408.037490718) + +LINESTRING (2553299.34441706 6673391.583714101, 2553296.217842666 6673446.466311243) + +LINESTRING (2553296.217842666 6673446.466311243, 2553241.3996715695 6673442.8554824535) + +LINESTRING (2553383.2587039513 6673452.957801227, 2553296.217842666 6673446.466311243) + +LINESTRING (2553296.217842666 6673446.466311243, 2553289.5852151928 6673546.189200528) + +LINESTRING (2553399.287553679 6673503.929500706, 2553386.5337700048 6673649.462904828) + +LINESTRING (2553433.0446576863 6673508.920646318, 2553466.348037177 6673655.7443466) + +LINESTRING (2553289.5852151928 6673546.189200528, 2553282.366870616 6673641.751134754) + +LINESTRING (2553386.5337700048 6673649.462904828, 2553282.366870616 6673641.751134754) + +LINESTRING (2552966.162130491 6673509.980889674, 2552963.6212732 6673523.774055605) + +LINESTRING (2552963.6212732 6673523.774055605, 2552872.472142659 6673518.93294443) + +LINESTRING (2553112.030437689 6673518.282795202, 2553112.269674252 6673535.126661356) + +LINESTRING (2553233.3316247175 6673542.7184038805, 2553112.269674252 6673535.126661356) + +LINESTRING (2553289.5852151928 6673546.189200528, 2553233.3316247175 6673542.7184038805) + +LINESTRING (2552872.472142659 6673518.93294443, 2552867.3904280774 6673610.51396492) + +LINESTRING (2552963.6212732 6673523.774055605, 2552956.9143998967 6673618.665836011) + +LINESTRING (2552785.5962721067 6673513.141615152, 2552777.759212281 6673637.510161328) + +LINESTRING (2553112.269674252 6673535.126661356, 2553105.2658176287 6673629.888411916) + +LINESTRING (2553233.3316247175 6673542.7184038805, 2553226.0967810676 6673638.8804758545) + +LINESTRING (2553466.348037177 6673655.7443466, 2553386.5337700048 6673649.462904828) + +LINESTRING (2553479.8277800772 6673656.594541744, 2553466.348037177 6673655.7443466) + +LINESTRING (2553282.366870616 6673641.751134754, 2553275.9652301692 6673721.07934287) + +LINESTRING (2553386.5337700048 6673649.462904828, 2553381.666543376 6673728.240986674) + +LINESTRING (2553466.348037177 6673655.7443466, 2553485.148731222 6673735.572669507) + +LINESTRING (2553381.666543376 6673728.240986674, 2553275.9652301692 6673721.07934287) + +LINESTRING (2553485.148731222 6673735.572669507, 2553381.666543376 6673728.240986674) + +LINESTRING (2553275.9652301692 6673721.07934287, 2553270.223552655 6673799.537351251) + +LINESTRING (2553381.666543376 6673728.240986674, 2553376.452836208 6673806.188877968) + +LINESTRING (2553376.452836208 6673806.188877968, 2553270.223552655 6673799.537351251) + +LINESTRING (2553219.7776359874 6673717.488518672, 2553098.567193862 6673709.276633807) + +LINESTRING (2553275.9652301692 6673721.07934287, 2553219.7776359874 6673717.488518672) + +LINESTRING (2552867.3904280774 6673610.51396492, 2552854.5046518166 6673780.332943284, 2552851.1718390062 6673786.784424085, 2552848.061763686 6673823.792918604, 2552833.5590782403 6673841.386956944) + +LINESTRING (2552766.482095669 6673692.762843415, 2552769.3446848895 6673764.979419206) + +LINESTRING (2552766.482095669 6673692.762843415, 2552780.927034358 6673737.673151629, 2552809.51167888 6673793.335927845) + +LINESTRING (2553098.567193862 6673709.276633807, 2553092.8007677374 6673789.244988856) + +LINESTRING (2552769.3446848895 6673764.979419206, 2552784.020610605 6673770.010574002, 2552809.51167888 6673793.335927845) + +LINESTRING (2552952.212164001 6673697.553943111, 2552938.220949828 6673883.426606258) + +LINESTRING (2553270.223552655 6673799.537351251, 2553092.8007677374 6673789.244988856) + +LINESTRING (2552769.3446848895 6673764.979419206, 2552762.6213125126 6673869.363378341) + +LINESTRING (2552809.51167888 6673793.335927845, 2552833.5590782403 6673841.386956944) + +LINESTRING (2553092.8007677374 6673789.244988856, 2553085.706166211 6673889.8780870605) + +LINESTRING (2553270.223552655 6673799.537351251, 2553263.7229177677 6673904.271390739) + +LINESTRING (2552833.5590782403 6673841.386956944, 2552854.6036462565 6673878.245417026) + +LINESTRING (2552847.962769246 6673878.025366519, 2552762.6213125126 6673869.363378341) + +LINESTRING (2552854.6036462565 6673878.245417026, 2552847.962769246 6673878.025366519) + +LINESTRING (2552859.5616177884 6673878.415456055, 2552854.6036462565 6673878.245417026) + +LINESTRING (2552859.5616177884 6673878.415456055, 2552881.315645957 6673879.1456236495) + +LINESTRING (2552881.315645957 6673879.1456236495, 2552938.220949828 6673883.426606258) + +LINESTRING (2552938.220949828 6673883.426606258, 2553085.706166211 6673889.8780870605) + +LINESTRING (2553485.148731222 6673735.572669507, 2553526.9903811547 6673921.875431376, 2553457.3477926827 6673918.384630135) + +LINESTRING (2553376.452836208 6673806.188877968, 2553368.6157763824 6673912.273227392) + +LINESTRING (2553368.6157763824 6673912.273227392, 2553263.7229177677 6673904.271390739) + +LINESTRING (2553457.3477926827 6673918.384630135, 2553368.6157763824 6673912.273227392) + +LINESTRING (2553368.6157763824 6673912.273227392, 2553362.238884545 6674010.265719501) + +LINESTRING (2553457.3477926827 6673918.384630135, 2553449.865462933 6674015.21685593) + +LINESTRING (2553525.5384627027 6674020.678109446, 2553529.522988909 6673971.076724494, 2553533.8044984345 6673961.534534286, 2553545.51884049 6673950.411981339) + +LINESTRING (2553565.094990981 6674021.468290815, 2553856.6418660334 6673963.835062323) + +LINESTRING (2553362.238884545 6674010.265719501, 2553256.4880741183 6674002.824011413) + +LINESTRING (2553449.865462933 6674015.21685593, 2553362.238884545 6674010.265719501) + +LINESTRING (2552854.6036462565 6673878.245417026, 2552885.225926333 6673938.009134526) + +LINESTRING (2552938.220949828 6673883.426606258, 2552935.6140962443 6673927.976831823, 2552921.309399678 6673955.193078739) + +LINESTRING (2553085.706166211 6673889.8780870605, 2553078.578566538 6673990.511185264) + +LINESTRING (2552885.225926333 6673938.009134526, 2552897.3527452215 6673947.931411976, 2552921.309399678 6673955.193078739) + +LINESTRING (2553263.7229177677 6673904.271390739, 2553256.4880741183 6674002.824011413) + +LINESTRING (2552885.225926333 6673938.009134526, 2552889.0537113426 6673977.008085913, 2552897.798220201 6673998.282969113) + +LINESTRING (2552921.309399678 6673955.193078739, 2552908.118390561 6673973.387254828, 2552897.798220201 6673998.282969113) + +LINESTRING (2553078.578566538 6673990.511185264, 2552932.619514437 6673980.83896521, 2552930.6726237857 6673980.708935365) + +LINESTRING (2552921.309399678 6673955.193078739, 2552929.47644097 6673963.905078394, 2552932.8422519267 6673978.828503751, 2552932.619514437 6673980.83896521, 2552928.601990084 6674017.417361009, 2552926.5643545296 6674030.050260625) + +LINESTRING (2553256.4880741183 6674002.824011413, 2553078.578566538 6673990.511185264) + +LINESTRING (2554045.5892536626 6673323.128001537, 2554066.3533374327 6673328.469227502, 2554097.445841099 6673345.293089065, 2554166.857442545 6673382.771691487, 2554229.4796753204 6673415.939304413) + +LINESTRING (2554443.794388175 6673363.117180209, 2554469.673184673 6673376.390226757) + +LINESTRING (2554393.620706217 6673334.840689938, 2554372.056417391 6673374.309749227, 2554372.741128934 6673408.547607805) + +LINESTRING (2554340.8071725285 6673346.863449508, 2554315.1511135204 6673404.156599942) + +LINESTRING (2554443.794388175 6673363.117180209, 2554419.5654990086 6673407.567382815, 2554372.741128934 6673408.547607805) + +LINESTRING (2554372.741128934 6673408.547607805, 2554325.1000547307 6673409.557839682, 2554315.1511135204 6673404.156599942) + +LINESTRING (2551749.36372288 6673705.585786651, 2551686.840484544 6673785.184056754) + +LINESTRING (2551263.5815071994 6673683.270664685, 2551224.519951121 6673823.852932379) + +LINESTRING (2551686.840484544 6673785.184056754, 2551606.0610215827 6673728.901138199) + +LINESTRING (2551429.8426690176 6673767.009885257, 2551326.8967010546 6673752.106464491) + +LINESTRING (2551435.485352092 6673768.170151572, 2551429.8426690176 6673767.009885257) + +LINESTRING (2551439.808109301 6673769.050353603, 2551435.485352092 6673768.170151572) + +LINESTRING (2551590.560142201 6673751.856407096, 2551577.2866377174 6673756.917568779, 2551552.7772643045 6673792.965842899) + +LINESTRING (2551492.902127236 6673776.792130565, 2551439.808109301 6673769.050353603) + +LINESTRING (2551590.560142201 6673751.856407096, 2551590.659136641 6673766.419749804, 2551567.4531900203 6673802.518035403) + +LINESTRING (2551840.6200973974 6673766.099676338, 2551813.8668500134 6673803.158182336) + +LINESTRING (2552118.0437656906 6673737.923209025, 2552177.8364073923 6673801.157723173, 2552199.0789642883 6673818.001589327, 2552221.748691026 6673826.953644082, 2552240.5658841445 6673806.108859601, 2552297.924912532 6673716.958396994, 2552318.0207838323 6673714.7078804355, 2552341.8371961657 6673705.855848638, 2552354.4919854 6673692.762843415, 2552359.6396962753 6673678.47956499, + 2552359.0127314893 6673658.444966471) + +LINESTRING (2552622.8329138323 6673749.445853804, 2552599.197991305 6673743.634519935) + +LINESTRING (2552643.258766599 6673756.567488425, 2552622.8329138323 6673749.445853804) + +LINESTRING (2552769.3446848895 6673764.979419206, 2552643.258766599 6673756.567488425) + +LINESTRING (2552063.959803357 6673790.795344708, 2552037.8417702955 6673754.316971866) + +LINESTRING (2552068.1670670523 6673793.766026565, 2552063.959803357 6673790.795344708) + +LINESTRING (2552073.859247347 6673797.806954075, 2552068.1670670523 6673793.766026565) + +LINESTRING (2552548.2323538284 6673736.992995514, 2552540.7087763953 6673856.620453472) + +LINESTRING (2552599.197991305 6673743.634519935, 2552588.985064922 6673860.221279966) + +LINESTRING (2552643.258766599 6673756.567488425, 2552645.4943910334 6673763.759139117, 2552639.3567357594 6673853.58975784) + +LINESTRING (2551173.7605520603 6673670.577751296, 2551136.8603745867 6673805.238659865) + +LINESTRING (2550919.047858189 6673708.456445551, 2550802.3251640056 6673777.652328005) + +LINESTRING (2550933.6990352944 6673730.841583586, 2550817.034087868 6673801.027693327) + +LINESTRING (2550817.034087868 6673801.027693327, 2550802.3251640056 6673777.652328005) + +LINESTRING (2550933.6990352944 6673730.841583586, 2550952.3512376794 6673762.378822294, 2550956.591499522 6673790.235216142, 2550954.025893621 6673808.149327948, 2550946.8735453384 6673823.68289335, 2550935.695423166 6673836.845914644, 2550919.9223090746 6673848.198520395, 2550889.720755367 6673857.050552192, 2550856.8546013194 6673849.638850993, 2550839.654317386 6673838.396270496, + 2550818.6674961266 6673809.159559825, 2550817.034087868 6673801.027693327) + +LINESTRING (2551219.034009243 6673822.6826637685, 2551179.254743475 6673814.2407261, 2551136.8603745867 6673805.238659865) + +LINESTRING (2550611.1504014786 6673856.980536122, 2550576.172366046 6673875.77484996, 2550569.952215405 6673874.444544616, 2550469.8028403698 6673808.719458809, 2550358.3021028917 6673752.836632086, 2550326.417643706 6673757.687745556, 2550254.9189094855 6673758.087837389) + +LINESTRING (2550802.3251640056 6673777.652328005, 2550686.8728984683 6673844.287622731, 2550673.723137034 6673835.385579455, 2550665.052874006 6673832.985028459, 2550654.493467083 6673834.665414156, 2550611.1504014786 6673856.980536122) + +LINESTRING (2551136.8603745867 6673805.238659865, 2551115.337333444 6673889.147919466, 2551121.829718794 6673902.991096875, 2551121.846217868 6673914.833815121) + +LINESTRING (2551224.519951121 6673823.852932379, 2551197.78320281 6673927.316680299) + +LINESTRING (2551552.7772643045 6673792.965842899, 2551536.0142058143 6673781.683253219, 2551492.902127236 6673776.792130565) + +LINESTRING (2551326.8967010546 6673752.106464491, 2551301.966601272 6673840.286704404) + +LINESTRING (2551567.4531900203 6673802.518035403, 2551552.7772643045 6673792.965842899) + +LINESTRING (2551435.485352092 6673768.170151572, 2551398.321189445 6673860.751401644) + +LINESTRING (2551731.78396026 6673845.057799509, 2551686.840484544 6673785.184056754) + +LINESTRING (2551813.8668500134 6673803.158182336, 2551795.5776272416 6673793.976074777, 2551731.78396026 6673845.057799509) + +LINESTRING (2551890.472047426 6673874.094464263, 2551864.411761121 6673781.5132141905, 2551840.6200973974 6673766.099676338) + +LINESTRING (2552037.8417702955 6673754.316971866, 2551998.169748504 6673877.825320601, 2552022.431635817 6673885.937182508) + +LINESTRING (2551224.519951121 6673823.852932379, 2551219.034009243 6673822.6826637685) + +LINESTRING (2551230.7978485185 6673825.183237722, 2551224.519951121 6673823.852932379) + +LINESTRING (2551458.163328367 6673872.90419106, 2551492.902127236 6673776.792130565) + +LINESTRING (2551301.966601272 6673840.286704404, 2551230.7978485185 6673825.183237722) + +LINESTRING (2551813.8668500134 6673803.158182336, 2551813.734857427 6673812.670365657, 2551763.684918519 6673879.0255961) + +LINESTRING (2551393.924186406 6673859.821188133, 2551301.966601272 6673840.286704404) + +LINESTRING (2551613.0318800593 6673913.813580948, 2551598.677686273 6673821.96249847, 2551567.4531900203 6673802.518035403) + +LINESTRING (2551398.321189445 6673860.751401644, 2551393.924186406 6673859.821188133) + +LINESTRING (2551398.9151560846 6673860.871429194, 2551398.321189445 6673860.751401644) + +LINESTRING (2551403.881377153 6673861.881661071, 2551398.9151560846 6673860.871429194) + +LINESTRING (2551458.163328367 6673872.90419106, 2551403.881377153 6673861.881661071) + +LINESTRING (2551731.78396026 6673845.057799509, 2551679.712884871 6673895.7394324085) + +LINESTRING (2551010.510471123 6674129.593108585, 2551015.4271949716 6674107.267984324, 2551014.2392616924 6674078.951484869, 2551005.090525538 6674055.06600246, 2550970.731205355 6674013.506463345, 2550957.655689751 6673913.943610793, 2550959.4458392058 6673875.394762719, 2550972.37286315 6673819.982043899, 2550981.414355328 6673794.056093143, 2551025.4503820115 6673705.495765989, + 2551039.1363633284 6673648.872769374) + +LINESTRING (2551189.6904073483 6673933.678140438, 2551121.846217868 6673914.833815121) + +LINESTRING (2551197.78320281 6673927.316680299, 2551195.696070036 6673935.398535319) + +LINESTRING (2551195.696070036 6673935.398535319, 2551189.6904073483 6673933.678140438) + +LINESTRING (2551201.2315091337 6673936.978898058, 2551195.696070036 6673935.398535319) + +LINESTRING (2551197.78320281 6673927.316680299, 2551221.475872094 6673934.808399865, 2551230.715353152 6673946.261028575) + +LINESTRING (2550674.9523179964 6674116.500103362, 2550664.4836559766 6674113.329375588, 2550650.0139686773 6674100.476425465, 2550640.1475228337 6674080.841918779, 2550633.943871266 6674042.0630179, 2550645.8562022015 6673991.161334492, 2550645.410727222 6673981.349082297, 2550637.8129039593 6673962.314713359, 2550616.265114207 6673944.200555637, 2550609.1292649973 6673933.918195537, + 2550602.87611621 6673919.264832167, 2550599.832037183 6673900.880612458, 2550603.0493564797 6673873.6943724295, 2550611.1504014786 6673856.980536122) + +LINESTRING (2551121.846217868 6673914.833815121, 2551116.9047454093 6673924.63606502, 2551105.1574052074 6673931.647674387, 2551100.4386702385 6673938.219182739, 2551075.632313506 6674031.200524644, 2551082.7021664227 6674042.903210748, 2551160.1818147204 6674064.618194965) + +LINESTRING (2551195.696070036 6673935.398535319, 2551162.9124113545 6674054.935972615) + +LINESTRING (2551162.9124113545 6674054.935972615, 2551160.1818147204 6674064.618194965) + +LINESTRING (2551613.0318800593 6673913.813580948, 2551502.8840665934 6673926.796560917, 2551483.992627645 6673920.395091594, 2551469.6384338588 6673908.462352687, 2551460.3907032646 6673891.558472757, 2551458.163328367 6673872.90419106) + +LINESTRING (2551301.966601272 6673840.286704404, 2551289.4438046245 6673900.360493075, 2551331.69793139 6673952.922557588, 2551365.6117765936 6673962.324715655) + +LINESTRING (2551763.684918519 6673879.0255961, 2551719.459152492 6673928.1468708515) + +LINESTRING (2551679.712884871 6673895.7394324085, 2551613.0318800593 6673913.813580948) + +LINESTRING (2551719.459152492 6673928.1468708515, 2551679.712884871 6673895.7394324085) + +LINESTRING (2551398.321189445 6673860.751401644, 2551383.892749829 6673906.171826945, 2551370.503751832 6673963.615011815) + +LINESTRING (2551890.472047426 6673874.094464263, 2551850.932018221 6673967.375875042) + +LINESTRING (2551924.608630119 6673968.396109215, 2551933.96360469 6673947.37128341, 2551890.472047426 6673874.094464263) + +LINESTRING (2551850.932018221 6673967.375875042, 2551763.684918519 6673879.0255961) + +LINESTRING (2551230.715353152 6673946.261028575, 2551201.2315091337 6673936.978898058) + +LINESTRING (2551719.459152492 6673928.1468708515, 2551694.4713059533 6673958.533845541, 2551697.0286623174 6673975.887828781) + +LINESTRING (2551370.503751832 6673963.615011815, 2551365.6117765936 6673962.324715655) + +LINESTRING (2551375.3132317043 6673964.885303384, 2551370.503751832 6673963.615011815) + +LINESTRING (2552017.9191392646 6673946.871168619, 2551981.9676585067 6673998.423001255, 2551977.1334300246 6673995.322289552) + +LINESTRING (2551469.6466833954 6673988.37069396, 2551375.3132317043 6673964.885303384) + +LINESTRING (2551966.153296732 6673989.120866146, 2551924.608630119 6673968.396109215) + +LINESTRING (2551924.608630119 6673968.396109215, 2551912.547807524 6673967.015792393, 2551863.776546798 6673999.603272161) + +LINESTRING (2551863.776546798 6673999.603272161, 2551850.932018221 6673967.375875042) + +LINESTRING (2551697.0286623174 6673975.887828781, 2551624.8452165546 6673987.740549323, 2551623.3190522725 6673977.108108871, 2551500.805183355 6673995.512333172, 2551469.6466833954 6673988.37069396) + +LINESTRING (2551966.153296732 6673989.120866146, 2551970.2203183044 6673991.151332197) + +LINESTRING (2551970.2203183044 6673991.151332197, 2551971.977469613 6673992.021531933) + +LINESTRING (2551971.977469613 6673992.021531933, 2551977.1334300246 6673995.322289552) + +LINESTRING (2551697.0286623174 6673975.887828781, 2551708.858497886 6674048.154416052) + +LINESTRING (2551230.715353152 6673946.261028575, 2551337.0023834617 6674078.751438953) + +LINESTRING (2551863.776546798 6673999.603272161, 2551820.4664793406 6674029.830210117) + +LINESTRING (2551370.503751832 6673963.615011815, 2551351.8597989837 6674088.353642936) + +LINESTRING (2551820.4664793406 6674029.830210117, 2551708.858497886 6674048.154416052) + +LINESTRING (2551469.6466833954 6673988.37069396, 2551435.5678474586 6674092.2645406) + +LINESTRING (2551708.858497886 6674048.154416052, 2551629.9186815997 6674060.237189397) + +LINESTRING (2551629.9186815997 6674060.237189397, 2551497.6291117417 6674081.552081781) + +LINESTRING (2552118.0437656906 6673737.923209025, 2552017.9191392646 6673946.871168619) + +LINESTRING (2552639.3567357594 6673853.58975784, 2552638.878262633 6673862.84188147) + +LINESTRING (2552588.985064922 6673860.221279966, 2552540.7087763953 6673856.620453472) + +LINESTRING (2552638.878262633 6673862.84188147, 2552588.985064922 6673860.221279966) + +LINESTRING (2552762.6213125126 6673869.363378341, 2552638.878262633 6673862.84188147) + +LINESTRING (2552017.9191392646 6673946.871168619, 2552033.906741309 6673956.733432294, 2552084.14641956 6674019.7879051175) + +LINESTRING (2552103.912309394 6674035.331472816, 2552084.14641956 6674019.7879051175) + +LINESTRING (2552540.7087763953 6673856.620453472, 2552537.656447832 6673859.791181246, 2552526.197841413 6673969.586382417, 2552522.6257920396 6673981.93921775, 2552497.6379455007 6674020.528075008, 2552484.6531748 6674074.850543585, 2552475.850919185 6674149.257622159, 2552457.3059607767 6674203.500072369, 2552433.3163081734 6674251.000975199, 2552457.9659237093 6674315.865863565, + 2552469.9772490845 6674314.32551001, 2552538.7948838905 6674256.922334322, 2552572.4117457746 6674236.2575911665, 2552769.740662649 6674190.066989088, 2552873.2723477148 6674175.9337451, 2552913.356846339 6674178.394309871) + +LINESTRING (2552103.912309394 6674035.331472816, 2552113.457023308 6674034.611307517, 2552123.8679385716 6674040.122572511, 2552211.725503986 6674130.563331279, 2552231.623386407 6674164.851201337, 2552240.7556234878 6674189.7869248055) + +LINESTRING (2552084.14641956 6674019.7879051175, 2551996.1238634125 6674305.1834116345) + +LINESTRING (2550186.3236131626 6672677.951759271, 2550192.3956711497 6672662.466360598, 2550198.6735685472 6672642.421759782, 2550210.569400409 6672635.2201067945, 2550222.366237831 6672634.639973638, 2550253.879467867 6672593.780595229) + +LINESTRING (2550210.858134192 6672667.677556718, 2550201.123680935 6672664.926925369) + +LINESTRING (2550210.858134192 6672667.677556718, 2550188.3451486505 6672696.864255909, 2550186.3236131626 6672697.641239392) + +LINESTRING (2550186.3236131626 6672840.2902741255, 2550231.5479721315 6672874.485025008) + +LINESTRING (2551337.5056051975 6674079.57162721, 2551337.0023834617 6674078.751438953) + +LINESTRING (2551337.0023834617 6674078.751438953, 2551351.8597989837 6674088.353642936) + +LINESTRING (2551497.6291117417 6674081.552081781, 2551435.5678474586 6674092.2645406) + +LINESTRING (2551337.5056051975 6674079.57162721, 2551349.888159722 6674101.536668821) + +LINESTRING (2551351.8597989837 6674088.353642936, 2551349.888159722 6674101.536668821) + +LINESTRING (2551435.5678474586 6674092.2645406, 2551354.903878011 6674102.476884628) + +LINESTRING (2551344.7569479207 6674104.177274917, 2551321.955228596 6674108.958372317, 2551288.7425940083 6674110.538735055, 2551160.388053137 6674084.392733793) + +LINESTRING (2551820.4664793406 6674029.830210117, 2551774.252574979 6674172.703003552) + +LINESTRING (2551349.888159722 6674101.536668821, 2551349.6159250126 6674103.367088956) + +LINESTRING (2551354.903878011 6674102.476884628, 2551349.6159250126 6674103.367088956) + +LINESTRING (2551349.6159250126 6674103.367088956, 2551349.393187523 6674103.407098139) + +LINESTRING (2551349.393187523 6674103.407098139, 2551344.7569479207 6674104.177274917) + +LINESTRING (2551629.9186815997 6674060.237189397, 2551642.8869532268 6674154.408804504) + +LINESTRING (2551708.858497886 6674048.154416052, 2551717.462764621 6674058.216725643, 2551765.689555927 6674150.397883883, 2551774.252574979 6674172.703003552) + +LINESTRING (2551910.081196063 6674119.950895418, 2551932.222952455 6674128.192787171, 2551949.7284692447 6674120.340984955, 2551978.9235794796 6674133.013893754) + +LINESTRING (2551497.6291117417 6674081.552081781, 2551512.4040318974 6674180.384766739) + +LINESTRING (2551435.5678474586 6674092.2645406, 2551406.347988614 6674187.896490896, 2551504.6329683647 6674213.782432468) + +LINESTRING (2551642.8869532268 6674154.408804504, 2551656.515187787 6674153.24853819, 2551661.473159319 6674188.036523038) + +LINESTRING (2551349.6159250126 6674103.367088956, 2551363.8216271386 6674239.708383223) + +LINESTRING (2551642.8869532268 6674154.408804504, 2551586.2951317485 6674163.840969459, 2551577.534123817 6674201.5996361645) + +LINESTRING (2551160.1818147204 6674064.618194965, 2551154.9681075523 6674083.052426154) + +LINESTRING (2551160.388053137 6674084.392733793, 2551154.9681075523 6674083.052426154) + +LINESTRING (2551010.510471123 6674129.593108585, 2550944.2006954607 6674110.598748831, 2550826.075580046 6674079.33157211, 2550804.717529637 6674077.471145088, 2550763.8328259564 6674081.84214836, 2550737.2775674523 6674091.744421218, 2550705.054877264 6674109.718546798, 2550685.833456849 6674116.240043671, 2550674.9523179964 6674116.500103362) + +LINESTRING (2551154.9681075523 6674083.052426154, 2551132.743855794 6674162.540671003) + +LINESTRING (2551126.696945423 6674160.830278418, 2551010.510471123 6674129.593108585) + +LINESTRING (2551132.743855794 6674162.540671003, 2551126.696945423 6674160.830278418) + +LINESTRING (2551138.2462967453 6674164.10102915, 2551132.743855794 6674162.540671003) + +LINESTRING (2550674.9523179964 6674116.500103362, 2550674.0861166473 6674139.545392922, 2550653.6437648074 6674194.578024501, 2550637.09519427 6674216.643089072) + +LINESTRING (2550917.7691800063 6674209.481445267, 2550921.547467796 6674198.3989015035, 2550926.0847129584 6674192.2975010555, 2550948.762689233 6674188.726681449, 2550977.471076805 6674174.703462715, 2550997.6824416188 6674154.628855012, 2551010.510471123 6674129.593108585) + +LINESTRING (2551132.743855794 6674162.540671003, 2551107.195040762 6674255.151927963) + +LINESTRING (2551577.534123817 6674201.5996361645, 2551512.4040318974 6674180.384766739) + +LINESTRING (2551774.252574979 6674172.703003552, 2551844.6623703605 6674216.3330179015) + +LINESTRING (2551774.252574979 6674172.703003552, 2551758.8424405004 6674218.34347936) + +LINESTRING (2551512.4040318974 6674180.384766739, 2551504.6329683647 6674213.782432468) + +LINESTRING (2551358.9049032903 6674237.5978988055, 2551259.0442620376 6674199.259098943, 2551138.2462967453 6674164.10102915) + +LINESTRING (2551758.8424405004 6674218.34347936, 2551661.473159319 6674188.036523038) + +LINESTRING (2551577.534123817 6674201.5996361645, 2551570.9674926368 6674229.8961310275) + +LINESTRING (2551849.810081235 6674219.603768633, 2551844.6623703605 6674216.3330179015) + +LINESTRING (2551570.9674926368 6674229.8961310275, 2551504.6329683647 6674213.782432468) + +LINESTRING (2551363.8216271386 6674239.708383223, 2551358.9049032903 6674237.5978988055) + +LINESTRING (2551369.464310213 6674242.12893881, 2551363.8216271386 6674239.708383223) + +LINESTRING (2551661.473159319 6674188.036523038, 2551631.1726111714 6674317.166162021) + +LINESTRING (2551363.8216271386 6674239.708383223, 2551370.726489322 6674304.233193532) + +LINESTRING (2551758.8424405004 6674218.34347936, 2551750.089682106 6674243.499253337, 2551705.5504336855 6674335.160292194) + +LINESTRING (2551631.1726111714 6674317.166162021, 2551431.1625948832 6674269.815293629, 2551369.464310213 6674242.12893881) + +LINESTRING (2551376.426919153 6674304.123168278, 2551370.726489322 6674304.233193532) + +LINESTRING (2551370.726489322 6674304.233193532, 2551366.3872330394 6674304.313211898) + +LINESTRING (2551366.3872330394 6674304.313211898, 2551307.7165283235 6674304.733308323) + +LINESTRING (2551528.069902012 6674337.650863852, 2551387.6545385453 6674303.813097107, 2551376.426919153 6674304.123168278) + +LINESTRING (2551705.5504336855 6674335.160292194, 2551631.1726111714 6674317.166162021) + +LINESTRING (2551765.8792952704 6674350.123726735, 2551705.5504336855 6674335.160292194) + +LINESTRING (2551770.499035799 6674351.273990754, 2551765.8792952704 6674350.123726735) + +LINESTRING (2551370.726489322 6674304.233193532, 2551381.0115790316 6674388.38925647) + +LINESTRING (2551705.5504336855 6674335.160292194, 2551683.6644129306 6674375.029443317) + +LINESTRING (2551683.6644129306 6674375.029443317, 2551528.069902012 6674337.650863852) + +LINESTRING (2551528.069902012 6674337.650863852, 2551515.260872156 6674388.38925647) + +LINESTRING (2551747.745465269 6674388.38925647, 2551683.6644129306 6674375.029443317) + +LINESTRING (2551307.7165283235 6674304.733308323, 2551296.652848637 6674388.38925647) + +LINESTRING (2551101.9400859103 6674253.821622619, 2550917.7691800063 6674209.481445267) + +LINESTRING (2551105.107907987 6674254.621806284, 2551101.9400859103 6674253.821622619) + +LINESTRING (2551107.195040762 6674255.151927963, 2551105.107907987 6674254.621806284) + +LINESTRING (2551113.5801821356 6674256.752295293, 2551107.195040762 6674255.151927963) + +LINESTRING (2551307.7165283235 6674304.733308323, 2551113.5801821356 6674256.752295293) + +LINESTRING (2550917.7691800063 6674209.481445267, 2550888.227589232 6674330.749279739, 2550873.7280407273 6674388.38925647) + +LINESTRING (2551107.195040762 6674255.151927963, 2551074.820848694 6674388.38925647) + +LINESTRING (2551683.6644129306 6674375.029443317, 2551676.005218592 6674388.38925647) + +LINESTRING (2552103.912309394 6674035.331472816, 2552115.816390793 6674056.896422595, 2552118.159259204 6674071.259719387, 2552103.541080245 6674163.490889105, 2552103.6483242214 6674198.088830333, 2552109.596240152 6674212.962244211, 2552214.6540894997 6674348.383327263, 2552236.9129845714 6674388.38925647) + +LINESTRING (2552733.706686524 6674363.156718183, 2552660.019657893 6674388.38925647) + +LINESTRING (2552914.2312972248 6674016.43713602, 2552910.4942571186 6674007.865168505, 2552913.191855606 6673994.342064562, 2552919.956475666 6673982.849426669, 2552930.6726237857 6673980.708935365) + +LINESTRING (2552897.798220201 6673998.282969113, 2552914.2312972248 6674016.43713602) + +LINESTRING (2552914.2312972248 6674016.43713602, 2552926.5643545296 6674030.050260625) + +LINESTRING (2553078.578566538 6673990.511185264, 2553073.3731089067 6674056.326291733) + +LINESTRING (2553073.3731089067 6674056.326291733, 2553186.1607741034 6674064.068068695, 2553184.535615382 6674084.792825625) + +LINESTRING (2553073.3731089067 6674056.326291733, 2553070.4445233927 6674102.01677902) + +LINESTRING (2553184.535615382 6674084.792825625, 2553183.7354103257 6674109.328457262) + +LINESTRING (2552926.5643545296 6674030.050260625, 2552926.457110553 6674058.066691205, 2552918.3478160175 6674178.664371858) + +LINESTRING (2553164.7944741575 6674108.238207018, 2553070.4445233927 6674102.01677902) + +LINESTRING (2553183.7354103257 6674109.328457262, 2553164.7944741575 6674108.238207018) + +LINESTRING (2553525.5384627027 6674020.678109446, 2553449.865462933 6674015.21685593) + +LINESTRING (2553558.1158829676 6674022.108437747, 2553525.5384627027 6674020.678109446) + +LINESTRING (2553565.094990981 6674021.468290815, 2553561.6796828043 6674022.26847448) + +LINESTRING (2553561.6796828043 6674022.26847448, 2553558.1158829676 6674022.108437747) + +LINESTRING (2553362.238884545 6674010.265719501, 2553358.3863509255 6674072.089909939) + +LINESTRING (2553449.865462933 6674015.21685593, 2553442.6636174303 6674102.896981052) + +LINESTRING (2553358.3863509255 6674072.089909939, 2553357.000428767 6674095.115194907) + +LINESTRING (2553442.6636174303 6674102.896981052, 2553357.000428767 6674095.115194907) + +LINESTRING (2553358.3863509255 6674072.089909939, 2553284.6107445876 6674067.3188148355, 2553277.4088990847 6674161.500432238) + +LINESTRING (2553442.6636174303 6674102.896981052, 2553437.3179176752 6674178.624362675, 2553369.1437467285 6674168.962144917) + +LINESTRING (2553183.7354103257 6674109.328457262, 2553182.3164900206 6674153.00848309) + +LINESTRING (2553070.4445233927 6674102.01677902, 2553025.905274973 6674099.6162280245, 2553022.6054603094 6674161.260377139, 2553017.0947698215 6674169.642301032, 2552992.205917722 6674154.008712672, 2552984.0471259668 6674152.608391258) + +LINESTRING (2553277.4088990847 6674161.500432238, 2553182.3164900206 6674153.00848309) + +LINESTRING (2553182.3164900206 6674153.00848309, 2553179.3384072864 6674191.97742759) + +LINESTRING (2552918.3478160175 6674178.664371858, 2552913.356846339 6674178.394309871) + +LINESTRING (2552923.314037086 6674179.344527974, 2552918.3478160175 6674178.664371858) + +LINESTRING (2553179.3384072864 6674191.97742759, 2553177.2842726586 6674217.663323245, 2553204.730481122 6674219.923842099) + +LINESTRING (2552918.3478160175 6674178.664371858, 2552914.355040275 6674234.33715037) + +LINESTRING (2553163.4662987553 6674260.113066687, 2553128.925488766 6674268.164914819, 2553107.33645133 6674270.555463519, 2553091.6540821423 6674268.094898748, 2553075.1385097513 6674260.663192958, 2552952.7153857374 6674183.425464666, 2552923.314037086 6674179.344527974) + +LINESTRING (2553288.8592559667 6674230.566284847, 2553275.363013993 6674225.595143827, 2553204.730481122 6674219.923842099) + +LINESTRING (2553369.1437467285 6674168.962144917, 2553277.4088990847 6674161.500432238) + +LINESTRING (2553547.647220948 6674163.500891401, 2553528.970269953 6674165.071251844, 2553483.0615984476 6674205.110441996) + +LINESTRING (2553369.1437467285 6674168.962144917, 2553366.421399631 6674205.580549899) + +LINESTRING (2553483.0615984476 6674205.110441996, 2553460.3671230995 6674213.062267169, 2553366.421399631 6674205.580549899) + +LINESTRING (2553366.421399631 6674205.580549899, 2553288.8592559667 6674230.566284847) + +LINESTRING (2553483.0615984476 6674205.110441996, 2553466.0675529307 6674218.483511502, 2553459.682411557 6674219.213679096, 2553394.453325197 6674215.742882448, 2553367.3288486637 6674217.343249778, 2553304.7891112543 6674245.439698726, 2553285.9141713795 6674257.772529467) + +LINESTRING (2553288.8592559667 6674230.566284847, 2553285.9141713795 6674257.772529467) + +LINESTRING (2553481.741672582 6674232.366698094, 2553434.3233358683 6674261.343349073) + +LINESTRING (2553433.2838942492 6674233.7470149165, 2553434.3233358683 6674261.343349073) + +LINESTRING (2553434.3233358683 6674261.343349073, 2553409.995452262 6674269.305176542, 2553343.2319520838 6674273.286090277, 2553328.6632703445 6674268.35495844, 2553305.457323724 6674260.503156224, 2553285.9141713795 6674257.772529467) + +LINESTRING (2553204.730481122 6674219.923842099, 2553185.104833411 6674226.165274688, 2553164.414995471 6674250.2107938295, 2553163.4662987553 6674260.113066687) + +LINESTRING (2553285.9141713795 6674257.772529467, 2553190.731017412 6674254.171702973, 2553163.4662987553 6674260.113066687) + +LINESTRING (2552914.355040275 6674234.33715037, 2552908.753604884 6674299.502107611) + +LINESTRING (2552906.715969329 6674283.478429713, 2552905.7342744665 6674299.052004299) + +LINESTRING (2552908.753604884 6674299.502107611, 2552905.7342744665 6674299.052004299) + +LINESTRING (2552915.658467067 6674300.512339488, 2552908.753604884 6674299.502107611) + +LINESTRING (2552905.7342744665 6674299.052004299, 2552838.467552552 6674293.070631401, 2552834.1117971963 6674327.438519824, 2552733.706686524 6674363.156718183) + +LINESTRING (2552908.753604884 6674299.502107611, 2552904.4841809357 6674388.38925647) + +LINESTRING (2552915.658467067 6674300.512339488, 2552992.4286552123 6674304.88334276, 2553005.4134259126 6674311.614887844, 2553009.026722969 6674320.076830104, 2553005.1839963407 6674388.38925647) + +LINESTRING (2552733.706686524 6674363.156718183, 2552732.181598501 6674388.38925647) \ No newline at end of file diff --git a/data/shops.wkt b/data/shops.wkt new file mode 100644 index 000000000..0db258f86 --- /dev/null +++ b/data/shops.wkt @@ -0,0 +1,71 @@ +LINESTRING (2552448.388211649 6673384.4020657055, 2552468.486211755 6673358.59603276, 2552447.349579492 6673343.299785728, 2552464.8707351834 6673317.99144973) + +LINESTRING (2552468.486211755 6673358.59603276, 2552494.9070020826 6673364.992645155, 2552499.078705819 6673325.778630037, 2552491.8477526763 6673292.405000148) + +LINESTRING (2552275.651163554 6673509.600802434, 2552269.1375383674 6673460.82612385, 2552232.711082539 6673436.321053566, 2552212.113232209 6673461.839839912) + +LINESTRING (2552269.1375383674 6673460.82612385, 2552298.941002227 6673417.776676054, 2552259.865349611 6673387.310912997, 2552232.711082539 6673436.321053566) + +LINESTRING (2552259.865349611 6673387.310912997, 2552258.5407512174 6673340.287670019, 2552324.108371708 6673351.546756366, 2552298.941002227 6673417.776676054) + +LINESTRING (2552491.8477526763 6673292.405000148, 2552529.0486969245 6673296.548545875) + +LINESTRING (2552464.8707351834 6673317.99144973, 2552491.8477526763 6673292.405000148) + +LINESTRING (2552674.216004995 6673336.247571644, 2552716.189496259 6673336.313874838, 2552740.032267347 6673368.766535485, 2552720.809051393 6673409.434952837) + +LINESTRING (2552716.189496259 6673336.313874838, 2552742.0191649375 6673307.172710176) + +POINT (2552447.349579492 6673343.299785728) + +POINT (2552494.9070020826 6673364.992645155) + +POINT (2552499.078705819 6673325.778630037) + +POINT (2552464.8707351834 6673317.99144973) + +POINT (2552491.8477526763 6673292.405000148) + +POINT (2552324.108371708 6673351.546756366) + +POINT (2552258.5407512174 6673340.287670019) + +POINT (2552259.865349611 6673387.310912997) + +POINT (2552298.941002227 6673417.776676054) + +POINT (2552269.1375383674 6673460.82612385) + +POINT (2552232.711082539 6673436.321053566) + +POINT (2552742.0191649375 6673307.172710176) + +POINT (2552716.189496259 6673336.313874838) + +POINT (2552740.032267347 6673368.766535485) + +LINESTRING (2552244.2457294916 6673589.567364379, 2552275.113595061 6673548.410210286, 2552304.398493165 6673567.405819868, 2552296.4836558397 6673607.771490227, 2552245.037213224 6673588.775880646) + +POINT (2552245.037213224 6673588.775880646) + +POINT (2552296.4836558397 6673607.771490227) + +POINT (2552304.398493165 6673567.405819868) + +POINT (2552275.113595061 6673548.410210286) + +LINESTRING (2552275.113595061 6673548.410210286, 2552256.454491749 6673534.296470803) + +LINESTRING (2552296.4836558397 6673607.771490227, 2552317.179331093 6673633.669279735) + +LINESTRING (2552798.3065660596 6673482.146870521, 2552800.516540576 6673446.05062009, 2552823.8909809357 6673448.244671392, 2552847.2814310095 6673449.964078932, 2552844.716030899 6673485.8301613815, 2552798.3065660596 6673482.146870521) + +LINESTRING (2552823.8909809357 6673448.244671392, 2552825.95680176 6673415.918938927) + +POINT (2552798.3065660596 6673482.146870521) + +POINT (2552844.716030899 6673485.8301613815) + +POINT (2552847.2814310095 6673449.964078932) + +POINT (2552800.516540576 6673446.05062009) \ No newline at end of file diff --git a/data/throwboxes.wkt b/data/throwboxes.wkt new file mode 100644 index 000000000..781180028 --- /dev/null +++ b/data/throwboxes.wkt @@ -0,0 +1,11 @@ +LINESTRING (2553039.1292822366 6673301.743093083) + +LINESTRING (2552275.9398973365 6673509.820852942) + +LINESTRING (2552559.517719977 6673146.45745054) + +LINESTRING (2552017.9191392646 6673946.871168619) + +LINESTRING (2551949.8274636846 6673239.518810811) + +LINESTRING (2552473.318311431 6673253.912114491) \ No newline at end of file diff --git a/data/tram10.wkt b/data/tram10.wkt new file mode 100644 index 000000000..abbf36bb5 --- /dev/null +++ b/data/tram10.wkt @@ -0,0 +1 @@ +LINESTRING (2552787.726166266 6672530.040305593, 2552686.56058452 6672754.707532612, 2552579.465099618 6673027.760206092, 2552440.104393391 6673297.548247428, 2552172.432960881 6673639.590638857, 2551943.3598269443 6674056.316289438, 2551761.5729668215 6674388.38925647) \ No newline at end of file diff --git a/data/tram3.wkt b/data/tram3.wkt new file mode 100644 index 000000000..a43536365 --- /dev/null +++ b/data/tram3.wkt @@ -0,0 +1,2 @@ +LINESTRING (2552480.8583879373 6673392.573941387, 2552720.809051393 6673409.434952837, 2552930.1703346907 6673422.44040407, 2553055.669603237 6673293.861283979, 2553058.119715625 6673058.3372244015, 2553281.9791423935 6672606.85359586, 2553180.9635660085 6672364.467961353, 2552883.7245106613 6672239.799346303, 2552708.001130296 6672220.484913082, 2552440.7491407027 6672213.753367998, + 2552483.811722061 6672500.92928317, 2552341.7794494093 6672696.104081427, 2552261.900555275 6672932.613958296, 2552508.7708714856 6673110.496865532) \ No newline at end of file diff --git a/data/tram4.wkt b/data/tram4.wkt new file mode 100644 index 000000000..57a9effea --- /dev/null +++ b/data/tram4.wkt @@ -0,0 +1,2 @@ +LINESTRING (2554383.251038637 6673258.043062663, 2554164.2258403506 6673085.173384075, 2553841.6277093147 6673119.391238062, 2553707.4902432454 6673207.421443538, 2553241.3996715695 6673442.8554824535, 2552930.1703346907 6673422.44040407, 2552720.809051393 6673409.434952837, 2552480.8583879373 6673392.573941387, 2552172.432960881 6673639.590638857, 2551943.3598269443 6674056.316289438, + 2551761.5729668215 6674388.38925647) \ No newline at end of file diff --git a/default_settings.txt b/default_settings.txt new file mode 100644 index 000000000..3af13ebe9 --- /dev/null +++ b/default_settings.txt @@ -0,0 +1 @@ +# # Default settings for the simulation # ## Scenario settings Scenario.name = default_scenario Scenario.simulateConnections = true Scenario.updateInterval = 0.1 # 43200s == 12h Scenario.endTime = 10000000 Scenario.endTime = 43200 ## Interface-specific settings: # type : which interface class the interface belongs to # For different types, the sub-parameters are interface-specific # For SimpleBroadcastInterface, the parameters are: # transmitSpeed : transmit speed of the interface (bytes per second) # transmitRange : range of the interface (meters) # "Bluetooth" interface for all nodes btInterface.type = SimpleBroadcastInterface # Transmit speed of 2 Mbps = 250kBps btInterface.transmitSpeed = 250k btInterface.transmitRange = 10 # High speed, long range, interface for group 4 highspeedInterface.type = SimpleBroadcastInterface highspeedInterface.transmitSpeed = 10M highspeedInterface.transmitRange = 10 # Define 6 different node groups Scenario.nrofHostGroups = 6 ## Group-specific settings: # groupID : Group's identifier. Used as the prefix of host names # nrofHosts: number of hosts in the group # movementModel: movement model of the hosts (valid class name from movement package) # waitTime: minimum and maximum wait times (seconds) after reaching destination # speed: minimum and maximum speeds (m/s) when moving on a path # bufferSize: size of the message buffer (bytes) # router: router used to route messages (valid class name from routing package) # activeTimes: Time intervals when the nodes in the group are active (start1, end1, start2, end2, ...) # msgTtl : TTL (minutes) of the messages created by this host group, default=infinite ## Group and movement model specific settings # pois: Points Of Interest indexes and probabilities (poiIndex1, poiProb1, poiIndex2, poiProb2, ... ) # for ShortestPathMapBasedMovement # okMaps : which map nodes are OK for the group (map file indexes), default=all # for all MapBasedMovent models # routeFile: route's file path - for MapRouteMovement # routeType: route's type - for MapRouteMovement # Common settings for all groups Group.movementModel = ShortestPathMapBasedMovement Group.router = EpidemicRouter Group.bufferSize = 5M Group.waitTime = 0, 120 # All nodes have the bluetooth interface Group.nrofInterfaces = 1 Group.interface1 = btInterface # Walking speeds Group.speed = 0.5, 1.5 # Message TTL of 300 minutes (5 hours) Group.msgTtl = 300 Group.nrofHosts = 40 # group1 (pedestrians) specific settings Group1.groupID = p # group2 specific settings Group2.groupID = c # cars can drive only on roads Group2.okMaps = 1 # 10-50 km/h Group2.speed = 2.7, 13.9 # another group of pedestrians Group3.groupID = w # The Tram groups Group4.groupID = t Group4.bufferSize = 50M Group4.movementModel = MapRouteMovement Group4.routeFile = data/tram3.wkt Group4.routeType = 1 Group4.waitTime = 10, 30 Group4.speed = 7, 10 Group4.nrofHosts = 2 Group4.nrofInterfaces = 2 Group4.interface1 = btInterface Group4.interface2 = highspeedInterface Group5.groupID = t Group5.bufferSize = 50M Group5.movementModel = MapRouteMovement Group5.routeFile = data/tram4.wkt Group5.routeType = 2 Group5.waitTime = 10, 30 Group5.speed = 7, 10 Group5.nrofHosts = 2 Group6.groupID = t Group6.bufferSize = 50M Group6.movementModel = MapRouteMovement Group6.routeFile = data/tram10.wkt Group6.routeType = 2 Group6.waitTime = 10, 30 Group6.speed = 7, 10 Group6.nrofHosts = 2 ## Message creation parameters # How many event generators Events.nrof = 1 # Class of the first event generator Events1.class = MessageEventGenerator # (following settings are specific for the MessageEventGenerator class) # Creation interval in seconds (one new message every 25 to 35 seconds) Events1.interval = 25,35 # Message sizes (500kB - 1MB) Events1.size = 500k,1M # range of message source/destination addresses Events1.hosts = 0,125 # Message ID prefix Events1.prefix = M ## Movement model settings # seed for movement models' pseudo random number generator (default = 0) MovementModel.rngSeed = 1 # World's size for Movement Models without implicit size (width, height; meters) MovementModel.worldSize = 4500, 3400 # How long time to move hosts in the world before real simulation MovementModel.warmup = 1000 ## Map based movement -movement model specific settings MapBasedMovement.nrofMapFiles = 4 MapBasedMovement.mapFile1 = data/roads.wkt MapBasedMovement.mapFile2 = data/main_roads.wkt MapBasedMovement.mapFile3 = data/pedestrian_paths.wkt MapBasedMovement.mapFile4 = data/shops.wkt ## Reports - all report names have to be valid report classes # how many reports to load Report.nrofReports = 2 # length of the warm up period (simulated seconds) Report.warmup = 0 # default directory of reports (can be overridden per Report with output setting) Report.reportDir = reports/ # Report classes to load Report.report1 = ContactTimesReport Report.report2 = ConnectivityONEReport ## Default settings for some routers settings ProphetRouter.secondsInTimeUnit = 30 SprayAndWaitRouter.nrofCopies = 6 SprayAndWaitRouter.binaryMode = true ## Optimization settings -- these affect the speed of the simulation ## see World class for details. Optimization.cellSizeMult = 5 Optimization.randomizeUpdateOrder = true ## GUI settings # GUI underlay image settings GUI.UnderlayImage.fileName = data/helsinki_underlay.png # Image offset in pixels (x, y) GUI.UnderlayImage.offset = 64, 20 # Scaling factor for the image GUI.UnderlayImage.scale = 4.75 # Image rotation (radians) GUI.UnderlayImage.rotate = -0.015 # how many events to show in the log panel (default = 30) GUI.EventLogPanel.nrofEvents = 100 # Regular Expression log filter (see Pattern-class from the Java API for RE-matching details) #GUI.EventLogPanel.REfilter = .*p[1-9]<->p[1-9]$ \ No newline at end of file diff --git a/doc/create_docs.sh b/doc/create_docs.sh new file mode 100755 index 000000000..519f6a185 --- /dev/null +++ b/doc/create_docs.sh @@ -0,0 +1 @@ +javadoc -sourcepath ../ -subpackages core:ui:gui:input:movement:report:routing:applications:interfaces diff --git a/ee/1000c_100n_12h.txt b/ee/1000c_100n_12h.txt new file mode 100644 index 000000000..aa257520f --- /dev/null +++ b/ee/1000c_100n_12h.txt @@ -0,0 +1,1000 @@ +3662.5 C M1 4 2 1262799 +3721.7 C M2 90 76 1292645 +3730.6 C M3 33 99 1236983 +3805.4 C M4 62 12 1191810 +3817.3 C M5 67 19 606629 +3824.3 C M6 1 73 1221142 +3829.0 C M7 19 13 291138 +3833.8 C M8 59 71 1633127 +3836.6 C M9 38 26 1333674 +3843.8 C M10 45 99 446071 +3911.7 C M11 16 32 1302999 +3931.6 C M12 98 55 355706 +3937.4 C M13 71 47 1461414 +3971.9 C M14 89 85 1740698 +3979.8 C M15 10 53 368358 +3982.3 C M16 4 65 1403045 +4158.1 C M17 22 30 380626 +4166.2 C M18 63 89 1310520 +4199.1 C M19 16 6 196677 +4228.7 C M20 15 7 373643 +4228.8 C M21 67 61 1674459 +4247.1 C M22 56 67 1620485 +4323.8 C M23 58 91 388046 +4345.5 C M24 48 96 782313 +4408.9 C M25 15 81 1481536 +4460.2 C M26 20 40 976940 +4507.1 C M27 27 35 838388 +4568.8 C M28 81 69 280627 +4611.1 C M29 71 69 1998915 +4627.5 C M30 18 74 366352 +4633.8 C M31 49 50 599555 +4689.5 C M32 64 65 1178765 +4766.1 C M33 48 42 1560790 +4774.5 C M34 28 6 1285812 +4795.3 C M35 32 35 1241222 +4841.2 C M36 20 99 684460 +4906.2 C M37 69 51 882871 +4981.0 C M38 86 84 1553340 +5019.2 C M39 63 28 1324262 +5052.1 C M40 38 89 1077849 +5075.4 C M41 22 18 855648 +5193.1 C M42 97 50 209684 +5238.5 C M43 20 94 164648 +5282.8 C M44 0 65 1847702 +5451.3 C M45 81 44 1843909 +5509.0 C M46 14 43 648591 +5532.5 C M47 50 74 1949898 +5611.7 C M48 65 92 863925 +5730.2 C M49 78 51 484860 +5757.1 C M50 84 51 1716060 +5760.6 C M51 67 33 578684 +5811.1 C M52 56 69 1518453 +5823.3 C M53 98 78 603301 +5897.9 C M54 20 96 1165140 +5900.2 C M55 39 97 1776324 +5902.7 C M56 31 44 1725415 +5913.1 C M57 67 60 1237350 +5935.8 C M58 35 40 1526123 +5951.8 C M59 24 3 1140961 +5996.5 C M60 41 1 232984 +6013.6 C M61 68 78 973388 +6125.8 C M62 29 23 1566926 +6139.8 C M63 22 44 1799231 +6189.2 C M64 7 54 1665121 +6223.4 C M65 27 71 433846 +6236.5 C M66 72 89 1195085 +6236.6 C M67 52 72 1552004 +6247.9 C M68 56 45 1825341 +6306.3 C M69 90 47 709513 +6356.9 C M70 71 53 306924 +6361.5 C M71 6 17 1066000 +6362.0 C M72 78 47 281610 +6392.6 C M73 49 40 1662727 +6417.6 C M74 83 81 1624882 +6462.6 C M75 35 53 1192657 +6467.5 C M76 41 78 300608 +6637.3 C M77 93 46 1294919 +6687.9 C M78 44 41 1042049 +6787.9 C M79 52 74 1242800 +6797.5 C M80 74 77 760887 +6806.7 C M81 38 18 1087267 +6808.4 C M82 51 1 1004662 +6923.5 C M83 73 21 1252983 +6944.3 C M84 32 22 758106 +6946.3 C M85 3 95 1888380 +6950.9 C M86 77 98 657253 +6951.5 C M87 41 25 1820027 +6979.3 C M88 52 16 646677 +6990.4 C M89 94 51 336746 +7086.2 C M90 18 27 196905 +7173.0 C M91 32 88 1465406 +7232.0 C M92 37 92 1094587 +7286.4 C M93 1 73 319722 +7343.7 C M94 47 84 866526 +7346.9 C M95 40 85 1847187 +7365.6 C M96 7 52 340336 +7366.7 C M97 52 12 1308061 +7398.1 C M98 77 84 894105 +7399.8 C M99 34 27 204625 +7419.4 C M100 77 44 1747465 +7442.8 C M101 84 37 1918900 +7478.0 C M102 44 1 100589 +7500.4 C M103 77 56 360257 +7572.7 C M104 97 67 978906 +7616.3 C M105 78 91 1047161 +7749.1 C M106 85 91 1756952 +7752.6 C M107 91 59 1665637 +7838.8 C M108 27 99 1662818 +7875.1 C M109 60 24 588447 +7924.6 C M110 87 36 1202622 +7932.4 C M111 84 28 1943087 +7955.9 C M112 92 28 1977543 +7980.3 C M113 3 42 372636 +8023.5 C M114 20 23 140976 +8029.1 C M115 27 4 111926 +8053.3 C M116 14 25 1372247 +8171.7 C M117 50 54 1819821 +8217.1 C M118 67 7 1788059 +8260.1 C M119 75 32 1053871 +8304.0 C M120 64 29 632281 +8312.5 C M121 43 5 774335 +8341.4 C M122 70 49 1906331 +8385.2 C M123 81 22 503746 +8422.4 C M124 75 29 269857 +8435.4 C M125 94 39 222633 +8472.7 C M126 96 85 1627872 +8483.9 C M127 29 92 738755 +8497.5 C M128 95 66 515861 +8505.1 C M129 85 21 1528054 +8507.4 C M130 49 89 578108 +8560.9 C M131 8 58 1008444 +8620.1 C M132 61 27 1263755 +8680.3 C M133 66 26 1196312 +8718.8 C M134 61 7 923923 +8773.7 C M135 49 26 246936 +8777.1 C M136 46 51 600608 +8833.8 C M137 63 92 616223 +8834.4 C M138 43 26 1766835 +8839.1 C M139 29 68 607788 +8928.1 C M140 33 12 965027 +8972.7 C M141 28 8 1101991 +8986.3 C M142 38 72 551350 +9105.1 C M143 20 78 1147486 +9107.9 C M144 73 94 1989187 +9110.6 C M145 57 75 1227342 +9169.5 C M146 76 82 1619943 +9222.8 C M147 80 88 1858797 +9223.2 C M148 91 78 470351 +9244.3 C M149 87 3 1179166 +9266.3 C M150 20 86 1559691 +9326.6 C M151 62 54 1154601 +9334.8 C M152 82 53 1440020 +9382.5 C M153 77 2 1338161 +9436.2 C M154 51 43 565911 +9569.8 C M155 60 20 1989385 +9579.2 C M156 78 41 1756292 +9638.2 C M157 46 52 931500 +9664.0 C M158 61 63 455263 +9680.4 C M159 72 83 1210846 +9707.3 C M160 77 31 1909404 +9721.9 C M161 6 10 951977 +9727.8 C M162 24 10 1443762 +9735.6 C M163 99 96 1874401 +9763.7 C M164 62 51 1273522 +9801.6 C M165 15 7 738537 +9830.8 C M166 63 26 1390105 +9932.8 C M167 65 20 1585070 +9951.8 C M168 41 17 962442 +9980.5 C M169 10 86 1298423 +9995.7 C M170 76 70 1892434 +10072.5 C M171 86 63 1487240 +10122.3 C M172 86 31 251661 +10212.2 C M173 75 56 1862858 +10260.0 C M174 82 61 1841415 +10368.3 C M175 92 27 1395978 +10372.2 C M176 11 93 1513613 +10460.9 C M177 9 33 1789900 +10472.1 C M178 77 20 1259156 +10612.9 C M179 23 82 759663 +10620.0 C M180 45 6 1781497 +10645.6 C M181 71 90 607195 +10666.3 C M182 12 87 1948964 +10673.7 C M183 4 75 947004 +10710.0 C M184 18 85 1890392 +10714.4 C M185 91 83 1381064 +10811.5 C M186 4 23 1629494 +10856.6 C M187 81 23 1873656 +10904.9 C M188 17 42 502267 +10961.2 C M189 67 81 1497741 +10985.3 C M190 63 31 700836 +10997.4 C M191 59 2 1977890 +11001.0 C M192 35 59 589188 +11014.7 C M193 4 57 391467 +11019.4 C M194 22 12 117674 +11100.0 C M195 51 11 527463 +11120.0 C M196 17 92 1666673 +11135.9 C M197 2 30 912759 +11184.9 C M198 0 74 239910 +11192.8 C M199 17 98 859143 +11236.2 C M200 26 6 1743884 +11295.6 C M201 73 2 1247158 +11362.2 C M202 92 49 625088 +11401.3 C M203 62 5 1653356 +11402.2 C M204 58 34 883068 +11469.4 C M205 18 20 264413 +11551.2 C M206 59 28 1125072 +11560.1 C M207 34 85 840984 +11564.8 C M208 19 59 487329 +11566.6 C M209 31 84 861558 +11626.1 C M210 41 17 1651402 +11661.0 C M211 37 44 1981871 +11667.7 C M212 6 26 418681 +11671.5 C M213 51 45 324146 +11682.9 C M214 9 20 1450886 +11684.4 C M215 32 96 775951 +11687.1 C M216 49 33 968141 +11698.3 C M217 80 3 1713069 +11733.2 C M218 57 12 1644958 +11750.9 C M219 21 33 395441 +11878.7 C M220 47 96 868701 +11889.4 C M221 94 45 584897 +11920.3 C M222 27 50 1884079 +11976.0 C M223 94 78 510486 +12011.8 C M224 38 65 1074798 +12130.8 C M225 41 68 417912 +12161.4 C M226 34 79 1863151 +12305.8 C M227 10 99 651545 +12359.5 C M228 85 62 997591 +12399.8 C M229 45 8 1021729 +12405.5 C M230 36 41 1167789 +12417.5 C M231 67 89 909812 +12428.1 C M232 43 7 1230962 +12440.8 C M233 35 32 251110 +12480.0 C M234 79 56 1962150 +12509.5 C M235 54 14 1464139 +12512.6 C M236 69 45 337456 +12552.5 C M237 27 97 1254509 +12716.2 C M238 68 56 1401758 +12742.4 C M239 28 6 1034685 +12821.5 C M240 43 39 1350307 +12824.4 C M241 90 95 1029933 +12838.0 C M242 99 69 995821 +12862.7 C M243 69 76 805218 +12945.8 C M244 41 42 1541845 +12953.3 C M245 62 8 1291459 +12957.5 C M246 98 67 1065190 +12980.1 C M247 90 29 309283 +12994.5 C M248 85 55 1597308 +13032.1 C M249 40 37 765514 +13054.8 C M250 89 27 403054 +13095.3 C M251 58 21 1908887 +13150.7 C M252 27 75 180934 +13153.0 C M253 96 36 1223301 +13210.0 C M254 89 64 1421593 +13245.5 C M255 86 24 555449 +13249.2 C M256 55 91 655953 +13293.6 C M257 84 44 1666751 +13294.1 C M258 92 76 105130 +13320.3 C M259 84 42 541799 +13426.8 C M260 34 11 252875 +13444.1 C M261 76 13 239256 +13451.3 C M262 28 62 541648 +13522.2 C M263 73 67 105030 +13522.7 C M264 1 45 1132319 +13577.9 C M265 28 96 254809 +13578.4 C M266 55 14 366545 +13581.8 C M267 76 38 800976 +13585.7 C M268 69 66 999133 +13614.9 C M269 30 45 219188 +13620.6 C M270 33 84 667441 +13621.0 C M271 66 48 730097 +13674.7 C M272 51 10 1313087 +13745.3 C M273 41 43 1080896 +13822.6 C M274 14 19 1112946 +13823.4 C M275 20 44 494962 +13836.4 C M276 80 18 678857 +13867.7 C M277 7 99 1073257 +13904.5 C M278 94 82 628681 +13951.2 C M279 71 7 840252 +13971.4 C M280 76 6 124559 +13993.1 C M281 67 86 977220 +14015.9 C M282 49 36 1260396 +14033.6 C M283 75 23 1414421 +14073.5 C M284 63 5 1551708 +14085.3 C M285 64 12 1607818 +14103.3 C M286 76 83 1501998 +14112.8 C M287 51 36 1795082 +14195.9 C M288 45 70 1785612 +14217.5 C M289 46 50 1275001 +14278.0 C M290 50 76 1521698 +14301.9 C M291 7 25 367708 +14324.1 C M292 63 43 314767 +14334.3 C M293 12 62 476486 +14359.5 C M294 80 65 1377551 +14453.4 C M295 54 27 1887752 +14485.0 C M296 68 45 1198279 +14505.5 C M297 71 7 905571 +14557.1 C M298 76 59 1958711 +14578.1 C M299 75 85 774845 +14596.7 C M300 62 44 1536918 +14707.0 C M301 62 37 1481561 +14750.7 C M302 96 95 678130 +14756.8 C M303 78 82 1996531 +14767.1 C M304 88 4 1145902 +14810.3 C M305 57 39 376772 +14811.5 C M306 61 49 1114712 +14889.0 C M307 5 64 689846 +14907.5 C M308 78 64 802740 +14992.7 C M309 1 86 1484847 +14993.3 C M310 24 54 1568013 +15005.2 C M311 8 48 1585450 +15007.0 C M312 3 45 1943486 +15070.6 C M313 18 31 279392 +15121.3 C M314 3 49 171714 +15171.2 C M315 32 99 525614 +15188.0 C M316 54 60 1756473 +15214.0 C M317 79 89 927874 +15255.4 C M318 52 48 203411 +15271.7 C M319 38 35 813048 +15300.5 C M320 94 49 1360390 +15313.8 C M321 88 34 1069884 +15405.4 C M322 28 73 136440 +15411.8 C M323 81 33 518156 +15419.8 C M324 88 94 1992522 +15470.6 C M325 60 48 1004219 +15471.5 C M326 96 51 1200561 +15492.2 C M327 16 24 1021306 +15535.0 C M328 20 6 1733914 +15544.5 C M329 76 86 1815870 +15545.5 C M330 81 24 1646792 +15577.9 C M331 45 88 1716611 +15647.6 C M332 93 86 906730 +15665.0 C M333 37 26 1869940 +15722.3 C M334 27 47 1202040 +15742.3 C M335 77 24 1886430 +15793.3 C M336 3 94 399935 +15804.1 C M337 56 43 618517 +15844.5 C M338 63 38 1083416 +15846.7 C M339 34 90 962940 +15869.9 C M340 26 4 1536044 +15916.3 C M341 96 81 1945126 +15990.7 C M342 60 21 1637254 +15999.9 C M343 13 33 1965073 +16031.4 C M344 83 54 208347 +16157.6 C M345 86 10 483833 +16175.4 C M346 9 76 1242101 +16228.0 C M347 38 13 652701 +16232.3 C M348 85 91 686275 +16235.5 C M349 13 15 757626 +16309.4 C M350 42 60 412856 +16309.6 C M351 38 18 1759223 +16328.8 C M352 11 87 1989701 +16338.6 C M353 90 83 973385 +16342.7 C M354 76 50 1133603 +16385.4 C M355 27 55 1716299 +16473.1 C M356 18 16 1140403 +16505.1 C M357 8 10 181302 +16510.1 C M358 76 29 577653 +16539.9 C M359 48 9 659712 +16599.3 C M360 68 91 775046 +16601.2 C M361 27 78 1751672 +16608.5 C M362 4 16 1413931 +16611.9 C M363 45 47 746611 +16649.0 C M364 50 14 700635 +16662.0 C M365 26 1 724928 +16684.6 C M366 83 54 692965 +16787.9 C M367 34 71 683484 +16797.8 C M368 39 63 300452 +16806.8 C M369 77 17 1073583 +16863.8 C M370 55 69 1747799 +16892.3 C M371 23 79 962002 +16949.5 C M372 77 53 297155 +17053.0 C M373 24 9 454684 +17132.5 C M374 38 18 1918313 +17142.3 C M375 36 95 371174 +17198.9 C M376 9 63 1821768 +17316.4 C M377 25 73 1895785 +17428.0 C M378 57 36 1173191 +17448.4 C M379 48 90 1420711 +17475.8 C M380 38 46 1431848 +17487.7 C M381 78 10 1161158 +17512.2 C M382 16 79 699063 +17563.5 C M383 54 98 1921083 +17593.8 C M384 30 8 1731499 +17624.3 C M385 52 37 1274935 +17640.4 C M386 8 5 1111034 +17804.7 C M387 76 33 977442 +17828.3 C M388 75 87 1816509 +17834.7 C M389 38 1 852791 +17892.3 C M390 89 40 746511 +17949.7 C M391 32 31 221336 +17984.2 C M392 97 70 892845 +18057.7 C M393 14 93 242777 +18118.4 C M394 23 56 1192547 +18123.7 C M395 50 40 499524 +18127.3 C M396 30 35 522870 +18129.2 C M397 83 28 1000168 +18152.7 C M398 99 17 787026 +18159.5 C M399 86 39 161208 +18162.1 C M400 31 50 590219 +18241.9 C M401 0 7 217642 +18243.3 C M402 68 92 903180 +18352.3 C M403 17 80 1554778 +18366.7 C M404 33 25 1558304 +18423.4 C M405 19 26 1565257 +18426.2 C M406 91 37 902285 +18449.9 C M407 23 72 1967567 +18454.9 C M408 81 97 1048227 +18525.4 C M409 68 42 1809154 +18590.1 C M410 45 21 325851 +18617.1 C M411 75 13 467201 +18645.8 C M412 40 85 185372 +18692.4 C M413 92 20 732963 +18710.2 C M414 15 4 1069516 +18778.2 C M415 38 52 1687053 +18831.8 C M416 75 23 1138144 +18942.1 C M417 2 3 410959 +18981.9 C M418 57 68 1233408 +19023.1 C M419 66 59 1531648 +19089.6 C M420 38 42 1402539 +19107.1 C M421 86 30 1750781 +19136.7 C M422 78 10 1424623 +19170.0 C M423 53 57 1360381 +19179.3 C M424 64 19 1189141 +19207.3 C M425 53 66 1891592 +19208.5 C M426 73 46 1719441 +19251.5 C M427 81 95 543088 +19297.1 C M428 92 73 209574 +19308.0 C M429 34 59 1584128 +19326.1 C M430 16 8 1859699 +19329.7 C M431 76 15 568827 +19339.9 C M432 67 34 828725 +19369.0 C M433 12 25 1151597 +19374.1 C M434 94 99 1348064 +19427.0 C M435 14 71 1544500 +19520.4 C M436 75 33 885722 +19593.3 C M437 21 31 1250413 +19644.6 C M438 35 89 1011907 +19660.1 C M439 95 2 434915 +19666.4 C M440 64 80 1068215 +19726.6 C M441 54 7 1014441 +19808.1 C M442 26 69 909824 +19846.9 C M443 51 84 1818634 +19909.3 C M444 6 42 718662 +20011.5 C M445 23 69 1083666 +20051.7 C M446 67 86 816203 +20053.7 C M447 76 25 1174274 +20063.9 C M448 47 1 1704849 +20071.5 C M449 81 44 1370489 +20074.5 C M450 51 73 251812 +20077.6 C M451 0 43 1150403 +20103.5 C M452 98 58 343490 +20132.4 C M453 17 55 225635 +20142.9 C M454 79 16 1475711 +20172.8 C M455 65 61 128815 +20218.0 C M456 73 24 1480721 +20219.6 C M457 77 6 1157562 +20298.0 C M458 47 37 701183 +20343.6 C M459 93 12 351269 +20361.7 C M460 70 42 592836 +20464.0 C M461 95 34 429171 +20465.2 C M462 99 72 585128 +20520.7 C M463 73 97 289722 +20613.1 C M464 83 71 269900 +20664.1 C M465 62 45 710278 +20679.1 C M466 22 7 1810962 +20679.8 C M467 26 73 849862 +20694.9 C M468 99 9 913876 +20793.1 C M469 5 99 242752 +20810.9 C M470 93 70 318886 +20849.5 C M471 28 56 1004162 +20924.0 C M472 96 46 174264 +20929.9 C M473 43 68 918737 +20947.4 C M474 22 25 360192 +20952.7 C M475 29 88 853798 +20971.5 C M476 76 3 985020 +21014.1 C M477 87 53 984504 +21044.0 C M478 24 19 1974691 +21046.7 C M479 98 73 1090972 +21077.9 C M480 87 8 928015 +21132.6 C M481 42 92 1943645 +21138.6 C M482 96 71 1218903 +21148.6 C M483 15 12 1253409 +21180.3 C M484 76 86 1815323 +21232.0 C M485 99 6 1432298 +21278.9 C M486 18 33 422468 +21281.9 C M487 29 55 1551332 +21282.9 C M488 14 4 659564 +21342.7 C M489 92 22 1317641 +21392.8 C M490 28 95 247936 +21431.9 C M491 79 83 1252609 +21450.8 C M492 0 98 1280576 +21455.9 C M493 34 54 1165965 +21499.3 C M494 82 90 875789 +21586.5 C M495 86 50 1071708 +21700.5 C M496 82 2 561207 +21706.3 C M497 90 62 1877878 +21815.6 C M498 87 34 1777859 +21922.7 C M499 24 60 1292580 +21952.4 C M500 90 69 332002 +21974.2 C M501 91 54 1539214 +21981.8 C M502 94 78 1360177 +21997.1 C M503 88 79 413282 +22023.4 C M504 3 98 127672 +22078.8 C M505 17 96 1331938 +22083.5 C M506 71 54 1485143 +22099.4 C M507 33 48 336264 +22133.7 C M508 40 89 667486 +22144.2 C M509 44 51 1829965 +22234.2 C M510 89 82 1167317 +22256.0 C M511 70 52 184170 +22268.1 C M512 55 12 556447 +22310.9 C M513 39 5 1621020 +22343.8 C M514 60 99 219085 +22347.6 C M515 80 72 173183 +22377.0 C M516 51 85 834438 +22438.0 C M517 3 29 1124703 +22460.7 C M518 13 42 1637904 +22492.0 C M519 10 44 1467838 +22501.4 C M520 19 17 1478197 +22510.6 C M521 44 40 308992 +22522.7 C M522 98 17 1845859 +22535.5 C M523 12 76 973275 +22576.4 C M524 71 43 187944 +22611.0 C M525 57 62 1963753 +22643.5 C M526 14 6 848322 +22717.5 C M527 2 56 708073 +22791.7 C M528 11 30 775253 +22850.9 C M529 11 79 1431149 +22889.6 C M530 49 40 1126781 +22907.4 C M531 43 66 590276 +22981.3 C M532 63 20 1070893 +22997.1 C M533 60 98 272482 +23011.7 C M534 28 85 967535 +23017.1 C M535 16 90 403686 +23087.6 C M536 33 53 560915 +23126.5 C M537 97 64 1417086 +23220.9 C M538 83 44 1197335 +23233.0 C M539 92 62 134433 +23239.3 C M540 51 4 229652 +23263.9 C M541 2 5 675323 +23305.6 C M542 94 92 1584593 +23338.0 C M543 79 45 1521644 +23338.3 C M544 45 35 1723034 +23368.6 C M545 42 68 494338 +23385.9 C M546 73 61 1480927 +23442.7 C M547 13 10 676448 +23446.8 C M548 35 74 1755806 +23509.1 C M549 95 79 1266926 +23532.3 C M550 46 21 1506514 +23564.9 C M551 59 62 1680532 +23565.1 C M552 41 31 1597270 +23616.4 C M553 50 44 1868842 +23618.9 C M554 9 20 522782 +23632.9 C M555 99 97 1304747 +23633.0 C M556 84 8 1683873 +23651.5 C M557 6 75 297748 +23764.7 C M558 46 73 358181 +23793.2 C M559 61 83 909271 +23822.6 C M560 67 27 1120658 +23854.0 C M561 88 63 427020 +23868.8 C M562 60 4 1422164 +23948.4 C M563 81 87 1473163 +23962.1 C M564 57 78 1187538 +23967.3 C M565 40 1 936010 +23970.9 C M566 7 62 480482 +23984.6 C M567 57 95 1817993 +24036.7 C M568 34 74 1297067 +24075.6 C M569 88 31 133006 +24164.6 C M570 39 68 609031 +24188.5 C M571 76 78 512814 +24217.3 C M572 53 57 566227 +24242.8 C M573 75 46 1363302 +24258.8 C M574 50 24 1998672 +24260.0 C M575 61 55 1421951 +24262.0 C M576 62 60 1847182 +24311.0 C M577 33 67 538559 +24366.8 C M578 37 31 1968065 +24382.9 C M579 26 66 871176 +24429.8 C M580 77 56 778054 +24460.6 C M581 3 69 470220 +24474.8 C M582 71 55 654367 +24538.4 C M583 80 43 902198 +24572.0 C M584 88 98 533907 +24578.4 C M585 96 66 1205883 +24580.5 C M586 40 54 1780970 +24595.2 C M587 43 2 1142121 +24599.8 C M588 24 42 615636 +24617.9 C M589 5 45 1034915 +24726.7 C M590 84 52 1233190 +24749.8 C M591 82 92 1901935 +24785.0 C M592 95 69 1671309 +24807.7 C M593 39 26 1467707 +24821.2 C M594 68 8 1691437 +24826.8 C M595 79 98 1687403 +24843.5 C M596 57 77 1293714 +24856.1 C M597 56 97 889073 +24872.7 C M598 57 12 1717569 +24893.6 C M599 19 2 1702639 +24895.5 C M600 22 2 182509 +24909.8 C M601 8 35 1202186 +24910.0 C M602 71 50 1441912 +25053.1 C M603 52 63 655681 +25068.4 C M604 69 77 1645822 +25096.6 C M605 72 36 649330 +25107.8 C M606 35 18 478021 +25109.6 C M607 64 80 1619874 +25163.0 C M608 59 56 1245309 +25176.0 C M609 96 1 1896645 +25207.2 C M610 13 22 972450 +25252.6 C M611 31 0 1386235 +25261.1 C M612 19 76 327211 +25272.7 C M613 52 67 198076 +25377.0 C M614 75 89 1572534 +25383.9 C M615 72 53 1867870 +25386.0 C M616 18 75 952308 +25391.4 C M617 19 37 1808264 +25462.0 C M618 76 35 537522 +25515.3 C M619 43 8 1830264 +25535.8 C M620 20 67 1316515 +25601.0 C M621 99 23 288035 +25621.9 C M622 31 54 1588812 +25642.4 C M623 37 26 505172 +25726.7 C M624 72 88 1533334 +25733.8 C M625 58 17 208604 +25789.1 C M626 16 60 452823 +25825.2 C M627 12 99 558467 +25848.8 C M628 41 37 1691773 +25903.6 C M629 70 46 645855 +25940.3 C M630 44 57 521833 +25986.7 C M631 24 11 596793 +25997.5 C M632 35 61 1334752 +26138.3 C M633 81 68 940093 +26138.7 C M634 11 98 787812 +26276.9 C M635 13 11 1387582 +26401.8 C M636 86 71 1458876 +26464.8 C M637 83 39 1904233 +26493.0 C M638 32 62 1325545 +26577.2 C M639 84 50 1400901 +26606.3 C M640 14 51 688331 +26620.9 C M641 16 17 1456920 +26674.6 C M642 99 17 1132256 +26706.5 C M643 84 80 1246007 +26721.9 C M644 18 91 1115373 +26749.9 C M645 8 95 1642137 +26776.8 C M646 4 82 497695 +26786.8 C M647 13 11 644643 +26794.4 C M648 3 35 1330429 +26818.7 C M649 74 64 183776 +26851.2 C M650 98 50 1244597 +26918.6 C M651 74 37 1436208 +26950.7 C M652 19 84 661231 +27046.8 C M653 94 39 1833520 +27142.0 C M654 77 27 163705 +27146.4 C M655 54 18 1868180 +27214.4 C M656 60 63 823379 +27233.5 C M657 3 4 708407 +27355.8 C M658 60 53 1581436 +27389.9 C M659 85 57 1963801 +27447.5 C M660 94 53 258703 +27493.1 C M661 13 87 1434909 +27530.5 C M662 62 73 1999904 +27568.2 C M663 30 24 1119695 +27581.8 C M664 15 41 1723845 +27677.7 C M665 33 6 1395754 +27752.8 C M666 25 42 401611 +27759.3 C M667 64 5 809444 +27819.6 C M668 31 34 841871 +27827.1 C M669 33 29 1326922 +27834.6 C M670 46 26 1207848 +27836.0 C M671 78 93 1021467 +27852.7 C M672 26 33 288325 +27954.7 C M673 84 23 1268627 +28005.1 C M674 17 20 182453 +28029.0 C M675 0 89 641414 +28122.2 C M676 64 22 1235938 +28134.8 C M677 23 37 1791397 +28135.5 C M678 63 84 732721 +28165.5 C M679 58 14 976937 +28177.9 C M680 28 35 1625364 +28178.3 C M681 78 35 312527 +28180.0 C M682 72 18 206044 +28276.9 C M683 53 92 823803 +28297.0 C M684 66 79 1217721 +28301.2 C M685 30 92 1640432 +28309.3 C M686 58 49 1807705 +28433.0 C M687 26 98 1228498 +28450.1 C M688 90 27 936373 +28558.8 C M689 85 68 1731392 +28598.1 C M690 30 54 1449060 +28662.8 C M691 30 31 1869326 +28669.4 C M692 99 55 444334 +28835.9 C M693 40 0 1481743 +28863.1 C M694 96 74 903132 +28888.2 C M695 22 29 408706 +28959.8 C M696 38 33 1846337 +28964.7 C M697 21 52 1013919 +28987.5 C M698 59 74 521478 +29120.6 C M699 7 66 351200 +29171.8 C M700 89 83 203310 +29175.2 C M701 22 80 1841967 +29273.2 C M702 17 76 868216 +29380.0 C M703 64 98 544852 +29402.1 C M704 71 90 1700651 +29419.9 C M705 83 26 1591744 +29438.7 C M706 52 55 750234 +29473.3 C M707 34 71 466628 +29493.3 C M708 55 21 956773 +29496.5 C M709 28 74 417242 +29530.8 C M710 1 37 856189 +29633.8 C M711 55 90 1187165 +29636.7 C M712 56 63 1469065 +29650.4 C M713 70 95 820035 +29710.2 C M714 77 72 931149 +29769.4 C M715 58 87 991490 +29786.6 C M716 92 13 450182 +29829.0 C M717 50 11 1040113 +29889.4 C M718 77 84 352204 +29983.7 C M719 42 21 1895067 +30025.5 C M720 8 15 1421610 +30040.8 C M721 91 45 875072 +30041.8 C M722 81 84 1788208 +30086.1 C M723 70 31 286292 +30086.2 C M724 29 86 1600757 +30163.2 C M725 67 47 433839 +30167.0 C M726 58 38 476070 +30167.8 C M727 90 35 1161076 +30169.1 C M728 39 29 1114237 +30174.9 C M729 41 11 334098 +30204.4 C M730 1 77 856273 +30217.5 C M731 59 22 1544311 +30228.0 C M732 81 41 1751614 +30269.9 C M733 72 35 842863 +30271.9 C M734 8 55 1570624 +30316.9 C M735 72 78 1717123 +30332.0 C M736 86 67 1842328 +30368.5 C M737 68 32 1218895 +30382.0 C M738 23 88 628837 +30391.2 C M739 3 25 710030 +30397.0 C M740 83 19 1746946 +30402.7 C M741 62 19 573438 +30468.6 C M742 2 68 383054 +30487.7 C M743 58 14 1499801 +30496.9 C M744 61 3 971135 +30514.0 C M745 37 75 1537403 +30611.2 C M746 15 62 705239 +30644.3 C M747 59 52 913814 +30688.0 C M748 35 82 652288 +30691.7 C M749 87 28 1674256 +30728.4 C M750 6 18 767371 +30735.4 C M751 79 53 396543 +30735.8 C M752 2 44 458982 +30742.7 C M753 42 61 438111 +30751.4 C M754 12 13 213326 +30815.2 C M755 70 68 1133691 +30876.7 C M756 7 92 1582585 +30948.6 C M757 34 97 1067975 +31015.7 C M758 55 47 1797327 +31021.6 C M759 31 73 943455 +31037.0 C M760 0 72 685978 +31090.0 C M761 63 56 1938196 +31091.2 C M762 56 65 162009 +31148.2 C M763 94 45 1382547 +31160.3 C M764 7 38 974835 +31166.0 C M765 21 0 1237998 +31197.9 C M766 67 89 1016940 +31229.3 C M767 65 1 1324060 +31288.5 C M768 87 95 1278949 +31297.1 C M769 87 74 1035301 +31299.8 C M770 58 41 1747118 +31370.7 C M771 32 70 267306 +31390.5 C M772 38 48 1018207 +31435.8 C M773 76 64 1893376 +31541.0 C M774 21 40 826566 +31546.5 C M775 24 15 1259941 +31548.2 C M776 5 93 1723307 +31582.8 C M777 70 93 683674 +31606.0 C M778 26 80 1612310 +31651.7 C M779 35 81 1211549 +31684.6 C M780 64 27 307903 +31744.2 C M781 78 59 1802903 +31793.9 C M782 91 57 851985 +31809.4 C M783 99 18 245437 +31897.4 C M784 29 47 1747313 +31935.5 C M785 75 57 1163776 +31960.4 C M786 89 15 1995309 +31967.1 C M787 44 93 1017166 +31967.2 C M788 69 42 582466 +31982.1 C M789 62 10 1542802 +32053.4 C M790 65 19 627220 +32131.1 C M791 16 48 389536 +32188.0 C M792 22 20 1988901 +32273.8 C M793 60 80 1409788 +32334.2 C M794 86 25 762021 +32336.6 C M795 71 44 476781 +32342.8 C M796 15 54 595357 +32406.3 C M797 99 42 1735506 +32427.2 C M798 11 20 1689178 +32453.5 C M799 4 13 1587363 +32466.1 C M800 65 12 1569190 +32479.2 C M801 26 11 1733085 +32596.0 C M802 56 22 1424350 +32635.4 C M803 60 40 641667 +32640.5 C M804 74 10 112118 +32643.6 C M805 88 12 1851832 +32848.5 C M806 0 52 980732 +32887.5 C M807 74 3 449699 +32898.8 C M808 51 31 1866204 +32981.2 C M809 97 69 1378065 +33054.8 C M810 43 21 1381555 +33091.0 C M811 29 79 810887 +33161.8 C M812 45 94 167798 +33194.8 C M813 87 57 322180 +33210.8 C M814 66 76 1135047 +33235.2 C M815 18 1 176580 +33239.2 C M816 54 85 1240199 +33241.8 C M817 95 13 496688 +33252.3 C M818 82 19 1118074 +33282.7 C M819 38 81 453773 +33295.4 C M820 91 80 257434 +33314.9 C M821 80 87 916220 +33322.8 C M822 26 97 1477609 +33338.9 C M823 94 23 366690 +33383.4 C M824 37 15 755284 +33411.0 C M825 13 26 1013162 +33442.8 C M826 24 25 407463 +33544.6 C M827 26 6 1136911 +33597.8 C M828 41 26 1987693 +33644.1 C M829 9 37 1251596 +33650.3 C M830 65 96 1937730 +33698.4 C M831 89 47 296549 +33762.4 C M832 58 24 1678436 +33811.9 C M833 42 79 817327 +33818.2 C M834 32 23 1931716 +33834.3 C M835 82 39 935319 +33855.6 C M836 0 43 1348053 +33875.5 C M837 21 58 1830414 +33894.7 C M838 69 89 1841284 +33917.3 C M839 10 25 849493 +34000.8 C M840 33 25 1346895 +34023.1 C M841 62 75 414423 +34032.4 C M842 81 86 1957174 +34070.6 C M843 60 81 845172 +34070.8 C M844 86 44 942703 +34077.3 C M845 64 24 650854 +34096.9 C M846 10 43 810121 +34116.3 C M847 9 27 672981 +34145.1 C M848 60 47 381964 +34154.7 C M849 38 55 1411450 +34155.6 C M850 1 31 1798873 +34178.8 C M851 96 31 1534750 +34214.9 C M852 50 6 1074871 +34248.5 C M853 32 88 296900 +34263.5 C M854 70 37 1541275 +34304.5 C M855 82 5 1851953 +34444.8 C M856 77 14 1760793 +34457.0 C M857 39 0 1585469 +34486.3 C M858 93 96 168561 +34549.3 C M859 89 92 1588964 +34565.7 C M860 98 81 1549252 +34578.9 C M861 89 49 625127 +34768.2 C M862 27 47 1874486 +34808.5 C M863 80 49 885930 +34878.2 C M864 61 52 1794687 +34958.3 C M865 20 31 1383667 +34965.9 C M866 40 1 1907364 +34990.4 C M867 0 76 1818616 +35035.1 C M868 70 45 1122869 +35038.7 C M869 10 93 493939 +35137.7 C M870 99 7 1257341 +35143.8 C M871 34 81 1328394 +35164.2 C M872 31 44 1141473 +35217.1 C M873 67 12 883853 +35223.8 C M874 86 62 1545016 +35244.7 C M875 84 33 1867693 +35278.0 C M876 1 71 1765088 +35283.5 C M877 57 81 1043162 +35292.1 C M878 95 75 1848071 +35334.9 C M879 30 83 487382 +35372.7 C M880 52 10 465176 +35475.4 C M881 91 31 724314 +35499.4 C M882 65 10 369585 +35501.5 C M883 86 36 676991 +35539.3 C M884 47 98 1539302 +35546.5 C M885 53 55 564273 +35568.9 C M886 36 89 1905434 +35571.6 C M887 95 60 105177 +35630.6 C M888 25 80 1256680 +35636.4 C M889 80 87 982849 +35648.1 C M890 15 35 772756 +35719.0 C M891 44 32 1456847 +35743.6 C M892 65 25 203494 +35766.7 C M893 47 38 1526387 +35817.1 C M894 47 74 1092987 +35817.5 C M895 11 60 1654370 +35873.5 C M896 89 74 1291868 +35889.8 C M897 80 34 161081 +35896.3 C M898 21 98 1988457 +35956.6 C M899 16 3 1882895 +35994.6 C M900 52 43 677407 +36023.2 C M901 0 31 1781484 +36026.3 C M902 50 18 1146208 +36089.6 C M903 12 46 1218898 +36193.4 C M904 90 11 929069 +36225.9 C M905 88 81 228170 +36277.7 C M906 61 4 1583703 +36287.1 C M907 13 26 980262 +36298.9 C M908 95 53 1145176 +36303.1 C M909 95 77 336110 +36317.6 C M910 95 28 1494750 +36437.3 C M911 27 84 1798535 +36447.5 C M912 13 51 928315 +36452.6 C M913 87 47 748101 +36523.4 C M914 9 7 451630 +36578.2 C M915 70 32 108506 +36625.2 C M916 66 80 511852 +36661.6 C M917 79 19 1149756 +36671.7 C M918 32 22 1335596 +36682.4 C M919 8 13 892990 +36754.4 C M920 41 8 836797 +36757.9 C M921 92 1 205386 +36761.5 C M922 82 54 719312 +36766.8 C M923 33 24 1362251 +36788.1 C M924 12 35 759073 +36811.8 C M925 22 93 1887817 +36814.7 C M926 28 26 1888450 +36819.0 C M927 22 19 645716 +36872.1 C M928 86 17 1169217 +36886.9 C M929 44 77 757136 +36909.7 C M930 5 0 586431 +36985.5 C M931 34 71 1790604 +37005.7 C M932 47 71 1040437 +37050.2 C M933 32 16 1195556 +37054.3 C M934 83 41 141586 +37190.5 C M935 47 32 1077814 +37341.7 C M936 24 38 630378 +37447.1 C M937 40 91 1991958 +37492.6 C M938 24 99 1042671 +37546.4 C M939 46 54 236312 +37561.1 C M940 38 26 1882318 +37577.4 C M941 87 58 1376242 +37606.5 C M942 10 72 398781 +37617.1 C M943 24 54 903983 +37646.9 C M944 9 43 588759 +37655.3 C M945 15 35 116562 +37706.7 C M946 42 3 1748741 +37730.5 C M947 25 59 192395 +37747.0 C M948 74 88 279886 +37911.2 C M949 77 34 870781 +37984.7 C M950 88 20 1734230 +38008.8 C M951 87 67 858388 +38025.8 C M952 26 30 681244 +38042.7 C M953 29 88 235101 +38042.8 C M954 11 6 592520 +38059.9 C M955 61 38 1540372 +38097.2 C M956 48 91 1019246 +38101.1 C M957 27 47 1566255 +38140.9 C M958 12 74 1499989 +38183.1 C M959 67 94 1827901 +38295.7 C M960 68 41 839503 +38316.2 C M961 51 13 740576 +38319.2 C M962 29 7 256722 +38334.8 C M963 89 35 1725889 +38362.5 C M964 10 85 1654587 +38369.8 C M965 39 97 1914653 +38438.0 C M966 59 69 1217475 +38439.8 C M967 82 85 1698128 +38532.1 C M968 6 47 1872840 +38562.7 C M969 50 69 751676 +38563.2 C M970 53 59 1066887 +38608.9 C M971 61 82 1380130 +38611.2 C M972 29 47 271298 +38671.2 C M973 81 51 1956378 +38710.4 C M974 70 90 724390 +38730.5 C M975 70 30 203423 +38777.0 C M976 85 49 169012 +38877.6 C M977 95 99 1681836 +38882.9 C M978 96 99 937124 +38891.2 C M979 53 43 1478797 +38912.2 C M980 47 99 809061 +38961.2 C M981 99 96 332729 +38996.6 C M982 10 94 1215731 +39000.3 C M983 57 89 1809702 +39036.2 C M984 76 86 879890 +39129.6 C M985 41 68 558058 +39134.4 C M986 91 4 1304267 +39161.4 C M987 50 63 473197 +39229.8 C M988 91 6 1174815 +39288.4 C M989 42 61 1383696 +39301.2 C M990 82 75 1577956 +39305.5 C M991 1 31 248875 +39322.8 C M992 63 0 440597 +39381.8 C M993 62 39 598584 +39427.2 C M994 17 66 1673250 +39469.8 C M995 58 1 724679 +39489.2 C M996 58 67 1704143 +39540.9 C M997 34 62 762975 +39577.3 C M998 0 36 1728516 +39583.3 C M999 25 81 1780559 +39591.5 C M1000 76 69 790397 diff --git a/ee/100_events_10_nodes_500ks.txt b/ee/100_events_10_nodes_500ks.txt new file mode 100644 index 000000000..50365e3ca --- /dev/null +++ b/ee/100_events_10_nodes_500ks.txt @@ -0,0 +1,100 @@ +4853.0 C M1 3 5 994 +5332.4 C M2 3 9 366 +20133.6 C M3 7 6 335 +24536.1 C M4 9 3 505 +34077.4 C M5 9 8 798 +37390.4 C M6 6 5 238 +39586.9 C M7 7 3 853 +43308.8 C M8 3 2 524 +44657.8 C M9 4 1 282 +45120.8 C M10 1 9 46 +50037.5 C M11 8 7 806 +51492.3 C M12 8 6 164 +57970.3 C M13 8 9 275 +59844.2 C M14 8 1 941 +60493.8 C M15 7 8 245 +67115.7 C M16 5 4 357 +70503.6 C M17 1 3 804 +76761.6 C M18 8 9 583 +100292.8 C M19 9 5 701 +106148.2 C M20 6 2 641 +107957.9 C M21 1 6 254 +109344.3 C M22 7 6 430 +109520.9 C M23 4 3 619 +122977.1 C M24 7 8 223 +129896.9 C M25 2 5 132 +134968.4 C M26 8 9 799 +137458.7 C M27 2 9 88 +141872.1 C M28 1 2 390 +150292.5 C M29 8 7 740 +152778.1 C M30 7 8 217 +165284.9 C M31 4 8 445 +166535.5 C M32 8 3 387 +168872.1 C M33 3 7 705 +173562.4 C M34 9 4 879 +182688.7 C M35 6 3 255 +188482.5 C M36 8 3 496 +191815.7 C M37 8 4 57 +192731.3 C M38 2 3 416 +192877.8 C M39 5 4 487 +199086.4 C M40 8 3 479 +202481.2 C M41 9 8 943 +207880.8 C M42 3 2 214 +209634.7 C M43 5 8 287 +213532.6 C M44 6 2 653 +220067.8 C M45 6 2 948 +220897.5 C M46 3 8 910 +232556.8 C M47 7 5 191 +238827.8 C M48 8 9 275 +244921.6 C M49 9 4 885 +244977.4 C M50 6 9 666 +255643.0 C M51 8 2 234 +255653.2 C M52 3 1 810 +257231.2 C M53 5 8 42 +270339.7 C M54 1 2 205 +272792.6 C M55 8 4 468 +282221.8 C M56 6 1 704 +285957.4 C M57 6 2 530 +309169.7 C M58 3 2 407 +310622.1 C M59 5 8 245 +314080.3 C M60 3 8 259 +321277.3 C M61 2 7 235 +329410.0 C M62 4 9 844 +330196.4 C M63 5 7 966 +331450.9 C M64 1 8 324 +335446.2 C M65 7 4 837 +344234.1 C M66 8 6 847 +347592.6 C M67 8 1 593 +347928.5 C M68 4 5 424 +354610.1 C M69 2 7 486 +366148.6 C M70 1 4 205 +368833.0 C M71 5 2 608 +371621.9 C M72 7 6 420 +372977.8 C M73 2 6 750 +386962.7 C M74 8 7 607 +389204.2 C M75 9 7 360 +397473.8 C M76 1 5 205 +399854.5 C M77 8 2 122 +404105.7 C M78 1 6 767 +404135.7 C M79 8 5 146 +411056.7 C M80 4 9 351 +415812.8 C M81 1 6 358 +417325.1 C M82 8 7 962 +425934.5 C M83 2 3 658 +426258.2 C M84 1 3 745 +426933.9 C M85 6 1 473 +427017.4 C M86 5 4 717 +431216.7 C M87 3 8 61 +436772.9 C M88 6 1 218 +437006.6 C M89 5 4 758 +446968.4 C M90 9 3 864 +450368.0 C M91 3 5 762 +457962.5 C M92 8 4 71 +461441.0 C M93 9 4 930 +462494.5 C M94 4 8 874 +473952.8 C M95 5 4 435 +476942.9 C M96 1 7 294 +483222.0 C M97 7 5 834 +485624.4 C M98 2 4 794 +490443.2 C M99 7 6 449 +494819.2 C M100 5 2 975 diff --git a/ee/1400_events_2000_nodes_700ks.txt b/ee/1400_events_2000_nodes_700ks.txt new file mode 100644 index 000000000..93ce216e3 --- /dev/null +++ b/ee/1400_events_2000_nodes_700ks.txt @@ -0,0 +1,1400 @@ +63.3 C M1 107 523 787779 +91.7 C M2 1539 297 656581 +199.4 C M3 1694 1586 991511 +587.6 C M4 561 116 211621 +1359.9 C M5 612 164 577560 +1465.7 C M6 1667 945 415673 +1633.7 C M7 1860 1588 372050 +1656.5 C M8 15 1874 827584 +2826.1 C M9 755 1769 944022 +3348.2 C M10 1739 823 77230 +3391.0 C M11 1282 1343 6923 +3792.9 C M12 1540 359 312696 +3810.2 C M13 855 924 648992 +4279.2 C M14 41 878 470726 +4549.9 C M15 1131 1166 897215 +4647.2 C M16 1050 911 247019 +4917.1 C M17 1731 1817 46189 +4924.6 C M18 1232 1337 874650 +5427.3 C M19 1559 1608 938085 +6124.6 C M20 1536 102 153650 +6556.4 C M21 1783 1002 745826 +6745.8 C M22 1970 848 825067 +7567.2 C M23 569 1364 428984 +7613.2 C M24 1428 1226 923851 +7624.7 C M25 1118 1623 987800 +7985.0 C M26 1549 1584 425259 +9400.8 C M27 1686 1281 119931 +9818.9 C M28 842 1081 203458 +10270.9 C M29 1597 668 948005 +10998.5 C M30 1141 1581 544146 +11768.4 C M31 1156 1961 772483 +11955.5 C M32 1016 1885 574834 +12446.6 C M33 1731 1354 341591 +12772.5 C M34 183 1725 220919 +13494.4 C M35 1042 1745 435647 +14262.7 C M36 384 738 427946 +14385.5 C M37 409 1630 474603 +14702.7 C M38 744 561 715547 +15415.5 C M39 1724 193 850703 +16275.1 C M40 1946 682 284203 +17871.1 C M41 1572 935 983082 +18217.3 C M42 157 166 101992 +18313.6 C M43 1128 1551 386500 +18585.1 C M44 364 1672 535943 +19045.8 C M45 864 1183 385382 +19133.5 C M46 1285 1586 934936 +20016.0 C M47 1311 1479 760329 +20133.6 C M48 207 655 932511 +20585.5 C M49 76 170 259746 +20984.7 C M50 130 1268 725774 +21509.5 C M51 1912 1454 686745 +21771.6 C M52 565 1692 752664 +22471.1 C M53 456 1770 595158 +22572.5 C M54 412 1276 853512 +23503.7 C M55 462 483 322338 +23675.3 C M56 1089 1259 266212 +23947.1 C M57 985 1389 268736 +23986.2 C M58 1980 216 80847 +24129.8 C M59 1148 1793 235588 +25196.3 C M60 1509 1452 377284 +25744.0 C M61 895 1720 197180 +25757.9 C M62 278 1123 763276 +26079.9 C M63 547 1767 476636 +26163.7 C M64 1625 166 396130 +27028.2 C M65 7 1496 608374 +27100.1 C M66 1248 967 330565 +28021.8 C M67 1671 1052 836593 +28533.1 C M68 999 128 220220 +28678.8 C M69 1250 375 56231 +31083.6 C M70 1788 1530 430170 +31584.6 C M71 596 195 123273 +32615.7 C M72 297 1970 710473 +33158.5 C M73 1674 1132 506771 +33833.2 C M74 1585 287 628286 +34226.4 C M75 680 1159 892116 +34524.6 C M76 1193 126 827227 +34723.4 C M77 1554 1325 326606 +35552.7 C M78 1858 337 841437 +36229.1 C M79 1095 254 943753 +36344.7 C M80 994 467 140775 +36593.6 C M81 1031 793 204827 +36923.1 C M82 256 1986 229502 +38092.9 C M83 1443 234 248078 +38453.0 C M84 697 101 656068 +38602.1 C M85 871 1713 488432 +38901.7 C M86 1655 825 194571 +42964.0 C M87 1756 298 237006 +43278.2 C M88 1188 109 906702 +43309.6 C M89 614 1455 764436 +43319.0 C M90 801 886 294941 +44136.3 C M91 1137 799 208580 +44382.8 C M92 1555 975 404651 +44522.7 C M93 1950 1649 657198 +44557.8 C M94 1002 1925 498485 +45103.3 C M95 1267 749 199225 +45143.8 C M96 622 1821 704120 +45221.5 C M97 869 952 347797 +46276.9 C M98 1170 1742 693309 +46630.5 C M99 1993 1087 51698 +46643.0 C M100 903 96 481728 +46915.0 C M101 416 1814 363934 +46964.9 C M102 1300 464 940515 +47212.4 C M103 1940 651 362211 +48266.8 C M104 1491 301 784440 +49655.6 C M105 225 1504 710141 +49952.9 C M106 825 300 926164 +51525.6 C M107 1409 271 399797 +52192.9 C M108 910 783 892385 +53082.7 C M109 1112 726 34131 +53924.4 C M110 275 146 36791 +53964.5 C M111 617 1030 470524 +54115.7 C M112 1877 1028 903218 +54634.4 C M113 802 1897 125212 +54791.3 C M114 1117 1007 894859 +56186.8 C M115 981 1504 896988 +56469.0 C M116 536 842 552574 +57302.5 C M117 965 405 250696 +57759.1 C M118 203 726 546721 +57959.8 C M119 1879 17 393329 +58843.7 C M120 987 1113 919132 +59921.6 C M121 357 1497 397782 +59986.1 C M122 1213 250 504753 +61374.2 C M123 727 56 384263 +62003.3 C M124 801 415 713201 +62812.1 C M125 83 748 782326 +63341.4 C M126 222 621 667360 +63511.7 C M127 1800 1953 677927 +64108.9 C M128 250 725 807583 +64836.9 C M129 782 1828 110191 +64873.8 C M130 152 1823 856368 +64882.9 C M131 1061 556 523440 +65072.7 C M132 743 220 560165 +65241.1 C M133 1569 351 335126 +65669.2 C M134 947 812 558064 +65797.2 C M135 1352 1724 220265 +67347.8 C M136 967 692 323987 +67439.6 C M137 1074 786 385378 +69049.8 C M138 1334 1591 32211 +69132.7 C M139 596 623 727104 +69283.4 C M140 451 1294 85472 +70015.9 C M141 1900 1829 870852 +70043.0 C M142 572 647 703762 +70633.6 C M143 707 597 64377 +71254.0 C M144 1303 1682 799182 +72334.5 C M145 186 78 387348 +72791.8 C M146 431 707 905012 +73387.0 C M147 1070 1041 529807 +73968.1 C M148 1742 1661 629748 +74260.8 C M149 701 1642 784151 +74315.4 C M150 366 1672 123166 +74797.4 C M151 1776 1161 398152 +74948.1 C M152 760 786 60962 +75321.7 C M153 668 1107 606957 +75960.4 C M154 1520 1565 416824 +76110.5 C M155 765 1245 143991 +76121.2 C M156 1775 1175 88351 +76168.4 C M157 989 1368 301504 +76720.8 C M158 1080 1223 481774 +77410.6 C M159 1777 106 994861 +77473.6 C M160 1155 1242 123354 +77551.8 C M161 816 1843 750718 +77840.1 C M162 696 902 168367 +77957.9 C M163 1818 1758 665485 +78780.6 C M164 53 813 670498 +79006.3 C M165 812 1181 559545 +80284.5 C M166 1334 192 594704 +80742.8 C M167 185 673 980093 +80797.6 C M168 362 1088 858938 +81672.0 C M169 1382 690 692156 +82167.8 C M170 323 1717 326110 +82348.3 C M171 619 15 587099 +82931.8 C M172 2 980 187815 +83129.6 C M173 706 24 831219 +83580.1 C M174 1456 862 253588 +83631.9 C M175 266 147 62968 +83746.2 C M176 752 786 470227 +83985.2 C M177 1899 1957 595817 +84126.1 C M178 1918 177 827637 +85268.2 C M179 780 378 147851 +85444.8 C M180 218 371 181125 +85932.7 C M181 269 357 482861 +86055.9 C M182 1774 16 170186 +86278.6 C M183 1633 515 981556 +86349.6 C M184 291 214 27865 +86369.7 C M185 546 1586 638044 +87007.4 C M186 1047 82 389895 +87225.9 C M187 482 196 144661 +87557.1 C M188 192 887 436797 +87786.5 C M189 527 729 217971 +87798.1 C M190 1165 87 422069 +88900.1 C M191 1755 1904 467271 +89120.0 C M192 74 1227 92224 +89677.1 C M193 732 421 302241 +89971.5 C M194 795 1361 878050 +90092.5 C M195 1071 543 245759 +90987.9 C M196 1806 1148 813491 +91952.7 C M197 473 404 275301 +92929.0 C M198 767 1251 88989 +94024.0 C M199 586 1533 444795 +94324.0 C M200 1789 1481 283614 +94804.3 C M201 176 897 67295 +94840.1 C M202 101 67 671928 +95580.0 C M203 1848 2 457901 +95793.5 C M204 591 1954 519835 +96270.5 C M205 989 194 27446 +97537.6 C M206 862 1006 677387 +98575.3 C M207 261 1901 982459 +98853.4 C M208 88 1947 535548 +100594.0 C M209 202 1643 671056 +100665.5 C M210 959 1539 954467 +101644.8 C M211 193 1157 309322 +101951.1 C M212 582 512 457879 +102301.8 C M213 512 487 178018 +102560.9 C M214 1506 807 940700 +103116.0 C M215 1974 855 469991 +103700.7 C M216 1007 1805 283179 +103728.4 C M217 81 986 47823 +103743.3 C M218 385 104 967831 +103816.4 C M219 357 402 748541 +104307.0 C M220 1297 104 732867 +105079.8 C M221 689 1110 141769 +105274.2 C M222 1711 206 580237 +105339.0 C M223 930 568 127545 +105639.8 C M224 510 826 414606 +105963.9 C M225 1211 1216 31902 +106196.1 C M226 1211 989 539028 +106786.7 C M227 1436 137 152824 +107191.7 C M228 1258 1243 83514 +107322.9 C M229 1075 1968 957980 +108559.4 C M230 1832 1299 566118 +109215.7 C M231 25 1403 968776 +109863.8 C M232 1985 567 497322 +110504.0 C M233 424 1935 105597 +110527.1 C M234 873 1971 133156 +110984.1 C M235 444 403 100188 +111714.2 C M236 985 1948 727252 +112250.9 C M237 1322 1900 796127 +112499.6 C M238 1816 1134 926881 +114257.3 C M239 966 1347 980311 +114455.2 C M240 953 1794 483851 +115106.4 C M241 1799 1867 7689 +116005.6 C M242 1647 684 264897 +116089.0 C M243 1005 655 555169 +116377.1 C M244 1799 1934 76351 +116627.4 C M245 139 1430 307726 +116770.9 C M246 385 1758 955615 +117808.7 C M247 1134 1843 264315 +117822.0 C M248 840 261 387810 +117960.7 C M249 1719 1862 524630 +118038.5 C M250 290 1451 6620 +119802.2 C M251 639 1165 660479 +120151.7 C M252 510 404 227222 +120304.0 C M253 1463 1712 47646 +120346.8 C M254 119 375 452600 +120856.4 C M255 1128 627 573677 +121731.2 C M256 677 650 812301 +122500.4 C M257 1801 1157 909591 +122533.8 C M258 854 1719 434339 +123146.1 C M259 873 1386 810020 +123224.9 C M260 1487 459 793116 +123249.3 C M261 1138 333 553201 +123517.2 C M262 1463 584 283805 +123676.6 C M263 1942 1156 503878 +123772.4 C M264 121 1709 21634 +124750.1 C M265 1730 1822 589473 +125123.3 C M266 1413 221 539263 +125174.4 C M267 750 1640 614643 +125379.2 C M268 509 1672 659977 +125859.7 C M269 724 1550 281805 +126388.4 C M270 46 1021 560020 +127327.8 C M271 969 1668 279862 +127370.0 C M272 662 306 864716 +129321.5 C M273 1368 1298 465876 +129883.7 C M274 1599 336 763591 +130056.4 C M275 1514 1081 613876 +130947.0 C M276 217 1369 958968 +131674.6 C M277 257 1676 707159 +131705.6 C M278 1626 1753 400577 +132080.3 C M279 638 464 976967 +132393.4 C M280 445 1638 914153 +132472.9 C M281 864 1678 80040 +133072.0 C M282 1098 669 945269 +135554.2 C M283 1498 1872 120169 +135731.7 C M284 1095 478 602744 +136630.9 C M285 1168 996 390331 +137160.3 C M286 438 432 329914 +138038.8 C M287 120 1859 484433 +138368.5 C M288 1558 526 478577 +139180.7 C M289 1017 1564 487378 +139228.1 C M290 1674 975 455687 +139756.3 C M291 1720 392 845642 +139857.6 C M292 1674 845 15418 +139990.8 C M293 1678 373 177627 +140049.4 C M294 931 1293 354202 +140768.0 C M295 802 762 837307 +140924.4 C M296 361 1124 122940 +141684.7 C M297 1008 278 123144 +142295.1 C M298 1010 117 88857 +142407.8 C M299 1765 573 752443 +143621.4 C M300 489 1968 662764 +144174.5 C M301 375 239 719247 +145738.9 C M302 779 1974 225403 +145823.9 C M303 1241 1396 275910 +145848.5 C M304 780 934 414749 +146251.1 C M305 207 1963 989867 +146648.4 C M306 1192 1435 144442 +147589.3 C M307 1627 1364 183717 +148542.4 C M308 236 846 629802 +148623.2 C M309 677 104 381646 +148720.6 C M310 832 1580 119261 +149432.6 C M311 1372 903 552039 +149967.9 C M312 1113 61 442356 +151103.7 C M313 1374 125 518365 +151858.7 C M314 502 1119 583713 +151906.2 C M315 733 908 675182 +152266.6 C M316 1475 169 215631 +152762.9 C M317 1376 836 573015 +152883.6 C M318 273 1746 636284 +153390.9 C M319 657 1667 389610 +154544.8 C M320 1359 350 646506 +154747.6 C M321 888 1872 221654 +154898.8 C M322 1441 800 520826 +155174.9 C M323 786 959 402070 +156091.0 C M324 407 741 388509 +156671.6 C M325 1662 1450 412304 +156748.0 C M326 1394 1019 525089 +156828.9 C M327 485 526 253138 +157368.1 C M328 611 854 249595 +157894.7 C M329 874 800 657004 +158285.1 C M330 122 463 141321 +158468.0 C M331 1752 318 770341 +159109.0 C M332 1831 1818 849179 +159744.2 C M333 323 1442 554000 +159998.6 C M334 1072 211 931291 +160407.7 C M335 1624 328 525694 +160880.8 C M336 910 1329 522791 +161131.2 C M337 1710 423 433092 +161536.4 C M338 365 183 434916 +162036.2 C M339 1008 1350 65954 +162466.5 C M340 1203 556 85035 +162480.5 C M341 762 1222 534409 +163045.7 C M342 724 803 429603 +163319.5 C M343 718 1903 664413 +163635.5 C M344 882 763 538745 +165170.3 C M345 324 1690 848500 +165475.2 C M346 1989 542 188028 +166002.6 C M347 923 849 240011 +166236.3 C M348 697 1619 827027 +166608.6 C M349 543 15 617880 +167133.9 C M350 313 975 486580 +167656.8 C M351 189 495 260735 +168229.8 C M352 37 751 371068 +169106.6 C M353 1275 1501 437903 +169837.7 C M354 1121 748 561160 +170845.8 C M355 140 893 477598 +170870.2 C M356 195 292 355341 +171380.5 C M357 780 1888 158664 +172341.9 C M358 1789 434 850644 +172723.6 C M359 676 232 947891 +174813.6 C M360 1455 1361 611931 +176153.7 C M361 240 1776 156207 +176240.0 C M362 1075 1646 652623 +177541.0 C M363 249 1644 980057 +178088.4 C M364 588 66 456539 +178651.8 C M365 1274 1682 79116 +179140.7 C M366 1120 1624 931000 +179500.2 C M367 1434 215 799543 +179658.9 C M368 256 1454 645812 +180227.4 C M369 1502 677 419785 +180288.9 C M370 536 1966 971072 +180601.9 C M371 1679 846 702068 +180629.6 C M372 1818 976 937563 +181530.7 C M373 784 1060 505213 +182114.2 C M374 357 1742 764569 +182882.6 C M375 1616 1847 709168 +183090.0 C M376 1827 825 817926 +183495.8 C M377 612 420 494131 +183694.5 C M378 789 1992 258027 +185535.3 C M379 1311 1402 878908 +185900.1 C M380 700 555 269172 +186723.9 C M381 38 1399 208267 +186894.6 C M382 1874 1651 538082 +187955.9 C M383 849 1824 168411 +189477.6 C M384 827 656 961424 +189527.9 C M385 751 42 371089 +189786.8 C M386 88 855 513504 +190082.5 C M387 964 331 404400 +190182.0 C M388 1011 1540 826173 +190468.2 C M389 1076 797 445954 +191156.4 C M390 1461 4 102282 +191222.3 C M391 1060 1760 701433 +191480.2 C M392 1176 624 484989 +192210.6 C M393 1837 1045 651567 +192477.0 C M394 369 542 262462 +193780.3 C M395 528 334 644572 +193942.0 C M396 549 1067 52791 +194567.0 C M397 668 21 815284 +195786.6 C M398 735 1814 684576 +196403.3 C M399 1894 506 529020 +196775.1 C M400 1289 1478 412857 +196890.8 C M401 1079 623 938996 +197136.8 C M402 27 1128 175924 +197335.9 C M403 717 1872 425203 +197649.5 C M404 1210 1511 834512 +198081.2 C M405 838 1685 996049 +198749.3 C M406 645 183 165587 +199235.7 C M407 338 442 628823 +199431.3 C M408 620 691 652167 +199475.8 C M409 1943 517 614195 +200780.7 C M410 680 218 468597 +200872.7 C M411 505 1397 63044 +201951.0 C M412 1007 1557 826861 +202702.8 C M413 1317 1256 51010 +202739.3 C M414 580 781 503813 +204223.4 C M415 1637 1127 695781 +204904.8 C M416 1008 1164 712098 +205354.6 C M417 427 882 703925 +205802.1 C M418 1400 794 415927 +205889.7 C M419 1334 1797 282806 +206039.7 C M420 1717 1072 544432 +207154.0 C M421 1592 352 589298 +209193.9 C M422 824 601 497477 +209534.8 C M423 906 1946 607420 +209717.7 C M424 1106 1285 688616 +209939.7 C M425 3 450 854789 +210568.5 C M426 1128 509 515180 +210763.6 C M427 1000 1278 518436 +210881.3 C M428 1109 748 844036 +210935.3 C M429 355 616 17775 +211319.9 C M430 1716 1097 437705 +211477.6 C M431 1480 1525 88451 +211729.8 C M432 384 1424 196433 +212125.7 C M433 1404 1628 602767 +213011.4 C M434 1769 162 740086 +213782.6 C M435 762 1692 63356 +214236.0 C M436 1404 644 529011 +215153.9 C M437 1057 1213 355978 +215465.1 C M438 1721 1447 513707 +215609.5 C M439 749 1132 681897 +215814.9 C M440 1958 1274 40512 +215843.0 C M441 433 316 145366 +216076.3 C M442 947 1885 49434 +216082.3 C M443 542 918 672083 +216506.0 C M444 1023 1950 545871 +216576.9 C M445 1779 239 370057 +217322.0 C M446 190 836 933542 +218708.5 C M447 94 672 264058 +218775.9 C M448 1322 1841 179554 +218805.4 C M449 1444 1233 979310 +219515.6 C M450 806 1225 332170 +220112.4 C M451 460 1904 607329 +220207.6 C M452 1615 1025 638986 +220213.9 C M453 82 1956 104438 +220783.6 C M454 1869 52 795586 +220941.3 C M455 1132 216 284653 +221340.3 C M456 280 828 652269 +221964.9 C M457 290 662 969893 +222186.6 C M458 116 1489 218287 +223151.7 C M459 1306 1779 912400 +224177.5 C M460 638 1493 89037 +224272.1 C M461 1930 1909 466623 +224461.1 C M462 790 303 840527 +224953.9 C M463 1623 989 39344 +225508.4 C M464 1815 1025 860971 +227420.6 C M465 1787 920 601742 +228185.0 C M466 1114 1434 408461 +229669.8 C M467 1763 306 191351 +230170.8 C M468 695 642 744969 +230319.9 C M469 956 567 965560 +230954.8 C M470 1297 1525 896858 +231633.2 C M471 1176 1315 784754 +232121.5 C M472 1925 231 156565 +232182.0 C M473 1656 1199 359560 +232471.7 C M474 1153 552 512895 +232878.2 C M475 380 145 233621 +233790.4 C M476 394 1521 994093 +236625.1 C M477 66 188 666143 +237567.4 C M478 1372 394 968241 +237827.2 C M479 1818 1930 145454 +237979.2 C M480 1223 262 775870 +238034.5 C M481 730 11 479878 +239709.9 C M482 1597 153 320317 +241403.0 C M483 1459 1444 955873 +241465.3 C M484 1530 403 827996 +241955.2 C M485 1197 588 699809 +242152.2 C M486 482 1702 474564 +244460.3 C M487 645 1148 246728 +245272.1 C M488 135 1712 205711 +246039.4 C M489 593 538 411725 +246335.4 C M490 906 1013 108505 +248003.3 C M491 231 1254 904545 +248563.0 C M492 1375 870 612271 +248606.2 C M493 1324 819 888009 +248741.5 C M494 1679 1532 92677 +248974.8 C M495 938 697 489737 +249232.2 C M496 284 1995 485918 +249299.2 C M497 1190 1049 884538 +250733.0 C M498 1093 1615 13828 +251034.7 C M499 271 1974 925147 +251545.9 C M500 597 275 65412 +251689.6 C M501 765 1416 507713 +252140.2 C M502 873 1844 776492 +252417.2 C M503 1149 456 899228 +252911.3 C M504 425 131 169760 +253877.2 C M505 1422 1299 139791 +254301.2 C M506 33 942 373111 +255711.8 C M507 239 204 274937 +256515.3 C M508 1731 510 388443 +256559.9 C M509 272 1471 852593 +256689.5 C M510 1972 715 357729 +256761.5 C M511 1108 410 479660 +256766.7 C M512 1998 416 446744 +256767.6 C M513 1884 357 707169 +257169.3 C M514 1474 1559 171766 +257755.3 C M515 923 1089 900239 +257860.7 C M516 1693 1439 718633 +258382.7 C M517 700 1669 840133 +258845.1 C M518 261 1883 225133 +259069.3 C M519 44 1934 985742 +259777.0 C M520 743 680 166459 +260109.5 C M521 688 1550 341859 +260176.4 C M522 1932 1018 532430 +260570.6 C M523 610 1925 643285 +260612.8 C M524 1526 1404 207984 +260637.2 C M525 202 1980 656096 +261895.5 C M526 969 581 220817 +262006.2 C M527 744 1002 566669 +262478.1 C M528 371 387 886649 +263313.0 C M529 563 801 758885 +263551.5 C M530 1484 1037 22285 +263901.0 C M531 916 1925 646883 +264737.9 C M532 146 602 836363 +264812.2 C M533 182 843 957373 +265035.3 C M534 1420 659 184197 +265053.5 C M535 1179 828 193932 +265569.0 C M536 1776 1211 21802 +266202.1 C M537 674 544 487944 +267307.5 C M538 1448 1485 114004 +267505.2 C M539 1620 1860 405746 +267556.3 C M540 784 1233 288900 +267632.6 C M541 1462 1591 36172 +267982.6 C M542 322 719 993644 +268256.6 C M543 1680 399 512468 +269056.9 C M544 545 1713 329283 +269146.8 C M545 1005 677 308614 +269275.5 C M546 1208 62 90742 +269281.0 C M547 180 915 922620 +270510.5 C M548 270 505 756418 +271016.2 C M549 722 1899 866330 +271025.3 C M550 768 238 525002 +271434.0 C M551 429 720 754132 +272403.5 C M552 1955 1472 501983 +273060.9 C M553 1354 740 332797 +274050.7 C M554 1994 132 238529 +274157.9 C M555 1598 672 374000 +274627.1 C M556 239 153 641339 +275036.3 C M557 419 400 945485 +275765.9 C M558 266 1531 235396 +275941.1 C M559 1720 1851 206073 +276019.8 C M560 1057 461 241822 +276356.3 C M561 1760 1276 884274 +276866.8 C M562 1534 558 315262 +276909.4 C M563 265 1797 391352 +277207.0 C M564 317 1072 844523 +277284.6 C M565 1663 230 881395 +277455.0 C M566 311 1336 499230 +278516.7 C M567 1620 716 47720 +278707.8 C M568 1967 654 222356 +279797.7 C M569 1113 689 519372 +280432.5 C M570 1557 1412 986988 +280623.9 C M571 1967 1508 88253 +281479.3 C M572 1374 1804 269274 +282116.4 C M573 926 1692 743949 +282506.6 C M574 1547 535 821193 +282691.5 C M575 1431 1727 537973 +283791.7 C M576 1073 1497 462760 +284061.6 C M577 195 1926 333937 +285668.4 C M578 750 507 323815 +285840.9 C M579 322 1157 721148 +286632.6 C M580 1796 724 882360 +287770.7 C M581 1264 1540 621764 +288091.8 C M582 166 44 555239 +288361.0 C M583 1282 997 746167 +288545.1 C M584 1017 1725 499405 +289035.7 C M585 1489 638 468001 +289717.8 C M586 856 781 151223 +289985.8 C M587 1242 712 730639 +290071.1 C M588 394 1850 193996 +290211.7 C M589 1204 1947 891823 +290272.8 C M590 1367 1558 840955 +290419.6 C M591 917 200 583195 +291081.5 C M592 207 49 830212 +291309.8 C M593 1362 1098 705309 +292250.7 C M594 1007 155 476858 +292399.6 C M595 296 774 8266 +294346.2 C M596 1991 278 543058 +294814.5 C M597 1993 1059 900042 +297680.1 C M598 130 183 28006 +298948.0 C M599 626 479 839085 +299074.5 C M600 1655 569 171046 +299154.3 C M601 247 1353 538100 +299550.6 C M602 776 192 3230 +300452.7 C M603 1226 921 311559 +300937.1 C M604 1503 209 795515 +302739.1 C M605 1555 756 923075 +302807.5 C M606 1090 884 703525 +302974.9 C M607 1140 267 742742 +303442.2 C M608 904 1433 54325 +305074.5 C M609 729 1675 186245 +306919.8 C M610 753 1344 411557 +307403.6 C M611 1679 1994 393869 +308166.4 C M612 1901 1573 974314 +309722.5 C M613 72 91 215418 +310041.3 C M614 506 1752 559820 +310069.0 C M615 1691 516 108897 +310199.4 C M616 1374 1567 152567 +310834.3 C M617 1670 71 390202 +312774.9 C M618 1478 6 514792 +312802.8 C M619 1536 908 292695 +313509.9 C M620 1650 1248 989299 +313534.5 C M621 586 1622 19868 +313736.8 C M622 7 953 472775 +313919.0 C M623 786 470 977192 +313999.3 C M624 326 1094 326061 +314049.5 C M625 438 456 77433 +314178.3 C M626 417 1134 658862 +315404.2 C M627 1669 22 160669 +316078.3 C M628 1058 1663 550937 +316388.3 C M629 1796 51 822383 +316674.2 C M630 1548 70 723551 +316727.7 C M631 337 936 781772 +317304.9 C M632 1597 17 955709 +318252.8 C M633 574 59 760583 +318350.1 C M634 1778 719 227731 +318475.5 C M635 944 1687 387845 +318556.0 C M636 1395 1176 431575 +318905.4 C M637 674 182 771774 +319714.2 C M638 1865 437 283385 +320162.3 C M639 669 29 284523 +320644.9 C M640 572 1250 979609 +320717.4 C M641 132 627 348158 +320891.9 C M642 1925 543 60181 +322543.8 C M643 1561 361 57578 +323223.2 C M644 1124 1442 943866 +323430.7 C M645 1445 1983 203512 +323532.1 C M646 1615 1189 227868 +323715.3 C M647 1806 572 691429 +323748.7 C M648 1655 1305 959611 +324793.0 C M649 1569 908 592298 +325134.2 C M650 1476 1916 993218 +325721.1 C M651 320 963 555341 +325818.0 C M652 1428 1817 586769 +326476.5 C M653 1123 181 738462 +327350.9 C M654 348 1858 687223 +328191.5 C M655 325 836 101320 +328435.7 C M656 1438 625 129531 +328767.3 C M657 901 1567 656974 +329095.8 C M658 998 1158 308175 +329239.2 C M659 1678 1541 213043 +329386.3 C M660 1365 971 333989 +329705.5 C M661 1667 427 508659 +330098.2 C M662 1329 582 753296 +330155.4 C M663 591 272 759084 +330180.0 C M664 730 1198 483505 +330401.9 C M665 155 991 497092 +330476.5 C M666 706 818 583853 +330700.4 C M667 383 1537 589317 +330907.1 C M668 982 1878 984777 +330965.6 C M669 22 1363 417939 +331007.1 C M670 81 799 486891 +331027.6 C M671 455 524 462785 +331433.0 C M672 904 1867 805431 +332260.3 C M673 1386 1840 345623 +332704.3 C M674 1294 777 301497 +332761.9 C M675 1883 824 388785 +333025.1 C M676 982 936 141453 +333452.7 C M677 725 1436 608906 +333499.7 C M678 1602 1527 929949 +334085.3 C M679 526 1363 94064 +334130.2 C M680 1536 954 309681 +334790.1 C M681 89 1680 366361 +335104.2 C M682 1081 1685 894415 +335981.4 C M683 973 1093 521144 +336416.4 C M684 1683 297 772576 +336497.9 C M685 100 1752 651479 +336687.8 C M686 541 828 612516 +336701.0 C M687 1490 1112 436061 +336790.5 C M688 1483 507 367065 +337117.6 C M689 679 1766 417908 +337966.4 C M690 1225 807 333045 +338021.3 C M691 1726 427 600868 +338166.7 C M692 1467 1147 550514 +338353.0 C M693 1598 1356 952565 +339178.0 C M694 213 1923 627413 +339347.1 C M695 1008 1203 627300 +339521.5 C M696 1098 860 311144 +339958.0 C M697 466 748 519266 +340010.1 C M698 1318 129 521116 +340957.7 C M699 1250 1668 667404 +341031.8 C M700 1869 57 873973 +341362.7 C M701 281 901 942724 +341543.7 C M702 1492 722 147907 +344206.4 C M703 165 801 724463 +344623.3 C M704 120 1102 989523 +344940.0 C M705 1472 1965 216534 +345134.6 C M706 1435 760 588829 +345586.2 C M707 1893 987 436679 +345760.5 C M708 508 1908 884631 +345806.3 C M709 1717 830 698515 +348384.3 C M710 367 895 389286 +348437.4 C M711 1515 1235 992942 +348487.1 C M712 15 760 457526 +348828.9 C M713 1490 167 818903 +349549.4 C M714 1943 868 942665 +349576.6 C M715 1559 1742 143124 +349858.1 C M716 1057 7 388277 +350736.8 C M717 1045 763 635267 +351931.1 C M718 351 1420 421598 +352020.0 C M719 771 174 142309 +352111.2 C M720 1342 1877 163336 +353309.2 C M721 1099 1290 494940 +354186.3 C M722 997 1072 114326 +354423.1 C M723 1642 1697 166216 +355015.1 C M724 161 626 501541 +355318.2 C M725 1568 1408 594086 +355922.5 C M726 1546 70 239887 +357093.5 C M727 1854 665 851946 +357161.7 C M728 356 1713 276066 +358968.0 C M729 105 145 793585 +359812.8 C M730 104 1904 423816 +361057.6 C M731 1957 887 511047 +361849.3 C M732 1670 1175 768219 +362861.9 C M733 701 194 991605 +363087.0 C M734 1101 1329 329933 +363239.8 C M735 1633 330 458400 +363769.3 C M736 1942 654 4481 +364078.2 C M737 1112 194 509078 +364155.2 C M738 768 178 369773 +366189.0 C M739 1943 540 954454 +366545.2 C M740 1243 1255 523164 +366598.5 C M741 1965 129 851050 +366654.6 C M742 1396 404 839142 +366769.9 C M743 1105 601 733428 +367239.0 C M744 492 232 89280 +368966.1 C M745 476 552 245903 +369410.4 C M746 1529 1640 742829 +369429.0 C M747 1790 1247 908832 +369807.6 C M748 1491 298 150991 +370903.8 C M749 270 1456 497043 +371045.8 C M750 1106 1350 431777 +371143.9 C M751 385 187 599427 +371604.6 C M752 1045 1630 789063 +371944.7 C M753 387 151 191261 +372278.5 C M754 409 609 904159 +374608.3 C M755 685 1430 437812 +374742.4 C M756 1155 177 420754 +374766.2 C M757 1529 1099 41013 +374886.6 C M758 1679 1291 244949 +375826.2 C M759 1582 104 634134 +376549.2 C M760 1961 833 433664 +376977.4 C M761 784 616 68785 +377251.5 C M762 680 1909 542751 +377427.9 C M763 1725 527 580834 +378104.4 C M764 1824 211 978198 +378353.3 C M765 1715 832 240413 +378446.2 C M766 639 1479 264953 +378508.5 C M767 259 1352 411793 +378680.0 C M768 677 1276 120908 +379545.6 C M769 1318 1208 523136 +379777.8 C M770 966 1513 318266 +380353.9 C M771 1261 848 922678 +381289.0 C M772 925 885 618660 +381585.3 C M773 544 266 944079 +382412.6 C M774 1813 403 497179 +382641.9 C M775 755 1919 282066 +382886.5 C M776 838 282 386426 +383550.9 C M777 771 871 109340 +383700.1 C M778 148 1009 206954 +384796.5 C M779 215 88 976069 +384893.0 C M780 161 1666 960739 +386742.9 C M781 1668 1741 223533 +387221.8 C M782 420 1750 218659 +388192.3 C M783 1244 139 269718 +389965.5 C M784 175 1690 11118 +390210.2 C M785 452 714 950169 +390308.9 C M786 489 134 391737 +391852.6 C M787 983 901 777010 +391887.4 C M788 1300 153 513867 +392400.6 C M789 34 1136 152881 +392830.3 C M790 154 809 204548 +393715.0 C M791 1817 40 411286 +393733.7 C M792 1683 75 931732 +394023.6 C M793 49 290 826563 +394232.0 C M794 712 762 417557 +394864.7 C M795 1191 320 689720 +394867.0 C M796 155 1414 461783 +395693.5 C M797 1748 247 984092 +396249.6 C M798 162 1158 643450 +396428.3 C M799 690 1762 991777 +396453.4 C M800 1703 1202 222213 +396695.0 C M801 1778 1056 125881 +396724.3 C M802 846 1396 918062 +397762.1 C M803 394 1967 190749 +397958.4 C M804 305 291 627425 +398407.9 C M805 787 1221 86465 +399163.3 C M806 969 1596 196851 +399169.7 C M807 1233 1118 391874 +399200.0 C M808 475 168 232458 +399226.0 C M809 673 830 626398 +400684.1 C M810 1266 1037 835922 +401297.1 C M811 1446 926 727448 +401310.1 C M812 1027 667 97747 +401698.8 C M813 130 1725 261785 +401863.0 C M814 1196 807 286876 +402132.2 C M815 609 929 132883 +402705.8 C M816 752 524 865503 +404375.1 C M817 1417 344 887926 +404854.5 C M818 1736 1979 632842 +405444.2 C M819 1390 1654 629258 +405671.0 C M820 1866 555 774438 +406075.9 C M821 320 557 713498 +406246.4 C M822 899 1684 375865 +407875.1 C M823 503 1832 152003 +408490.6 C M824 758 646 804647 +408530.5 C M825 628 821 662004 +409338.8 C M826 975 1289 227537 +409347.0 C M827 1465 1454 116626 +409834.1 C M828 668 1861 180916 +409941.5 C M829 859 191 862502 +409946.4 C M830 1390 1131 199302 +410346.0 C M831 1280 989 405179 +410771.2 C M832 1231 685 482584 +410975.3 C M833 331 889 885236 +412564.3 C M834 194 1668 7036 +413591.9 C M835 983 1631 134569 +413865.2 C M836 1461 432 170484 +416131.2 C M837 1302 1216 441376 +416373.5 C M838 1768 974 221228 +416457.1 C M839 452 1264 381276 +416672.4 C M840 1921 1920 549781 +417838.9 C M841 1230 1224 338129 +418200.4 C M842 1954 1301 66294 +418289.5 C M843 1081 203 18824 +418504.3 C M844 1422 602 471701 +418587.4 C M845 1304 1903 325995 +418947.6 C M846 1958 1562 551769 +419584.1 C M847 1044 632 719639 +419805.7 C M848 1255 358 447760 +419943.1 C M849 160 1081 581474 +420007.3 C M850 1345 950 639586 +420039.9 C M851 267 416 907013 +420154.7 C M852 1021 56 586538 +420251.8 C M853 1744 861 200715 +420447.8 C M854 809 931 30500 +420610.9 C M855 777 1185 644117 +420623.7 C M856 522 516 799759 +422355.2 C M857 1968 1481 674790 +422533.5 C M858 761 1605 80950 +422659.1 C M859 1346 555 987839 +423072.1 C M860 530 27 236517 +423196.2 C M861 15 547 492032 +423265.5 C M862 1685 1297 716924 +424121.5 C M863 1418 1144 469621 +425244.3 C M864 836 234 595356 +425625.2 C M865 99 1619 196396 +425645.5 C M866 1473 992 95501 +425808.4 C M867 825 19 741328 +425834.3 C M868 310 1970 454593 +425849.7 C M869 1275 819 585975 +426067.3 C M870 1232 1865 480732 +426393.1 C M871 570 1299 885394 +426744.6 C M872 1354 1805 406806 +426872.7 C M873 1580 31 687453 +427005.8 C M874 1313 791 192310 +428742.9 C M875 27 49 950893 +428897.8 C M876 272 1770 341908 +429459.7 C M877 937 699 548993 +431414.6 C M878 149 6 608277 +431530.8 C M879 1356 627 973481 +431617.3 C M880 1366 1328 36852 +432288.7 C M881 1345 1408 10880 +432635.7 C M882 453 745 839965 +432712.1 C M883 1108 1945 490302 +432758.5 C M884 1804 1961 211232 +433424.0 C M885 1160 1599 582564 +433776.9 C M886 175 817 747691 +433989.7 C M887 1259 1406 705581 +434768.5 C M888 26 1214 868651 +434835.4 C M889 204 144 853738 +434867.6 C M890 1725 1515 151122 +434875.3 C M891 1364 382 37276 +435153.6 C M892 1838 286 724752 +435350.5 C M893 1748 1454 66954 +436307.2 C M894 1516 991 957871 +436479.2 C M895 351 1043 431068 +436581.0 C M896 1063 913 224546 +437835.0 C M897 1310 278 962824 +438042.4 C M898 1090 150 997401 +439842.4 C M899 472 198 627157 +440001.5 C M900 329 1516 949302 +440230.2 C M901 175 510 102056 +441104.0 C M902 159 1703 321418 +442437.9 C M903 329 1074 993232 +443820.0 C M904 1682 1896 837624 +444504.7 C M905 96 199 714221 +444871.4 C M906 516 1197 876647 +445403.4 C M907 355 1599 8048 +445541.3 C M908 1853 464 154536 +445725.0 C M909 1208 1518 480849 +445982.5 C M910 822 1469 932311 +446016.2 C M911 1171 1174 582185 +446301.0 C M912 1532 1081 475696 +447015.0 C M913 152 1944 934965 +447447.9 C M914 1824 815 410879 +447483.9 C M915 131 1146 951632 +447500.0 C M916 208 969 438188 +448173.5 C M917 859 604 294401 +448599.5 C M918 468 937 142565 +450255.1 C M919 1281 54 212763 +452571.6 C M920 159 548 348792 +453368.0 C M921 1144 1773 325150 +454096.3 C M922 69 1875 136819 +454443.4 C M923 1332 1074 419700 +454803.9 C M924 821 572 631889 +455381.0 C M925 550 1223 892339 +455570.3 C M926 1397 1157 580842 +455658.0 C M927 100 755 831003 +455920.8 C M928 1590 1008 235918 +458203.6 C M929 1905 1135 771975 +459379.4 C M930 926 717 986138 +460015.6 C M931 750 1136 690623 +460049.9 C M932 1208 1599 339680 +460320.5 C M933 545 1636 839669 +460931.8 C M934 1366 1056 792268 +461152.7 C M935 1499 1665 430089 +461824.1 C M936 1778 624 250694 +461899.8 C M937 1104 11 121091 +462027.9 C M938 1031 133 612700 +462322.0 C M939 1038 670 222018 +463834.5 C M940 834 909 293567 +464139.2 C M941 1961 921 69308 +464449.7 C M942 1041 484 506676 +464535.4 C M943 265 124 949695 +464543.6 C M944 380 1304 248629 +465132.3 C M945 404 1492 628615 +465581.3 C M946 1757 780 383101 +466353.8 C M947 1496 1502 267575 +466914.8 C M948 446 1484 580056 +467490.3 C M949 915 1407 562858 +468566.5 C M950 1307 997 206408 +468817.6 C M951 859 983 474006 +469296.8 C M952 1249 105 324698 +470438.4 C M953 1796 1578 614586 +470536.9 C M954 1373 846 595413 +470764.5 C M955 69 1974 604681 +471117.7 C M956 1761 1530 202539 +471332.9 C M957 754 1210 85629 +471853.7 C M958 1323 788 834374 +472086.7 C M959 763 1094 705171 +472244.1 C M960 139 1298 841000 +472352.8 C M961 1053 1709 917441 +472438.7 C M962 745 1093 820737 +473390.5 C M963 1888 1866 676487 +473504.8 C M964 1897 1350 852212 +473927.4 C M965 436 966 360110 +473950.8 C M966 779 1559 938618 +476165.3 C M967 1206 1165 358709 +477191.7 C M968 1477 1533 393739 +478179.1 C M969 157 1095 872655 +478683.1 C M970 908 1687 584321 +479416.2 C M971 1059 535 608058 +479531.1 C M972 1523 1100 175324 +481233.1 C M973 874 1949 392992 +481242.3 C M974 1745 1122 623555 +481289.1 C M975 1414 391 635882 +482136.2 C M976 500 342 641312 +482430.9 C M977 187 1573 377318 +482442.4 C M978 1438 136 968935 +483005.8 C M979 427 148 680011 +483195.6 C M980 1123 1338 125589 +483382.1 C M981 1329 56 370112 +483567.8 C M982 1647 1969 799461 +484096.0 C M983 1646 1641 38668 +484466.9 C M984 320 365 707369 +484739.8 C M985 1959 1976 604334 +484760.6 C M986 1818 1736 361279 +485113.7 C M987 908 925 379237 +485670.0 C M988 1867 132 528170 +485722.2 C M989 1585 188 546214 +487575.3 C M990 116 553 787897 +488092.4 C M991 1663 96 880868 +488328.6 C M992 301 1952 716145 +488941.2 C M993 1790 134 359499 +489591.3 C M994 1015 1265 380547 +490091.3 C M995 995 1319 997382 +490300.4 C M996 43 1759 745249 +490538.2 C M997 644 907 342498 +490770.5 C M998 347 1861 150803 +491618.4 C M999 582 1542 494788 +491755.2 C M1000 329 797 728462 +491873.0 C M1001 1323 801 157382 +491955.5 C M1002 1899 265 598095 +492736.6 C M1003 1652 198 261330 +492982.8 C M1004 1915 503 687650 +493305.1 C M1005 1072 657 60667 +493476.7 C M1006 460 1740 650474 +493570.6 C M1007 61 978 883051 +493583.7 C M1008 1438 98 387956 +494286.3 C M1009 273 1508 245096 +494870.5 C M1010 16 850 98177 +496252.0 C M1011 1818 722 520685 +497110.9 C M1012 207 1382 95249 +498385.5 C M1013 313 789 886865 +498539.5 C M1014 290 155 423219 +499044.8 C M1015 480 1350 526539 +499195.5 C M1016 873 1393 813565 +499315.1 C M1017 1467 349 535005 +499937.8 C M1018 1392 213 959543 +500239.4 C M1019 353 168 392731 +500880.1 C M1020 1094 935 923645 +501596.4 C M1021 1634 1564 455988 +501912.7 C M1022 1857 1128 60726 +501947.6 C M1023 1671 1312 919661 +503953.7 C M1024 1981 420 394412 +504032.8 C M1025 1941 298 111335 +504420.1 C M1026 1699 1507 273492 +504908.5 C M1027 795 440 629277 +505014.8 C M1028 355 899 366803 +505640.3 C M1029 1603 1341 632717 +506076.5 C M1030 1008 450 216442 +507328.9 C M1031 1085 313 899685 +507697.5 C M1032 70 984 368136 +507751.8 C M1033 1735 407 527415 +507939.7 C M1034 492 10 270137 +508894.6 C M1035 1279 1812 694452 +510272.6 C M1036 82 878 836236 +510576.5 C M1037 1514 102 788269 +510665.9 C M1038 1939 672 580214 +511058.8 C M1039 123 731 670508 +511836.8 C M1040 1031 1835 684699 +512117.4 C M1041 1400 1094 534451 +512202.0 C M1042 1861 701 858862 +512999.0 C M1043 1815 139 236764 +513226.8 C M1044 691 142 899944 +513332.1 C M1045 66 903 10388 +513371.0 C M1046 1421 1245 245967 +515291.1 C M1047 1483 1937 774651 +516418.5 C M1048 921 544 706816 +517277.1 C M1049 1461 1696 153302 +517449.3 C M1050 156 1389 673160 +517757.1 C M1051 793 936 354822 +518162.7 C M1052 1755 577 74282 +518356.9 C M1053 1931 574 565663 +518400.9 C M1054 30 1627 999058 +519283.9 C M1055 4 1814 52094 +519981.3 C M1056 1052 1083 175345 +520935.3 C M1057 1129 11 130439 +520939.9 C M1058 1940 1314 253986 +521140.5 C M1059 1826 619 115245 +521231.2 C M1060 1680 1803 240259 +522053.1 C M1061 264 1732 919061 +522543.2 C M1062 1770 1610 255644 +523167.3 C M1063 1716 376 483927 +523236.7 C M1064 1351 745 888060 +524026.4 C M1065 633 944 627504 +524050.3 C M1066 1872 1385 118876 +524059.3 C M1067 1321 894 630863 +525586.2 C M1068 859 765 578189 +525686.9 C M1069 1938 153 870918 +526187.5 C M1070 1062 82 606996 +526845.8 C M1071 1533 871 217106 +527644.9 C M1072 1676 1875 713741 +528879.0 C M1073 1195 1615 395464 +529139.8 C M1074 1985 694 545039 +529201.0 C M1075 655 1250 253120 +529364.1 C M1076 241 822 659274 +529442.8 C M1077 1062 676 466793 +531116.5 C M1078 1375 330 929124 +531326.2 C M1079 419 745 861875 +531337.9 C M1080 637 138 134705 +531391.2 C M1081 1752 1108 202685 +532125.7 C M1082 1569 531 320179 +532302.1 C M1083 1830 66 155723 +532528.3 C M1084 24 1032 853963 +533934.1 C M1085 878 649 464152 +534223.4 C M1086 592 909 858244 +535059.7 C M1087 1953 171 692550 +535127.6 C M1088 1908 1964 202071 +536466.5 C M1089 200 180 474332 +536957.2 C M1090 162 695 299809 +536973.8 C M1091 1908 1447 949959 +537030.1 C M1092 2 1662 753231 +538908.4 C M1093 856 670 386692 +539034.1 C M1094 578 684 784081 +540484.9 C M1095 908 986 117911 +540818.9 C M1096 935 1257 733248 +541792.2 C M1097 1589 24 748959 +542016.3 C M1098 80 1324 104420 +542566.4 C M1099 700 585 479580 +542684.0 C M1100 1227 1608 608202 +542841.7 C M1101 958 1837 812842 +543769.8 C M1102 1810 589 35796 +544876.7 C M1103 865 982 814831 +545489.6 C M1104 719 1476 354737 +546411.1 C M1105 451 710 6684 +546711.8 C M1106 868 652 171247 +547181.4 C M1107 351 1786 529920 +547230.7 C M1108 1908 152 256198 +547255.7 C M1109 567 1421 218749 +548122.6 C M1110 61 651 218737 +548668.3 C M1111 1601 1258 107337 +548934.1 C M1112 432 1182 324069 +550986.2 C M1113 610 1909 748596 +551340.6 C M1114 830 962 520881 +552518.3 C M1115 747 1090 841973 +552839.6 C M1116 1882 1811 641488 +552961.3 C M1117 784 305 829970 +552974.8 C M1118 44 1169 612672 +553231.2 C M1119 903 894 273545 +554196.0 C M1120 346 1014 319521 +554483.8 C M1121 1990 408 857730 +555119.5 C M1122 816 1340 536118 +555213.5 C M1123 1288 1887 315066 +555848.5 C M1124 1814 623 532602 +556408.1 C M1125 1105 1087 427786 +556436.7 C M1126 330 771 498246 +556736.5 C M1127 956 718 905812 +556992.2 C M1128 584 770 933287 +557762.8 C M1129 103 931 640206 +558665.2 C M1130 849 246 746885 +558697.5 C M1131 910 1156 416121 +561610.0 C M1132 1218 553 678084 +561804.2 C M1133 963 1064 61327 +561941.1 C M1134 1688 1195 941700 +562251.2 C M1135 736 1672 769312 +562293.3 C M1136 752 567 257246 +562304.0 C M1137 1445 1747 150307 +562591.2 C M1138 1483 1684 181939 +562690.2 C M1139 210 718 667607 +562735.1 C M1140 1508 1363 574172 +563394.2 C M1141 150 677 970117 +563741.3 C M1142 1843 1875 21466 +563803.2 C M1143 1528 1507 545401 +563937.0 C M1144 231 834 697249 +564218.6 C M1145 1258 128 784209 +564299.2 C M1146 1933 987 551443 +564478.8 C M1147 204 415 550590 +564580.0 C M1148 1249 1065 733292 +564791.8 C M1149 161 596 393384 +564837.8 C M1150 446 355 429390 +565599.2 C M1151 1239 1698 698424 +566453.6 C M1152 1624 601 128852 +566934.1 C M1153 973 623 69205 +567573.3 C M1154 587 882 519761 +568088.7 C M1155 1319 579 15727 +568514.5 C M1156 1365 1410 960300 +569922.9 C M1157 497 1126 257303 +571050.2 C M1158 777 1437 484872 +571078.3 C M1159 1190 1029 329661 +571510.7 C M1160 396 1311 576285 +571720.1 C M1161 12 274 510805 +571856.1 C M1162 176 1547 146215 +572035.3 C M1163 920 71 394660 +572411.8 C M1164 87 1046 997926 +572581.5 C M1165 1007 1902 965837 +572719.8 C M1166 1236 457 828996 +572845.4 C M1167 1812 1963 608597 +573382.2 C M1168 1409 1304 437772 +573742.5 C M1169 1077 1330 796152 +573826.5 C M1170 1495 1578 439256 +574922.1 C M1171 621 1103 332231 +575033.6 C M1172 1334 436 323205 +575079.3 C M1173 1793 71 541577 +575082.2 C M1174 1996 1715 211294 +575113.5 C M1175 63 1728 792192 +575624.8 C M1176 1133 832 883395 +576111.8 C M1177 339 262 930966 +576397.0 C M1178 527 691 194287 +576611.4 C M1179 7 1954 683557 +576958.0 C M1180 1823 828 872874 +577032.5 C M1181 351 1894 584884 +577146.4 C M1182 1633 185 200752 +577491.4 C M1183 774 599 464922 +577772.5 C M1184 1165 466 649800 +578330.5 C M1185 1234 1441 948003 +578837.0 C M1186 648 667 642088 +579078.4 C M1187 1703 1867 613714 +579139.1 C M1188 1394 502 228876 +579157.3 C M1189 272 1234 757727 +579896.5 C M1190 1343 444 488936 +580422.4 C M1191 1205 923 531662 +581065.2 C M1192 1499 1177 745011 +582185.0 C M1193 524 1084 847693 +583383.0 C M1194 1287 1823 257032 +583655.1 C M1195 1850 669 116049 +583871.0 C M1196 695 619 615471 +584613.3 C M1197 682 477 19720 +584742.0 C M1198 1308 1945 902851 +586961.4 C M1199 1613 35 732510 +587451.2 C M1200 1732 815 436506 +587531.0 C M1201 437 1281 388508 +588449.7 C M1202 1888 603 633668 +589482.8 C M1203 587 976 719180 +590470.5 C M1204 673 601 735958 +590506.4 C M1205 60 340 480930 +592657.6 C M1206 1168 244 221507 +593421.6 C M1207 822 1203 934089 +593599.3 C M1208 1949 197 993246 +593662.8 C M1209 1007 678 566748 +593879.2 C M1210 1685 1094 542622 +594167.6 C M1211 1876 988 463074 +594749.5 C M1212 732 1841 475942 +594837.0 C M1213 414 1766 536698 +594861.7 C M1214 1305 617 949716 +596025.5 C M1215 1421 1022 845774 +596721.2 C M1216 1694 1895 163679 +596764.2 C M1217 958 1959 300490 +596827.4 C M1218 892 135 627832 +596901.7 C M1219 243 237 836994 +597849.9 C M1220 492 1708 126025 +597928.7 C M1221 1793 1112 377704 +598316.7 C M1222 1522 854 171525 +599013.3 C M1223 441 37 719249 +599784.2 C M1224 1281 680 944027 +600500.4 C M1225 1188 1687 735913 +601522.2 C M1226 528 625 323422 +602177.7 C M1227 852 321 131669 +602492.5 C M1228 47 1090 437285 +602660.0 C M1229 1399 1052 338312 +603263.2 C M1230 456 904 171375 +604809.4 C M1231 613 981 715628 +606453.6 C M1232 1513 269 320537 +606778.5 C M1233 827 451 256803 +606845.7 C M1234 779 539 368030 +607090.7 C M1235 553 70 843272 +607201.0 C M1236 1206 1433 720000 +607339.8 C M1237 637 1279 423829 +607426.0 C M1238 1876 103 441705 +608716.4 C M1239 609 1709 480178 +609746.1 C M1240 401 90 471139 +610654.0 C M1241 1745 1928 63545 +612249.9 C M1242 75 1114 119007 +612654.6 C M1243 1157 1197 679991 +612840.3 C M1244 1008 1294 368895 +614106.0 C M1245 1156 386 218086 +614281.4 C M1246 1342 1983 84935 +614647.0 C M1247 1001 262 889479 +615832.0 C M1248 809 1038 53431 +616384.7 C M1249 1082 602 322307 +617631.8 C M1250 1933 1727 767757 +618149.2 C M1251 1645 747 932365 +618149.6 C M1252 349 102 380346 +618153.6 C M1253 214 1377 817141 +618729.2 C M1254 1279 1945 861821 +618862.9 C M1255 1275 1995 962457 +618965.4 C M1256 1413 203 741189 +620572.9 C M1257 1443 300 542078 +620783.7 C M1258 1599 592 97302 +621090.2 C M1259 1929 983 323979 +621119.8 C M1260 690 307 173448 +621907.5 C M1261 187 936 871791 +622006.7 C M1262 421 819 14203 +622849.7 C M1263 1328 1257 415014 +623025.8 C M1264 1115 11 481534 +623063.2 C M1265 1922 1121 512983 +623860.1 C M1266 609 537 984085 +623869.3 C M1267 1458 1669 120863 +624638.1 C M1268 1394 439 137700 +625225.2 C M1269 1928 161 333847 +625862.7 C M1270 1680 460 361322 +626131.8 C M1271 1609 846 85895 +626187.8 C M1272 1946 323 541082 +626756.7 C M1273 1316 1727 552435 +628458.2 C M1274 141 877 843550 +628734.8 C M1275 779 1440 370153 +628763.0 C M1276 284 807 874370 +628953.9 C M1277 1471 1073 228895 +629384.3 C M1278 1337 547 463926 +630261.7 C M1279 1013 273 60693 +631218.1 C M1280 44 247 4571 +631380.2 C M1281 1333 838 467038 +631781.8 C M1282 1572 32 488972 +631813.7 C M1283 182 748 921166 +632653.0 C M1284 1638 673 481168 +632779.0 C M1285 1202 1942 306977 +633382.7 C M1286 760 590 276041 +633714.1 C M1287 1834 527 120278 +634192.4 C M1288 624 538 615456 +634368.4 C M1289 1649 1578 180876 +634371.9 C M1290 1654 1882 172605 +634982.4 C M1291 1905 978 325270 +634995.1 C M1292 766 46 290633 +635069.6 C M1293 1345 1571 142643 +635228.2 C M1294 1684 435 962119 +635677.9 C M1295 1784 180 652688 +636225.3 C M1296 391 857 817967 +637306.4 C M1297 513 1284 685 +637384.1 C M1298 859 1253 319504 +637590.7 C M1299 688 1747 829059 +637949.9 C M1300 1101 570 972975 +639784.1 C M1301 824 410 250552 +639861.2 C M1302 1637 1475 747898 +640789.1 C M1303 1672 1314 711595 +640961.3 C M1304 274 1985 347430 +641581.1 C M1305 130 575 929823 +641664.8 C M1306 268 225 327220 +642104.4 C M1307 592 1067 146924 +642543.7 C M1308 73 1711 55628 +643112.4 C M1309 1518 31 300461 +643644.0 C M1310 1813 1097 898636 +643662.3 C M1311 1859 1587 98934 +644407.0 C M1312 978 263 282475 +644407.5 C M1313 1696 1328 64007 +644426.3 C M1314 898 857 624777 +644734.3 C M1315 1005 1114 98086 +644905.2 C M1316 1604 1412 897700 +644931.2 C M1317 1807 710 118590 +645441.3 C M1318 1455 1508 735174 +645868.9 C M1319 976 651 389736 +645900.2 C M1320 1297 716 280942 +645937.6 C M1321 1043 1980 156788 +646920.5 C M1322 444 350 23653 +647586.7 C M1323 1729 1 189512 +647637.9 C M1324 1355 608 173243 +649284.2 C M1325 1214 1202 623396 +649489.9 C M1326 273 565 770827 +650900.5 C M1327 1950 1539 174471 +651201.3 C M1328 161 1003 247108 +652363.3 C M1329 1904 1017 420378 +652713.0 C M1330 1699 686 931026 +654243.9 C M1331 1776 1727 234082 +654748.7 C M1332 1949 1692 377783 +655301.5 C M1333 363 978 862189 +655682.7 C M1334 1006 823 856680 +656385.0 C M1335 225 948 256045 +659457.2 C M1336 789 618 717747 +659495.0 C M1337 472 224 25364 +661047.1 C M1338 408 1627 675565 +661181.9 C M1339 1154 1359 947118 +662039.9 C M1340 870 532 357423 +662455.1 C M1341 1806 1357 383697 +662516.4 C M1342 239 1205 99040 +662875.9 C M1343 76 1115 123156 +664899.3 C M1344 1222 1933 101608 +665680.3 C M1345 1050 1701 455706 +665823.0 C M1346 1322 607 104169 +666289.8 C M1347 1662 642 613401 +666780.1 C M1348 928 1814 314178 +667776.6 C M1349 849 556 495066 +668495.8 C M1350 1024 115 410700 +669609.8 C M1351 1883 1657 69285 +670553.1 C M1352 1441 523 503473 +670746.1 C M1353 18 1607 718422 +671276.0 C M1354 1368 482 227239 +672310.0 C M1355 1749 1535 882118 +672373.3 C M1356 19 667 747436 +672672.4 C M1357 1375 900 430330 +672822.9 C M1358 1315 1106 317565 +673026.0 C M1359 1256 828 795749 +673166.0 C M1360 573 1616 421141 +673167.8 C M1361 1764 854 152539 +673932.1 C M1362 1571 985 291758 +673968.0 C M1363 337 885 113455 +674835.4 C M1364 601 1357 771990 +675153.3 C M1365 722 968 673658 +675290.8 C M1366 1909 1220 483492 +677296.6 C M1367 1099 1049 453636 +678684.3 C M1368 227 1770 736793 +680311.0 C M1369 153 1651 856432 +681844.7 C M1370 217 689 312126 +682705.5 C M1371 1868 1224 383136 +682865.9 C M1372 875 201 271184 +683375.6 C M1373 802 36 963765 +684039.7 C M1374 1120 31 797925 +684873.5 C M1375 1389 1677 323087 +685650.7 C M1376 605 762 476958 +685737.1 C M1377 523 1365 360816 +687001.3 C M1378 360 215 428409 +687073.0 C M1379 1052 1350 967116 +687927.5 C M1380 472 790 136081 +688112.9 C M1381 476 719 380875 +689275.9 C M1382 1490 1214 672167 +689504.6 C M1383 578 1360 541546 +690062.3 C M1384 919 1586 794940 +690140.9 C M1385 517 1536 355753 +690391.1 C M1386 1682 976 934664 +691602.8 C M1387 882 347 203912 +692213.1 C M1388 1234 1284 919209 +693040.6 C M1389 378 1308 531612 +694138.1 C M1390 1407 1879 670217 +694449.2 C M1391 1637 1615 939083 +694735.0 C M1392 147 572 945359 +695453.9 C M1393 982 1960 473320 +695520.3 C M1394 1623 1162 448931 +696079.0 C M1395 160 671 734759 +696170.0 C M1396 567 1917 459311 +696754.8 C M1397 503 805 409283 +697560.5 C M1398 758 22 10573 +697738.6 C M1399 82 54 397598 +698034.1 C M1400 100 515 746011 diff --git a/ee/350_events_500_nodes_700ks.txt b/ee/350_events_500_nodes_700ks.txt new file mode 100644 index 000000000..8b55cb751 --- /dev/null +++ b/ee/350_events_500_nodes_700ks.txt @@ -0,0 +1,350 @@ +1513.7 C M1 424 401 507913 +2024.1 C M2 401 187 661715 +2251.0 C M3 200 372 675757 +4240.3 C M4 159 301 125201 +4386.9 C M5 241 70 328185 +5729.8 C M6 492 249 846774 +14158.3 C M7 269 441 38547 +15453.2 C M8 366 465 637737 +16883.0 C M9 7 443 724395 +17438.6 C M10 366 120 11557 +19342.9 C M11 236 315 406388 +21294.0 C M12 130 254 611849 +25205.0 C M13 430 464 579800 +25881.7 C M14 412 158 774709 +30970.6 C M15 7 101 972489 +31312.1 C M16 21 392 386343 +31335.4 C M17 187 342 214844 +37374.3 C M18 336 320 356737 +38145.7 C M19 53 382 842565 +40136.4 C M20 134 241 961764 +40282.6 C M21 143 175 471790 +40512.0 C M22 196 444 967743 +40630.6 C M23 192 473 515986 +42587.4 C M24 273 132 356034 +49434.9 C M25 44 260 691111 +52267.5 C M26 174 295 115038 +55348.1 C M27 42 301 953260 +55708.4 C M28 489 312 119338 +56718.5 C M29 103 306 605811 +57757.2 C M30 399 406 790684 +59159.1 C M31 75 476 320666 +63336.6 C M32 294 187 477230 +68731.1 C M33 492 369 892490 +70424.7 C M34 315 24 347482 +72912.6 C M35 301 493 73831 +74105.9 C M36 65 271 348435 +76499.2 C M37 90 439 272232 +79193.8 C M38 483 292 35546 +80569.1 C M39 408 127 626536 +81158.4 C M40 314 143 110050 +85031.2 C M41 395 245 249667 +87552.0 C M42 340 373 363800 +88347.0 C M43 162 102 522346 +91896.7 C M44 367 107 526986 +95718.2 C M45 187 370 278846 +98480.4 C M46 493 197 181652 +98832.3 C M47 277 171 27652 +100719.6 C M48 108 110 17837 +103638.6 C M49 79 94 28617 +104132.9 C M50 229 19 826598 +104653.1 C M51 107 498 171801 +104869.2 C M52 8 80 743743 +110989.6 C M53 429 166 433664 +112116.8 C M54 158 108 871273 +113108.4 C M55 106 214 205483 +113140.8 C M56 254 47 726917 +113232.2 C M57 163 315 162605 +114220.8 C M58 159 403 841275 +115414.4 C M59 235 73 959422 +119575.0 C M60 232 312 186514 +123819.9 C M61 221 248 97193 +123990.0 C M62 369 211 807401 +125236.7 C M63 401 328 792379 +126522.2 C M64 139 48 897607 +127411.6 C M65 461 143 179645 +127963.1 C M66 332 26 851579 +130782.4 C M67 364 449 346607 +131280.5 C M68 390 491 701725 +132688.1 C M69 487 488 525221 +133260.0 C M70 133 46 447404 +137333.1 C M71 76 384 571625 +138357.0 C M72 207 78 566370 +138457.3 C M73 371 161 416038 +139030.5 C M74 94 371 846920 +143201.3 C M75 228 265 728656 +146337.0 C M76 136 449 991399 +146726.9 C M77 309 371 59636 +149083.0 C M78 463 1 5882 +149226.3 C M79 54 253 520831 +149785.2 C M80 210 129 688097 +153832.2 C M81 138 356 481608 +161397.7 C M82 461 138 93956 +165100.4 C M83 195 107 370099 +167209.7 C M84 136 487 638020 +167586.3 C M85 28 499 156497 +170727.9 C M86 282 98 691895 +175496.7 C M87 385 336 338470 +177763.6 C M88 63 314 365624 +179683.2 C M89 9 238 782944 +182152.3 C M90 68 454 155192 +187176.5 C M91 154 272 582649 +187555.2 C M92 134 121 670337 +191126.0 C M93 315 373 408189 +191340.9 C M94 122 175 810722 +191997.5 C M95 4 292 752259 +194049.8 C M96 231 34 291769 +194370.9 C M97 220 80 587157 +196315.3 C M98 61 407 558314 +200565.8 C M99 268 410 125834 +200914.5 C M100 67 393 288972 +203734.4 C M101 461 22 938139 +207258.0 C M102 359 331 154341 +207953.4 C M103 280 162 666497 +212384.2 C M104 320 311 502291 +214197.9 C M105 214 377 87960 +215029.3 C M106 464 112 977388 +221246.0 C M107 70 352 311106 +221602.7 C M108 440 457 406366 +224046.5 C M109 333 399 545824 +226649.6 C M110 124 276 187250 +227136.6 C M111 432 44 582712 +227775.2 C M112 255 396 761936 +230852.1 C M113 264 47 180415 +234752.2 C M114 388 111 702085 +234919.2 C M115 410 307 617019 +236683.2 C M116 207 460 62920 +239824.0 C M117 65 337 444445 +241512.6 C M118 468 137 260388 +242866.8 C M119 287 448 493939 +244238.5 C M120 335 276 30920 +247885.3 C M121 173 78 812982 +250165.0 C M122 463 411 888306 +251329.7 C M123 201 419 492700 +251767.4 C M124 433 301 605979 +254215.2 C M125 319 454 330143 +254315.9 C M126 27 455 703255 +255513.0 C M127 445 182 652639 +255939.8 C M128 178 407 395344 +258068.6 C M129 391 389 914431 +262499.1 C M130 368 306 505561 +262720.5 C M131 64 90 72110 +267104.2 C M132 33 395 982238 +267884.1 C M133 170 249 19373 +268339.0 C M134 442 347 343085 +268908.6 C M135 126 9 29778 +272751.1 C M136 265 327 827332 +273025.7 C M137 222 419 604400 +275291.1 C M138 231 40 713326 +275758.1 C M139 84 254 868911 +277711.9 C M140 171 155 800844 +278010.4 C M141 446 38 464271 +279264.9 C M142 47 247 524925 +279568.5 C M143 47 373 496974 +282471.7 C M144 249 147 864265 +284153.1 C M145 143 403 956908 +284154.3 C M146 52 441 749587 +284569.3 C M147 457 360 197079 +284934.0 C M148 321 250 510024 +287782.4 C M149 274 383 277722 +292219.0 C M150 399 225 16678 +292381.9 C M151 221 59 94914 +293136.2 C M152 111 129 330492 +294921.3 C M153 382 345 901894 +295541.1 C M154 96 244 364913 +295901.1 C M155 46 423 993280 +297077.2 C M156 427 173 537515 +298108.2 C M157 416 158 796485 +298383.8 C M158 188 84 797887 +299542.8 C M159 262 205 396374 +301201.3 C M160 357 77 136318 +303699.8 C M161 471 2 420007 +304030.4 C M162 259 255 10801 +308810.8 C M163 431 193 627601 +309271.6 C M164 297 43 542233 +311100.5 C M165 225 21 837965 +311855.5 C M166 409 490 402009 +314167.3 C M167 161 249 874341 +316413.2 C M168 79 133 214092 +319515.2 C M169 458 355 888932 +319563.7 C M170 152 54 954517 +319656.9 C M171 470 379 793511 +321567.0 C M172 467 312 17093 +329892.7 C M173 130 245 147926 +332895.0 C M174 135 23 276838 +335805.4 C M175 227 156 94208 +337126.6 C M176 428 82 65814 +340819.8 C M177 449 58 937578 +342298.9 C M178 395 340 361855 +345084.5 C M179 48 165 133839 +347988.6 C M180 75 180 305348 +348018.0 C M181 181 85 97477 +348256.7 C M182 60 73 157993 +350443.2 C M183 373 166 375966 +353045.0 C M184 113 267 536593 +353980.3 C M185 495 340 889167 +356261.4 C M186 445 262 660399 +358666.4 C M187 246 355 806284 +359340.1 C M188 420 292 941162 +359580.1 C M189 36 359 237430 +362357.6 C M190 45 251 924647 +364997.6 C M191 476 12 963721 +365283.2 C M192 400 6 598286 +368448.0 C M193 126 291 702092 +371866.2 C M194 290 294 111663 +374569.4 C M195 227 283 95134 +382380.0 C M196 87 55 10628 +383687.9 C M197 183 459 55589 +388420.3 C M198 179 140 341755 +395368.4 C M199 180 405 630123 +395640.4 C M200 360 203 894371 +398078.5 C M201 329 209 546928 +398139.7 C M202 192 379 720157 +398422.7 C M203 364 23 393277 +398930.3 C M204 441 485 322385 +400352.7 C M205 404 244 883411 +404680.8 C M206 127 236 875354 +405337.5 C M207 21 281 289964 +410370.5 C M208 372 430 100214 +411311.3 C M209 368 213 763325 +417833.7 C M210 175 167 854076 +419933.1 C M211 41 388 374790 +424206.3 C M212 389 332 363973 +428203.2 C M213 258 226 945599 +430829.9 C M214 341 171 32282 +431752.1 C M215 485 234 585848 +435705.4 C M216 469 270 796241 +436661.6 C M217 266 88 229795 +441546.7 C M218 113 265 435690 +441899.7 C M219 91 431 391245 +445045.3 C M220 306 147 230900 +445523.2 C M221 137 67 939195 +447735.4 C M222 494 67 849938 +449670.7 C M223 252 55 37030 +450614.1 C M224 215 17 489152 +454650.3 C M225 89 241 182724 +455325.0 C M226 246 283 977559 +455715.2 C M227 157 483 75817 +455888.3 C M228 318 365 277396 +457404.0 C M229 262 230 784493 +458539.2 C M230 274 392 313343 +459630.3 C M231 7 223 153281 +460737.6 C M232 272 193 172270 +461078.1 C M233 202 248 738666 +461888.5 C M234 75 374 617371 +465051.5 C M235 342 97 420040 +465739.4 C M236 290 325 112500 +467464.0 C M237 390 163 956415 +467801.1 C M238 433 452 33730 +469002.5 C M239 370 91 827483 +474035.9 C M240 375 162 355177 +475731.6 C M241 391 167 109049 +476263.7 C M242 182 231 32580 +476914.6 C M243 396 347 878848 +481148.8 C M244 330 92 5949 +481293.4 C M245 249 45 760591 +484581.0 C M246 34 498 577572 +484619.5 C M247 73 297 407710 +484684.1 C M248 220 37 209156 +484950.0 C M249 426 197 439599 +485155.9 C M250 375 152 855917 +486067.6 C M251 483 188 914769 +490240.4 C M252 370 170 211881 +490888.7 C M253 54 174 302713 +492052.5 C M254 117 303 944684 +496852.8 C M255 367 223 271908 +498649.3 C M256 35 36 257463 +499860.5 C M257 125 341 602564 +500232.4 C M258 430 217 275227 +501906.3 C M259 3 47 576396 +505032.4 C M260 399 396 322137 +506179.5 C M261 40 384 380034 +507224.2 C M262 286 62 784210 +507622.2 C M263 486 324 731421 +514683.3 C M264 227 193 536223 +518114.0 C M265 262 180 557720 +527802.5 C M266 278 102 812608 +527808.9 C M267 5 13 757118 +528006.8 C M268 163 192 646049 +528052.9 C M269 300 25 679117 +529161.1 C M270 262 436 623830 +529162.0 C M271 85 44 898469 +540836.8 C M272 102 268 948204 +541364.8 C M273 246 355 431399 +541484.1 C M274 430 25 762704 +541489.0 C M275 322 163 780024 +541940.7 C M276 80 115 115625 +546470.3 C M277 340 490 677461 +548574.3 C M278 465 122 334356 +556513.5 C M279 359 41 483428 +556526.4 C M280 279 301 723822 +556920.9 C M281 193 86 192998 +557937.6 C M282 231 361 26870 +560138.8 C M283 366 395 537788 +560927.4 C M284 131 335 127689 +561610.1 C M285 453 45 590184 +561707.1 C M286 307 172 519133 +562345.6 C M287 416 183 394199 +563036.9 C M288 18 17 621612 +565371.0 C M289 397 224 521104 +566309.4 C M290 382 164 447498 +568379.5 C M291 397 273 795742 +572388.8 C M292 374 173 343242 +579259.6 C M293 262 169 976352 +585483.0 C M294 369 388 725647 +588902.0 C M295 167 337 391639 +591364.9 C M296 269 181 212553 +592603.3 C M297 187 104 79351 +593346.6 C M298 47 312 323008 +595180.2 C M299 365 133 771155 +597478.3 C M300 435 241 673288 +605232.8 C M301 330 50 397583 +605367.1 C M302 290 372 310940 +605438.3 C M303 403 59 444696 +607033.2 C M304 394 261 755952 +607914.4 C M305 278 417 49249 +609549.3 C M306 139 377 71760 +610832.6 C M307 73 122 267349 +612394.0 C M308 476 386 329566 +617273.5 C M309 222 245 797207 +617854.8 C M310 2 324 469260 +621503.7 C M311 68 344 695785 +622023.1 C M312 463 81 167638 +623384.9 C M313 245 358 859799 +623860.2 C M314 65 257 71852 +628874.8 C M315 457 27 663949 +628984.9 C M316 394 69 648285 +629081.8 C M317 207 319 178155 +630058.5 C M318 349 160 386961 +632495.9 C M319 180 70 976016 +635972.1 C M320 396 100 874162 +642979.7 C M321 267 215 328820 +644137.8 C M322 260 427 46217 +644426.3 C M323 281 80 276265 +647595.4 C M324 169 90 266801 +649836.9 C M325 306 159 931034 +657476.2 C M326 321 289 880499 +658783.2 C M327 486 487 269036 +658993.8 C M328 99 371 844157 +662017.0 C M329 300 248 254756 +663810.5 C M330 308 235 755404 +666717.9 C M331 498 447 914512 +667917.2 C M332 261 491 967369 +668125.3 C M333 169 268 604539 +670079.1 C M334 165 439 891397 +670970.6 C M335 190 303 624050 +671503.3 C M336 241 147 973887 +672981.9 C M337 380 206 4922 +677836.7 C M338 51 192 517053 +682476.8 C M339 347 293 984151 +685137.4 C M340 347 27 707720 +690663.1 C M341 316 394 524671 +691365.7 C M342 319 74 67091 +692083.1 C M343 26 25 224549 +693203.5 C M344 52 283 954854 +695970.7 C M345 460 95 648754 +696044.5 C M346 151 362 401676 +696055.2 C M347 171 297 159108 +697711.0 C M348 289 383 502773 +698292.6 C M349 31 56 905088 +699917.9 C M350 147 186 147722 diff --git a/ee/700_events_1000_nodes_700ks.txt b/ee/700_events_1000_nodes_700ks.txt new file mode 100644 index 000000000..691de3849 --- /dev/null +++ b/ee/700_events_1000_nodes_700ks.txt @@ -0,0 +1,700 @@ +285.7 C M1 163 509 550704 +558.6 C M2 752 241 100161 +1081.0 C M3 214 255 542599 +1221.9 C M4 405 423 389867 +1266.9 C M5 388 927 671217 +1736.4 C M6 510 124 805696 +2203.0 C M7 522 877 773572 +4478.6 C M8 79 734 333705 +5192.6 C M9 201 288 820324 +7207.4 C M10 265 340 624755 +7631.5 C M11 607 903 809456 +8486.8 C M12 340 829 70740 +11040.3 C M13 375 777 536748 +11535.7 C M14 496 760 816481 +12391.6 C M15 167 750 454501 +16127.8 C M16 134 531 775567 +16764.7 C M17 482 998 312182 +20379.6 C M18 207 615 738943 +20613.1 C M19 756 209 943975 +22398.6 C M20 759 155 919236 +23214.1 C M21 168 116 171765 +24438.3 C M22 558 773 508897 +24938.7 C M23 962 346 532184 +24981.2 C M24 621 714 311046 +25053.1 C M25 557 691 840622 +27879.8 C M26 376 535 213140 +28371.5 C M27 637 616 709034 +30518.5 C M28 647 190 886014 +31973.2 C M29 932 715 422690 +34315.3 C M30 136 682 960703 +35036.7 C M31 461 565 138443 +35423.3 C M32 542 379 737320 +36426.8 C M33 705 204 827546 +37953.8 C M34 120 766 684953 +38167.6 C M35 257 37 271179 +38832.1 C M36 545 821 854714 +40095.3 C M37 779 384 670577 +40593.1 C M38 133 262 980468 +41944.8 C M39 834 865 224727 +42409.9 C M40 851 46 787895 +43388.3 C M41 525 93 563435 +43494.2 C M42 521 494 121920 +43779.6 C M43 881 751 65191 +45066.3 C M44 560 607 296192 +45091.8 C M45 467 672 480260 +45841.0 C M46 411 368 747404 +45878.6 C M47 537 396 786321 +46184.5 C M48 515 41 424909 +48329.9 C M49 872 893 345472 +48488.9 C M50 280 123 727200 +48797.8 C M51 367 662 448102 +49399.7 C M52 971 615 761734 +49983.5 C M53 491 765 187647 +51499.0 C M54 852 786 215482 +52036.3 C M55 617 92 571604 +52537.8 C M56 554 764 235139 +54274.2 C M57 835 420 164295 +54934.8 C M58 846 556 389713 +55742.5 C M59 86 319 692629 +55814.2 C M60 442 399 484677 +55861.2 C M61 858 640 859677 +57283.9 C M62 405 532 293624 +58643.6 C M63 212 324 536733 +58756.2 C M64 28 881 904637 +58907.9 C M65 899 292 123388 +62828.6 C M66 84 986 818124 +64389.7 C M67 348 955 343829 +69185.1 C M68 3 848 384840 +71072.2 C M69 272 637 901174 +71925.0 C M70 677 199 429289 +71957.9 C M71 501 316 465605 +73528.1 C M72 764 531 398215 +74614.5 C M73 185 174 505861 +75950.2 C M74 873 18 474897 +75980.1 C M75 188 485 995019 +76307.2 C M76 752 519 380340 +76664.0 C M77 9 726 355547 +77206.3 C M78 899 620 807025 +79161.2 C M79 183 294 524332 +79463.2 C M80 391 877 275298 +80147.3 C M81 695 553 95540 +81211.5 C M82 886 477 679422 +81271.0 C M83 51 601 970552 +81364.7 C M84 709 2 981687 +82266.5 C M85 381 150 745162 +83454.6 C M86 400 321 340628 +86243.8 C M87 388 239 137008 +87742.9 C M88 69 680 39926 +87802.2 C M89 735 635 880275 +87979.9 C M90 923 283 169244 +88247.6 C M91 1 53 299199 +88324.1 C M92 588 572 541024 +90002.3 C M93 474 339 880558 +91655.8 C M94 349 88 783706 +92755.8 C M95 877 808 186308 +92787.0 C M96 426 776 672789 +95169.7 C M97 56 676 487057 +96798.6 C M98 738 729 64309 +96893.0 C M99 480 288 841006 +97520.5 C M100 366 789 884575 +97866.2 C M101 861 429 2566 +98547.9 C M102 524 723 526950 +98580.7 C M103 371 102 932891 +100285.9 C M104 142 441 356612 +102433.6 C M105 39 726 209486 +102713.3 C M106 512 741 70706 +103036.7 C M107 873 867 879182 +104044.4 C M108 983 752 802037 +104292.2 C M109 137 273 88970 +106715.0 C M110 164 948 24911 +107849.0 C M111 405 78 290245 +108632.4 C M112 991 706 483454 +110364.6 C M113 773 324 433597 +113583.5 C M114 567 138 296520 +113602.3 C M115 427 605 984474 +116396.0 C M116 732 509 319604 +116490.0 C M117 519 474 705013 +116670.6 C M118 102 695 638065 +117364.7 C M119 987 736 215547 +118776.2 C M120 191 833 58164 +118967.5 C M121 708 31 209544 +120015.5 C M122 896 412 277863 +121207.4 C M123 183 89 383526 +121230.8 C M124 367 46 176695 +121552.7 C M125 373 307 882676 +122424.3 C M126 165 348 716227 +122902.3 C M127 593 909 530092 +123711.2 C M128 723 58 325925 +124146.2 C M129 321 759 495280 +125990.3 C M130 219 656 445904 +126182.2 C M131 219 449 772913 +126987.2 C M132 323 503 843012 +128650.1 C M133 507 916 648530 +130173.7 C M134 7 724 102030 +130477.4 C M135 543 489 543415 +131509.5 C M136 964 412 368098 +132607.7 C M137 482 237 303584 +134135.1 C M138 207 874 761080 +134591.9 C M139 433 710 508852 +138653.4 C M140 892 535 321521 +139181.5 C M141 17 725 224879 +140617.7 C M142 425 255 870961 +141852.4 C M143 991 117 974255 +141986.1 C M144 372 566 622344 +142023.2 C M145 345 79 574154 +142961.0 C M146 497 890 622831 +143988.9 C M147 420 177 401164 +144044.5 C M148 586 580 69182 +144249.2 C M149 711 90 525502 +146571.1 C M150 717 919 220694 +146614.7 C M151 247 728 936875 +148577.1 C M152 318 961 504681 +149266.9 C M153 584 982 201437 +149946.5 C M154 46 178 82517 +150358.9 C M155 463 85 917670 +150586.4 C M156 479 654 810825 +150591.0 C M157 872 298 936815 +152874.3 C M158 236 320 125552 +155691.1 C M159 137 958 424673 +155918.2 C M160 336 551 750601 +158957.1 C M161 253 123 515131 +159040.6 C M162 281 469 449725 +159142.6 C M163 74 21 400333 +159812.3 C M164 319 587 327771 +159971.5 C M165 892 823 108388 +160033.7 C M166 411 995 800021 +162572.7 C M167 168 512 88489 +164048.7 C M168 870 887 874230 +165438.2 C M169 595 802 154323 +169025.9 C M170 375 360 970790 +171977.6 C M171 895 67 135487 +172480.4 C M172 496 415 403416 +174486.7 C M173 972 224 112313 +174986.0 C M174 246 357 235313 +176259.1 C M175 86 430 655878 +176302.3 C M176 931 28 920455 +176333.5 C M177 245 464 24132 +177985.3 C M178 45 882 541533 +178295.2 C M179 530 203 223092 +179457.9 C M180 313 882 464160 +180692.6 C M181 344 361 503743 +180785.0 C M182 100 198 280336 +180944.0 C M183 818 640 520735 +181263.5 C M184 741 71 796284 +181450.1 C M185 874 693 335279 +181629.2 C M186 726 230 563854 +182696.3 C M187 991 304 648611 +182905.9 C M188 318 872 371404 +183608.9 C M189 47 510 991901 +184716.3 C M190 903 216 214768 +184940.0 C M191 150 365 84974 +185028.4 C M192 724 907 917476 +186359.7 C M193 790 860 855620 +188552.1 C M194 26 901 870288 +189655.1 C M195 456 508 905635 +190545.1 C M196 837 738 799200 +191662.3 C M197 497 281 988193 +192860.4 C M198 801 472 118749 +194132.0 C M199 497 135 550796 +194865.6 C M200 278 339 246077 +198909.4 C M201 263 603 737773 +200407.8 C M202 156 461 548405 +200496.4 C M203 906 940 694447 +200514.4 C M204 349 23 747487 +200608.4 C M205 605 264 983853 +204560.0 C M206 819 707 36059 +205476.9 C M207 383 527 914893 +205955.9 C M208 535 930 872599 +206378.3 C M209 995 114 337877 +208698.4 C M210 424 790 391340 +210072.4 C M211 480 92 753081 +212783.2 C M212 378 468 967770 +214200.7 C M213 637 967 6956 +214753.7 C M214 735 73 777591 +215372.6 C M215 267 841 759716 +215850.5 C M216 283 731 426087 +216348.9 C M217 554 735 445598 +217107.7 C M218 691 52 184002 +218343.9 C M219 812 778 724159 +218562.9 C M220 985 946 710923 +222399.9 C M221 320 237 679220 +224729.6 C M222 779 942 671293 +226278.0 C M223 7 534 766891 +226293.7 C M224 150 485 176233 +227497.8 C M225 722 18 851636 +227712.6 C M226 411 720 551798 +228017.7 C M227 887 746 336693 +228774.7 C M228 369 553 470509 +229474.0 C M229 321 387 10419 +229827.6 C M230 338 977 612585 +230570.2 C M231 436 178 423851 +231013.0 C M232 999 289 461025 +231780.0 C M233 304 555 575885 +231827.8 C M234 634 32 763850 +232040.0 C M235 149 459 389953 +232327.2 C M236 790 243 117820 +232777.6 C M237 369 678 561225 +235383.0 C M238 506 243 680469 +235604.1 C M239 299 230 882554 +235901.0 C M240 761 687 274542 +236179.6 C M241 902 407 328111 +236314.5 C M242 375 172 555613 +237599.5 C M243 47 858 602845 +238014.5 C M244 403 224 894337 +240628.1 C M245 811 922 103632 +241018.1 C M246 720 376 560545 +241762.7 C M247 140 697 493819 +241903.1 C M248 93 494 119538 +242403.8 C M249 215 212 162004 +242564.2 C M250 408 425 646015 +245190.7 C M251 594 219 667102 +245664.3 C M252 907 136 545166 +245753.3 C M253 825 506 328621 +246286.2 C M254 710 645 688677 +248241.4 C M255 963 763 54516 +249022.2 C M256 994 208 57955 +250109.9 C M257 381 862 892189 +250404.2 C M258 146 553 261473 +251274.4 C M259 27 46 421072 +251566.9 C M260 575 809 689059 +251953.1 C M261 828 804 847808 +252551.8 C M262 753 14 610829 +256297.0 C M263 216 188 180069 +257088.7 C M264 155 922 876960 +257373.1 C M265 651 359 412818 +258050.7 C M266 85 71 296901 +258498.5 C M267 787 784 807393 +258869.9 C M268 4 976 897853 +259361.1 C M269 950 871 90024 +259433.3 C M270 967 161 841685 +259794.3 C M271 20 656 841997 +260310.3 C M272 515 896 672448 +260612.9 C M273 657 895 328242 +261533.7 C M274 486 367 989845 +263572.0 C M275 773 191 766593 +263818.1 C M276 726 638 985972 +263950.1 C M277 512 574 318336 +267186.0 C M278 530 318 283991 +267323.7 C M279 158 300 632805 +267648.9 C M280 722 715 257285 +268496.2 C M281 407 804 470243 +269129.5 C M282 132 359 520563 +270801.4 C M283 482 2 979069 +271712.8 C M284 188 170 278089 +272510.1 C M285 993 334 537377 +277265.4 C M286 565 197 45040 +277440.9 C M287 612 104 900142 +279421.2 C M288 95 368 53535 +280301.6 C M289 849 875 872855 +280838.4 C M290 243 63 470846 +282047.3 C M291 201 490 326689 +282509.6 C M292 80 73 921328 +286685.0 C M293 557 126 294197 +286846.9 C M294 473 567 487062 +288398.3 C M295 528 293 998804 +289039.6 C M296 646 663 483484 +289463.8 C M297 620 733 658605 +291045.0 C M298 724 366 968958 +291774.0 C M299 910 179 144581 +294538.6 C M300 992 602 618238 +297193.2 C M301 599 908 5465 +298082.1 C M302 386 987 504864 +298310.1 C M303 397 559 356285 +300318.7 C M304 864 150 279666 +300836.5 C M305 355 358 1408 +301203.0 C M306 276 826 299794 +301821.8 C M307 526 939 244094 +303526.2 C M308 41 950 7876 +305004.7 C M309 873 211 407667 +305650.0 C M310 853 524 920265 +306009.5 C M311 650 679 865041 +307348.7 C M312 176 682 608091 +308544.6 C M313 602 141 500157 +308644.8 C M314 915 196 186030 +308858.3 C M315 25 372 794104 +310647.3 C M316 91 752 930975 +310842.0 C M317 850 145 695991 +311150.5 C M318 219 355 900744 +311796.1 C M319 563 85 491332 +315133.9 C M320 970 258 786279 +315407.2 C M321 503 147 949494 +315423.6 C M322 378 154 950588 +316492.5 C M323 839 130 675101 +317341.4 C M324 390 533 470013 +317801.3 C M325 880 555 846589 +318798.0 C M326 30 534 694209 +319103.4 C M327 295 654 209865 +319737.5 C M328 609 983 11269 +319869.4 C M329 414 627 832348 +320839.3 C M330 424 682 73072 +322284.2 C M331 111 604 156695 +322441.4 C M332 577 974 146691 +322617.2 C M333 597 913 882575 +323055.1 C M334 410 810 719922 +323900.1 C M335 849 456 563877 +327291.0 C M336 897 995 510183 +327744.4 C M337 238 535 118072 +328634.1 C M338 903 727 173136 +328765.5 C M339 881 656 414586 +331111.5 C M340 521 474 556436 +331258.1 C M341 972 49 889171 +332232.8 C M342 51 540 822746 +333052.0 C M343 12 442 973945 +333625.3 C M344 334 921 564856 +334111.0 C M345 761 682 752256 +336740.8 C M346 255 618 963820 +336849.4 C M347 45 696 447452 +338300.0 C M348 944 490 740214 +338519.0 C M349 162 333 510633 +339448.0 C M350 136 112 215512 +340676.4 C M351 920 751 812040 +342915.0 C M352 398 840 959716 +345722.2 C M353 683 551 136183 +345874.7 C M354 493 869 258079 +347608.6 C M355 154 424 322913 +349892.0 C M356 580 603 433305 +350221.8 C M357 903 842 710254 +350453.0 C M358 639 627 576758 +350560.0 C M359 962 30 450330 +350894.8 C M360 826 33 847474 +351481.3 C M361 993 492 179412 +353170.0 C M362 517 938 32595 +353192.5 C M363 801 600 949508 +354758.3 C M364 172 376 608436 +355185.4 C M365 938 323 921384 +356869.7 C M366 627 943 74283 +356916.3 C M367 211 667 619779 +358365.8 C M368 898 104 312742 +358955.7 C M369 616 332 547160 +359453.6 C M370 60 228 425477 +359578.1 C M371 970 581 495942 +360814.9 C M372 769 5 915171 +362488.5 C M373 504 848 108642 +364190.5 C M374 515 810 512746 +364248.2 C M375 433 488 966826 +364988.6 C M376 467 99 665083 +367034.8 C M377 725 941 806936 +367110.5 C M378 214 745 39091 +367744.4 C M379 521 707 171760 +367851.7 C M380 578 546 944465 +367923.1 C M381 889 687 5760 +368020.7 C M382 872 508 398470 +370098.1 C M383 763 16 386968 +371644.4 C M384 6 770 243538 +372834.4 C M385 314 587 262702 +373319.4 C M386 372 793 319319 +374736.8 C M387 589 185 411254 +375116.6 C M388 355 945 557400 +376880.5 C M389 784 938 494698 +377625.8 C M390 793 192 736532 +377982.6 C M391 448 860 385369 +378574.8 C M392 668 170 333563 +378739.7 C M393 396 454 501295 +379436.0 C M394 177 680 64854 +379669.2 C M395 674 53 899055 +380550.8 C M396 455 60 59716 +380924.9 C M397 838 368 766254 +381518.5 C M398 480 754 364754 +384520.1 C M399 413 333 252807 +385293.5 C M400 887 867 638532 +385643.6 C M401 905 348 227416 +386449.1 C M402 339 520 189820 +386651.2 C M403 787 677 56349 +388538.1 C M404 311 856 912921 +388952.5 C M405 218 627 927107 +390007.0 C M406 844 629 80951 +390209.9 C M407 686 983 63733 +391799.6 C M408 252 82 572835 +393634.7 C M409 742 4 523528 +396314.7 C M410 531 878 544725 +398095.8 C M411 913 67 458322 +398529.0 C M412 564 651 285093 +398621.5 C M413 146 737 797141 +401593.4 C M414 497 124 45369 +402057.0 C M415 370 873 742789 +402128.5 C M416 606 118 642404 +406551.4 C M417 918 525 725287 +406578.6 C M418 8 760 347202 +408493.7 C M419 70 432 331665 +408885.1 C M420 135 635 43162 +410873.7 C M421 190 438 390820 +412391.4 C M422 508 327 697351 +417070.0 C M423 12 782 908527 +417821.7 C M424 813 742 880156 +418379.2 C M425 400 834 605847 +419777.9 C M426 583 386 868612 +420201.1 C M427 820 528 671684 +420603.1 C M428 310 61 895098 +420787.4 C M429 637 898 717671 +420861.7 C M430 232 908 156818 +421987.0 C M431 801 855 255202 +424071.7 C M432 909 911 826592 +424128.3 C M433 890 213 929375 +425617.9 C M434 703 952 223191 +426007.9 C M435 884 411 513776 +427471.0 C M436 182 976 924309 +429408.3 C M437 572 893 369198 +431059.4 C M438 681 540 863852 +431901.5 C M439 959 268 248601 +433147.3 C M440 995 489 370364 +434362.3 C M441 795 974 601896 +434686.2 C M442 235 738 953916 +437044.5 C M443 261 530 938490 +438765.1 C M444 662 417 209369 +439940.5 C M445 742 182 798990 +442730.8 C M446 228 797 857048 +443274.0 C M447 76 397 394029 +444683.0 C M448 635 963 112241 +445264.0 C M449 236 284 70618 +445776.8 C M450 378 851 840390 +446094.7 C M451 581 343 202210 +451116.5 C M452 312 633 205937 +451122.5 C M453 984 823 802103 +451401.6 C M454 675 403 189703 +452040.6 C M455 578 636 279094 +452790.0 C M456 614 425 960323 +453117.5 C M457 273 922 38332 +453592.4 C M458 699 506 189017 +454842.8 C M459 743 333 439616 +457952.6 C M460 168 537 648761 +458798.4 C M461 507 223 835928 +458906.1 C M462 898 101 995573 +460070.8 C M463 109 304 928689 +460316.5 C M464 262 605 434242 +460853.6 C M465 754 390 32499 +460888.1 C M466 966 991 208109 +461171.3 C M467 750 378 359162 +465945.8 C M468 613 827 195898 +465969.9 C M469 14 3 679481 +466237.9 C M470 204 696 393460 +467951.8 C M471 727 412 844991 +469042.9 C M472 54 958 712298 +470881.1 C M473 760 993 265255 +471844.9 C M474 940 662 99175 +471876.0 C M475 976 763 990567 +472647.9 C M476 345 388 919228 +474368.8 C M477 817 85 528977 +477480.9 C M478 326 193 972894 +477746.6 C M479 993 729 671969 +480033.8 C M480 531 529 307472 +481910.6 C M481 397 23 533590 +482543.4 C M482 749 999 166847 +482966.3 C M483 164 550 949348 +483405.0 C M484 857 497 65682 +484975.8 C M485 674 364 571947 +486257.0 C M486 35 650 717494 +486977.8 C M487 850 275 745953 +487455.5 C M488 630 924 965638 +488976.5 C M489 143 799 265514 +490061.1 C M490 651 649 58951 +492401.2 C M491 841 574 603538 +494771.3 C M492 909 462 640019 +495389.3 C M493 254 194 434881 +495397.7 C M494 59 399 272201 +496479.7 C M495 734 574 574684 +499014.5 C M496 979 735 194145 +499343.8 C M497 528 10 927961 +500569.4 C M498 423 733 265735 +500852.2 C M499 54 742 418825 +501536.6 C M500 914 789 411453 +501830.3 C M501 212 721 162286 +503372.5 C M502 268 736 692839 +503935.2 C M503 94 717 940466 +504165.0 C M504 110 451 839186 +504254.6 C M505 711 848 939561 +508417.0 C M506 272 178 13943 +509537.5 C M507 373 74 130392 +510128.3 C M508 713 587 724708 +511425.1 C M509 449 155 396644 +511431.3 C M510 584 719 919556 +512904.5 C M511 971 143 684806 +513510.9 C M512 2 712 154084 +514577.8 C M513 389 934 910475 +515723.7 C M514 704 187 858138 +515805.7 C M515 650 744 71271 +515823.4 C M516 628 663 707228 +520777.2 C M517 326 736 314071 +523695.1 C M518 46 209 351448 +524655.0 C M519 683 30 353057 +526130.4 C M520 409 390 766572 +526136.6 C M521 142 635 46220 +526365.3 C M522 742 791 457521 +528004.9 C M523 615 642 531976 +529912.6 C M524 565 378 377302 +530758.2 C M525 589 234 985191 +531149.2 C M526 960 157 314708 +531270.7 C M527 783 868 973499 +531635.7 C M528 531 633 392491 +533541.0 C M529 843 654 549789 +536633.9 C M530 503 364 808637 +537584.2 C M531 868 49 296884 +538886.7 C M532 830 158 127824 +541220.0 C M533 875 658 581720 +544973.0 C M534 570 923 425767 +545566.4 C M535 448 720 725417 +545835.6 C M536 845 282 490209 +546547.5 C M537 518 89 595305 +546575.5 C M538 770 325 470582 +548074.8 C M539 677 395 876635 +548482.4 C M540 541 883 971635 +549401.2 C M541 534 67 346180 +549714.1 C M542 672 735 326504 +550129.8 C M543 453 793 224541 +551131.0 C M544 502 790 667058 +551955.6 C M545 296 252 673487 +552501.6 C M546 797 113 648455 +552747.1 C M547 354 589 124177 +554185.8 C M548 895 373 317050 +554435.8 C M549 178 594 288019 +554828.1 C M550 770 623 925816 +555008.2 C M551 906 730 598140 +555522.5 C M552 851 333 497238 +557094.0 C M553 117 127 529141 +559553.4 C M554 939 131 747081 +560323.4 C M555 131 538 277485 +560696.6 C M556 432 766 15055 +563637.2 C M557 702 165 755718 +564566.3 C M558 229 411 972187 +565577.1 C M559 388 985 484796 +565599.6 C M560 466 825 863849 +565702.6 C M561 35 769 449736 +565822.3 C M562 922 424 405859 +566668.8 C M563 664 736 869445 +567304.0 C M564 711 122 140220 +568327.6 C M565 66 542 750254 +569195.8 C M566 651 377 762378 +571022.7 C M567 815 61 732684 +571783.8 C M568 592 930 986880 +572156.7 C M569 855 796 380831 +572476.0 C M570 553 959 320323 +573689.1 C M571 877 379 565223 +573754.9 C M572 540 236 431835 +575437.5 C M573 399 769 70645 +576984.5 C M574 472 280 149716 +577924.0 C M575 151 42 182660 +578379.6 C M576 965 936 23803 +580983.1 C M577 23 426 709634 +581973.5 C M578 854 918 690079 +582288.0 C M579 617 209 37516 +584271.0 C M580 98 169 839369 +584695.4 C M581 838 417 442068 +588679.4 C M582 531 469 548008 +588680.0 C M583 997 950 449141 +590377.2 C M584 746 702 188035 +590595.6 C M585 679 602 575301 +591951.0 C M586 545 495 679856 +592209.7 C M587 553 187 467632 +592357.6 C M588 176 200 268919 +592872.6 C M589 251 797 562046 +594202.6 C M590 656 308 430173 +594661.7 C M591 636 177 559087 +595146.6 C M592 634 878 841047 +595563.9 C M593 262 494 584162 +595885.6 C M594 699 300 749189 +596150.4 C M595 138 177 570062 +596904.6 C M596 310 315 977052 +599595.1 C M597 207 917 246173 +599664.7 C M598 262 438 301641 +601276.4 C M599 539 126 593573 +601290.3 C M600 581 549 465778 +601364.6 C M601 281 752 136840 +602569.5 C M602 570 598 549718 +603108.1 C M603 215 173 156242 +604200.9 C M604 767 332 447355 +604253.4 C M605 865 985 489453 +605450.6 C M606 780 916 711213 +608198.1 C M607 643 96 22121 +608977.0 C M608 316 380 715136 +609585.4 C M609 770 948 984342 +610287.6 C M610 808 463 702798 +611360.6 C M611 251 706 850964 +611385.0 C M612 906 928 188937 +611679.9 C M613 638 859 415150 +612437.0 C M614 301 977 397761 +615461.5 C M615 330 629 838563 +616180.5 C M616 885 565 682610 +617093.7 C M617 348 400 51930 +618228.9 C M618 635 474 125864 +618463.1 C M619 316 308 956196 +618485.1 C M620 659 422 468069 +618509.3 C M621 784 17 459902 +619874.8 C M622 789 95 464980 +621764.4 C M623 119 605 795666 +622281.2 C M624 911 548 32930 +622859.8 C M625 74 169 244128 +622915.6 C M626 361 221 145780 +623006.3 C M627 513 142 932600 +623133.8 C M628 302 725 829119 +625205.0 C M629 584 742 208214 +625567.0 C M630 570 524 209376 +627041.7 C M631 222 75 783142 +627087.2 C M632 566 729 244412 +627845.9 C M633 162 937 574544 +628046.8 C M634 919 457 729759 +628434.5 C M635 994 690 922567 +628696.1 C M636 993 375 528684 +628701.7 C M637 986 62 984408 +629131.0 C M638 527 355 870502 +633588.2 C M639 303 311 874483 +635788.9 C M640 857 230 989336 +635945.6 C M641 550 923 634720 +637364.6 C M642 950 409 62623 +638311.0 C M643 239 692 745891 +640353.6 C M644 37 172 640497 +642051.8 C M645 922 814 856200 +643866.6 C M646 685 270 742188 +645745.1 C M647 61 429 389125 +647065.6 C M648 395 715 527535 +648247.0 C M649 25 783 5441 +649082.8 C M650 22 632 173730 +649758.4 C M651 194 602 781429 +649839.2 C M652 708 213 595026 +650106.3 C M653 189 953 708245 +652280.8 C M654 724 721 389932 +653927.3 C M655 743 700 866134 +654351.6 C M656 516 293 178780 +656224.7 C M657 527 509 226524 +657030.5 C M658 659 439 454973 +659235.6 C M659 945 898 221170 +660611.0 C M660 45 598 995034 +661905.7 C M661 356 403 299125 +662296.4 C M662 985 312 347263 +662980.2 C M663 543 182 426904 +663995.9 C M664 96 469 279271 +666277.4 C M665 967 715 135361 +666813.9 C M666 334 660 243523 +668362.9 C M667 272 311 904077 +668381.6 C M668 595 677 865787 +669665.9 C M669 956 864 584864 +670221.4 C M670 586 365 849732 +670612.4 C M671 78 156 686798 +672251.3 C M672 612 534 48637 +674282.8 C M673 493 649 182676 +674360.7 C M674 493 715 62817 +675626.8 C M675 668 241 70790 +676155.9 C M676 280 924 590263 +676309.0 C M677 372 322 864669 +676838.2 C M678 58 645 225259 +679409.1 C M679 247 319 964149 +679489.6 C M680 13 850 211200 +684173.9 C M681 593 458 968508 +685074.4 C M682 223 804 497261 +687054.1 C M683 701 196 837456 +687497.0 C M684 712 989 206445 +688155.2 C M685 805 403 560798 +689551.3 C M686 10 729 830353 +691183.8 C M687 761 912 972723 +691678.1 C M688 822 571 364755 +691733.8 C M689 145 357 115220 +693064.4 C M690 719 300 714454 +693264.4 C M691 803 945 124796 +693874.6 C M692 51 921 141148 +694934.6 C M693 990 37 561472 +695316.1 C M694 569 609 347249 +696435.6 C M695 560 472 369254 +697552.9 C M696 717 49 935193 +698253.5 C M697 617 15 558090 +698285.0 C M698 918 270 771381 +698331.8 C M699 344 159 11488 +698690.2 C M700 378 563 470718 diff --git a/ee/70_events_100_nodes_700ks.txt b/ee/70_events_100_nodes_700ks.txt new file mode 100644 index 000000000..7127e484e --- /dev/null +++ b/ee/70_events_100_nodes_700ks.txt @@ -0,0 +1,70 @@ +10403.6 C M1 68 75 705189 +22828.0 C M2 91 60 334117 +45827.0 C M3 37 40 216100 +66567.1 C M4 18 40 285882 +70516.0 C M5 70 95 434904 +72037.6 C M6 10 72 794199 +74826.1 C M7 65 60 5520 +76436.1 C M8 55 44 807579 +77929.1 C M9 39 22 693824 +79001.1 C M10 60 54 269002 +82176.1 C M11 10 31 722650 +88897.1 C M12 29 37 516052 +106512.9 C M13 66 96 481182 +111643.1 C M14 15 37 203618 +162748.3 C M15 65 43 238528 +166179.5 C M16 10 32 268916 +167586.0 C M17 87 15 328930 +176849.8 C M18 35 19 457799 +182089.4 C M19 76 9 956895 +208708.8 C M20 66 73 476028 +216143.6 C M21 37 72 672786 +230857.0 C M22 81 72 725607 +245544.3 C M23 27 36 464891 +247153.8 C M24 16 69 670170 +257030.3 C M25 33 7 295683 +258708.1 C M26 86 60 936977 +262352.4 C M27 2 69 178141 +268475.6 C M28 10 5 356531 +270691.2 C M29 56 68 154934 +271328.9 C M30 76 57 46363 +276814.2 C M31 82 31 645088 +283504.6 C M32 62 9 807252 +293447.6 C M33 90 37 897702 +298798.4 C M34 86 45 917059 +301102.4 C M35 66 80 189446 +319110.4 C M36 22 74 228270 +331688.8 C M37 74 97 348840 +352754.0 C M38 59 21 247652 +360890.3 C M39 46 98 436984 +375571.9 C M40 12 69 198701 +390358.8 C M41 16 2 898281 +451682.3 C M42 33 5 445482 +464822.4 C M43 42 33 947919 +479024.0 C M44 83 12 45508 +487031.6 C M45 53 12 30278 +490618.8 C M46 18 6 676473 +492988.2 C M47 90 86 774031 +503872.9 C M48 45 73 799338 +516052.0 C M49 98 59 952608 +516423.1 C M50 5 80 364339 +536950.5 C M51 64 60 884147 +547342.6 C M52 72 32 602849 +558327.7 C M53 59 51 197374 +574178.9 C M54 37 44 886555 +584131.4 C M55 28 40 326896 +586986.7 C M56 5 30 832354 +590952.2 C M57 40 26 424089 +610442.8 C M58 3 77 451858 +615411.2 C M59 31 53 791071 +620397.7 C M60 14 96 850065 +635527.1 C M61 79 51 399811 +639019.9 C M62 97 66 495214 +663977.8 C M63 46 23 300723 +670328.0 C M64 38 6 900630 +679497.4 C M65 70 1 761630 +680160.1 C M66 36 2 391930 +682689.2 C M67 99 4 196145 +684784.6 C M68 91 53 169498 +686225.9 C M69 8 18 56664 +695255.0 C M70 22 29 874383 diff --git a/example_settings/cluster_settings.txt b/example_settings/cluster_settings.txt new file mode 100644 index 000000000..19d63d6e0 --- /dev/null +++ b/example_settings/cluster_settings.txt @@ -0,0 +1,116 @@ +# +# Default settings for the simulation +# + +## Scenario settings +Scenario.name = default_scenario +Scenario.simulateConnections = true +Scenario.updateInterval = 0.1 +# 43k ~= 12h +Scenario.endTime = 43k + +firstinterface.type = SimpleBroadcastInterface +# transmit speed of 2 Mbps = 250kBps +firstinterface.transmitSpeed = 250k +firstinterface.transmitRange = 10 + + +Scenario.nrofHostGroups = 4 + +# common settings for all groups +Group.movementModel = ClusterMovement +Group.router = EpidemicRouter +Group.bufferSize = 5M +Group.waitTime = 0, 120 +#All nodes have the firstinterface inteface +Group.nrofInterfaces = 1 +Group.interface1 = firstinterface +# walking speeds +Group.speed = 0.5, 1.5 +#Group.msgTtl = 60 + +Group.nrofHosts = 40 +Group.nrofApplications = 0 + +# group1 (pedestrians) specific settings +Group1.groupID = p + +Group2.groupID = q +Group2.clusterCenter = 600, 100 + +Group3.groupID = r +Group3.clusterCenter = 350, 533 + +# The Tram groups +Group4.groupID = s +Group4.bufferSize = 50M +Group4.movementModel = MapRouteMovement +Group4.routeFile = data/cluster/ferryroute.wkt +Group4.routeType = 1 +Group4.waitTime = 10, 30 +Group4.speed = 3, 5 +Group4.nrofHosts = 5 +Group4.nrofInterfaces = 1 +Group4.interface1 = firstinterface + +## Map based movement -movement model specific settings +MapBasedMovement.nrofMapFiles = 2 +MapBasedMovement.mapFile1 = data/cluster/ferryroute.wkt +MapBasedMovement.mapFile2 = data/cluster/origin.wkt + + +## Message creation parameters +# How many event generators +Events.nrof = 1 +# Class of the first event generator +Events1.class = MessageEventGenerator +# (following settings are specific for the MessageEventGenerator class) +# Creation interval in seconds (one new message every 25 to 35 seconds) +Events1.interval = 25,35 +# Message sizes (50kB - 150kB) +Events1.size = 50k,150k +# range of message source/destination addresses +Events1.hosts = 0,120 +# Message ID prefix +Events1.prefix = M + + +## Movement model settings +# seed for movement models' pseudo random number generator (default = 0) +MovementModel.rngSeed = 1 +# World's size for Movement Models without implicit size (width, height; meters) +MovementModel.worldSize = 4500, 3400 +# How long time to move hosts in the world before real simulation +MovementModel.warmup = 1000 + +# how many reports to load +Report.nrofReports = 1 +# length of the warm up period (simulated seconds) +Report.warmup = 0 +# default directory of reports (can be overridden per Report with output setting) +Report.reportDir = reports/ +# Report classes to load +Report.report1 = MessageStatsReport + +## Optimization settings -- these affect the speed of the simulation +## see World class for details. +Optimization.connectionAlg = 2 +Optimization.cellSizeMult = 5 +Optimization.randomizeUpdateOrder = true + + +## GUI settings + +# GUI underlay image settings +GUI.UnderlayImage.fileName = data/helsinki_underlay.png +# Image offset in pixels (x, y) +GUI.UnderlayImage.offset = 64, 20 +# Scaling factor for the image +GUI.UnderlayImage.scale = 4.75 +# Image rotation (radians) +GUI.UnderlayImage.rotate = -0.015 + +# how many events to show in the log panel (default = 30) +GUI.EventLogPanel.nrofEvents = 30 +# Regular Expression log filter (see Pattern-class from the Java API for RE-matching details) +#GUI.EventLogPanel.REfilter = .*p[1-9]<->p[1-9]$ \ No newline at end of file diff --git a/example_settings/epidemic_settings.txt b/example_settings/epidemic_settings.txt new file mode 100644 index 000000000..d96abb044 --- /dev/null +++ b/example_settings/epidemic_settings.txt @@ -0,0 +1,2 @@ +Scenario.name = Epidemic +Group.router = EpidemicRouter \ No newline at end of file diff --git a/example_settings/ping_app_settings.txt b/example_settings/ping_app_settings.txt new file mode 100644 index 000000000..30019c37b --- /dev/null +++ b/example_settings/ping_app_settings.txt @@ -0,0 +1,19 @@ +# This configuration file adds Ping application for all the nodes and +# a report module that counts the number of pings & pongs sent & received + +# Define new application +pingApp.type = PingApplication +pingApp.interval = 500 +pingApp.destinationRange = 0,125 +pingApp.pingSize = 5 +pingApp.pongSize = 5 +pingApp.passive = false + +# Set Ping app for all nodes +Group.nrofApplications = 1 +Group.application1 = pingApp + +# Add report for Ping app +Report.nrofReports = 2 +Report.report2 = PingAppReporter + diff --git a/example_settings/prophet_settings.txt b/example_settings/prophet_settings.txt new file mode 100644 index 000000000..8ecd25aa2 --- /dev/null +++ b/example_settings/prophet_settings.txt @@ -0,0 +1,18 @@ +## Test scenario using Prophet router and Points of Interest (POIs) + +Scenario.name = PRoPHET-%%ProphetRouter.secondsInTimeUnit%%siu +Group.router = ProphetRouter + +ProphetRouter.secondsInTimeUnit = 30 + +# Define POI data files +PointsOfInterest.poiFile1 = data/ParkPOIs.wkt +PointsOfInterest.poiFile2 = data/CentralPOIs.wkt +PointsOfInterest.poiFile3 = data/WestPOIs.wkt +PointsOfInterest.poiFile4 = data/shops.wkt + +# Define probabilities for different groups selecting POIs from different POI files +Group1.pois = 1,0.3, 2,0.1, 3,0.1, 4, 0.1 +Group2.pois = 2,0.3, 3,0.1 +Group3.pois = 3,0.3, 2,0.1, 1,0.1, 4, 0.1 +Group4.pois = 4,0.3, 2,0.1, 3,0.1, 1, 0.1 diff --git a/example_settings/snw_comparison_settings.txt b/example_settings/snw_comparison_settings.txt new file mode 100644 index 000000000..d29ce2fc2 --- /dev/null +++ b/example_settings/snw_comparison_settings.txt @@ -0,0 +1,13 @@ +Scenario.name = SNWComp-%%SprayAndWaitRouter.nrofCopies%%-B%%SprayAndWaitRouter.binaryMode%% + +Group.router = SprayAndWaitRouter + +SprayAndWaitRouter.nrofCopies = [1;2;3;4;5;6;7;8;9;10;11] +SprayAndWaitRouter.binaryMode = [true;false] + + +MovementModel.rngSeed = 0 +Report.nrofReports = 1 +Report.report1 = MessageStatsReport + +Report.reportDir = snwcomp_reports/ diff --git a/example_settings/snw_settings.txt b/example_settings/snw_settings.txt new file mode 100644 index 000000000..d231f36fe --- /dev/null +++ b/example_settings/snw_settings.txt @@ -0,0 +1,4 @@ +Scenario.name = SprayAndWait +Group.router = SprayAndWaitRouter +SprayAndWaitRouter.nrofCopies = 10 +SprayAndWaitRouter.binaryMode = true diff --git a/example_settings/wlan-interface.txt b/example_settings/wlan-interface.txt new file mode 100644 index 000000000..bc4fcd4b0 --- /dev/null +++ b/example_settings/wlan-interface.txt @@ -0,0 +1,14 @@ + +wlanInterface.type = DistanceCapacityInterface + +# values from http://www.xirrus.com/cdn/pdf/wifi-demystified/documents_posters_range_plotter +# 0-50ft:54Mbps, 75-100ft:48 Mbps, 125ft:36Mbps, 150ft:24 Mbps, 175ft:18Mbps, +# 200ft:12Mbps, 225ft:9Mbps, 250ft:6Mbps, 275ft:2Mbps, 300ft:1Mbps + +wlanInterface.transmitSpeeds = 6750k, 6750k, 6750k, 6000k, 6000k, 4500k, 3000k, 2250k, 1500k, 1125k, 750k, 250k, 125k +wlanInterface.transmitRange = 91 + +# dummy speed +wlanInterface.transmitSpeed = 0 + +Group.interface1 = wlanInterface \ No newline at end of file diff --git a/gui/DTNSimGUI.java b/gui/DTNSimGUI.java new file mode 100644 index 000000000..d1d78a3cb --- /dev/null +++ b/gui/DTNSimGUI.java @@ -0,0 +1,336 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import gui.playfield.PlayField; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +import movement.Path; +import ui.DTNSimUI; +import core.Coord; +import core.DTNHost; +import core.SimClock; + +/** + * Graphical User Interface for simulator + */ +public class DTNSimGUI extends DTNSimUI { + private MainWindow main; + private PlayField field; + private GUIControls guiControls; + private EventLogPanel eventLogPanel; + private InfoPanel infoPanel; + + private void startGUI() { + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + try { + initGUI(); + } catch (AssertionError e) { + processAssertionError(e); + } + } + }); + } catch (InterruptedException e) { + e.printStackTrace(); + System.exit(-1); + } catch (InvocationTargetException e) { + e.printStackTrace(); + System.exit(-1); + } + } + + /** + * Initializes the GUI + */ + private void initGUI() { + this.field = new PlayField(world, this); + + this.field.addMouseListener(new PlayfieldMouseHandler()); + this.field.addMouseWheelListener(new PlayfieldMouseHandler()); + + this.guiControls = new GUIControls(this,this.field); + this.eventLogPanel = new EventLogPanel(this); + this.infoPanel = new InfoPanel(this); + this.main = new MainWindow(this.scen.getName(), world, field, + guiControls, infoPanel, eventLogPanel, this); + + scen.addMessageListener(eventLogPanel); + scen.addConnectionListener(eventLogPanel); + + if (scen.getMap() != null ) { + field.setMap(scen.getMap()); + } + + // if user closes the main window, call closeSim() + this.main.addWindowListener(new WindowAdapter() { + private boolean closeAgain = false; + public void windowClosing(WindowEvent e) { + closeSim(); + if (closeAgain) { + // if method is called again, force closing + System.err.println("Forced close. "+ + "Some reports may have not been finalized."); + System.exit(-1); + } + closeAgain = true; + } + }); + + this.main.setVisible(true); + } + + @Override + protected void runSim() { + double simTime = SimClock.getTime(); + double endTime = scen.getEndTime(); + + startGUI(); + + // Startup DTN2Manager + // XXX: Would be nice if this wasn't needed.. + // DTN2Manager.setup(world); + + while (simTime < endTime && !simCancelled){ + if (guiControls.isPaused()) { + wait(10); // release CPU resources when paused + } + else { + try { + world.update(); + } catch (AssertionError e) { + // handles both assertion errors and SimErrors + processAssertionError(e); + } + simTime = SimClock.getTime(); + } + this.update(false); + } + + simDone = true; + done(); + this.update(true); // force final GUI update + + if (!simCancelled) { // NOT cancelled -> leave the GUI running + JOptionPane.showMessageDialog(getParentFrame(), + "Simulation done"); + } + else { // was cancelled -> exit immediately + System.exit(0); + } + } + + /** + * Processes assertion errors by showing a warning dialog to the user + * and pausing the simulation (if it's running) + * @param e The error that was thrown + */ + private void processAssertionError(AssertionError e) { + String title = e.getClass().getSimpleName() + " (simulation paused)"; + String msg = e.getMessage(); + String txt = (msg != null ? msg : "") + " at simtime " + + SimClock.getIntTime() + "\n\ncaught at:\n" + + e.getStackTrace()[0].toString() + + "\nNote that the simulation might be in inconsistent state, "+ + "continue only with caution.\n\n Show rest of the stack trace?"; + // rest of the update cycle that caused the exception is skipped + // so the user is warned about the consequences + + + if (guiControls != null) { + guiControls.setPaused(true); + } + + int selection = JOptionPane.showOptionDialog(getParentFrame(), txt, + title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, + null, null, null); + + if (selection == 0) { + txt = ""; + for (StackTraceElement trace : e.getStackTrace()) { + txt += trace.toString()+"\n"; + } + JOptionPane.showMessageDialog(getParentFrame(), txt, + "stack trace", JOptionPane.INFORMATION_MESSAGE); + } + } + + + + /** + * Closes the program if simulation is done or cancels it. + */ + public void closeSim() { + if (simDone) { + System.exit(0); + } + this.world.cancelSim(); + this.simCancelled = true; + } + + /** + * Updates the GUI + */ + public void update(boolean forcedUpdate) { + double guiUpdateInterval = guiControls.getUpdateInterval(); + + // update only if long enough simTime has passed (and not forced) + if (!forcedUpdate && guiUpdateInterval > (SimClock.getTime() + - this.lastUpdate)) { + return; + } + + try { + // run update in EDT, TODO: optimize threading + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + updateView(); + } + }); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + // wait a while if we don't want to run simulation at full speed + if (guiUpdateInterval < 0) { + wait(100*(int)(-guiUpdateInterval)); + } + + } + + /** + * Updates playfield and sim time field + * + */ + private void updateView() { + double simTime = SimClock.getTime(); + this.lastUpdate = simTime; + guiControls.setSimTime(simTime); //update time to control panel + + this.field.updateField(); + } + + /** + * Sets the pause of the simulation on/off + * @param paused True if pause should be set on + */ + public void setPaused(boolean paused) { + this.guiControls.setPaused(paused); + } + + /** + * Sets a node's graphical presentation in the center of the playfield view + * @param host The node to center + */ + public void setFocus(DTNHost host) { + centerViewAt(host.getLocation()); + infoPanel.showInfo(host); + showPath(host.getPath()); // show path on the playfield + } + + /** + * Shows a path on the playfield + * @param path The path to show + */ + public void showPath(Path path) { + field.addPath(path); + } + + /** + * Returns the world coordinates that are currently in the center + * of the viewport + * @return The coordinates + */ + public Coord getCenterViewCoord() { + JScrollPane sp = main.getPlayFieldScroll(); + double midX, midY; + + midX = sp.getHorizontalScrollBar().getValue() + + sp.getViewport().getWidth()/2; + midY = sp.getVerticalScrollBar().getValue() + + sp.getViewport().getHeight()/2; + + return this.field.getWorldPosition(new Coord(midX, midY)); + } + + /** + * Sets certain location to be in the center of the playfield view + * @param loc The location to center + */ + public void centerViewAt(Coord loc) { + JScrollPane sp = main.getPlayFieldScroll(); + Coord gLoc = this.field.getGraphicsPosition(loc); + int midX, midY; + + updateView(); // update graphics to match the values + + midX = (int)gLoc.getX() - sp.getViewport().getWidth()/2; + midY = (int)gLoc.getY() - sp.getViewport().getHeight()/2; + + sp.getHorizontalScrollBar().setValue(midX); + sp.getVerticalScrollBar().setValue(midY); + } + + /** + * Returns the info panel of the GUI + * @return the info panel of the GUI + */ + public InfoPanel getInfoPanel() { + return this.infoPanel; + } + + /** + * Returns the parent frame (window) of the gui. + * @return The parent frame + */ + public MainWindow getParentFrame() { + return this.main; + } + + /** + * Suspend thread for ms milliseconds + * @param ms The nrof milliseconds to wait + */ + private void wait(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + // nothing to do here + } + } + + /** + * Handler for playfield's mouse clicks. + */ + private class PlayfieldMouseHandler extends MouseAdapter implements + MouseWheelListener { + /** + * If mouse button is clicked, centers view at that location. + */ + public void mouseClicked(MouseEvent e) { + + java.awt.Point p = e.getPoint(); + centerViewAt(field.getWorldPosition(new Coord(p.x, p.y))); + } + + public void mouseWheelMoved(java.awt.event.MouseWheelEvent e) { + guiControls.changeZoom(e.getWheelRotation()); + } + } + +} diff --git a/gui/EventLogControl.java b/gui/EventLogControl.java new file mode 100644 index 000000000..f5ffa4145 --- /dev/null +++ b/gui/EventLogControl.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import javax.swing.JCheckBox; + +/** + * Class capsulates the references to the controls one can add to + * the EventLogControlPanel + * + */ +public class EventLogControl { + private JCheckBox show; + private JCheckBox pause; + + /** + * Constructor. + * @param show The checkbox that controls showing this type of event + * @param pause The checkbox that controls pausing on this type of event + */ + public EventLogControl(JCheckBox show, JCheckBox pause) { + this.show = show; + this.pause = pause; + } + + /** + * Returns true if this event type should be shown + * @return true if this event type should be shown + */ + public boolean showEvent() { + return this.show.isSelected(); + } + + /** + * Returns true if this event type should cause pause + * @return true if this event type should cause pause + */ + + public boolean pauseOnEvent() { + return this.pause.isSelected(); + } + + /** + * Sets ought this event type should be shown (return true for + * {@link #showEvent()} ) + * @param show If true, events are set to be shown + */ + public void setShowEvent(boolean show) { + this.show.setSelected(show); + } + + /** + * Sets ought this event type cause pause (return true for + * {@link #pauseOnEvent()} ) + * @param pause If true, events cause pause + */ + public void setPauseOnEvent(boolean pause) { + this.pause.setSelected(pause); + } + + +} diff --git a/gui/EventLogControlPanel.java b/gui/EventLogControlPanel.java new file mode 100644 index 000000000..43968b78c --- /dev/null +++ b/gui/EventLogControlPanel.java @@ -0,0 +1,159 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +/** + * Control panel for event log + * + */ +public class EventLogControlPanel extends JPanel implements ActionListener { + private static final String TITLE_TEXT = "Event log controls"; + private static final String SHOW_TEXT = "show"; + private static final String PAUSE_TEXT = "pause"; + private static final int PADDING = 5; + private Font smallFont = new Font("sans",Font.PLAIN,11); + private Font headingFont = new Font("sans",Font.BOLD,11); + private Vector logControls; + + private JCheckBox showAllCheck; + private JCheckBox pauseAllCheck; + + private GridBagLayout layout; + private GridBagConstraints c; + + /** + * Constructor. Creates a new control panel. + */ + public EventLogControlPanel() { + layout = new GridBagLayout(); + c = new GridBagConstraints(); + logControls = new Vector(); + + c.ipadx = PADDING; + + setLayout(layout); + this.setBorder(BorderFactory.createTitledBorder( + getBorder(), TITLE_TEXT)); + + c.fill = GridBagConstraints.BOTH; + addLabel(" "); + addLabel(SHOW_TEXT + ""); + c.gridwidth = GridBagConstraints.REMAINDER; //end row + addLabel(PAUSE_TEXT); + + // create "show/pause on all selections + c.gridwidth = 1; + addLabel("all"); + showAllCheck = addCheckBox(true,false); + pauseAllCheck = addCheckBox(false,true); + showAllCheck.addActionListener(this); + pauseAllCheck.addActionListener(this); + + this.setMinimumSize(new Dimension(0,0)); + } + + /** + * Adds a new filter&pause control + * @param name Name of the control + * @param showOn Is "show" initially selected + * @param pauseOn Is "pause" initially selected + * @return Event log control object that can be queried for status + */ + public EventLogControl addControl(String name, boolean showOn, + boolean pauseOn) { + JCheckBox filterCheck; + JCheckBox pauseCheck; + EventLogControl control; + + c.gridwidth = 1; // one component/cell + addLabel(name); + filterCheck = addCheckBox(showOn, false); + pauseCheck = addCheckBox(pauseOn, true); + + control = new EventLogControl(filterCheck, pauseCheck); + this.logControls.add(control); + return control; + } + + /** + * Creates and adds a new checkbox to this panel + * @param selected Is the checkbox initially selected + * @param endOfRow Is the box last in the row in the layout + * @return The created checkbox + */ + private JCheckBox addCheckBox(boolean selected, boolean endOfRow) { + JCheckBox box = new JCheckBox(); + box.setSelected(selected); + + if (endOfRow) { + c.gridwidth = GridBagConstraints.REMAINDER; // use rest of the line + } + else { + c.gridwidth = 1; // default + } + + layout.setConstraints(box, c); + add(box); + + return box; + } + + /** + * Adds a new filter&pause control with initially "show" checked + * but "pause" unchecked + * @param name Name of the control + * @return Event log control object that can be queried for status + * @see #addControl(String name, boolean showOn, boolean pauseOn) + */ + public EventLogControl addControl(String name) { + return addControl(name, true, false); + } + + /** + * Adds a new heading in the control panel. Subsequent addControl + * controls will be under this heading + * @param name The heading text + */ + public void addHeading(String name) { + c.gridwidth = GridBagConstraints.REMAINDER; + addLabel(name).setFont(this.headingFont); + } + + private JLabel addLabel(String txt) { + JLabel label = new JLabel(txt); + label.setFont(this.smallFont); + layout.setConstraints(label, c); + add(label); + return label; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == this.showAllCheck) { + for (EventLogControl elc : logControls) { + elc.setShowEvent(this.showAllCheck.isSelected()); + } + } + else if (e.getSource() == this.pauseAllCheck) { + for (EventLogControl elc : logControls) { + elc.setPauseOnEvent(this.pauseAllCheck.isSelected()); + } + } + + + } +} diff --git a/gui/EventLogPanel.java b/gui/EventLogPanel.java new file mode 100644 index 000000000..2ada1ed67 --- /dev/null +++ b/gui/EventLogPanel.java @@ -0,0 +1,332 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import java.awt.Color; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.Timer; + +import core.ConnectionListener; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import core.Settings; +import core.SimClock; + +/** + * Event log panel where log entries are displayed. + */ +public class EventLogPanel extends JPanel + implements ConnectionListener, MessageListener, ActionListener { + + /** Event log panel settings namespace ({@value}) */ + public static final String EL_PANEL_NS = "GUI.EventLogPanel"; + + /** Number of events -setting id ({@value}). Defines the number of + * events to show in the panel. */ + public static final String NROF_EVENTS_S = "nrofEvents"; + + /** Regular expression filter -setting id ({@value}). Defines the regular + * expression against which the event texts are matched; only matching + * events are not shown */ + public static final String EVENTS_RE_S = "REfilter"; + + private static final String PANEL_TITLE = "Event log"; + /** format of a single log entry */ + private static final String ENTRY_FORMAT = "% 9.1f: %s "; + private static final int FONT_SIZE = 12; + private static final String FONT_TYPE = "monospaced"; + private static final Color LOG_BUTTON_BG = Color.WHITE; + private static final String HOST_DELIM = "<->"; + private static final Color HIGHLIGHT_BG_COLOR = Color.GREEN; + + // constants used for button property + private static final String HOST_PROP = "host"; + private static final String MSG_PROP = "message"; + + /** How often the log is updated (milliseconds) */ + public static final int LOG_UP_INTERVAL = 500; + + /** Regular expression to filter log entries (changed trough Settings) */ + private String regExp = null; + public static final int DEFAULT_MAX_NROF_EVENTS = 30; + /** how many events to show in log (changed trough Settings) */ + private int maxNrofEvents; + + private Font font; // font used in log entries + private DTNSimGUI gui; + private Vector eventPanes; + private GridLayout layout; + + private EventLogControlPanel controls; + private EventLogControl conUpCheck; + private EventLogControl conDownCheck; + private EventLogControl msgCreateCheck; + private EventLogControl msgTransferStartCheck; + private EventLogControl msgRelayCheck; + private EventLogControl msgRemoveCheck; + private EventLogControl msgDeliveredCheck; + private EventLogControl msgDropCheck; + private EventLogControl msgAbortCheck; + + /** + * Creates a new log panel + * @param gui The where this log belongs to (for callbacks) + */ + public EventLogPanel(DTNSimGUI gui) { + this.gui = gui; + String title = PANEL_TITLE; + Settings s = new Settings(EL_PANEL_NS); + + this.maxNrofEvents = s.getInt(NROF_EVENTS_S, + DEFAULT_MAX_NROF_EVENTS); + this.regExp = s.getSetting(EVENTS_RE_S, null); + + layout = new GridLayout(maxNrofEvents,1); + + this.setLayout(layout); + if (this.regExp != null) { + title += " - RE-filter: " + regExp; + } + this.setBorder(BorderFactory.createTitledBorder( + getBorder(), title)); + + this.eventPanes = new Vector(maxNrofEvents); + this.font = new Font(FONT_TYPE,Font.PLAIN, FONT_SIZE); + this.controls = createControls(); + + // set log view to update every LOG_UP_INTERVAL milliseconds + // also ensures that the update is done in Swing's EDT + ActionListener taskPerformer = new ActionListener() { + public void actionPerformed(ActionEvent evt) { + updateLogView(); + } + }; + Timer t = new Timer(LOG_UP_INTERVAL, taskPerformer); + t.start(); + } + + /** + * Creates a control panel for the log + * @return The created EventLogControls + */ + private EventLogControlPanel createControls() { + EventLogControlPanel c = new EventLogControlPanel(); + c.addHeading("connections"); + conUpCheck = c.addControl("up"); + conDownCheck = c.addControl("down"); + c.addHeading("messages"); + msgCreateCheck = c.addControl("created"); + msgTransferStartCheck = c.addControl("started relay"); + msgRelayCheck = c.addControl("relayed"); + msgDeliveredCheck = c.addControl("delivered"); + msgRemoveCheck = c.addControl("removed"); + msgDropCheck = c.addControl("dropped"); + msgAbortCheck = c.addControl("aborted"); + return c; + } + + /** + * Returns the control panel that this log uses + * @return The control panel + */ + public EventLogControlPanel getControls() { + return this.controls; + } + + /** + * Adds a new event to the event log panel + * @param description Textual description of the event + * @param host1 Host that caused the event or null if there was not any + * @param host2 Another host that was involved in the event (or null) + * @param message Message that was involved in the event (or null) + * @param highlight If true, the log entry is highlighted + */ + private void addEvent(String description, DTNHost host1, + DTNHost host2, Message message, boolean highlight) { + JPanel eventPane = new JPanel(); + eventPane.setLayout(new BoxLayout(eventPane,BoxLayout.LINE_AXIS)); + + String text = String.format(ENTRY_FORMAT, + SimClock.getTime(),description); + JLabel label = new JLabel(text); + label.setFont(font); + eventPane.add(label); + + if (host1 != null) { + addInfoButton(eventPane,host1,HOST_PROP); + } + if (host2 != null) { + JLabel betweenLabel = new JLabel(HOST_DELIM); + betweenLabel.setFont(font); + eventPane.add(betweenLabel); + addInfoButton(eventPane,host2,HOST_PROP); + } + if (message != null) { + addInfoButton(eventPane, message, MSG_PROP); + } + + if (highlight) { + eventPane.setBackground(HIGHLIGHT_BG_COLOR); + } + + eventPanes.add(eventPane); + + // if the log is full, remove oldest entries first + if (this.eventPanes.size() > maxNrofEvents) { + eventPanes.remove(0); + } + } + + /** + * Updates the log view + */ + private void updateLogView() { + //TODO Optimization: Check if update is really necessary + this.removeAll(); + for (int i=0; i< this.eventPanes.size(); i++) { + this.add(eventPanes.get(i)); + } + revalidate(); + } + + + /** + * Adds a new button to a log entry panel and attaches a client + * property into it + * @param panel Panel where to add the button + * @param o Client property object to add + * @param clientProp Client property key to use for the object + */ + private void addInfoButton(JPanel panel, Object o, String clientProp) { + JButton hButton; + hButton = new JButton(o.toString()); + hButton.putClientProperty(clientProp, o); + hButton.addActionListener(this); + hButton.setFont(font); + hButton.setMargin(new Insets(0,0,0,0)); + hButton.setBackground(LOG_BUTTON_BG); + panel.add(hButton); + } + + /** + * Processes a log event + * @param check EventLogControls used to check if this entry type should + * be shown and/or paused upon + * @param name Text description of the event + * @param host1 First host involved in the event (if any, can be null) + * @param host2 Second host involved in the event (if any, can be null) + * @param message The message involved in the event (if any, can be null) + */ + private void processEvent(EventLogControl check, final String name, + final DTNHost host1, final DTNHost host2, final Message message) { + String descString; // String format description of the event + + if (!check.showEvent()) { + return; // if event's "show" is not checked, won't pause either + } + + descString = name + " " + + (host1!=null ? host1 : "") + + (host2!= null ? (HOST_DELIM + host2) : "") + + (message!=null ? " " + message : ""); + + if (regExp != null && !descString.matches(regExp)){ + return; // description doesn't match defined regular expression + } + + if (check.pauseOnEvent()) { + gui.setPaused(true); + if (host1 != null) { + gui.setFocus(host1); + } + } + + addEvent(name, host1, host2, message, check.pauseOnEvent()); + } + + // Implementations of ConnectionListener and MessageListener interfaces + public void hostsConnected(DTNHost host1, DTNHost host2) { + processEvent(conUpCheck, "Connection UP", host1, host2, null); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + processEvent(conDownCheck, "Connection DOWN", host1, host2, null); + } + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + if (!dropped) { + processEvent(msgRemoveCheck, "Message removed", where, null, m); + } + else { + processEvent(msgDropCheck, "Message dropped", where, null, m); + } + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery) { + processEvent(msgDeliveredCheck, "Message delivered", from, to, m); + } + else if (to == m.getTo()) { + processEvent(msgDeliveredCheck, "Message delivered again", + from, to, m); + } + else { + processEvent(msgRelayCheck, "Message relayed", from, to, m); + } + } + + public void newMessage(Message m) { + processEvent(msgCreateCheck, "Message created", m.getFrom(), null, m); + } + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + processEvent(msgAbortCheck, "Message relay aborted", from, to, m); + } + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + processEvent(msgTransferStartCheck,"Message relay started", from, + to,m); + + } + + // end of message interface implementations + + + /** + * Action listener for log entry (host & message) buttons + */ + public void actionPerformed(ActionEvent e) { + JButton source = (JButton)e.getSource(); + + if (source.getClientProperty(HOST_PROP) != null) { + // button was a host button -> focus it on GUI + gui.setFocus((DTNHost)source.getClientProperty(HOST_PROP)); + } + else if (source.getClientProperty(MSG_PROP) != null) { + // was a message button -> show information about the message + Message m = (Message)source.getClientProperty(MSG_PROP); + gui.getInfoPanel().showInfo(m); + } + } + + public String toString() { + return this.getClass().getSimpleName() + " with " + + this.eventPanes.size() + " events"; + } + +} diff --git a/gui/GUIControls.java b/gui/GUIControls.java new file mode 100644 index 000000000..d10dccad9 --- /dev/null +++ b/gui/GUIControls.java @@ -0,0 +1,396 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import gui.playfield.PlayField; + +import java.awt.FlowLayout; +import java.awt.Graphics2D; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.event.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.File; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import core.Coord; +import core.SimClock; + +/** + * GUI's control panel + * + */ +public class GUIControls extends JPanel implements ActionListener, ChangeListener { + private static final String PATH_GRAPHICS = "buttonGraphics/"; + private static final String ICON_PAUSE = "Pause16.gif"; + private static final String ICON_PLAY = "Play16.gif"; + private static final String ICON_ZOOM = "Zoom24.gif"; + private static final String ICON_STEP = "StepForward16.gif"; + private static final String ICON_FFW = "FastForward16.gif"; + + private static final String TEXT_PAUSE = "pause simulation"; + private static final String TEXT_PLAY = "play simulation"; + private static final String TEXT_PLAY_UNTIL = "play simulation until sim time..."; + private static final String TEXT_STEP = "step forward one interval"; + private static final String TEXT_FFW = "enable/disable fast forward"; + private static final String TEXT_UP_CHOOSER = "GUI update:"; + private static final String TEXT_SCREEN_SHOT = "screen shot"; + private static final String TEXT_SIMTIME = "Simulation time - "+ + "click to force update, right click to change format"; + private static final String TEXT_SEPS = "simulated seconds per second"; + + // "simulated events per second" averaging time (milliseconds) + private static final int EPS_AVG_TIME = 2000; + private static final String SCREENSHOT_FILE_TYPE = "png"; + private static final String SCREENSHOT_FILE = "screenshot"; + + private JTextField simTimeField; + private JLabel sepsField; // simulated events per second field + private JButton playButton; + private JButton playUntilButton; + private boolean paused; + private JButton stepButton; + private boolean step; + private JButton ffwButton; + private boolean isFfw; + private int oldSpeedIndex; // what speed was selected before FFW + + private JButton screenShotButton; + private JComboBox guiUpdateChooser; + + /** + * GUI update speeds. Negative values -> how many 1/10 seconds to wait + * between updates. Positive values -> show every Nth update + */ + public static final String[] UP_SPEEDS = {"-10", "-1", "0.1", "1", "10", + "100", "1000", "10000", "100000"}; + + /** Smallest value for the zoom level */ + public static final double ZOOM_MIN = 0.001; + /** Highest value for the zoom level */ + public static final double ZOOM_MAX = 10; + + /** index of initial update speed setting */ + public static final int INITIAL_SPEED_SELECTION = 3; + /** index of FFW speed setting */ + public static final int FFW_SPEED_INDEX = 7; + + private double guiUpdateInterval; + private javax.swing.JSpinner zoomSelector; + + private PlayField pf; + private DTNSimGUI gui; + + private long lastUpdate; + private double lastSimTime; + private double playUntilTime; + + private boolean useHourDisplay = false; + + public GUIControls(DTNSimGUI gui, PlayField pf) { + /* TODO: read values for paused, isFfw etc from a file */ + this.pf = pf; + this.gui = gui; + this.lastUpdate = System.currentTimeMillis(); + this.lastSimTime = 0; + this.paused = true; + this.isFfw = false; + this.playUntilTime = Double.MAX_VALUE; + initPanel(); + } + + /** + * Creates panel's components and initializes them + */ + private void initPanel() { + this.setLayout(new FlowLayout()); + this.simTimeField = new JTextField("0.0"); + this.simTimeField.setColumns(6); + this.simTimeField.setEditable(false); + this.simTimeField.setToolTipText(TEXT_SIMTIME); + this.simTimeField.addMouseListener(new MouseAdapter(){ + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + useHourDisplay = !useHourDisplay; + } + setSimTime(SimClock.getTime()); + } + }); + + this.sepsField = new JLabel("0.00"); + this.sepsField.setToolTipText(TEXT_SEPS); + + this.screenShotButton = new JButton(TEXT_SCREEN_SHOT); + this.guiUpdateChooser = new JComboBox(UP_SPEEDS); + + this.zoomSelector = new JSpinner(new SpinnerNumberModel(1.0, ZOOM_MIN, + ZOOM_MAX, 0.001)); + + this.add(simTimeField); + this.add(sepsField); + + playButton = addButton(paused ? ICON_PLAY : ICON_PAUSE, + paused ? TEXT_PLAY : TEXT_PAUSE); + stepButton = addButton(ICON_STEP, TEXT_STEP); + ffwButton = addButton(ICON_FFW, TEXT_FFW); + playUntilButton = addButton(ICON_PLAY, TEXT_PLAY_UNTIL); + playUntilButton.setText("..."); + + this.add(new JLabel(TEXT_UP_CHOOSER)); + this.add(this.guiUpdateChooser); + this.guiUpdateChooser.setSelectedIndex(INITIAL_SPEED_SELECTION); + this.updateUpdateInterval(); + + this.add(new JLabel(createImageIcon(ICON_ZOOM))); + this.updateZoomScale(false); + + this.add(this.zoomSelector); + this.add(this.screenShotButton); + + guiUpdateChooser.addActionListener(this); + zoomSelector.addChangeListener(this); + this.screenShotButton.addActionListener(this); + } + + + private ImageIcon createImageIcon(String path) { + java.net.URL imgURL = getClass().getResource(PATH_GRAPHICS+path); + return new ImageIcon(imgURL); + } + + + private JButton addButton(String iconPath, String tooltip) { + JButton button = new JButton(createImageIcon(iconPath)); + button.setToolTipText(tooltip); + button.addActionListener(this); + this.add(button); + return button; + } + + /** + * Sets the simulation time that control panel shows + * @param time The time to show + */ + public void setSimTime(double time) { + long timeSinceUpdate = System.currentTimeMillis() - this.lastUpdate; + + if (timeSinceUpdate > EPS_AVG_TIME) { + double val = ((time - this.lastSimTime) * 1000)/timeSinceUpdate; + String sepsValue = String.format("%.2f 1/s", val); + + this.sepsField.setText(sepsValue); + this.lastSimTime = time; + this.lastUpdate = System.currentTimeMillis(); + } + + if (this.useHourDisplay) { + int hours = (int)(time / 3600); + int mins = (int)((time - hours * 3600) / 60); + double secs = time % 60; + this.simTimeField.setText(String.format("%02d:%02d:%02.1f", + hours, mins, secs)); + } else { + this.simTimeField.setText(String.format("%.1f", time)); + } + } + + /** + * Sets simulation to pause or play. + * @param paused If true, simulation is put to pause + */ + public void setPaused(boolean paused) { + if (!paused) { + this.playButton.setIcon(createImageIcon(ICON_PAUSE)); + this.playButton.setToolTipText(TEXT_PAUSE); + this.paused = false; + if (SimClock.getTime() >= this.playUntilTime) { + // playUntilTime passed -> disable it + this.playUntilTime = Double.MAX_VALUE; + } + } + else { + this.playButton.setIcon(createImageIcon(ICON_PLAY)); + this.playButton.setToolTipText(TEXT_PLAY); + this.paused = true; + this.setSimTime(SimClock.getTime()); + this.pf.updateField(); + } + } + + private void switchFfw() { + if (isFfw) { + this.isFfw = false; // set to normal play + this.ffwButton.setIcon(createImageIcon(ICON_FFW)); + this.guiUpdateChooser.setSelectedIndex(oldSpeedIndex); + this.ffwButton.setSelected(false); + } + else { + this.oldSpeedIndex = this.guiUpdateChooser.getSelectedIndex(); + this.guiUpdateChooser.setSelectedIndex(FFW_SPEED_INDEX); + this.isFfw = true; // set to FFW + this.ffwButton.setIcon(createImageIcon(ICON_PLAY)); + } + } + + /** + * Has user requested the simulation to be paused + * @return True if pause is requested + */ + public boolean isPaused() { + if (step) { // if we want to step, return false once and reset stepping + step = false; + return false; + } + if (SimClock.getTime() >= this.playUntilTime) { + this.setPaused(true); + } + return this.paused; + } + + /** + * Is fast forward turned on + * @return True if FFW is on, false if not + */ + public boolean isFfw() { + return this.isFfw; + } + + /** + * Returns the selected update interval of GUI + * @return The update interval (seconds) + */ + public double getUpdateInterval() { + return this.guiUpdateInterval; + } + + /** + * Changes the zoom level + * @param delta How much to change the current level (can be negative or + * positive) + */ + public void changeZoom(int delta) { + SpinnerNumberModel model = + (SpinnerNumberModel)this.zoomSelector.getModel(); + double curZoom = model.getNumber().doubleValue(); + Number newValue = new Double(curZoom + model.getStepSize(). + doubleValue() * delta * curZoom * 100); + + if (newValue.doubleValue() < ZOOM_MIN) { + newValue = ZOOM_MIN; + } else if (newValue.doubleValue() > ZOOM_MAX) { + newValue = ZOOM_MAX; + } + + model.setValue(newValue); + this.updateZoomScale(true); + } + + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == this.playButton) { + setPaused(!this.paused); // switch pause/play + } + else if (e.getSource() == this.stepButton) { + setPaused(true); + this.step = true; + } + else if (e.getSource() == this.ffwButton) { + switchFfw(); + } + else if (e.getSource() == this.playUntilButton) { + setPlayUntil(); + } + else if (e.getSource() == this.guiUpdateChooser) { + updateUpdateInterval(); + } + else if (e.getSource() == this.screenShotButton) { + takeScreenShot(); + } + } + + + public void stateChanged(ChangeEvent e) { + updateZoomScale(true); + } + + + private void setPlayUntil() { + setPaused(true); + String value = JOptionPane.showInputDialog(TEXT_PLAY_UNTIL); + if (value == null) { + return; + } + try { + this.playUntilTime = Double.parseDouble(value); + setPaused(false); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(gui.getParentFrame(), + "Invalid number '" + value+"'", + "error",JOptionPane.ERROR_MESSAGE); + } + } + + + private void updateUpdateInterval() { + String selString = (String)this.guiUpdateChooser.getSelectedItem(); + this.guiUpdateInterval = Double.parseDouble(selString); + } + + /** + * Updates zoom scale to the one selected by zoom chooser + * @param centerView If true, the center of the viewport should remain + * the same + */ + private void updateZoomScale(boolean centerView) { + double scale = ((SpinnerNumberModel)zoomSelector.getModel()). + getNumber().doubleValue(); + + if (centerView) { + Coord center = gui.getCenterViewCoord(); + this.pf.setScale(scale); + gui.centerViewAt(center); + } + else { + this.pf.setScale(scale); + } + } + + private void takeScreenShot() { + try { + JFileChooser fc = new JFileChooser(); + fc.setSelectedFile(new File(SCREENSHOT_FILE + + "." + SCREENSHOT_FILE_TYPE)); + int retVal = fc.showSaveDialog(this); + if (retVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + BufferedImage i = new BufferedImage(this.pf.getWidth(), + this.pf.getHeight(), BufferedImage.TYPE_INT_RGB); + Graphics2D g2 = i.createGraphics(); + + this.pf.paint(g2); // paint playfield to buffered image + ImageIO.write(i, SCREENSHOT_FILE_TYPE, file); + } + } + catch (Exception e) { + JOptionPane.showMessageDialog(gui.getParentFrame(), + "screenshot failed (problems with output file?)", + "Exception", JOptionPane.ERROR_MESSAGE); + } + } + +} diff --git a/gui/InfoPanel.java b/gui/InfoPanel.java new file mode 100644 index 000000000..c34c7a8d7 --- /dev/null +++ b/gui/InfoPanel.java @@ -0,0 +1,134 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Collections; +import java.util.Vector; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import movement.Path; +import core.DTNHost; +import core.Message; + +/** + * Information panel that shows data of selected messages and nodes. + */ +public class InfoPanel extends JPanel implements ActionListener{ + private JComboBox msgChooser; + private JLabel info; + private JButton infoButton; + private JButton routingInfoButton; + private Message selectedMessage; + private DTNHost selectedHost; + private DTNSimGUI gui; + + public InfoPanel(DTNSimGUI gui) { + this.gui = gui; + reset(); + } + + private void reset() { + this.removeAll(); + this.repaint(); + this.info = null; + this.infoButton = null; + this.selectedMessage = null; + } + + /** + * Show information about a host + * @param host Host to show the information of + */ + public void showInfo(DTNHost host) { + Vector messages = + new Vector(host.getMessageCollection()); + Collections.sort(messages); + reset(); + this.selectedHost = host; + String text = (host.isMovementActive() ? "" : "INACTIVE ") + host + + " at " + host.getLocation(); + + msgChooser = new JComboBox(messages); + msgChooser.insertItemAt(messages.size() + " messages", 0); + msgChooser.setSelectedIndex(0); + msgChooser.addActionListener(this); + + routingInfoButton = new JButton("routing info"); + routingInfoButton.addActionListener(this); + + this.add(new JLabel(text)); + this.add(msgChooser); + this.add(routingInfoButton); + this.revalidate(); + } + + /** + * Show information about a message + * @param message Message to show the information of + */ + public void showInfo(Message message) { + reset(); + this.add(new JLabel(message.toString())); + setMessageInfo(message); + this.revalidate(); + } + + private void setMessageInfo(Message m) { + int ttl = m.getTtl(); + String txt = " [" + m.getFrom() + "->" + m.getTo() + "] " + + "size:" + m.getSize() + ", UI:" + m.getUniqueId() + + ", received @ " + String.format("%.2f", m.getReceiveTime()); + if (ttl != Integer.MAX_VALUE) { + txt += " TTL: " + ttl; + } + + String butTxt = "path: " + (m.getHops().size()-1) + " hops"; + + if (this.info == null) { + this.info = new JLabel(txt); + this.infoButton = new JButton(butTxt); + this.add(info); + this.add(infoButton); + infoButton.addActionListener(this); + } + else { + this.info.setText(txt); + this.infoButton.setText(butTxt); + } + + this.selectedMessage = m; + infoButton.setToolTipText("path:" + m.getHops()); + + this.revalidate(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == msgChooser) { + if (msgChooser.getSelectedIndex() == 0) { // title text selected + return; + } + Message m = (Message)msgChooser.getSelectedItem(); + setMessageInfo(m); + } + else if (e.getSource() == this.infoButton) { + Path p = new Path(); + for (DTNHost h : this.selectedMessage.getHops()) { + p.addWaypoint(h.getLocation()); + } + + this.gui.showPath(p); + } + else if (e.getSource() == this.routingInfoButton) { + new RoutingInfoWindow(this.selectedHost); + } + } + +} \ No newline at end of file diff --git a/gui/MainWindow.java b/gui/MainWindow.java new file mode 100644 index 000000000..6e55fea10 --- /dev/null +++ b/gui/MainWindow.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import gui.playfield.PlayField; + +import java.awt.BorderLayout; +import java.awt.Dimension; + +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; + +import core.Settings; +import core.World; + +/** + * Main window for the program. Takes care of layouting the main components + * in the window. + */ +public class MainWindow extends JFrame { + /** The namespace for general GUI settings */ + public static final String GUI_NS = "GUI"; + + /** Main window settings namespace ({@value}) */ + public static final String GUI_WIN_NS = GUI_NS + ".window"; + + /** Window width -setting id ({@value}). Defines the width of the GUI + * window. Default {@link #WIN_DEFAULT_WIDTH} */ + public static final String WIN_WIDTH_S = "width"; + /** Window height -setting id ({@value}). Defines the height of the GUI + * window. Default {@link #WIN_DEFAULT_HEIGHT} */ + public static final String WIN_HEIGHT_S = "height"; + + /** Default width for the GUI window */ + public static final int WIN_DEFAULT_WIDTH = 900; + /** Default height for the GUI window */ + public static final int WIN_DEFAULT_HEIGHT = 700; + + public static final String WINDOW_TITLE = "ONE"; + /** log panel's initial weight in the split panel */ + private static final double SPLIT_PANE_LOG_WEIGHT = 0.2; + + private JScrollPane playFieldScroll; + + public MainWindow(String scenName, World world, PlayField field, + GUIControls guiControls, InfoPanel infoPanel, + EventLogPanel elp, DTNSimGUI gui) { + super(WINDOW_TITLE + " - " + scenName); + JFrame.setDefaultLookAndFeelDecorated(true); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + JPanel leftPane = new JPanel(); + leftPane.setLayout(new BoxLayout(leftPane,BoxLayout.Y_AXIS)); + JScrollPane hostListScroll; + JSplitPane fieldLogSplit; + JSplitPane logControlSplit; + JSplitPane mainSplit; + Settings s = new Settings(GUI_WIN_NS); + NodeChooser chooser = new NodeChooser(world.getHosts(),gui); + + setLayout(new BorderLayout()); + setJMenuBar(new SimMenuBar(field, chooser)); + + playFieldScroll = new JScrollPane(field); + playFieldScroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, + Integer.MAX_VALUE)); + + hostListScroll = new JScrollPane(chooser); + hostListScroll.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + logControlSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + new JScrollPane(elp.getControls()),new JScrollPane(elp)); + logControlSplit.setResizeWeight(0.1); + logControlSplit.setOneTouchExpandable(true); + + fieldLogSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + leftPane, logControlSplit); + fieldLogSplit.setResizeWeight(1-SPLIT_PANE_LOG_WEIGHT); + fieldLogSplit.setOneTouchExpandable(true); + + setPreferredSize(new Dimension( + s.getInt(WIN_WIDTH_S, WIN_DEFAULT_WIDTH), + s.getInt(WIN_HEIGHT_S, WIN_DEFAULT_HEIGHT))); + + leftPane.add(guiControls); + leftPane.add(playFieldScroll); + leftPane.add(infoPanel); + + mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + fieldLogSplit, hostListScroll); + mainSplit.setOneTouchExpandable(true); + mainSplit.setResizeWeight(0.8); + this.getContentPane().add(mainSplit); + + pack(); + } + + /** + * Returns a reference of the play field scroll panel + * @return a reference of the play field scroll panel + */ + public JScrollPane getPlayFieldScroll() { + return this.playFieldScroll; + } + +} diff --git a/gui/NodeChooser.java b/gui/NodeChooser.java new file mode 100644 index 000000000..7e8afdb0d --- /dev/null +++ b/gui/NodeChooser.java @@ -0,0 +1,212 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JPanel; +import javax.swing.Timer; + +import gui.nodefilter.*; +import gui.playfield.NodeGraphic; +import core.DTNHost; +import core.Settings; + +/** + * Node chooser panel + */ +public class NodeChooser extends JPanel implements ActionListener { + private DTNSimGUI gui; + /** the maximum number of allNodes to show in the list per page */ + public static final int MAX_NODE_COUNT = 500; + private Timer refreshTimer; + /** how often auto refresh is performed */ + private static final int AUTO_REFRESH_DELAY = 100; + + /** Default message node filters -setting id ({@value}). Comma separate + * list of message IDs from which the default filter set is created. */ + public static final String NODE_MESSAGE_FILTERS_S = "nodeMessageFilters"; + + private static final String HOST_KEY = "host"; + private List allNodes; + private List shownNodes; + + private JComboBox groupChooser; + private JPanel nodesPanel; + private JPanel chooserPanel; + private Vector filters; + + + public NodeChooser(List nodes, DTNSimGUI gui) { + Settings s = new Settings(MainWindow.GUI_NS); + // create a replicate to not interfere with original's ordering + this.allNodes = new ArrayList(nodes); + this.shownNodes = allNodes; + this.gui = gui; + this.filters = new Vector(); + + if (s.contains(NODE_MESSAGE_FILTERS_S)) { + String[] filterIds = s.getCsvSetting(NODE_MESSAGE_FILTERS_S); + for (String id : filterIds) { + this.filters.add(new NodeMessageFilter(id)); + this.refreshTimer = new Timer(AUTO_REFRESH_DELAY, this); + this.refreshTimer.start(); + } + } + + Collections.sort(this.allNodes); + + init(); + } + + /** + * Adds a new node filter to the node chooser + * @param f The filter to add + */ + public void addFilter(NodeFilter f) { + this.filters.add(f); + updateShownNodes(); + if (this.refreshTimer == null) { + this.refreshTimer = new Timer(AUTO_REFRESH_DELAY, this); + this.refreshTimer.start(); + } + } + + /** + * Clears all node filters + */ + public void clearFilters() { + this.filters = new Vector(); + this.shownNodes = allNodes; + if (this.refreshTimer != null) { + this.refreshTimer.stop(); + } + this.refreshTimer = null; + + NodeGraphic.setHighlightedNodes(null); + updateList(); + } + + private void updateList() { + setNodes(0); + if (this.groupChooser != null) { + this.groupChooser.setSelectedIndex(0); + } + } + + + private void updateShownNodes() { + List oldShownNodes = shownNodes; + Listnodes = new Vector(); + + for (DTNHost node : allNodes) { + for (NodeFilter f : this.filters) { + if (f.filterNode(node)) { + nodes.add(node); + break; + } + } + } + + if (nodes.size() == oldShownNodes.size() && + oldShownNodes.containsAll(nodes)) { + return; /* nothing to update */ + } else { + this.shownNodes = nodes; + updateList(); + NodeGraphic.setHighlightedNodes(nodes); + } + + } + + /** + * Initializes the node chooser panels + */ + private void init() { + nodesPanel = new JPanel(); + chooserPanel = new JPanel(); + + this.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.anchor = GridBagConstraints.FIRST_LINE_START; + + nodesPanel.setLayout(new BoxLayout(nodesPanel,BoxLayout.Y_AXIS)); + nodesPanel.setBorder(BorderFactory.createTitledBorder(getBorder(), + "Nodes")); + + if (shownNodes.size() > MAX_NODE_COUNT) { + String[] groupNames = new String[(shownNodes.size()-1) + / MAX_NODE_COUNT+1]; + int last = 0; + for (int i=0, n=shownNodes.size(); + i <= (n-1) / MAX_NODE_COUNT; i++) { + int next = MAX_NODE_COUNT * (i+1) - 1; + if (next > n) { + next = n-1; + } + groupNames[i] = (last + "..." + next); + last = next + 1; + } + groupChooser = new JComboBox(groupNames); + groupChooser.addActionListener(this); + chooserPanel.add(groupChooser); + } + + setNodes(0); + c.gridy = 0; + this.add(chooserPanel, c); + c.gridy = 1; + this.add(nodesPanel, c); + } + + /** + * Sets the right set of allNodes to display + * @param offset Index of the first node to show + */ + private void setNodes(int offset) { + nodesPanel.removeAll(); + + for (int i=offset; i< shownNodes.size() && + i < offset + MAX_NODE_COUNT; i++) { + DTNHost h = shownNodes.get(i); + JButton jb = new JButton(h.toString()); + jb.putClientProperty(HOST_KEY, h); + jb.addActionListener(this); + nodesPanel.add(jb); + } + + revalidate(); + repaint(); + } + + /** + * Action listener method for buttons and node set chooser + */ + public void actionPerformed(ActionEvent e) { + if (e.getSource() instanceof JButton) { + JButton source = (JButton)e.getSource(); + DTNHost host = (DTNHost)source.getClientProperty(HOST_KEY); + gui.setFocus(host); + } + else if (e.getSource() == this.groupChooser) { + setNodes(groupChooser.getSelectedIndex() * MAX_NODE_COUNT); + } + else if (e.getSource() == this.refreshTimer) { + updateShownNodes(); + } + } + +} diff --git a/gui/RoutingInfoWindow.java b/gui/RoutingInfoWindow.java new file mode 100644 index 000000000..74366ac9a --- /dev/null +++ b/gui/RoutingInfoWindow.java @@ -0,0 +1,119 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Vector; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.Timer; +import javax.swing.tree.DefaultMutableTreeNode; + +import routing.util.RoutingInfo; +import core.DTNHost; +import core.SimClock; + +/** + * A window for displaying routing information + */ +public class RoutingInfoWindow extends JFrame implements ActionListener { + private DTNHost host; + private JButton refreshButton; + private JCheckBox autoRefresh; + private JScrollPane treePane; + private JTree tree; + private Timer refreshTimer; + /** how often auto refresh is performed */ + private static final int AUTO_REFRESH_DELAY = 1000; + + public RoutingInfoWindow(DTNHost host) { + Container cp = this.getContentPane(); + JPanel refreshPanel = new JPanel(); + this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + this.host = host; + this.setLayout(new BorderLayout()); + refreshPanel.setLayout(new BorderLayout()); + this.autoRefresh = new JCheckBox("Auto refresh"); + this.autoRefresh.addActionListener(this); + this.treePane = new JScrollPane(); + updateTree(); + + cp.add(treePane, BorderLayout.CENTER); + cp.add(refreshPanel, BorderLayout.SOUTH); + + this.refreshButton = new JButton("refresh"); + this.refreshButton.addActionListener(this); + refreshPanel.add(refreshButton, BorderLayout.EAST); + refreshPanel.add(autoRefresh, BorderLayout.WEST); + + this.pack(); + this.setVisible(true); + } + + + private void updateTree() { + super.setTitle("Routing Info of " + host + " at " + + SimClock.getFormattedTime(2)); + RoutingInfo ri = host.getRoutingInfo(); + DefaultMutableTreeNode top = new DefaultMutableTreeNode(ri); + Vector expanded = new Vector(); + + addChildren(top, ri); + + if (this.tree != null) { /* store expanded state */ + for (int i=0; i < this.tree.getRowCount(); i++) { + if (this.tree.isExpanded(i)) { + expanded.add(i); + } + } + } + + this.tree = new JTree(top); + + for (int i=0; i < this.tree.getRowCount(); i++) { /* restore expanded */ + if (expanded.size() > 0 && expanded.firstElement() == i) { + this.tree.expandRow(i); + expanded.remove(0); + } + } + + this.treePane.setViewportView(this.tree); + this.treePane.revalidate(); + } + + + private void addChildren(DefaultMutableTreeNode node, RoutingInfo info) { + for (RoutingInfo ri : info.getMoreInfo()) { + DefaultMutableTreeNode child = new DefaultMutableTreeNode(ri); + node.add(child); + // recursively add children of this info + addChildren(child, ri); + } + } + + public void actionPerformed(ActionEvent e) { + Object s = e.getSource(); + if (s == this.refreshButton || s == this.refreshTimer) { + updateTree(); + } + if (e.getSource() == this.autoRefresh) { + if (this.autoRefresh.isSelected()) { + this.refreshTimer = new Timer(AUTO_REFRESH_DELAY, this); + this.refreshTimer.start(); + } else { + this.refreshTimer.stop(); + } + } + } + +} \ No newline at end of file diff --git a/gui/SimMenuBar.java b/gui/SimMenuBar.java new file mode 100644 index 000000000..dff5a5250 --- /dev/null +++ b/gui/SimMenuBar.java @@ -0,0 +1,259 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui; + +import gui.nodefilter.NodeMessageFilter; +import gui.playfield.PlayField; +import gui.playfield.NodeGraphic; + +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.Box; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; + +import core.Settings; +import core.SettingsError; + +/** + * Menu bar of the simulator GUI + * + */ +public class SimMenuBar extends JMenuBar implements ActionListener { + /** title of the about window */ + public static final String ABOUT_TITLE = "about ONE"; + /** GPLv3 license text for about window */ + public static final String ABOUT_TEXT = + "Copyright (C) 2007-2011 Aalto University, Comnet\n\n"+ + "This program is free software: you can redistribute it and/or modify\n"+ + "it under the terms of the GNU General Public License as published by\n"+ + "the Free Software Foundation, either version 3 of the License, or\n"+ + "(at your option) any later version.\n\n"+ + "This program is distributed in the hope that it will be useful,\n"+ + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"+ + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"+ + "GNU General Public License for more details.\n\n" + + "You should have received a copy of the GNU General Public License\n"+ + "along with this program. If not, see .\n\n"+ + "Map data copyright: Maanmittauslaitos, 2007"; + + private JCheckBoxMenuItem enableBgImage; + private JCheckBoxMenuItem showNodeName; + private JCheckBoxMenuItem showNodeCoverage; + private JCheckBoxMenuItem showNodeConnections; + private JCheckBoxMenuItem showBuffer; + + private JCheckBoxMenuItem enableMapGraphic; + private JCheckBoxMenuItem autoClearOverlay; + private JCheckBoxMenuItem focusOnClick; + + private JMenuItem clearOverlay; + private JMenuItem addNodeMessageFilter; + private JMenuItem clearNodeFilters; + + private JMenuItem about; + private PlayField field; + private NodeChooser chooser; + + /** Show node name string -setting id ({@value})*/ + public static final String SHOW_NODE_NAMESTR_S = "showNodeNameStrings"; + /** Show node radio coverage -setting id ({@value})*/ + public static final String SHOW_RADIO_COVERAGES_S = "showNodeRadioCoverages"; + /** Show node connections -setting id ({@value})*/ + public static final String SHOW_CONNECTIONS_S = "showNodeConnections"; + /** Show nodes' messages -setting id ({@value})*/ + public static final String SHOW_BUFFER_S = "showMessageBuffer"; + /** Show node connections -setting id ({@value})*/ + public static final String FOCUS_ON_CLICK_S = "focusOnClick"; + /** The namespace where underlay image -related settings are found */ + public static final String UNDERLAY_NS = "GUI.UnderlayImage"; + + public SimMenuBar(PlayField field, NodeChooser nodeChooser) { + this.field = field; + this.chooser = nodeChooser; + init(); + } + + private void init() { + JMenu pfMenu = new JMenu("Playfield options"); + JMenu pfToolsMenu = new JMenu("Tools"); + JMenu help = new JMenu("Help"); + JMenu nodeFilters = new JMenu("Add node filter"); + Settings settings = new Settings(UNDERLAY_NS); + + if (settings.contains("fileName")) { + // create underlay image menu item only if filename is specified + enableBgImage = createCheckItem(pfMenu,"Show underlay image", + false, null); + } + + settings.setNameSpace(gui.MainWindow.GUI_NS); + + showNodeName = createCheckItem(pfMenu, "Show node name strings", + true, SHOW_NODE_NAMESTR_S); + showNodeCoverage = createCheckItem(pfMenu, + "Show node radio coverages", true, SHOW_RADIO_COVERAGES_S); + showNodeConnections = createCheckItem(pfMenu, + "Show node connections", true, SHOW_CONNECTIONS_S); + showBuffer = createCheckItem(pfMenu, + "Show message buffer", true, SHOW_BUFFER_S); + focusOnClick = createCheckItem(pfMenu, + "Focus to closest node on mouse click", false,FOCUS_ON_CLICK_S); + + enableMapGraphic = createCheckItem(pfMenu,"Show map graphic", + true, null); + autoClearOverlay = createCheckItem(pfMenu, "Autoclear overlay", + true, null); + clearOverlay = createMenuItem(pfToolsMenu, "Clear overlays"); + + + pfToolsMenu.addSeparator(); + addNodeMessageFilter = createMenuItem(nodeFilters, "message filter"); + pfToolsMenu.add(nodeFilters); + clearNodeFilters = createMenuItem(pfToolsMenu, "Clear node filters"); + + updatePlayfieldSettings(); + + about = createMenuItem(help,"about"); + this.add(pfMenu); + this.add(pfToolsMenu); + this.add(Box.createHorizontalGlue()); + this.add(help); + } + + private JMenuItem createMenuItem(Container c, String txt) { + JMenuItem i = new JMenuItem(txt); + i.addActionListener(this); + c.add(i); + return i; + } + + /** + * Creates a new check box menu item to the given container + * @param c The container + * @param txt Text for the menu item + * @param selected Is the check box selected (by default) + * @param setting Name of the setting where the check-box-selected + * true/false value is read from (if not found, the "selected" parameter + * value is used). If null, no setting is read and the default is + * used as such. + * @return The created check box menu item + */ + private JCheckBoxMenuItem createCheckItem(Container c,String txt, + boolean selected, String setting) { + Settings s = new Settings(gui.MainWindow.GUI_NS); + + JCheckBoxMenuItem i = new JCheckBoxMenuItem(txt); + if (setting == null) { + i.setSelected(selected); + } else { + i.setSelected(s.getBoolean(setting, selected)); + } + + i.addActionListener(this); + c.add(i); + + return i; + } + + + private void updatePlayfieldSettings() { + NodeGraphic.setDrawNodeName(showNodeName.isSelected()); + NodeGraphic.setDrawCoverage(showNodeCoverage.isSelected()); + NodeGraphic.setDrawConnections(showNodeConnections.isSelected()); + NodeGraphic.setDrawBuffer(showBuffer.isSelected()); + field.setShowMapGraphic(enableMapGraphic.isSelected()); + field.setAutoClearOverlay(autoClearOverlay.isSelected()); + field.setFocusOnClick(focusOnClick.isSelected()); + } + + private String getFilterString(String message) { + return (String)JOptionPane.showInputDialog( + this, message, "Filter input", JOptionPane.PLAIN_MESSAGE); + } + + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + if (source == enableBgImage) { + toggleUnderlayImage(); + } + else if (source == this.showNodeName || + source == this.showNodeCoverage || + source == this.showNodeConnections || + source == this.enableMapGraphic || + source == this.autoClearOverlay || + source == this.showBuffer || + source == this.focusOnClick) { + updatePlayfieldSettings(); + } + + else if (source == this.clearOverlay) { + field.clearOverlays(); + } + else if (source == addNodeMessageFilter) { + chooser.addFilter( + new NodeMessageFilter(getFilterString("Message ID"))); + } + else if (source == clearNodeFilters) { + chooser.clearFilters(); + } + else if (source == this.about) { + JOptionPane.showMessageDialog(this, ABOUT_TEXT, ABOUT_TITLE, + JOptionPane.INFORMATION_MESSAGE); + } + } + + /** + * Toggles the showing of underlay image. Image is read from the file only + * when it is enabled to save some memory. + */ + private void toggleUnderlayImage() { + if (enableBgImage.isSelected()) { + String imgFile = null; + int[] offsets; + double scale, rotate; + BufferedImage image; + try { + Settings settings = new Settings(UNDERLAY_NS); + imgFile = settings.getSetting("fileName"); + offsets = settings.getCsvInts("offset", 2); + scale = settings.getDouble("scale"); + rotate = settings.getDouble("rotate"); + image = ImageIO.read(new File(imgFile)); + } catch (IOException ex) { + warn("Couldn't set underlay image " + imgFile + ". " + + ex.getMessage()); + enableBgImage.setSelected(false); + return; + } + catch (SettingsError er) { + warn("Problem with the underlay image settings: " + + er.getMessage()); + return; + } + field.setUnderlayImage(image, offsets[0], offsets[1], + scale, rotate); + } + else { + // disable the image + field.setUnderlayImage(null, 0, 0, 0, 0); + } + } + + private void warn(String txt) { + JOptionPane.showMessageDialog(null, txt, "warning", + JOptionPane.WARNING_MESSAGE); + } + +} \ No newline at end of file diff --git a/gui/buttonGraphics/FastForward16.gif b/gui/buttonGraphics/FastForward16.gif new file mode 100644 index 000000000..679d89446 Binary files /dev/null and b/gui/buttonGraphics/FastForward16.gif differ diff --git a/gui/buttonGraphics/FastForward24.gif b/gui/buttonGraphics/FastForward24.gif new file mode 100644 index 000000000..814664c6c Binary files /dev/null and b/gui/buttonGraphics/FastForward24.gif differ diff --git a/gui/buttonGraphics/Pause16.gif b/gui/buttonGraphics/Pause16.gif new file mode 100644 index 000000000..678bc8532 Binary files /dev/null and b/gui/buttonGraphics/Pause16.gif differ diff --git a/gui/buttonGraphics/Pause24.gif b/gui/buttonGraphics/Pause24.gif new file mode 100644 index 000000000..7afeafda8 Binary files /dev/null and b/gui/buttonGraphics/Pause24.gif differ diff --git a/gui/buttonGraphics/Play16.gif b/gui/buttonGraphics/Play16.gif new file mode 100644 index 000000000..a8bfcf559 Binary files /dev/null and b/gui/buttonGraphics/Play16.gif differ diff --git a/gui/buttonGraphics/Play24.gif b/gui/buttonGraphics/Play24.gif new file mode 100644 index 000000000..572467c59 Binary files /dev/null and b/gui/buttonGraphics/Play24.gif differ diff --git a/gui/buttonGraphics/StepForward16.gif b/gui/buttonGraphics/StepForward16.gif new file mode 100644 index 000000000..63303945b Binary files /dev/null and b/gui/buttonGraphics/StepForward16.gif differ diff --git a/gui/buttonGraphics/StepForward24.gif b/gui/buttonGraphics/StepForward24.gif new file mode 100644 index 000000000..31a246fda Binary files /dev/null and b/gui/buttonGraphics/StepForward24.gif differ diff --git a/gui/buttonGraphics/Zoom16.gif b/gui/buttonGraphics/Zoom16.gif new file mode 100644 index 000000000..9e488969a Binary files /dev/null and b/gui/buttonGraphics/Zoom16.gif differ diff --git a/gui/buttonGraphics/Zoom24.gif b/gui/buttonGraphics/Zoom24.gif new file mode 100644 index 000000000..86ae8631b Binary files /dev/null and b/gui/buttonGraphics/Zoom24.gif differ diff --git a/gui/nodefilter/NodeFilter.java b/gui/nodefilter/NodeFilter.java new file mode 100644 index 000000000..4b8f634f3 --- /dev/null +++ b/gui/nodefilter/NodeFilter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package gui.nodefilter; + +import core.DTNHost; + +/** + * Interface for node filtering classes + */ +public interface NodeFilter { + + /** + * Returns true if the given node should be included in the filtered set + * @param node The node to check + * @return true if the node should be included, false if not + */ + public boolean filterNode(DTNHost node); + + /** + * Returns a String presentations of the filter + */ + public String toString(); +} diff --git a/gui/nodefilter/NodeMessageFilter.java b/gui/nodefilter/NodeMessageFilter.java new file mode 100644 index 000000000..a35ca3b86 --- /dev/null +++ b/gui/nodefilter/NodeMessageFilter.java @@ -0,0 +1,33 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package gui.nodefilter; + +import core.DTNHost; + +/** + * Node filter that filters nodes by the messages they have in their buffer + */ +public class NodeMessageFilter implements NodeFilter { + private String messageId; + + /** + * Creates a new filter with the given message ID + * @param messageId The message ID used for filtering + */ + public NodeMessageFilter(String messageId) { + this.messageId = messageId; + } + + public boolean filterNode(DTNHost node) { + return node.getRouter().hasMessage(messageId); + } + + @Override + public String toString() { + return "Filters nodes with message ID " + messageId; + } + +} diff --git a/gui/package.html b/gui/package.html new file mode 100644 index 000000000..308cdd55a --- /dev/null +++ b/gui/package.html @@ -0,0 +1,8 @@ + + + + +Contains the classes of Graphical User Interface. + + + \ No newline at end of file diff --git a/gui/playfield/MapGraphic.java b/gui/playfield/MapGraphic.java new file mode 100644 index 000000000..1ceb5a057 --- /dev/null +++ b/gui/playfield/MapGraphic.java @@ -0,0 +1,53 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui.playfield; + +import java.awt.Color; +import java.awt.Graphics2D; + +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; + +/** + * PlayfieldGraphic for SimMap visualization + * + */ +public class MapGraphic extends PlayFieldGraphic { + private SimMap simMap; + private final Color PATH_COLOR = Color.LIGHT_GRAY; + private final Color BG_COLOR = Color.WHITE; + + public MapGraphic(SimMap simMap) { + this.simMap = simMap; + + } + + // TODO: draw only once and store to buffer + @Override + public void draw(Graphics2D g2) { + Coord c,c2; + + if (simMap == null) { + return; + } + + g2.setColor(PATH_COLOR); + g2.setBackground(BG_COLOR); + + // draws all edges between map nodes (bidirectional edges twice) + for (MapNode n : simMap.getNodes()) { + c = n.getLocation(); + + // draw a line to adjacent nodes + for (MapNode n2 : n.getNeighbors()) { + c2 = n2.getLocation(); + g2.drawLine(scale(c2.getX()), scale(c2.getY()), + scale(c.getX()), scale(c.getY())); + } + } + } + +} diff --git a/gui/playfield/MessageGraphic.java b/gui/playfield/MessageGraphic.java new file mode 100644 index 000000000..14cd8ca7f --- /dev/null +++ b/gui/playfield/MessageGraphic.java @@ -0,0 +1,43 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui.playfield; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Polygon; + +import core.DTNHost; + +/** + * Visualization of a message + * + */ +public class MessageGraphic extends PlayFieldGraphic { + private Color msgColor = Color.RED; + + private DTNHost from; + private DTNHost to; + + public MessageGraphic(DTNHost from, DTNHost to) { + this.to = to; + this.from = from; + } + + @Override + public void draw(Graphics2D g2) { + g2.setColor(msgColor); + + int fromX = scale(from.getLocation().getX()); + int fromY = scale(from.getLocation().getY()); + int toX = scale(to.getLocation().getX()); + int toY = scale(to.getLocation().getY()); + + // line from "from host" to "to host" + Polygon p = new Polygon(new int[] {fromX, toX}, + new int[] {fromY,toY}, 2); + + g2.draw(p); + } +} diff --git a/gui/playfield/NodeGraphic.java b/gui/playfield/NodeGraphic.java new file mode 100644 index 000000000..dc746deff --- /dev/null +++ b/gui/playfield/NodeGraphic.java @@ -0,0 +1,208 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui.playfield; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Ellipse2D; +import java.util.ArrayList; +import java.util.List; + +import core.Connection; +import core.Coord; +import core.DTNHost; +import core.NetworkInterface; + +/** + * Visualization of a DTN Node + * + */ +public class NodeGraphic extends PlayFieldGraphic { + private static boolean drawCoverage; + private static boolean drawNodeName; + private static boolean drawConnections; + private static boolean drawBuffer; + private static List highlightedNodes; + + private static Color rangeColor = Color.GREEN; + private static Color conColor = Color.BLACK; + private static Color hostColor = Color.BLUE; + private static Color hostNameColor = Color.BLUE; + private static Color msgColor1 = Color.BLUE; + private static Color msgColor2 = Color.GREEN; + private static Color msgColor3 = Color.RED; + + private static Color highlightedNodeColor = Color.MAGENTA; + + private DTNHost node; + + public NodeGraphic(DTNHost node) { + this.node = node; + } + + @Override + public void draw(Graphics2D g2) { + drawHost(g2); + if (drawBuffer) { + drawMessages(g2); + } + } + + /** + * @return true if the node this graphic represents should be highlighted + */ + private boolean isHighlighted() { + if (highlightedNodes == null) { + return false; + } else { + return highlightedNodes.contains(node); + } + } + + /** + * Visualize node's location, radio ranges and connections + * @param g2 The graphic context to draw to + */ + private void drawHost(Graphics2D g2) { + Coord loc = node.getLocation(); + + if (drawCoverage && node.isRadioActive()) { + ArrayList interfaces = + new ArrayList(); + interfaces.addAll(node.getInterfaces()); + for (NetworkInterface ni : interfaces) { + double range = ni.getTransmitRange(); + Ellipse2D.Double coverage; + + coverage = new Ellipse2D.Double(scale(loc.getX()-range), + scale(loc.getY()-range), scale(range * 2), + scale(range * 2)); + + // draw the "range" circle + g2.setColor(rangeColor); + g2.draw(coverage); + } + } + + if (drawConnections) { + g2.setColor(conColor); + Coord c1 = node.getLocation(); + ArrayList conList = new ArrayList(); + // create a copy to prevent concurrent modification exceptions + conList.addAll(node.getConnections()); + for (Connection c : conList) { + DTNHost otherNode = c.getOtherNode(node); + Coord c2; + + if (otherNode == null) { + continue; /* disconnected before drawn */ + } + c2 = otherNode.getLocation(); + g2.drawLine(scale(c1.getX()), scale(c1.getY()), + scale(c2.getX()), scale(c2.getY())); + } + } + + + /* draw node rectangle */ + g2.setColor(hostColor); + g2.drawRect(scale(loc.getX()-1),scale(loc.getY()-1), + scale(2),scale(2)); + + if (isHighlighted()) { + g2.setColor(highlightedNodeColor); + g2.fillRect(scale(loc.getX()) - 3 ,scale(loc.getY()) - 3, 6, 6); + } + + if (drawNodeName) { + g2.setColor(hostNameColor); + // Draw node's address next to it + g2.drawString(node.toString(), scale(loc.getX()), + scale(loc.getY())); + } + } + + /** + * Sets whether radio coverage of nodes should be drawn + * @param draw If true, radio coverage is drawn + */ + public static void setDrawCoverage(boolean draw) { + drawCoverage = draw; + } + + /** + * Sets whether node's name should be displayed + * @param draw If true, node's name is displayed + */ + public static void setDrawNodeName(boolean draw) { + drawNodeName = draw; + } + + /** + * Sets whether node's connections to other nodes should be drawn + * @param draw If true, node's connections to other nodes is drawn + */ + public static void setDrawConnections(boolean draw) { + drawConnections = draw; + } + + /** + * Sets whether node's message buffer is shown + * @param draw If true, node's message buffer is drawn + */ + public static void setDrawBuffer(boolean draw) { + drawBuffer = draw; + } + + public static void setHighlightedNodes(List nodes) { + highlightedNodes = nodes; + } + + /** + * Visualize the messages this node is carrying + * @param g2 The graphic context to draw to + */ + private void drawMessages(Graphics2D g2) { + int nrofMessages = node.getNrofMessages(); + Coord loc = node.getLocation(); + + drawBar(g2,loc, nrofMessages % 10, 1); + drawBar(g2,loc, nrofMessages / 10, 2); + } + + /** + * Draws a bar (stack of squares) next to a location + * @param g2 The graphic context to draw to + * @param loc The location where to draw + * @param nrof How many squares in the stack + * @param col Which column + */ + private void drawBar(Graphics2D g2, Coord loc, int nrof, int col) { + final int BAR_HEIGHT = 5; + final int BAR_WIDTH = 5; + final int BAR_DISPLACEMENT = 2; + + // draws a stack of squares next loc + for (int i=1; i <= nrof; i++) { + if (i%2 == 0) { // use different color for every other msg + g2.setColor(msgColor1); + } + else { + if (col > 1) { + g2.setColor(msgColor3); + } + else { + g2.setColor(msgColor2); + } + } + + g2.fillRect(scale(loc.getX()-BAR_DISPLACEMENT-(BAR_WIDTH*col)), + scale(loc.getY()- BAR_DISPLACEMENT- i* BAR_HEIGHT), + scale(BAR_WIDTH), scale(BAR_HEIGHT)); + } + + } + +} diff --git a/gui/playfield/PathGraphic.java b/gui/playfield/PathGraphic.java new file mode 100644 index 000000000..a383971f5 --- /dev/null +++ b/gui/playfield/PathGraphic.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui.playfield; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.List; + +import movement.Path; +import core.Coord; + +/** + * Visualization of a Path + * + */ +public class PathGraphic extends PlayFieldGraphic { + private final static Color PATH_COLOR = Color.RED; + private List coords; + + public PathGraphic(Path path) { + if (path == null) { + this.coords = null; + } + else { + this.coords = path.getCoords(); + assert this.coords != null && this.coords.size() > 0 : + "No coordinates in the path (" + path + ")"; + } + } + + /** + * Draws a line trough all path's coordinates. + * @param g2 The graphics context to draw to + */ + @Override + public void draw(Graphics2D g2) { + if (coords == null) { + return; + } + + g2.setColor(PATH_COLOR); + Coord prev = coords.get(0); + + for (int i=1, n=coords.size(); i < n; i++) { + Coord next = coords.get(i); + g2.drawLine(scale(prev.getX()), scale(prev.getY()), + scale(next.getX()), scale(next.getY())); + prev = next; + } + } + +} diff --git a/gui/playfield/PlayField.java b/gui/playfield/PlayField.java new file mode 100644 index 000000000..a562041e4 --- /dev/null +++ b/gui/playfield/PlayField.java @@ -0,0 +1,310 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package gui.playfield; + +import gui.DTNSimGUI; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.swing.JPanel; + +import movement.Path; +import movement.map.SimMap; +import core.Coord; +import core.DTNHost; +import core.World; + +/** + * The canvas where node graphics and message visualizations are drawn. + * + */ +public class PlayField extends JPanel { + public static final int PLAYFIELD_OFFSET = 10; + + private World w; + private DTNSimGUI gui; + + private Color bgColor = Color.WHITE; + + private List overlayGraphics; + private boolean autoClearOverlay; // automatically clear overlay graphics + private MapGraphic mapGraphic; + private boolean showMapGraphic; + private ScaleReferenceGraphic refGraphic; + private boolean focusOnClick; + + private BufferedImage underlayImage; + private AffineTransform imageTransform; + private AffineTransform curTransform; + private double underlayImgDx; + private double underlayImgDy; + + /** + * Creates a playfield + * @param w The world that contains the actors to be drawn + */ + public PlayField (World w, DTNSimGUI gui) { + this.w = w; + this.gui = gui; + + this.refGraphic = new ScaleReferenceGraphic(); + updateFieldSize(); + this.setBackground(bgColor); + this.overlayGraphics = Collections.synchronizedList( + new ArrayList()); + this.mapGraphic = null; + this.underlayImage = null; + this.imageTransform = null; + this.autoClearOverlay = true; + + this.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (focusOnClick) { + focusClosestNode(e.getX(), e.getY()); + } + } + }); + } + + /** + * Schedule the play field to be drawn + */ + public void updateField() { + this.repaint(); + } + + /** + * Sets an image to show under the host graphics + * @param image The image to set or null to remove the image + * @param dx X offset of the image + * @param dy Y offset of the image + * @param scale Image scaling factor + * @param rotation Rotatation angle of the image (radians) + */ + public void setUnderlayImage(BufferedImage image, + double dx, double dy, double scale, double rotation) { + if (image == null) { + this.underlayImage = null; + this.imageTransform = null; + this.curTransform = null; + return; + } + this.underlayImage = image; + this.imageTransform = AffineTransform.getRotateInstance(rotation); + this.imageTransform.scale(scale, scale); + this.curTransform = new AffineTransform(imageTransform); + this.underlayImgDx = dx; + this.underlayImgDy = dy; + + curTransform.scale(PlayFieldGraphic.getScale(), + PlayFieldGraphic.getScale()); + curTransform.translate(this.underlayImgDx, this.underlayImgDy); + + } + + /** + * Sets the zooming/scaling factor + * @param scale The new scale + */ + public void setScale(double scale) { + PlayFieldGraphic.setScale(scale); + this.updateFieldSize(); + if (this.imageTransform != null) { + this.curTransform = new AffineTransform(imageTransform); + curTransform.scale(scale, scale); + curTransform.translate(this.underlayImgDx, this.underlayImgDy); + } + } + + /** + * Sets the source for the map graphics and enables map graphics showing + * @param simMap The map to show + */ + public void setMap(SimMap simMap) { + this.mapGraphic = new MapGraphic(simMap); + this.showMapGraphic = true; + } + + /** + * Enables/disables showing of map graphics + * @param show True if the map graphics should be shown (false if not) + */ + public void setShowMapGraphic(boolean show) { + this.showMapGraphic = show; + } + + /** + * Enables or disables the automatic clearing of overlay graphics. + * If enabled, overlay graphics are cleared every time a new graphics + * object is set to be drawn. + * @param clear Auto clear is enabled if this is true, disabled on false + */ + public void setAutoClearOverlay(boolean clear) { + this.autoClearOverlay = clear; + } + + /** + * Enables or disables the automatic clearing of overlay graphics. + * If enabled, overlay graphics are cleared every time a new graphics + * object is set to be drawn. + * @param clear Auto clear is enabled if this is true, disabled on false + */ + public void setFocusOnClick(boolean focus) { + this.focusOnClick = focus; + } + + /** + * Draws the play field. To be called by Swing framework or directly if + * different context than screen is desired + * @param g The graphics context to draw the field to + */ + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D)g; + g2.setBackground(bgColor); + + g2.translate(PLAYFIELD_OFFSET, PLAYFIELD_OFFSET); + + // clear old playfield graphics + g2.clearRect(-PLAYFIELD_OFFSET, -PLAYFIELD_OFFSET, + this.getWidth() + PLAYFIELD_OFFSET, + this.getHeight() + PLAYFIELD_OFFSET); + if (underlayImage != null) { + g2.drawImage(underlayImage,curTransform, null); + } + + // draw map (is exists and drawing requested) + if (mapGraphic != null && showMapGraphic) { + mapGraphic.draw(g2); + } + + // draw hosts + for (DTNHost h : w.getHosts()) { + new NodeGraphic(h).draw(g2); + } + + // draw overlay graphics + for (int i=0, n=overlayGraphics.size(); i= 1000) { + scaleUnit = "km"; + meterLen /= 1000; + } + endX = X_POS + (int)pixelLen; + + g2.setFont(new Font(null, Font.PLAIN, FONT_SIZE)); + + g2.setColor(REF_COLOR); + g2.drawLine(X_POS, Y_POS-h, X_POS, Y_POS+h); // left end + g2.drawLine(X_POS, Y_POS, endX, Y_POS); // horizontal line + g2.drawLine(endX, Y_POS-h, endX, Y_POS+h); + + g2.drawString(meterLen + scaleUnit, X_POS + 10, Y_POS - 1); + } + +} diff --git a/gui/playfield/package.html b/gui/playfield/package.html new file mode 100644 index 000000000..f469e8567 --- /dev/null +++ b/gui/playfield/package.html @@ -0,0 +1,9 @@ + + + + +Contains the classes of Graphical User Interface's playfield -view +(the graphical presentation of the nodes' locations and other information). + + + \ No newline at end of file diff --git a/input/BinaryEventsReader.java b/input/BinaryEventsReader.java new file mode 100644 index 000000000..b51b038cc --- /dev/null +++ b/input/BinaryEventsReader.java @@ -0,0 +1,137 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.List; + +import core.SimError; + +/** + * Reads External Events from a binary file. Can also create binary files + * from a list of external events. + */ +public class BinaryEventsReader implements ExternalEventsReader { + /** Extension of binary external events file */ + public static final String BINARY_EXT = ".binee"; + + private ObjectInputStream in; + private int eventsLeft; + + /** + * Constructor. + * @param eventsFile The file where the events are read + */ + public BinaryEventsReader(File eventsFile) { + try { + FileInputStream fis = new FileInputStream(eventsFile); + in = new ObjectInputStream(fis); + // first object should tell the amount of events + eventsLeft = (Integer)in.readObject(); + } catch (IOException e) { + throw new SimError(e); + } catch (ClassNotFoundException e) { + throw new SimError("Invalid binary input file for external " + + "events:" + eventsFile.getAbsolutePath(), e); + } + + } + + /** + * Read events from a binary file created with storeBinaryFile method + * @param nrof Maximum number of events to read + * @return Events in an ArrayList (empty list if didn't read any) + * @see #storeToBinaryFile(String, List) + */ + @SuppressWarnings("unchecked") // suppress cast warnings + public List readEvents(int nrof) { + ArrayList events = new ArrayList(nrof); + + if (eventsLeft == 0) { + return events; + } + + try { + for (int i=0; i < nrof && eventsLeft > 0; i++) { + events.add((ExternalEvent)in.readObject()); + eventsLeft--; + } + if (eventsLeft == 0) { + in.close(); + } + } catch (Exception e) { // FIXME: quick 'n' dirty exception handling + throw new SimError(e); + } + return events; + } + + /** + * Checks if the given file is a binary external events file + * @param file The file to check + * @return True if the file is a binary ee file, false if not + */ + public static boolean isBinaryEeFile(File file) { + if (!file.getName().endsWith(BINARY_EXT)) { + return false; + } + + // extension matches, try to read an event + try { + BinaryEventsReader r = new BinaryEventsReader(file); + r.readEvents(1); + r.close(); + } + catch (SimError e) { + return false; // read failed -> not a valid file + } + + return true; // seems to be a valid binary ee file + } + + /** + * Stores the events to a binary file + * @param fileName Path to the file where the events are stored + * @param events List of events to store + * @throws IOException if something in storing went wrong + */ + public static void storeToBinaryFile(String fileName, + List events) throws IOException { + + // make sure the file name ends with binary extension + if (!fileName.endsWith(BINARY_EXT)) { + fileName += "BINARY_EXT"; + } + + ObjectOutputStream out; + FileOutputStream fos = new FileOutputStream(fileName); + out = new ObjectOutputStream(fos); + + // store the number of events + out.writeObject(new Integer(events.size())); + + // store events + for (ExternalEvent ee : events) { + out.writeObject(ee); + } + + out.close(); + } + + public void close() { + try { + this.in.close(); + } + catch (IOException ioe) { + throw new SimError(ioe); + } + } + +} diff --git a/input/ConnectionEvent.java b/input/ConnectionEvent.java new file mode 100644 index 000000000..e5f616aa7 --- /dev/null +++ b/input/ConnectionEvent.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import core.DTNHost; +import core.World; + +/** + * A connection up/down event. + */ +public class ConnectionEvent extends ExternalEvent { + /** address of the node the (dis)connection is from */ + protected int fromAddr; + /** address of the node the (dis)connection is to */ + protected int toAddr; + /** Is this a "connection up" event*/ + protected boolean isUp; + /** What is the interface number for this event*/ + protected String interfaceId; + + /** + * Creates a new connection event + * @param from End point of connection + * @param to Another end of connection + * @param interf The number of interface for the connection + * @param up If true, this was a "connection up" event, if false, this + * was a "connection down" event + * @param time Time when the Connection event occurs + */ + public ConnectionEvent(int from, int to, String interf, boolean up, double time) { + super(time); + assert to != from : "Can't self connect"; + this.fromAddr = from; + this.toAddr= to; + this.isUp = up; + this.interfaceId = interf; + } + + @Override + public void processEvent(World world) { + DTNHost from = world.getNodeByAddress(this.fromAddr); + DTNHost to = world.getNodeByAddress(this.toAddr); + + from.forceConnection(to, interfaceId, this.isUp); + } + + @Override + public String toString() { + return "CONN " + (isUp ? "up" : "down") + " @" + this.time + " " + + this.fromAddr+"<->"+this.toAddr; + } +} diff --git a/input/DTN2Events.java b/input/DTN2Events.java new file mode 100644 index 000000000..ec0311648 --- /dev/null +++ b/input/DTN2Events.java @@ -0,0 +1,256 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package input; + +import fi.tkk.netlab.dtn.DTNConsoleConnection; +import fi.tkk.netlab.dtn.ecla.Bundle; +import fi.tkk.netlab.dtn.ecla.CLAInterface; +import fi.tkk.netlab.dtn.ecla.CLAParser; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; + +import core.DTN2Manager; +import core.Debug; +import core.Settings; +import core.SimClock; + +/** + * Delivers bundles from dtnd to ONE. Must be configured as an + * external events generator in the configuration file. + * @author teemuk + */ +public class DTN2Events implements EventQueue { + + private Queue events; + + /** + For keeping track of bundles we've seen in the past + Due to the routing implementation in dtnd it's likely + that dtnd will immediately return a bundle that is + forwarded to it from the ONE. */ + private Map bundle_list; + + /** + * Creates a new events object. + * @param s Settings + */ + public DTN2Events(Settings s) { + this.events = new LinkedList(); + this.bundle_list = new HashMap(); + DTN2Manager.setEvents(this); + } + + + //************************************************************************// + // ParserHandler // + //************************************************************************// + + /** + * Inner class that implements the CLA interface for receiving bundles from + * dtnd. + * @author teemuk + */ + public class ParserHandler implements CLAInterface { + private int host_id; + private DTN2Events events; + private String c_host; + private int c_port; + private DTNConsoleConnection console; + + /** + * Creates a new parser handler. + * @param hostID ID of the host that this parser corresponds to + * @param eventsHandler Reference to the events handler + * @param consoleHost Hostname of the dtnd + * @param consolePort Console port of the dtnd + */ + public ParserHandler(int hostID, DTN2Events eventsHandler, + String consoleHost, int consolePort) { + this.host_id = hostID; + this.events = eventsHandler; + this.c_host = consoleHost; + this.c_port = consolePort; + } + + //********************************************************************// + // CLAInterface Implementation // + //********************************************************************// + public BundleTransferReceipt incomingBundle(String location, + CLAParser.BundleAttributes attributes) { + FileInputStream f_in; + + CLAInterface.BundleTransferReceipt r = + new CLAInterface.BundleTransferReceipt(); + + // Open the bundle file + try { + f_in = new FileInputStream(new File(location)); + } catch (FileNotFoundException ex) { + Debug.p("CLAInterfaceImpl: Couldn't open file "+location+ + " (file not found)"); + return r; + } + + // Make a copy of the bundle + String filepath = "bundles/"+Math.round(Math.random()*1000000000)+ + ".bundle"; + File new_f = new File(filepath); + try { + while (!new_f.createNewFile()) { + filepath = "bundles/"+Math.round(Math.random()*1000000000)+ + ".bundle"; + new_f = new File(filepath); + } + FileOutputStream f_out = new FileOutputStream(new_f); + int i; + while ( (i=f_in.read()) != -1 ) { + f_out.write(i); + } + f_in.close(); + f_out.close(); + } catch (Exception e) { + // TBD + } + + // Parse the bundle + Bundle bundle = new Bundle(new_f); + + // Check that we haven't forwarded this bundle before + if (isReg(bundle)) { + r.reply = false; + r.bytes_sent = 0; + return r; + } else { + regMsg(bundle); + } + + // Lookup the receiving host + Collection c = + DTN2Manager.getHosts(bundle.destination_EID); + if (c==null || c.isEmpty()) { + Debug.p( "Couldn't find destination matching '" + + bundle.destination_EID+"'"); + r.reply = false; + r.bytes_sent = 0; + return r; + } + + // Create a message for each matched recipient + // XXX: Ideally we'd only have one message, + // but ONE requires each message to have exactly one recipient + for (DTN2Manager.EIDHost e : c) { + // Create a new message in the queue + this.events.enqueMsg(this.host_id, e.host_id, bundle); + } + + // Pretend we've transmitted the whole bundle + r.reply = true; + r.bytes_sent = bundle.file.length(); + + return r; + } + + public void connected() { + /* The ECLA has been connected, we can now set it up through + the console */ + this.console = new DTNConsoleConnection(this.c_host, this.c_port); + Thread t = new Thread(this.console); + t.start(); + this.console.queue("link add one dtn:one ALWAYSON extcl " + + "protocol=ONE\n"); + this.console.queue("route add \"dtn://*\" one\n"); + } + + public boolean error(String reason, Exception exception, + boolean fatal) { + return false; + } + + public boolean parseError(String reason) { + return false; + } + //********************************************************************// + } + //************************************************************************// + + + + //************************************************************************// + // EventQueue Implementation // + //************************************************************************// + public ExternalEvent nextEvent() { + if (!this.events.isEmpty()) { + return this.events.remove(); + } else + return new ExternalEvent(Double.MAX_VALUE); + } + + public double nextEventsTime() { + if (!this.events.isEmpty()) + return SimClock.getTime(); + else + return Double.MAX_VALUE; + } + //************************************************************************// + + + //************************************************************************// + // Public Methods // + //************************************************************************// + + /** + * Creates a parser handler for the given host. + * @param hostID ID of the host that this parser corresponds to + * @param consoleHost Hostname of the dtnd + * @param consolePort Console port of the dtnd + */ + public DTN2Events.ParserHandler getParserHandler(int hostID, + String consoleHost, int consolePort) { + return new ParserHandler(hostID, this, consoleHost, consolePort); + } + //************************************************************************// + + + //************************************************************************// + // Private Methods // + //************************************************************************// + private void enqueMsg(int from, int to, Bundle bundle) { + String id; + id = "bundle."+from+"-"+to+"-"+bundle.creation_timestamp_time+ + "-"+bundle.creation_timestamp_seq_no; + MessageCreateEvent e = new MessageCreateEvent(from, to, id, + (int)(bundle.file.length()), 0, SimClock.getTime()); + synchronized (this.events) { + this.events.add(e); + } + DTN2Manager.addBundle(id,bundle); + } + + // Keep track of the bundles we've received + private void regMsg(Bundle bundle) { + String key = bundle.source_EID+":"+bundle.destination_EID+":"+ + bundle.creation_timestamp_time+":"+bundle.creation_timestamp_seq_no; + if (!this.bundle_list.containsKey(key)) + this.bundle_list.put(key,null); + } + + // Check if the bundle has been received before + private boolean isReg(Bundle bundle) { + String key = bundle.source_EID+":"+bundle.destination_EID+":"+ + bundle.creation_timestamp_time+":"+bundle.creation_timestamp_seq_no; + return this.bundle_list.containsKey(key); + } + //************************************************************************// + +} diff --git a/input/EventQueue.java b/input/EventQueue.java new file mode 100644 index 000000000..df0c67bd9 --- /dev/null +++ b/input/EventQueue.java @@ -0,0 +1,30 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +/** + * Interface for event queues. Any class that is not a movement model or a + * routing module but wishes to provide events for the simulation (like creating + * messages) must implement this interface and register itself to the + * simulator. See the {@link EventQueueHandler} class for configuration + * instructions. + */ +public interface EventQueue { + + /** + * Returns the next event in the queue or ExternalEvent with time of + * double.MAX_VALUE if there are no events left. + * @return The next event + */ + public ExternalEvent nextEvent(); + + /** + * Returns next event's time or Double.MAX_VALUE if there are no + * events left in the queue. + * @return Next event's time + */ + public double nextEventsTime(); + +} diff --git a/input/EventQueueHandler.java b/input/EventQueueHandler.java new file mode 100644 index 000000000..90fa5f4d7 --- /dev/null +++ b/input/EventQueueHandler.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.ArrayList; +import java.util.List; + +import core.Settings; + +/** + *

+ * Handler for managing event queues. Supports two different type of event + * queues: external event queues and event generator classes. + * For external event queues, the events are defined in external data + * file(s) (see e.g. input.StandarEventsReader). Event generator classes + * define events dynamically. Both type of event queues must implement + * the input.EventQueue interface. + *

+ * The total number of event queues to load is defined with variable + * NROF_SETTING, e.g.
+ * Events.nrof = 3
+ * Separate event queues are configured with syntax + * EventsN.variable = value e.g.:
+ * Events1.filePath = ee/messages.txt
+ * or
+ * Events2.class = RandomMessageGenerator + *

+ * External event files are used when the variable PATH_SETTING + * is used to define the path to the event file and event generator class + * is loaded when the name of the class is defined with + * CLASS_SETTING. + */ +public class EventQueueHandler { + /** Event queue settings main namespace ({@value})*/ + public static final String SETTINGS_NAMESPACE = "Events"; + /** number of event queues -setting id ({@value})*/ + public static final String NROF_SETTING = "nrof"; + + /** name of the events class (for class based events) -setting id + * ({@value}) */ + public static final String CLASS_SETTING = "class"; + /** name of the package where event generator classes are looked from */ + public static final String CLASS_PACKAGE = "input"; + + /** number of events to preload from file -setting id ({@value})*/ + public static final String PRELOAD_SETTING = "nrofPreload"; + /** path of external events file -setting id ({@value})*/ + public static final String PATH_SETTING = "filePath"; + + private List queues; + + /** + * Creates a new EventQueueHandler which can be queried for + * event queues. + */ + public EventQueueHandler() { + Settings settings = new Settings(SETTINGS_NAMESPACE); + int nrof = settings.getInt(NROF_SETTING); + this.queues = new ArrayList(); + + for (int i=1; i <= nrof; i++) { + Settings s = new Settings(SETTINGS_NAMESPACE + i); + + if (s.contains(PATH_SETTING)) { // external events file + int preload = 0; + String path = ""; + if (s.contains(PRELOAD_SETTING)) { + preload = s.getInt(PRELOAD_SETTING); + } + path = s.getSetting(PATH_SETTING); + + queues.add(new ExternalEventsQueue(path, preload)); + } + else if (s.contains(CLASS_SETTING)) { // event generator class + String className = CLASS_PACKAGE + "." + + s.getSetting(CLASS_SETTING); + EventQueue eq = (EventQueue)s.createIntializedObject(className); + + queues.add(eq); + } + } + } + + /** + * Returns all the loaded event queues + * @return all the loaded event queues + */ + public List getEventQueues() { + return this.queues; + } + +} diff --git a/input/ExternalEvent.java b/input/ExternalEvent.java new file mode 100644 index 000000000..9a81fc86c --- /dev/null +++ b/input/ExternalEvent.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.io.Serializable; + +import core.World; + +/** + * Super class for all external events. All new classes of external events + * must extend this class. This can also be used as a dummy event if only + * an update request (and no further actions) to all hosts is needed. + */ +public class ExternalEvent implements Comparable, Serializable { + /** Time of the event (simulated seconds) */ + protected double time; + + public ExternalEvent(double time) { + this.time = time; + } + + /** + * Processes the external event. + * @param world World where the actors of the event are + */ + public void processEvent(World world) { + // this is just a dummy event + } + + /** + * Returns the time when this event should happen. + * @return Event's time + */ + public double getTime() { + return this.time; + } + + /** + * Compares two external events by their time. + * @return -1, zero, 1 if this event happens before, at the same time, + * or after the other event + * @param other The other external event + */ + public int compareTo(ExternalEvent other) { + if (this.time == other.time) { + return 0; + } + else if (this.time < other.time) { + return -1; + } + else { + return 1; + } + } + + /** + * Returns a String representation of the event + * @return a String representation of the event + */ + public String toString() { + return "ExtEvent @ " + this.time; + } + +} diff --git a/input/ExternalEventsQueue.java b/input/ExternalEventsQueue.java new file mode 100644 index 000000000..108540a20 --- /dev/null +++ b/input/ExternalEventsQueue.java @@ -0,0 +1,163 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import core.Settings; + +/** + * Queue of external events. This class also takes care of buffering + * the events and preloading only a proper amount of them. + */ +public class ExternalEventsQueue implements EventQueue { + /** ExternalEvents namespace ({@value})*/ + public static final String SETTINGS_NAMESPACE = "ExternalEvents"; + /** number of event to preload -setting id ({@value})*/ + public static final String PRELOAD_SETTING = "nrofPreload"; + /** path of external events file -setting id ({@value})*/ + public static final String PATH_SETTING = "filePath"; + + /** default number of preloaded events */ + public static final int DEFAULT_NROF_PRELOAD = 500; + + private File eventsFile; + private ExternalEventsReader reader; + private int nextEventIndex; + private int nrofPreload; + private List queue; + private boolean allEventsRead = false; + + /** + * Creates a new Queue from a file + * @param filePath Path to the file where the events are read from. If + * file ends with extension defined in {@link BinaryEventsReader#BINARY_EXT} + * the file is assumed to be a binary file. + * @param nrofPreload How many events to preload + * @see BinaryEventsReader#BINARY_EXT + * @see BinaryEventsReader#storeToBinaryFile(String, List) + */ + public ExternalEventsQueue(String filePath, int nrofPreload) { + setNrofPreload(nrofPreload); + init(filePath); + } + + /** + * Create a new Queue based on the given settings: {@link #PRELOAD_SETTING} + * and {@link #PATH_SETTING}. The path setting supports value filling. + * @param s The settings + */ + public ExternalEventsQueue(Settings s) { + if (s.contains(PRELOAD_SETTING)) { + setNrofPreload(s.getInt(PRELOAD_SETTING)); + } + else { + setNrofPreload(DEFAULT_NROF_PRELOAD); + } + String eeFilePath = s.valueFillString(s.getSetting(PATH_SETTING)); + init(eeFilePath); + } + + /** + * Sets maximum number of events that are read when the next preload occurs + * @param nrof Maximum number of events to read. If less than 1, default + * value ( {@value DEFAULT_NROF_PRELOAD} ) is used. + */ + public void setNrofPreload(int nrof) { + if (nrof < 1) { + nrof = DEFAULT_NROF_PRELOAD; + } + this.nrofPreload = nrof; + } + + private void init(String eeFilePath) { + this.eventsFile = new File(eeFilePath); + + if (BinaryEventsReader.isBinaryEeFile(eventsFile)) { + this.reader = new BinaryEventsReader(eventsFile); + } + else { + this.reader = new StandardEventsReader(eventsFile); + } + + this.queue = readEvents(nrofPreload); + this.nextEventIndex = 0; + } + + /** + * Returns next event's time or Double.MAX_VALUE if there are no + * events left + * @return Next event's time + */ + public double nextEventsTime() { + if (eventsLeftInBuffer() <= 0 ) { + // in case user request time of an event that doesn't exist + return Double.MAX_VALUE; + } + else { + return queue.get(nextEventIndex).getTime(); + } + } + + /** + * Returns the next event in the queue or ExternalEvent with time of + * double.MAX_VALUE if there are no events left + * @return The next event + */ + public ExternalEvent nextEvent() { + if (queue.size() == 0) { // no more events + return new ExternalEvent(Double.MAX_VALUE); + } + + ExternalEvent ee = queue.get(nextEventIndex); + nextEventIndex++; + + if (nextEventIndex >= queue.size()) { // ran out of events + queue = readEvents(nrofPreload); + nextEventIndex = 0; + } + + return ee; + } + + /** + * Returns the amount of events left in the buffer at the moment + * (the amount can increase later if more events are read). + * @return The amount of events left or 0 there aren't any events + */ + public int eventsLeftInBuffer() { + if (queue == null || queue.size() == 0) { + return 0; + } + else { + return this.queue.size() - this.nextEventIndex; + } + } + + + /** + * Read some events from the external events reader + * @param nrof Maximum number of events to read + * @return A List of events that were read or an empty list if no events + * could be read + */ + private List readEvents(int nrof) { + if (allEventsRead) { + return new ArrayList(0); + } + + List events = reader.readEvents(nrof); + + if (nrof > 0 && events.size() == 0) { + reader.close(); + allEventsRead = true; + } + + return events; + } + +} diff --git a/input/ExternalEventsReader.java b/input/ExternalEventsReader.java new file mode 100644 index 000000000..01fc065df --- /dev/null +++ b/input/ExternalEventsReader.java @@ -0,0 +1,27 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.List; + +/** + * Interface for external event readers. + */ +public interface ExternalEventsReader { + + /** + * Read events from the reader + * @param nrof Maximum number of events to read + * @return Events in a List + */ + public List readEvents(int nrof); + + /** + * Closes the input file streams of the reader. + */ + public void close(); + + +} diff --git a/input/ExternalMovementReader.java b/input/ExternalMovementReader.java new file mode 100644 index 000000000..1ef7a480f --- /dev/null +++ b/input/ExternalMovementReader.java @@ -0,0 +1,216 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +import util.Tuple; + +import core.Coord; +import core.SettingsError; + + +/** + * Reader for ExternalMovement movement model's time-location tuples. + *

+ * First line of the file should be the offset header. Syntax of the header + * should be:
+ * minTime maxTime minX maxX minY maxY minZ maxZ + *
+ * Last two values (Z-axis) are ignored at the moment but can be present + * in the file. + *

+ * Following lines' syntax should be:
+ * time id xPos yPos
+ * where time is the time when a node with id should + * be at location (xPos, yPos). + *

+ *

+ * All lines must be sorted by time. Sampling interval (time difference between + * two time instances) must be same for the whole file. + *

+ */ +public class ExternalMovementReader { + /* Prefix for comment lines (lines starting with this are ignored) */ + public static final String COMMENT_PREFIX = "#"; + private Scanner scanner; + private double lastTimeStamp = -1; + private String lastLine; + private double minTime; + private double maxTime; + private double minX; + private double maxX; + private double minY; + private double maxY; + private boolean normalize; + + + /** + * Constructor. Creates a new reader that reads the data from a file. + * @param inFilePath Path to the file where the data is read + * @throws SettingsError if the file wasn't found + */ + public ExternalMovementReader(String inFilePath) { + this.normalize = true; + File inFile = new File(inFilePath); + try { + scanner = new Scanner(inFile); + } catch (FileNotFoundException e) { + throw new SettingsError("Couldn't find external movement input " + + "file " + inFile); + } + + String offsets = scanner.nextLine(); + + try { + Scanner lineScan = new Scanner(offsets); + minTime = lineScan.nextDouble(); + maxTime = lineScan.nextDouble(); + minX = lineScan.nextDouble(); + maxX = lineScan.nextDouble(); + minY = lineScan.nextDouble(); + maxY = lineScan.nextDouble(); + } catch (Exception e) { + throw new SettingsError("Invalid offset line '" + offsets + "'"); + } + + lastLine = scanner.nextLine(); + } + + /** + * Sets normalizing of read values on/off. If on, values returned by + * {@link #readNextMovements()} are decremented by minimum values of the + * offsets. Default is on (normalize). + * @param normalize If true, normalizing is on (false -> off). + */ + public void setNormalize(boolean normalize) { + this.normalize = normalize; + } + + /** + * Reads all new id-coordinate tuples that belong to the same time instance + * @return A list of tuples or empty list if there were no more moves + * @throws SettingError if an invalid line was read + */ + public List> readNextMovements() { + ArrayList> moves = + new ArrayList>(); + + if (!scanner.hasNextLine()) { + return moves; + } + + Scanner lineScan = new Scanner(lastLine); + double time = lineScan.nextDouble(); + String id = lineScan.next(); + double x = lineScan.nextDouble(); + double y = lineScan.nextDouble(); + + if (normalize) { + time -= minTime; + x -= minX; + y -= minY; + } + + lastTimeStamp = time; + + while (scanner.hasNextLine() && lastTimeStamp == time) { + lastLine = scanner.nextLine(); + + if (lastLine.trim().length() == 0 || + lastLine.startsWith(COMMENT_PREFIX)) { + continue; /* skip empty and comment lines */ + } + + // add previous line's tuple + moves.add(new Tuple(id, new Coord(x,y))); + + lineScan = new Scanner(lastLine); + + try { + time = lineScan.nextDouble(); + id = lineScan.next(); + x = lineScan.nextDouble(); + y = lineScan.nextDouble(); + } catch (Exception e) { + throw new SettingsError("Invalid line '" + lastLine + "'"); + } + + if (normalize) { + time -= minTime; + x -= minX; + y -= minY; + } + } + + if (!scanner.hasNextLine()) { // add the last tuple of the file + moves.add(new Tuple(id, new Coord(x,y))); + } + + return moves; + } + + /** + * Returns the time stamp where the last moves read with + * {@link #readNextMovements()} belong to. + * @return The time stamp + */ + public double getLastTimeStamp() { + return lastTimeStamp; + } + + /** + * Returns offset maxTime + * @return the maxTime + */ + public double getMaxTime() { + return maxTime; + } + + /** + * Returns offset maxX + * @return the maxX + */ + public double getMaxX() { + return maxX; + } + + /** + * Returns offset maxY + * @return the maxY + */ + public double getMaxY() { + return maxY; + } + + /** + * Returns offset minTime + * @return the minTime + */ + public double getMinTime() { + return minTime; + } + + /** + * Returns offset minX + * @return the minX + */ + public double getMinX() { + return minX; + } + + /** + * Returns offset minY + * @return the minY + */ + public double getMinY() { + return minY; + } + +} diff --git a/input/ExternalPathMovementReader.java b/input/ExternalPathMovementReader.java new file mode 100644 index 000000000..b49d95628 --- /dev/null +++ b/input/ExternalPathMovementReader.java @@ -0,0 +1,353 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package input; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import core.SettingsError; + + +/** + *

External movement reader for traces that are in path format. Uses two + * trace files, one for the paths and one for specifying activity times. + * Nodes will follow the paths in the trace file, and pause between paths. + * Activity times refer to the periods of time when there is valid trace data + * about the node.

+ * + *

Reads external traces that are of the form:

+ * id time_1,x_1,y_1 time_2,x_2,y_2 ... \n + * + *

The first line should be: + * maxID minTime maxTime minX maxX minY maxY + * + *

Activity trace file format is:

+ * id activeStart activeEnd\n + * + *

+ * The ID in the trace files must match IDs of nodes in the simulation, the + * coordinates must match the ONE coordinate system (units in meters) and the + * times must match the ONE simulation time. + *

+ * + *

Trace and activity files ending in .zip are assumed to be + * compressed and will be automatically uncompressed during reading. The whole + * trace is loaded into memory at once.

+ * + * @author teemuk + * + */ +public class ExternalPathMovementReader { + // Singletons are evil, but I'm lazy + private static Map singletons = + new HashMap(); + + /** + * Represents a point on the path. + */ + public class Entry { + public double time; + public double x; + public double y; + } + + /** + * Describes a node's activity time + */ + public class ActiveTime { + public double start; + public double end; + } + + // Path cache + private List>> paths = null; + // Activity cache + private List> activeTimes = null; + + // Settings + private boolean normalize = true; + private double minTime; + private double maxTime; + private double minX; + private double maxX; + private double minY; + private double maxY; + private int maxID; + + /** + * Creates a new reader by parsing the given files and building the internal + * caches. + * + * @param traceFilePath path to the trace file + * @param activityFilePath path to the activity file + */ + private ExternalPathMovementReader(String traceFilePath, + String activityFilePath) throws IOException { + // Open the trace file for reading + File inFile = new File(traceFilePath); + long traceSize = inFile.length(); + long totalRead = 0; + long readSize = 0; + long printSize = 5*1024*1024; + + BufferedReader reader = null; + try { + if (traceFilePath.endsWith(".zip")) { + // Grab the first entry from the zip file + // TODO: try to find the correct entry based on file name + ZipFile zf = new ZipFile(traceFilePath); + ZipEntry ze = zf.entries().nextElement(); + reader = new BufferedReader( + new InputStreamReader(zf.getInputStream(ze))); + traceSize = ze.getSize(); + } else { + reader = new BufferedReader( + new FileReader(traceFilePath)); + } + } catch (FileNotFoundException e1) { + throw new SettingsError("Couldn't find external movement input " + + "file " + inFile); + } + + /*Scanner scanner = null; + try { + scanner = new Scanner(inFile); + } catch (FileNotFoundException e) { + throw new SettingsError("Couldn't find external movement input " + + "file " + inFile); + }*/ + + // Parse header + String offsets = reader.readLine(); + if (offsets == null) { + throw new SettingsError("No offset line found."); + } + readSize += offsets.length() + 1; + try { + Scanner lineScan = new Scanner(offsets); + this.maxID = lineScan.nextInt(); + this.minTime = lineScan.nextDouble(); + this.maxTime = lineScan.nextDouble(); + this.minX = lineScan.nextDouble(); + this.maxX = lineScan.nextDouble(); + this.minY = lineScan.nextDouble(); + this.maxY = lineScan.nextDouble(); + } catch (Exception e) { + throw new SettingsError("Invalid offset line '" + offsets + "'"); + } + + // Initialize path cache + this.paths = new ArrayList>>(this.maxID + 1); + for (int i=0; i<=this.maxID; i++) { + this.paths.add(i, new LinkedList>()); + } + + // Parse traces + String line = reader.readLine(); + while (line != null) { + + readSize += line.length() + 1; + if (readSize >= printSize) { + totalRead += readSize; + readSize = 0; + System.out.println("Processed " + (totalRead/1024) + "KB out" + + " of " + (traceSize/1024) + "KB (" + + Math.round(100.0*totalRead/traceSize) + "%)"); + } + + if (line.equals("")) { + line = reader.readLine(); + continue; // Skip empty lines + } + Scanner traceScan = new Scanner(line); + int id = traceScan.nextInt(); + List> paths = this.paths.get(id); + List path = new LinkedList(); + while (traceScan.hasNext()) { + String dataPoint = traceScan.next(); + int d1 = dataPoint.indexOf(','); + int d2 = dataPoint.indexOf(',', d1+1); + + Entry e = new Entry(); + e.time = Double.parseDouble(dataPoint.substring(0, d1)); + e.x = Double.parseDouble(dataPoint.substring(d1+1, d2)); + e.y = Double.parseDouble(dataPoint.substring(d2+1)); + + if (this.normalize) { + e.time -= this.minTime; + e.x -= this.minX; + e.y -= this.minY; + } + + path.add(e); + } + paths.add(path); + + line = reader.readLine(); + } + + // Parse activity times + inFile = new File(activityFilePath); + reader = null; + try { + if (activityFilePath.endsWith(".zip")) { + // Grab the first entry from the zip file + // TODO: try to find the correct entry based on file name + ZipFile zf = new ZipFile(activityFilePath); + ZipEntry ze = zf.entries().nextElement(); + reader = new BufferedReader( + new InputStreamReader(zf.getInputStream(ze))); + } else { + reader = new BufferedReader( + new FileReader(activityFilePath)); + } + } catch (FileNotFoundException e) { + throw new SettingsError("Couldn't find external activity input " + + "file " + inFile); + } + + // Init activity cache + this.activeTimes = new ArrayList>(this.maxID + 1); + for (int i=0; i<=this.maxID; i++) { + this.activeTimes.add(new LinkedList()); + } + + // Parse the file + line = reader.readLine(); + while (line != null) { + Scanner traceScan = new Scanner(line); + int id = traceScan.nextInt(); + double start = traceScan.nextDouble(); + double end = traceScan.nextDouble(); + List times = this.activeTimes.get(id); + ActiveTime a = new ActiveTime(); + a.start = start; + a.end = end; + if (this.normalize) { + a.start -= this.minTime; + a.end -= this.minTime; + } + times.add(a); + + line = reader.readLine(); + } + } + + /** + * Returns the path for the node with the given ID. + * + * @param ID ID of the node + * @return full path for the node. + */ + public List> getPaths(int ID) { + return this.paths.get(ID); + } + + /** + * Returns the active time for the given ID. + * + * @param ID ID of the node + * @return active times for the node. + */ + public List getActive(int ID) { + return this.activeTimes.get(ID); + } + + /** + * Sets normalizing of read values on/off. If on, values returned by + * {@link #readNextMovements()} are decremented by minimum values of the + * offsets. Default is on (normalize). + * @param normalize If true, normalizing is on (false -> off). + */ + public void setNormalize(boolean normalize) { + this.normalize = normalize; + } + + + /** + * Returns offset maxTime + * @return the maxTime + */ + public double getMaxTime() { + return maxTime; + } + + /** + * Returns offset maxX + * @return the maxX + */ + public double getMaxX() { + return maxX; + } + + /** + * Returns offset maxY + * @return the maxY + */ + public double getMaxY() { + return maxY; + } + + /** + * Returns offset minTime + * @return the minTime + */ + public double getMinTime() { + return minTime; + } + + /** + * Returns offset minX + * @return the minX + */ + public double getMinX() { + return minX; + } + + /** + * Returns offset minY + * @return the minY + */ + public double getMinY() { + return minY; + } + + + /** + * Get an instance of the reader for the given file path. If the file has + * already been read previously it will not be read again and instead the + * previous instance of the reader will be returned. + * + * @param filePath path where the file is read from + * @return instance of the reader that has loaded all the paths from the + * given trace file. + */ + public static ExternalPathMovementReader getInstance(String traceFilePath, + String activeFilePath) { + if (!ExternalPathMovementReader.singletons.containsKey(traceFilePath)) { + try { + ExternalPathMovementReader.singletons.put(traceFilePath, + new ExternalPathMovementReader(traceFilePath, + activeFilePath)); + } catch (IOException e) { + System.exit(1); + } + } + return ExternalPathMovementReader.singletons.get(traceFilePath); + } +} diff --git a/input/MessageBurstGenerator.java b/input/MessageBurstGenerator.java new file mode 100644 index 000000000..1dcb0b11e --- /dev/null +++ b/input/MessageBurstGenerator.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import core.Settings; + +/** + * Message creation -external events generator. Creates bursts of messages where + * every source node (defined with {@link MessageEventGenerator#HOST_RANGE_S}) + * creates a new message to every destination node (defined with + * {@link MessageEventGenerator#TO_HOST_RANGE_S})on every interval. + * The message size, burst times, and inter-burst intervals can be configured + * like with {@link MessageEventGenerator}. + * @see MessageEventGenerator + */ +public class MessageBurstGenerator extends MessageEventGenerator { + /** next index to use from the "from" range */ + private int nextFromOffset; + private int nextToOffset; + + public MessageBurstGenerator(Settings s) { + super(s); + this.nextFromOffset = 0; + this.nextToOffset = 0; + + if (this.toHostRange == null) { + this.toHostRange = this.hostRange; + } + } + + /** + * Returns the next message creation event + * @see input.EventQueue#nextEvent() + */ + public ExternalEvent nextEvent() { + int responseSize = 0; /* no responses requested */ + int msgSize; + int interval; + int from; + int to; + boolean nextBurst = false; + + from = this.hostRange[0] + nextFromOffset; + to = this.toHostRange[0] + nextToOffset; + + if (to == from) { /* skip self */ + to = this.toHostRange[0] + (++nextToOffset); + } + + msgSize = drawMessageSize(); + MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), + msgSize, responseSize, this.nextEventsTime); + + if (to < this.toHostRange[1] - 1) { + this.nextToOffset++; + } else { + if (from < this.hostRange[1] - 1) { + this.nextFromOffset++; + this.nextToOffset = 0; + } else { + nextBurst = true; + } + } + + if (this.hostRange[0] + nextFromOffset == + this.toHostRange[0] + nextToOffset) { + /* to and from would be same for next event */ + nextToOffset++; + if (nextToOffset >= toHostRange[1]) { + /* TODO: doesn't work correctly with non-aligned ranges */ + nextBurst = true; + } + } + + if (nextBurst) { + interval = drawNextEventTimeDiff(); + this.nextEventsTime += interval; + this.nextFromOffset = 0; + this.nextToOffset = 0; + } + + if (this.msgTime != null && this.nextEventsTime > this.msgTime[1]) { + /* next event would be later than the end time */ + this.nextEventsTime = Double.MAX_VALUE; + } + + return mce; + } + +} \ No newline at end of file diff --git a/input/MessageCreateEvent.java b/input/MessageCreateEvent.java new file mode 100644 index 000000000..27d8f0236 --- /dev/null +++ b/input/MessageCreateEvent.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import core.DTNHost; +import core.Message; +import core.World; + +/** + * External event for creating a message. + */ +public class MessageCreateEvent extends MessageEvent { + private int size; + private int responseSize; + + /** + * Creates a message creation event with a optional response request + * @param from The creator of the message + * @param to Where the message is destined to + * @param id ID of the message + * @param size Size of the message + * @param responseSize Size of the requested response message or 0 if + * no response is requested + * @param time Time, when the message is created + */ + public MessageCreateEvent(int from, int to, String id, int size, + int responseSize, double time) { + super(from,to, id, time); + this.size = size; + this.responseSize = responseSize; + } + + + /** + * Creates the message this event represents. + */ + @Override + public void processEvent(World world) { + DTNHost to = world.getNodeByAddress(this.toAddr); + DTNHost from = world.getNodeByAddress(this.fromAddr); + + Message m = new Message(from, to, this.id, this.size); + m.setResponseSize(this.responseSize); + from.createNewMessage(m); + } + + @Override + public String toString() { + return super.toString() + " [" + fromAddr + "->" + toAddr + "] " + + "size:" + size + " CREATE"; + } +} diff --git a/input/MessageDeleteEvent.java b/input/MessageDeleteEvent.java new file mode 100644 index 000000000..b29671779 --- /dev/null +++ b/input/MessageDeleteEvent.java @@ -0,0 +1,59 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.ArrayList; +import java.util.List; + +import core.DTNHost; +import core.Message; +import core.World; + +/** + * External event for deleting a message. + */ + +public class MessageDeleteEvent extends MessageEvent { + /** is the delete caused by a drop (not "normal" removing) */ + private boolean drop; + + /** + * Creates a message delete event + * @param host Where to delete the message + * @param id ID of the message + * @param time Time when the message is deleted + */ + public MessageDeleteEvent(int host, String id, double time, + boolean drop) { + super(host, host, id, time); + this.drop = drop; + } + + /** + * Deletes the message + */ + @Override + public void processEvent(World world) { + DTNHost host = world.getNodeByAddress(this.fromAddr); + + if (id.equals(StandardEventsReader.ALL_MESSAGES_ID)) { + List ids = new ArrayList(); + for (Message m : host.getMessageCollection()) { + ids.add(m.getId()); + } + for (String nextId : ids) { + host.deleteMessage(nextId, drop); + } + } else { + host.deleteMessage(id, drop); + } + } + + @Override + public String toString() { + return super.toString() + " [" + fromAddr + "] DELETE"; + } + +} diff --git a/input/MessageEvent.java b/input/MessageEvent.java new file mode 100644 index 000000000..fb267b143 --- /dev/null +++ b/input/MessageEvent.java @@ -0,0 +1,36 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +/** + * A message related external event + */ +public abstract class MessageEvent extends ExternalEvent { + /** address of the node the message is from */ + protected int fromAddr; + /** address of the node the message is to */ + protected int toAddr; + /** identifier of the message */ + protected String id; + + /** + * Creates a message event + * @param from Where the message comes from + * @param to Who the message goes to + * @param id ID of the message + * @param time Time when the message event occurs + */ + public MessageEvent(int from, int to, String id, double time) { + super(time); + this.fromAddr = from; + this.toAddr= to; + this.id = id; + } + + @Override + public String toString() { + return "MSG @" + this.time + " " + id; + } +} diff --git a/input/MessageEventGenerator.java b/input/MessageEventGenerator.java new file mode 100644 index 000000000..1c9aa45bd --- /dev/null +++ b/input/MessageEventGenerator.java @@ -0,0 +1,231 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.Random; + +import core.Settings; +import core.SettingsError; + +/** + * Message creation -external events generator. Creates uniformly distributed + * message creation patterns whose message size and inter-message intervals can + * be configured. + */ +public class MessageEventGenerator implements EventQueue { + /** Message size range -setting id ({@value}). Can be either a single + * value or a range (min, max) of uniformly distributed random values. + * Defines the message size (bytes). */ + public static final String MESSAGE_SIZE_S = "size"; + /** Message creation interval range -setting id ({@value}). Can be either a + * single value or a range (min, max) of uniformly distributed + * random values. Defines the inter-message creation interval (seconds). */ + public static final String MESSAGE_INTERVAL_S = "interval"; + /** Sender/receiver address range -setting id ({@value}). + * The lower bound is inclusive and upper bound exclusive. */ + public static final String HOST_RANGE_S = "hosts"; + /** (Optional) receiver address range -setting id ({@value}). + * If a value for this setting is defined, the destination hosts are + * selected from this range and the source hosts from the + * {@link #HOST_RANGE_S} setting's range. + * The lower bound is inclusive and upper bound exclusive. */ + public static final String TO_HOST_RANGE_S = "tohosts"; + + /** Message ID prefix -setting id ({@value}). The value must be unique + * for all message sources, so if you have more than one message generator, + * use different prefix for all of them. The random number generator's + * seed is derived from the prefix, so by changing the prefix, you'll get + * also a new message sequence. */ + public static final String MESSAGE_ID_PREFIX_S = "prefix"; + /** Message creation time range -setting id ({@value}). Defines the time + * range when messages are created. No messages are created before the first + * and after the second value. By default, messages are created for the + * whole simulation time. */ + public static final String MESSAGE_TIME_S = "time"; + + /** Time of the next event (simulated seconds) */ + protected double nextEventsTime = 0; + /** Range of host addresses that can be senders or receivers */ + protected int[] hostRange = {0, 0}; + /** Range of host addresses that can be receivers */ + protected int[] toHostRange = null; + /** Next identifier for a message */ + private int id = 0; + /** Prefix for the messages */ + protected String idPrefix; + /** Size range of the messages (min, max) */ + private int[] sizeRange; + /** Interval between messages (min, max) */ + private int[] msgInterval; + /** Time range for message creation (min, max) */ + protected double[] msgTime; + + /** Random number generator for this Class */ + protected Random rng; + + /** + * Constructor, initializes the interval between events, + * and the size of messages generated, as well as number + * of hosts in the network. + * @param s Settings for this generator. + */ + public MessageEventGenerator(Settings s){ + this.sizeRange = s.getCsvInts(MESSAGE_SIZE_S); + this.msgInterval = s.getCsvInts(MESSAGE_INTERVAL_S); + this.hostRange = s.getCsvInts(HOST_RANGE_S, 2); + this.idPrefix = s.getSetting(MESSAGE_ID_PREFIX_S); + + if (s.contains(MESSAGE_TIME_S)) { + this.msgTime = s.getCsvDoubles(MESSAGE_TIME_S, 2); + } + else { + this.msgTime = null; + } + if (s.contains(TO_HOST_RANGE_S)) { + this.toHostRange = s.getCsvInts(TO_HOST_RANGE_S, 2); + } + else { + this.toHostRange = null; + } + + /* if prefix is unique, so will be the rng's sequence */ + this.rng = new Random(idPrefix.hashCode()); + + if (this.sizeRange.length == 1) { + /* convert single value to range with 0 length */ + this.sizeRange = new int[] {this.sizeRange[0], this.sizeRange[0]}; + } + else { + s.assertValidRange(this.sizeRange, MESSAGE_SIZE_S); + } + if (this.msgInterval.length == 1) { + this.msgInterval = new int[] {this.msgInterval[0], + this.msgInterval[0]}; + } + else { + s.assertValidRange(this.msgInterval, MESSAGE_INTERVAL_S); + } + s.assertValidRange(this.hostRange, HOST_RANGE_S); + + if (this.hostRange[1] - this.hostRange[0] < 2) { + if (this.toHostRange == null) { + throw new SettingsError("Host range must contain at least two " + + "nodes unless toHostRange is defined"); + } + else if (toHostRange[0] == this.hostRange[0] && + toHostRange[1] == this.hostRange[1]) { + // XXX: teemuk: Since (X,X) == (X,X+1) in drawHostAddress() + // there's still a boundary condition that can cause an + // infinite loop. + throw new SettingsError("If to and from host ranges contain" + + " only one host, they can't be the equal"); + } + } + + /* calculate the first event's time */ + this.nextEventsTime = (this.msgTime != null ? this.msgTime[0] : 0) + + msgInterval[0] + + (msgInterval[0] == msgInterval[1] ? 0 : + rng.nextInt(msgInterval[1] - msgInterval[0])); + } + + + /** + * Draws a random host address from the configured address range + * @param hostRange The range of hosts + * @return A random host address + */ + protected int drawHostAddress(int hostRange[]) { + if (hostRange[1] == hostRange[0]) { + return hostRange[0]; + } + return hostRange[0] + rng.nextInt(hostRange[1] - hostRange[0]); + } + + /** + * Generates a (random) message size + * @return message size + */ + protected int drawMessageSize() { + int sizeDiff = sizeRange[0] == sizeRange[1] ? 0 : + rng.nextInt(sizeRange[1] - sizeRange[0]); + return sizeRange[0] + sizeDiff; + } + + /** + * Generates a (random) time difference between two events + * @return the time difference + */ + protected int drawNextEventTimeDiff() { + int timeDiff = msgInterval[0] == msgInterval[1] ? 0 : + rng.nextInt(msgInterval[1] - msgInterval[0]); + return msgInterval[0] + timeDiff; + } + + /** + * Draws a destination host address that is different from the "from" + * address + * @param hostRange The range of hosts + * @param from the "from" address + * @return a destination address from the range, but different from "from" + */ + protected int drawToAddress(int hostRange[], int from) { + int to; + do { + to = this.toHostRange != null ? drawHostAddress(this.toHostRange): + drawHostAddress(this.hostRange); + } while (from==to); + + return to; + } + + /** + * Returns the next message creation event + * @see input.EventQueue#nextEvent() + */ + public ExternalEvent nextEvent() { + int responseSize = 0; /* zero stands for one way messages */ + int msgSize; + int interval; + int from; + int to; + + /* Get two *different* nodes randomly from the host ranges */ + from = drawHostAddress(this.hostRange); + to = drawToAddress(hostRange, from); + + msgSize = drawMessageSize(); + interval = drawNextEventTimeDiff(); + + /* Create event and advance to next event */ + MessageCreateEvent mce = new MessageCreateEvent(from, to, this.getID(), + msgSize, responseSize, this.nextEventsTime); + this.nextEventsTime += interval; + + if (this.msgTime != null && this.nextEventsTime > this.msgTime[1]) { + /* next event would be later than the end time */ + this.nextEventsTime = Double.MAX_VALUE; + } + + return mce; + } + + /** + * Returns next message creation event's time + * @see input.EventQueue#nextEventsTime() + */ + public double nextEventsTime() { + return this.nextEventsTime; + } + + /** + * Returns a next free message ID + * @return next globally unique message ID + */ + protected String getID(){ + this.id++; + return idPrefix + this.id; + } +} diff --git a/input/MessageRelayEvent.java b/input/MessageRelayEvent.java new file mode 100644 index 000000000..4d9d43199 --- /dev/null +++ b/input/MessageRelayEvent.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import core.DTNHost; +import core.World; + +/** + * External event for all the stages of relaying a message between two + * hosts (start and possible abort or delivery). + */ +public class MessageRelayEvent extends MessageEvent { + private int stage; + + /** Message relay stage constant for start of sending */ + public static final int SENDING = 1; + /** Message relay stage constant for ready delivery */ + public static final int TRANSFERRED = 2; + /** Message relay stage constant for aborted delivery */ + public static final int ABORTED = 3; + /** Stage constant -> String representation mapping */ + public static final String[] STAGE_STRINGS = {"SENDING", + "TRANSFERRED", "ABORTED"}; + + /** + * Creates a message relaying event + * @param from Where the message comes from (at this hop) + * @param to Who the message goes to (at this hop) + * @param id ID of the message + * @param time Time when this event happens + * @param stage The stage of the event (SENDING, TRANSFERRED, or ABORTED) + */ + public MessageRelayEvent(int from, int to, String id, double time, + int stage) { + super(from, to, id, time); + this.stage = stage; + } + + /** + * Relays the message + */ + public void processEvent(World world) { + // get DTNHosts and pass messages between them + DTNHost from = world.getNodeByAddress(this.fromAddr); + DTNHost to = world.getNodeByAddress(this.toAddr); + + switch(stage) { + case SENDING: + from.sendMessage(id, to); + break; + case TRANSFERRED: + to.messageTransferred(id, from); + break; + case ABORTED: + to.messageAborted(id, from, -1); + break; + default: + assert false : "Invalid stage (" + stage + ") for " + this; + } + } + + @Override + public String toString() { + return super.toString() + " [" + fromAddr + "->" + toAddr + "] " + + STAGE_STRINGS[stage-1]; + } + +} diff --git a/input/OneFromEachMessageGenerator.java b/input/OneFromEachMessageGenerator.java new file mode 100644 index 000000000..b30399819 --- /dev/null +++ b/input/OneFromEachMessageGenerator.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import core.Settings; +import core.SettingsError; + +/** + * Message creation -external events generator. Creates one message from + * every source node (defined with {@link MessageEventGenerator#HOST_RANGE_S}) + * to one of the destination nodes (defined with + * {@link MessageEventGenerator#TO_HOST_RANGE_S}). + * The message size, first messages time and the intervals between creating + * messages can be configured like with {@link MessageEventGenerator}. End + * time is not respected, but messages are created until every from-node has + * created a message. + * @see MessageEventGenerator + */ +public class OneFromEachMessageGenerator extends MessageEventGenerator { + private List fromIds; + + public OneFromEachMessageGenerator(Settings s) { + super(s); + this.fromIds = new ArrayList(); + + if (toHostRange == null) { + throw new SettingsError("Destination host (" + TO_HOST_RANGE_S + + ") must be defined"); + } + for (int i = hostRange[0]; i < hostRange[1]; i++) { + fromIds.add(i); + } + Collections.shuffle(fromIds, rng); + } + + /** + * Returns the next message creation event + * @see input.EventQueue#nextEvent() + */ + public ExternalEvent nextEvent() { + int responseSize = 0; /* no responses requested */ + int from; + int to; + + from = this.fromIds.remove(0); + to = drawToAddress(toHostRange, -1); + + if (to == from) { /* skip self */ + if (this.fromIds.size() == 0) { /* oops, no more from addresses */ + this.nextEventsTime = Double.MAX_VALUE; + return new ExternalEvent(Double.MAX_VALUE); + } else { + from = this.fromIds.remove(0); + } + } + + if (this.fromIds.size() == 0) { + this.nextEventsTime = Double.MAX_VALUE; /* no messages left */ + } else { + this.nextEventsTime += drawNextEventTimeDiff(); + } + + MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), + drawMessageSize(), responseSize, this.nextEventsTime); + + return mce; + } + +} \ No newline at end of file diff --git a/input/OneToEachMessageGenerator.java b/input/OneToEachMessageGenerator.java new file mode 100644 index 000000000..157fa27e5 --- /dev/null +++ b/input/OneToEachMessageGenerator.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import core.Settings; +import core.SettingsError; + +/** + * Message creation -external events generator. Creates one message from + * source node/nodes (defined with {@link MessageEventGenerator#HOST_RANGE_S}) + * to all destination nodes (defined with + * {@link MessageEventGenerator#TO_HOST_RANGE_S}). + * The message size, first messages time and the intervals between creating + * messages can be configured like with {@link MessageEventGenerator}. End + * time is not respected, but messages are created until there's a message for + * every destination node. + * @see MessageEventGenerator + */ +public class OneToEachMessageGenerator extends MessageEventGenerator { + private List toIds; + + public OneToEachMessageGenerator(Settings s) { + super(s); + this.toIds = new ArrayList(); + + if (toHostRange == null) { + throw new SettingsError("Destination host (" + TO_HOST_RANGE_S + + ") must be defined"); + } + for (int i = toHostRange[0]; i < toHostRange[1]; i++) { + toIds.add(i); + } + Collections.shuffle(toIds, rng); + } + + /** + * Returns the next message creation event + * @see input.EventQueue#nextEvent() + */ + public ExternalEvent nextEvent() { + int responseSize = 0; /* no responses requested */ + int from; + int to; + + from = drawHostAddress(hostRange); + to = this.toIds.remove(0); + + if (to == from) { /* skip self */ + if (this.toIds.size() == 0) { /* oops, no more from addresses */ + this.nextEventsTime = Double.MAX_VALUE; + return new ExternalEvent(Double.MAX_VALUE); + } else { + to = this.toIds.remove(0); + } + } + + if (this.toIds.size() == 0) { + this.nextEventsTime = Double.MAX_VALUE; /* no messages left */ + } else { + this.nextEventsTime += drawNextEventTimeDiff(); + } + + MessageCreateEvent mce = new MessageCreateEvent(from, to, getID(), + drawMessageSize(), responseSize, this.nextEventsTime); + + return mce; + } + +} \ No newline at end of file diff --git a/input/ScheduledUpdatesQueue.java b/input/ScheduledUpdatesQueue.java new file mode 100644 index 000000000..b4b98f7a4 --- /dev/null +++ b/input/ScheduledUpdatesQueue.java @@ -0,0 +1,105 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.util.ArrayList; +import java.util.List; + +/** + * Event queue where simulation objects can request an update to happen + * at the specified simulation time. Multiple updates at the same time + * are merged to a single update. + */ +public class ScheduledUpdatesQueue implements EventQueue { + /** Time of the event (simulated seconds) */ + private ExternalEvent nextEvent; + private List updates; + + /** + * Constructor. Creates an empty update queue. + */ + public ScheduledUpdatesQueue(){ + this.nextEvent = new ExternalEvent(Double.MAX_VALUE); + this.updates = new ArrayList(); + } + + /** + * Returns the next scheduled event or event with time Double.MAX_VALUE + * if there aren't any. + * @return the next scheduled event + */ + public ExternalEvent nextEvent() { + ExternalEvent event = this.nextEvent; + + if (this.updates.size() == 0) { + this.nextEvent = new ExternalEvent(Double.MAX_VALUE); + } + else { + this.nextEvent = this.updates.remove(0); + } + + return event; + } + + /** + * Returns the next scheduled event's time or Double.MAX_VALUE if there + * aren't any events left + * @return the next scheduled event's time + */ + public double nextEventsTime() { + return this.nextEvent.getTime(); + } + + /** + * Add a new update request for the given time + * @param simTime The time when the update should happen + */ + public void addUpdate(double simTime) { + ExternalEvent ee = new ExternalEvent(simTime); + + if (ee.compareTo(nextEvent) == 0) { // this event is already next + return; + } + else if (this.nextEvent.getTime() > simTime) { // new nextEvent + putToQueue(this.nextEvent); // put the old nextEvent back to q + this.nextEvent = ee; + } + else { // given event happens later.. + putToQueue(ee); + } + } + + /** + * Puts a event to the queue in the right place + * @param ee The event to put to the queue + */ + private void putToQueue(ExternalEvent ee) { + double eeTime = ee.getTime(); + + for (int i=0, n=this.updates.size(); i no need for new + } + else if (eeTime < time) { + this.updates.add(i, ee); + return; + } + } + + /* all existing updates are earlier -> add to the end of the list */ + this.updates.add(ee); + } + + public String toString() { + String times = "updates @ " + this.nextEvent.getTime(); + + for (ExternalEvent ee : this.updates) { + times += ", " + ee.getTime(); + } + + return times; + } +} diff --git a/input/StandardEventsReader.java b/input/StandardEventsReader.java new file mode 100644 index 000000000..7e09f661c --- /dev/null +++ b/input/StandardEventsReader.java @@ -0,0 +1,235 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.regex.Pattern; + +import core.SimError; + +/** + *

+ * External events reader for standard-format events + * (created e.g by the dtnsim2parser). + *

+ *

+ * Syntax:
+ * + * <time> <actionId> <msgId> <hostId> + * [<host2Id> [<size>] [<respSize>]] + * + *

+ * All actions (except CONNECTION) must have first four fields. SEND, DELIVERED + * and ABORT actions need host2Id field too (the host who the message is/was + * being transferred to). CREATE action needs the additional size + * (of the message) field and can have also size-of-the-response field if + * a response to this message is requested.

+ *

CONNNECTION action is followed by the two hosts which connect (or + * disconnect) to each other and then either "up" or "down" depending on whether + * the connection was created or destroyed. + *

+ *

Message DROP and REMOVE events can use {@value #ALL_MESSAGES_ID} as the + * message ID for referring to all messages the node has in message buffer + * (i.e., to delete all messages). + *

+ */ +public class StandardEventsReader implements ExternalEventsReader { + /** Identifier of message creation event ({@value}) */ + public static final String CREATE = "C"; + /** Identifier of message transfer start event ({@value}) */ + public static final String SEND = "S"; + /** Identifier of message delivered event ({@value}) */ + public static final String DELIVERED = "DE"; + /** Identifier of message transfer aborted event ({@value}) */ + public static final String ABORT = "A"; + /** Identifier of message dropped event ({@value}) */ + public static final String DROP = "DR"; + /** Identifier of message removed event ({@value}) */ + public static final String REMOVE = "R"; + /** Identifier of connection event ({@value}) */ + public static final String CONNECTION = "CONN"; + /** Value identifier of connection down event ({@value}) */ + public static final String CONNECTION_DOWN = "down"; + /** Value identifier of connection up event ({@value}) */ + public static final String CONNECTION_UP = "up"; + /** Message identifier to use to refer to all messages ({@value}) */ + public static final String ALL_MESSAGES_ID = "*"; + + //private Scanner scanner; + private BufferedReader reader; + + public StandardEventsReader(File eventsFile){ + try { + //this.scanner = new Scanner(eventsFile); + this.reader = new BufferedReader(new FileReader(eventsFile)); + } catch (FileNotFoundException e) { + throw new SimError(e.getMessage(),e); + } + } + + + public List readEvents(int nrof) { + ArrayList events = new ArrayList(nrof); + int eventsRead = 0; + // skip empty and comment lines + Pattern skipPattern = Pattern.compile("(#.*)|(^\\s*$)"); + + String line; + try { + line = this.reader.readLine(); + } catch (IOException e1) { + throw new SimError("Reading from external event file failed."); + } + while (eventsRead < nrof && line != null) { + Scanner lineScan = new Scanner(line); + if (skipPattern.matcher(line).matches()) { + // skip empty and comment lines + try { + line = this.reader.readLine(); + } catch (IOException e) { + throw new SimError("Reading from external event file " + + "failed."); + } + continue; + } + + double time; + String action; + String msgId; + int hostAddr; + int host2Addr; + + try { + time = lineScan.nextDouble(); + action = lineScan.next(); + + if (action.equals(DROP)) { + msgId = lineScan.next(); + hostAddr = getHostAddress(lineScan.next()); + events.add(new MessageDeleteEvent(hostAddr, msgId, + time, true)); + } + else if (action.equals(REMOVE)) { + msgId = lineScan.next(); + hostAddr = getHostAddress(lineScan.next()); + events.add(new MessageDeleteEvent(hostAddr, msgId, + time, false)); + } + else if (action.equals(CONNECTION)) { + String connEventType; + boolean isUp; + hostAddr = getHostAddress(lineScan.next()); + host2Addr = getHostAddress(lineScan.next()); + connEventType = lineScan.next(); + + String interfaceId = null; + if (lineScan.hasNext()) { + interfaceId = lineScan.next(); + } + + if (connEventType.equalsIgnoreCase(CONNECTION_UP)) { + isUp = true; + } + else if (connEventType.equalsIgnoreCase(CONNECTION_DOWN)) { + isUp = false; + } + else { + throw new SimError("Unknown up/down value '" + + connEventType + "'"); + } + + ConnectionEvent ce = new ConnectionEvent(hostAddr, + host2Addr, interfaceId, isUp, time); + + events.add(ce); + } + else { + msgId = lineScan.next(); + hostAddr = getHostAddress(lineScan.next()); + + host2Addr = getHostAddress(lineScan.next()); + + if (action.equals(CREATE)){ + int size = lineScan.nextInt(); + int respSize = 0; + if (lineScan.hasNextInt()) { + respSize = lineScan.nextInt(); + } + events.add(new MessageCreateEvent(hostAddr, host2Addr, + msgId, size, respSize, time)); + } + else { + int stage = -1; + if (action.equals(SEND)) { + stage = MessageRelayEvent.SENDING; + } + else if (action.equals(DELIVERED)) { + stage = MessageRelayEvent.TRANSFERRED; + } + else if (action.equals(ABORT)) { + stage = MessageRelayEvent.ABORTED; + } + else { + throw new SimError("Unknown action '" + action + + "' in external events"); + } + events.add(new MessageRelayEvent(hostAddr, host2Addr, + msgId, time, stage)); + } + } + // discard the newline in the end + if (lineScan.hasNextLine()) { + lineScan.nextLine(); // TODO: test + } + eventsRead++; + if (eventsRead < nrof) { + line = this.reader.readLine(); + } + } catch (Exception e) { + throw new SimError("Can't parse external event " + + (eventsRead+1) + " from '" + line + "'", e); + } + } + + return events; + } + + /** + * Parses a host address from a hostId string (the numeric part after + * optional non-numeric part). + * @param hostId The id to parse the address from + * @return The address + * @throws SimError if no address could be parsed from the id + */ + private int getHostAddress(String hostId) { + String addressPart = ""; + if (hostId.matches("^\\d+$")) { + addressPart = hostId; // host id is only the address + } + else if (hostId.matches("^\\D+\\d+$")) { + String [] parts = hostId.split("\\D"); + addressPart = parts[parts.length-1]; // last occurence is the addr + } + else { + throw new SimError("Invalid host ID '" + hostId + "'"); + } + + return Integer.parseInt(addressPart); + } + + public void close() { + try { + this.reader.close(); + } catch (IOException e) {} + } + +} diff --git a/input/WKTMapReader.java b/input/WKTMapReader.java new file mode 100644 index 000000000..24ac27ec6 --- /dev/null +++ b/input/WKTMapReader.java @@ -0,0 +1,159 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Collection; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; + +/** + * "Well-known text syntax" map data reader.
+ * Note: Understands only LINESTRINGs and + * MULTILINESTRINGs. Skips all POINT data. + * Other data causes IOException. + */ +public class WKTMapReader extends WKTReader { + private Hashtable nodes; + /** are all paths bidirectional */ + private boolean bidirectionalPaths = true; + private int nodeType = -1; + + /** + * Constructor. Creates a new WKT reader ready for addPaths() calls. + * @param bidi If true, all read paths are set bidirectional (i.e. if node A + * is a neighbor of node B, node B is also a neighbor of node A). + */ + public WKTMapReader(boolean bidi) { + this.bidirectionalPaths = bidi; + this.nodes = new Hashtable(); + } + + /** + * Sets bidirectional paths on/off. + * @param bidi If true, all paths are set bidirectional (false -> not) + */ + public void setBidirectional(boolean bidi) { + this.bidirectionalPaths = bidi; + } + + /** + * Returns the map nodes that were read in a collection + * @return the map nodes that were read in a collection + */ + public Collection getNodes() { + return this.nodes.values(); + } + + /** + * Returns the original Map object that was used to read the map + * @return the original Map object that was used to read the map + */ + public Map getNodesHash() { + return this.nodes; + } + + /** + * Returns new a SimMap that is based on the read map + * @return new a SimMap that is based on the read map + */ + public SimMap getMap() { + return new SimMap(this.nodes); + } + + /** + * Adds paths to the map and adds given type to all nodes' type. + * @param file The file where the WKT data is read from + * @param type The type to use (integer value, see class {@link MapNode})) + * @throws IOException If something went wrong while reading the file + */ + public void addPaths(File file, int type) throws IOException { + addPaths(new FileReader(file), type); + } + + + /** + * Add paths to current path set. Adding paths multiple times + * has the same result as concatenating the data before adding it. + * @param input Reader where the WKT data is read from + * @param nodeType The type to use (integer value, see class + * {@link MapNode})) + * @throws IOException if something went wrong with reading from the input + */ + public void addPaths(Reader input, int nodeType) throws IOException { + this.nodeType = nodeType; + String type; + String contents; + + init(input); + + while((type = nextType()) != null) { + if (type.equals(LINESTRING)) { + contents = readNestedContents(); + updateMap(parseLineString(contents)); + } + else if (type.equals(MULTILINESTRING)) { + for (List list : parseMultilinestring()) { + updateMap(list); + } + } + else { + // known type but not interesting -> skip + readNestedContents(); + } + } + } + + /** + * Updates simulation map with coordinates in the list + * @param coords The list of coordinates + */ + private void updateMap(List coords) { + MapNode previousNode = null; + for (Coord c : coords) { + previousNode = createOrUpdateNode(c, previousNode); + } + } + + /** + * Creates or updates a node that is in location c and next to + * node previous + * @param c The location coordinates of the node + * @param previous Previous node whose neighbor node at c is + * @return The created/updated node + */ + private MapNode createOrUpdateNode(Coord c, MapNode previous) { + MapNode n = null; + + n = nodes.get(c); // try to get the node at that location + + if (n == null) { // no node in that location -> create new + n = new MapNode(c); + nodes.put(c, n); + } + + if (previous != null) { + n.addNeighbor(previous); + if (bidirectionalPaths) { + previous.addNeighbor(n); + } + } + + if (nodeType != -1) { + n.addType(nodeType); + } + + return n; + } + +} diff --git a/input/WKTReader.java b/input/WKTReader.java new file mode 100644 index 000000000..2c8c83caf --- /dev/null +++ b/input/WKTReader.java @@ -0,0 +1,327 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package input; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +import core.Coord; + +/** + * Class for reading "Well-known text syntax" files. See e.g. + * Wikipedia for + * WKT syntax details. For example, Open JUMP + * GIS program can save compatible data from many other formats.
+ */ +public class WKTReader { + /** known WKT type LINESTRING */ + public static final String LINESTRING = "LINESTRING"; + /** known WKT type MULTILINESTRING */ + public static final String MULTILINESTRING = "MULTILINESTRING"; + /** known WKT type POINT */ + public static final String POINT = "POINT"; + + /** are all lines of the file read */ + private boolean done; + /** reader for the data */ + private BufferedReader reader; + + /** + * Read point data from a file + * @param file The file to read points from + * @return A list of coordinates read from the file + * @throws IOException if something went wrong while reading + */ + public List readPoints(File file) throws IOException { + return readPoints(new FileReader(file)); + } + + /** + * Read point data from a Reader + * @param r The Reader to read points from + * @return A list of coordinates that were read + * @throws IOException if something went wrong while reading + */ + public List readPoints(Reader r) throws IOException { + List points = new ArrayList(); + + String type; + init(r); + + while((type = nextType()) != null) { + if (type.equals(POINT)) { + points.add(parsePoint()); + } + else { + // known type but not interesting -> skip + readNestedContents(); + } + } + + return points; + } + + /** + * Read line (LINESTRING) data from a file + * @param file The file to read data from + * @return A list of coordinate lists read from the file + * @throws IOException if something went wrong while reading + */ + public List> readLines(File file) throws IOException { + List> lines = new ArrayList>(); + + String type; + init(new FileReader(file)); + + while((type = nextType()) != null) { + if (type.equals(LINESTRING)) { + lines.add(parseLineString(readNestedContents())); + } + else { + // known type but not interesting -> skip + readNestedContents(); + } + } + + return lines; + } + + + /** + * Initialize the reader to use a certain input reader + * @param input The input to use + */ + protected void init(Reader input) { + setDone(false); + reader = new BufferedReader(input); + } + + /** + * Returns the next type read from the reader given at init or null + * if no more types can be read + * @return the next type read from the reader given at init + * @throws IOException + */ + protected String nextType() throws IOException { + String type = null; + + while (!done && type == null) { + type = readWord(reader); + + if (type.length() < 1) { // discard empty lines + type = null; + continue; + } + } + + return type; + } + + /** + * Returns true if type is one of the known WKT types + * @param type The type to check + * @return true if type is one of the known WKT types + */ + protected boolean isKnownType(String type) { + if (type.equals(LINESTRING)) { + return true; + } + else if (type.equals(MULTILINESTRING)) { + return true; + } + else if (type.equals(POINT)) { + return true; + } + else { + return false; + } + } + + /** + * Reads a "word", ie whitespace delimited string of characters, from + * the reader + * @param r Reader to read the characters from + * @return The word that was read (or empty string if nothing was read) + * @throws IOException + */ + protected String readWord(Reader r) throws IOException { + StringBuffer buf = new StringBuffer(); + char c = skipAllWhitespace(r); + + // read non-whitespace part + while(c != (char)-1 && !Character.isWhitespace(c)) { + buf.append(c); + c = (char)r.read(); + } + + if (c == (char)-1) { + setDone(true); + } + return buf.toString(); + } + + /** + * Parses a MULTILINESTRING statement that has nested linestrings from + * the current reader + * @return List of parsed Coord lists + * @throws IOException + */ + protected List> parseMultilinestring() + throws IOException { + List> list = new ArrayList>(); + String multiContents = readNestedContents(reader); + StringReader r2 = new StringReader(multiContents); + String lineString = readNestedContents(r2); + + while (lineString.length() > 0) { + list.add(parseLineString(lineString)); + lineString = readNestedContents(r2); + } + + return list; + } + + /** + * Parses a WKT point data from the intialized reader + * @return Point data as a Coordinate + * @throws IOException if couldn't parse coordinate values + */ + protected Coord parsePoint() throws IOException { + String coords = readNestedContents(reader); + Scanner s = new Scanner(coords); + double x,y; + + try { + x = s.nextDouble(); + y = s.nextDouble(); + } catch (RuntimeException e) { + throw new IOException("Bad coordinate values: '" + coords + "'"); + } + + return new Coord(x,y); + } + + /** + * Reads and skips all characters until character "until" is read or + * end of stream is reached. Also the expected character is discarded. + * @param r Reader to read characters from + * @param until What character to expect + * @throws IOException + */ + protected void skipUntil(Reader r, char until) throws IOException { + char c; + do { + c = (char)r.read(); + } while (c != until && c != (char)-1); + } + + /** + * Skips all consecutive whitespace characters from reader + * @param r Reader where the whitespace is skipped + * @return First non-whitespace character read from the reader + * @throws IOException + */ + protected char skipAllWhitespace(Reader r) throws IOException { + char c; + do { + c = (char)r.read(); + } while (Character.isWhitespace(c) && c != (char)-1); + + return c; + } + + /** + * Reads everything from the first opening parenthesis until line that + * ends to a closing parenthesis and returns the contents in one string + * @param r Reader to read the input from + * @return The text between the parentheses + */ + public String readNestedContents(Reader r) throws IOException { + StringBuffer contents = new StringBuffer(); + int parOpen; // nrof open parentheses + char c = '\0'; + + skipUntil(r,'('); + parOpen = 1; + + while (c != (char)-1 && parOpen > 0) { + c = (char)r.read(); + if (c == '(') { + parOpen++; + } + if (c == ')') { + parOpen--; + } + if (Character.isWhitespace(c)) { + c = ' '; // convert all whitespace to basic space + } + contents.append(c); + } + + contents.deleteCharAt(contents.length()-1); // remove last ')' + return contents.toString(); + } + + /** + * Returns nested contents from the reader given at init + * @return nested contents from the reader given at init + * @throws IOException + * @see #readNestedContents(Reader) + */ + public String readNestedContents() throws IOException { + return readNestedContents(reader); + } + + /** + * Parses coordinate tuples from "LINESTRING" lines + * @param line String that contains the whole "LINESTRING"'s content + * @return List of coordinates parsed from the linestring + */ + protected List parseLineString(String line) { + List coords = new ArrayList(); + Scanner lineScan; + Scanner tupleScan; + double x,y; + Coord c; + + lineScan = new Scanner(line); + lineScan.useDelimiter(","); + + while (lineScan.hasNext()) { + tupleScan = new Scanner(lineScan.next()); + x = Double.parseDouble(tupleScan.next()); + y = Double.parseDouble(tupleScan.next()); + c = new Coord(x,y); + + coords.add(c); + } + + return coords; + } + + /** + * Returns true if the whole file has been read + * @return true if the whole file has been read + */ + protected boolean isDone() { + return this.done; + } + + /** + * Sets the "is file read" state + * @param done If true, reading is done + */ + protected void setDone(boolean done) { + this.done = done; + } + +} diff --git a/input/package.html b/input/package.html new file mode 100644 index 000000000..ab7fd2259 --- /dev/null +++ b/input/package.html @@ -0,0 +1,8 @@ + + + + +Provides interfaces and classes for reading input data from external sources. + + + \ No newline at end of file diff --git a/interfaces/ConnectivityGrid.java b/interfaces/ConnectivityGrid.java new file mode 100644 index 000000000..4ee1082ae --- /dev/null +++ b/interfaces/ConnectivityGrid.java @@ -0,0 +1,323 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +import movement.MovementModel; + +import core.Coord; +import core.DTNSim; +import core.NetworkInterface; +import core.Settings; +import core.SettingsError; +import core.World; + +/** + *

+ * Overlay grid of the world where each interface is put on a cell depending + * of its location. This is used in cell-based optimization of connecting + * the interfaces.

+ * + *

The idea in short:
+ * Instead of checking for every interface if some of the other interfaces are close + * enough (this approach obviously doesn't scale) we check only interfaces that + * are "close enough" to be possibly connected. Being close enough is + * determined by keeping track of the approximate location of the interfaces + * by storing them in overlay grid's cells and updating the cell information + * every time the interfaces move. If two interfaces are in the same cell or in + * neighboring cells, they have a chance of being close enough for + * connection. Then only that subset of interfaces is checked for possible + * connectivity. + *

+ *

+ * Note: this class does NOT support negative + * coordinates. Also, it makes sense to normalize the coordinates to start + * from zero to conserve memory. + */ +public class ConnectivityGrid extends ConnectivityOptimizer { + + /** + * Cell based optimization cell size multiplier -setting id ({@value}). + * Used in {@link World#OPTIMIZATION_SETTINGS_NS} name space. + * Single ConnectivityCell's size is the biggest radio range times this. + * Larger values save memory and decrease startup time but may result in + * slower simulation. + * Default value is {@link #DEF_CON_CELL_SIZE_MULT}. + * Smallest accepted value is 1. + */ + public static final String CELL_SIZE_MULT_S = "cellSizeMult"; + /** default value for cell size multiplier ({@value}) */ + public static final int DEF_CON_CELL_SIZE_MULT = 5; + + private GridCell[][] cells; + private HashMap ginterfaces; + private int cellSize; + private int rows; + private int cols; + private static int worldSizeX; + private static int worldSizeY; + private static int cellSizeMultiplier; + + static HashMap gridobjects; + + static { + DTNSim.registerForReset(ConnectivityGrid.class.getCanonicalName()); + reset(); + } + + public static void reset() { + gridobjects = new HashMap(); + + Settings s = new Settings(MovementModel.MOVEMENT_MODEL_NS); + int [] worldSize = s.getCsvInts(MovementModel.WORLD_SIZE,2); + worldSizeX = worldSize[0]; + worldSizeY = worldSize[1]; + + s.setNameSpace(World.OPTIMIZATION_SETTINGS_NS); + if (s.contains(CELL_SIZE_MULT_S)) { + cellSizeMultiplier = s.getInt(CELL_SIZE_MULT_S); + } + else { + cellSizeMultiplier = DEF_CON_CELL_SIZE_MULT; + } + if (cellSizeMultiplier < 1) { + throw new SettingsError("Too small value (" + cellSizeMultiplier + + ") for " + World.OPTIMIZATION_SETTINGS_NS + + "." + CELL_SIZE_MULT_S); + } + } + + /** + * Creates a new overlay connectivity grid + * @param cellSize Cell's edge's length (must be larger than the largest + * radio coverage's diameter) + */ + private ConnectivityGrid(int cellSize) { + this.rows = worldSizeY/cellSize + 1; + this.cols = worldSizeX/cellSize + 1; + // leave empty cells on both sides to make neighbor search easier + this.cells = new GridCell[rows+2][cols+2]; + this.cellSize = cellSize; + + for (int i=0; i(); + } + + /** + * Returns a connectivity grid object based on a hash value + * @param key A hash value that separates different interfaces from each other + * @param maxRange Maximum range used by the radio technology using this + * connectivity grid. + * @return The connectivity grid object for a specific interface + */ + public static ConnectivityGrid ConnectivityGridFactory(int key, + double maxRange) { + if (gridobjects.containsKey((Integer)key)) { + return (ConnectivityGrid)gridobjects.get((Integer)key); + } else { + ConnectivityGrid newgrid = + new ConnectivityGrid((int)Math.ceil(maxRange * + cellSizeMultiplier)); + gridobjects.put((Integer)key,newgrid); + return newgrid; + } + } + + /** + * Adds a network interface to the overlay grid + * @param ni The new network interface + */ + public void addInterface(NetworkInterface ni) { + GridCell c = cellFromCoord(ni.getLocation()); + c.addInterface(ni); + ginterfaces.put(ni,c); + } + + /** + * Removes a network interface from the overlay grid + * @param ni The interface to be removed + */ + public void removeInterface(NetworkInterface ni) { + GridCell c = ginterfaces.get(ni); + if (c != null) { + c.removeInterface(ni); + } + ginterfaces.remove(ni); + } + + /** + * Adds interfaces to overlay grid + * @param interfaces Collection of interfaces to add + */ + public void addInterfaces(Collection interfaces) { + for (NetworkInterface n : interfaces) { + addInterface(n); + } + } + + /** + * Checks and updates (if necessary) interface's position in the grid + * @param ni The interface to update + */ + public void updateLocation(NetworkInterface ni) { + GridCell oldCell = (GridCell)ginterfaces.get(ni); + GridCell newCell = cellFromCoord(ni.getLocation()); + + if (newCell != oldCell) { + oldCell.moveInterface(ni, newCell); + ginterfaces.put(ni,newCell); + } + } + + /** + * Finds all neighboring cells and the cell itself based on the coordinates + * @param c The coordinates + * @return Array of neighboring cells + */ + private GridCell[] getNeighborCellsByCoord(Coord c) { + // +1 due empty cells on both sides of the matrix + int row = (int)(c.getY()/cellSize) + 1; + int col = (int)(c.getX()/cellSize) + 1; + return getNeighborCells(row,col); + } + + /** + * Returns an array of Cells that contains the neighbors of a certain + * cell and the cell itself. + * @param row Row index of the cell + * @param col Column index of the cell + * @return Array of neighboring Cells + */ + private GridCell[] getNeighborCells(int row, int col) { + return new GridCell[] { + cells[row-1][col-1],cells[row-1][col],cells[row-1][col+1],//1st row + cells[row][col-1],cells[row][col],cells[row][col+1],//2nd row + cells[row+1][col-1],cells[row+1][col],cells[row+1][col+1]//3rd row + }; + } + + /** + * Get the cell having the specific coordinates + * @param c Coordinates + * @return The cell + */ + private GridCell cellFromCoord(Coord c) { + // +1 due empty cells on both sides of the matrix + int row = (int)(c.getY()/cellSize) + 1; + int col = (int)(c.getX()/cellSize) + 1; + + assert row > 0 && row <= rows && col > 0 && col <= cols : "Location " + + c + " is out of world's bounds"; + + return this.cells[row][col]; + } + + /** + * Returns all interfaces that use the same technology and channel + */ + public Collection getAllInterfaces() { + return (Collection)ginterfaces.keySet(); + } + + /** + * Returns all interfaces that are "near" (i.e., in neighboring grid cells) + * and use the same technology and channel as the given interface + * @param ni The interface whose neighboring interfaces are returned + * @return List of near interfaces + */ + public Collection getNearInterfaces( + NetworkInterface ni) { + ArrayList niList = new ArrayList(); + GridCell loc = (GridCell)ginterfaces.get(ni); + + if (loc != null) { + GridCell[] neighbors = + getNeighborCellsByCoord(ni.getLocation()); + for (int i=0; i < neighbors.length; i++) { + niList.addAll(neighbors[i].getInterfaces()); + } + } + + return niList; + } + + + /** + * Returns a string representation of the ConnectivityCells object + * @return a string representation of the ConnectivityCells object + */ + public String toString() { + return getClass().getSimpleName() + " of size " + + this.cols + "x" + this.rows + ", cell size=" + this.cellSize; + } + + /** + * A single cell in the cell grid. Contains the interfaces that are + * currently in that part of the grid. + */ + public class GridCell { + // how large array is initially chosen + private static final int EXPECTED_INTERFACE_COUNT = 5; + private ArrayList interfaces; + + private GridCell() { + this.interfaces = new ArrayList( + EXPECTED_INTERFACE_COUNT); + } + + /** + * Returns a list of of interfaces in this cell + * @return a list of of interfaces in this cell + */ + public ArrayList getInterfaces() { + return this.interfaces; + } + + /** + * Adds an interface to this cell + * @param ni The interface to add + */ + public void addInterface(NetworkInterface ni) { + this.interfaces.add(ni); + } + + /** + * Removes an interface from this cell + * @param ni The interface to remove + */ + public void removeInterface(NetworkInterface ni) { + this.interfaces.remove(ni); + } + + /** + * Moves a interface in a Cell to another Cell + * @param ni The interface to move + * @param to The cell where the interface should be moved to + */ + public void moveInterface(NetworkInterface ni, GridCell to) { + to.addInterface(ni); + boolean removeOk = this.interfaces.remove(ni); + assert removeOk : "interface " + ni + + " not found from cell with " + interfaces.toString(); + } + + /** + * Returns a string representation of the cell + * @return a string representation of the cell + */ + public String toString() { + return getClass().getSimpleName() + " with " + + this.interfaces.size() + " interfaces :" + this.interfaces; + } + } + +} \ No newline at end of file diff --git a/interfaces/ConnectivityOptimizer.java b/interfaces/ConnectivityOptimizer.java new file mode 100644 index 000000000..59e8b5290 --- /dev/null +++ b/interfaces/ConnectivityOptimizer.java @@ -0,0 +1,48 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.Collection; + +import core.NetworkInterface; + +/** + * A superclass for schemes for optimizing the location of possible contacts + * with network interfaces of a specific range + */ +abstract public class ConnectivityOptimizer { + + /** + * Adds a network interface to the optimizer (unless it is already present) + */ + abstract public void addInterface(NetworkInterface ni); + + /** + * Adds a collection of network interfaces to the optimizer (except of those + * already added + */ + abstract public void addInterfaces(Collection interfaces); + + /** + * Updates a network interface's location + */ + abstract public void updateLocation(NetworkInterface ni); + + /** + * Finds all network interfaces that might be located so that they can be + * connected with the network interface + * + * @param ni network interface that needs to be connected + * @return A collection of network interfaces within proximity + */ + abstract public Collection getNearInterfaces( + NetworkInterface ni); + + /** + * Finds all other interfaces that are registered to the + * ConnectivityOptimizer + */ + abstract public Collection getAllInterfaces(); +} diff --git a/interfaces/DistanceCapacityInterface.java b/interfaces/DistanceCapacityInterface.java new file mode 100644 index 000000000..83059869f --- /dev/null +++ b/interfaces/DistanceCapacityInterface.java @@ -0,0 +1,163 @@ +/* + * Copyright 2014 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.Collection; +import core.Connection; +import core.NetworkInterface; +import core.Settings; +import core.VBRConnection; + +/** + * A Network Interface that that takes in to account he distance from the + * other (connected) interface when determining the capacity of the links. + * The distance-dependent transmission speeds are given as comma-separated + * values using setting {@link this#TRANSMIT_SPEEDS_S}. + */ +public class DistanceCapacityInterface extends NetworkInterface { + + /** + * Comma-separated list of speed values -setting id ({@value} ). The first + * value is the speed at distance 0 and the following are speeds at equal + * steps until the last one is the speed at the end of the transmit range ( + * {@link NetworkInterface#TRANSMIT_RANGE_S}). The speed between the steps + * is linearly interpolated. + */ + public static final String TRANSMIT_SPEEDS_S = "transmitSpeeds"; + + protected final int[] transmitSpeeds; + + /** + * Reads the interface settings from the Settings file + */ + public DistanceCapacityInterface(Settings s) { + super(s); + transmitSpeeds = s.getCsvInts(TRANSMIT_SPEEDS_S); + } + + /** + * Copy constructor + * @param ni the copied network interface object + */ + public DistanceCapacityInterface(DistanceCapacityInterface ni) { + super(ni); + transmitSpeeds = ni.transmitSpeeds; + } + + public NetworkInterface replicate() { + return new DistanceCapacityInterface(this); + } + + /** + * Tries to connect this host to another host. The other host must be + * active and within range of this host for the connection to succeed. + * @param anotherInterface The interface to connect to + */ + public void connect(NetworkInterface anotherInterface) { + if (isScanning() + && anotherInterface.getHost().isRadioActive() + && isWithinRange(anotherInterface) + && !isConnected(anotherInterface) + && (this != anotherInterface)) { + + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con,anotherInterface); + } + } + + /** + * Updates the state of current connections (i.e. tears down connections + * that are out of range and creates new ones). + */ + public void update() { + if (optimizer == null) { + return; /* nothing to do */ + } + + // First break the old ones + optimizer.updateLocation(this); + for (int i=0; i interfaces = + optimizer.getNearInterfaces(this); + for (NetworkInterface i : interfaces) { + connect(i); + } + + /* update all connections */ + for (Connection con : getConnections()) { + con.update(); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * @param anotherInterface The interface to create the connection to + */ + public void createConnection(NetworkInterface anotherInterface) { + if (!isConnected(anotherInterface) && (this != anotherInterface)) { + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con,anotherInterface); + } + } + + /** + * Returns the transmit speed to another interface based on the + * distance to this interface + * @param ni The other network interface + */ + @Override + public int getTransmitSpeed(NetworkInterface ni) { + double distance; + double fractionIndex; + double decimal; + double speed; + int index; + + /* distance to the other interface */ + distance = ni.getLocation().distance(this.getLocation()); + + if (distance >= this.transmitRange) { + return 0; + } + + /* interpolate between the two speeds */ + fractionIndex = (distance / this.transmitRange) * + (this.transmitSpeeds.length - 1); + index = (int)(fractionIndex); + decimal = fractionIndex - index; + + speed = this.transmitSpeeds[index] * (1-decimal) + + this.transmitSpeeds[index + 1] * decimal; + + return (int)speed; + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return "DistanceCapacityInterface " + super.toString(); + } + +} diff --git a/interfaces/InterferenceLimitedInterface.java b/interfaces/InterferenceLimitedInterface.java new file mode 100644 index 000000000..90b9426c0 --- /dev/null +++ b/interfaces/InterferenceLimitedInterface.java @@ -0,0 +1,166 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.Collection; + +import core.Connection; +import core.NetworkInterface; +import core.Settings; +import core.VBRConnection; + +/** + * A simple Network Interface that provides a variable bit-rate service, where + * the bit-rate depends on the number of other transmitting stations within + * range The current transmit speed is updated only if there are ongoing + * transmissions. The configured transmit speed is the maximum obtainable speed. + */ +public class InterferenceLimitedInterface extends NetworkInterface { + protected int currentTransmitSpeed; + protected int numberOfTransmissions; + + public InterferenceLimitedInterface(Settings s) { + super(s); + this.currentTransmitSpeed = 0; + this.numberOfTransmissions = 0; + } + + /** + * Copy constructor + * @param ni the copied network interface object + */ + public InterferenceLimitedInterface(InterferenceLimitedInterface ni) { + super(ni); + this.transmitRange = ni.transmitRange; + this.transmitSpeed = ni.transmitSpeed; + this.currentTransmitSpeed = 0; + this.numberOfTransmissions = 0; + } + + + public NetworkInterface replicate() { + return new InterferenceLimitedInterface(this); + } + + /** + * Returns the transmit speed of this network layer + * @return the transmit speed + */ + @Override + public int getTransmitSpeed(NetworkInterface ni) { + return this.currentTransmitSpeed; + } + + /** + * Tries to connect this host to another host. The other host must be + * active and within range of this host for the connection to succeed. + * @param anotherInterface The host to connect to + */ + public void connect(NetworkInterface anotherInterface) { + if (isScanning() + && anotherInterface.getHost().isRadioActive() + && isWithinRange(anotherInterface) + && !isConnected(anotherInterface) + && (this != anotherInterface)) { + // new contact within range + + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con, anotherInterface); + } + } + + /** + * Updates the state of current connections (i.e., tears down connections + * that are out of range). + */ + public void update() { + if (optimizer == null) { + return; /* nothing to do */ + } + + // First break the old ones + optimizer.updateLocation(this); + for (int i=0; i interfaces = + optimizer.getNearInterfaces(this); + for (NetworkInterface i : interfaces) + connect(i); + + // Find the current number of transmissions + // (to calculate the current transmission speed + numberOfTransmissions = 0; + int numberOfActive = 1; + for (Connection con : this.connections) { + if (con.getMessage() != null) { + numberOfTransmissions++; + } + if (((InterferenceLimitedInterface)con.getOtherInterface(this)). + isTransferring() == true) { + numberOfActive++; + } + } + + int ntrans = numberOfTransmissions; + if ( numberOfTransmissions < 1) ntrans = 1; + if ( numberOfActive <2 ) numberOfActive = 2; + + // Based on the equation of Gupta and Kumar - and the transmission speed + // is divided equally to all the ongoing transmissions + currentTransmitSpeed = (int)Math.floor((double)transmitSpeed / + (Math.sqrt((1.0*numberOfActive) * + Math.log(1.0*numberOfActive))) / + ntrans ); + + for (Connection con : getConnections()) { + con.update(); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * @param anotherInterface The interface to create the connection to + */ + public void createConnection(NetworkInterface anotherInterface) { + if (!isConnected(anotherInterface) && (this != anotherInterface)) { + // new contact within range + + Connection con = new VBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface); + connect(con,anotherInterface); + } + } + + /** + * Returns true if this interface is actually transmitting data + */ + public boolean isTransferring() { + return (numberOfTransmissions > 0); + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return "InterfaceLimitedInterface " + super.toString(); + } + +} \ No newline at end of file diff --git a/interfaces/SimpleBroadcastInterface.java b/interfaces/SimpleBroadcastInterface.java new file mode 100644 index 000000000..a1ad967df --- /dev/null +++ b/interfaces/SimpleBroadcastInterface.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package interfaces; + +import java.util.Collection; + +import core.CBRConnection; +import core.Connection; +import core.NetworkInterface; +import core.Settings; + +/** + * A simple Network Interface that provides a constant bit-rate service, where + * one transmission can be on at a time. + */ +public class SimpleBroadcastInterface extends NetworkInterface { + + /** + * Reads the interface settings from the Settings file + */ + public SimpleBroadcastInterface(Settings s) { + super(s); + } + + /** + * Copy constructor + * @param ni the copied network interface object + */ + public SimpleBroadcastInterface(SimpleBroadcastInterface ni) { + super(ni); + } + + public NetworkInterface replicate() { + return new SimpleBroadcastInterface(this); + } + + /** + * Tries to connect this host to another host. The other host must be + * active and within range of this host for the connection to succeed. + * @param anotherInterface The interface to connect to + */ + public void connect(NetworkInterface anotherInterface) { + if (isScanning() + && anotherInterface.getHost().isRadioActive() + && isWithinRange(anotherInterface) + && !isConnected(anotherInterface) + && (this != anotherInterface)) { + // new contact within range + // connection speed is the lower one of the two speeds + int conSpeed = anotherInterface.getTransmitSpeed(this); + if (conSpeed > this.transmitSpeed) { + conSpeed = this.transmitSpeed; + } + + Connection con = new CBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface, conSpeed); + connect(con,anotherInterface); + } + } + + /** + * Updates the state of current connections (i.e. tears down connections + * that are out of range and creates new ones). + */ + public void update() { + if (optimizer == null) { + return; /* nothing to do */ + } + + // First break the old ones + optimizer.updateLocation(this); + for (int i=0; i interfaces = + optimizer.getNearInterfaces(this); + for (NetworkInterface i : interfaces) { + connect(i); + } + } + + /** + * Creates a connection to another host. This method does not do any checks + * on whether the other node is in range or active + * @param anotherInterface The interface to create the connection to + */ + public void createConnection(NetworkInterface anotherInterface) { + if (!isConnected(anotherInterface) && (this != anotherInterface)) { + // connection speed is the lower one of the two speeds + int conSpeed = anotherInterface.getTransmitSpeed(this); + if (conSpeed > this.transmitSpeed) { + conSpeed = this.transmitSpeed; + } + + Connection con = new CBRConnection(this.host, this, + anotherInterface.getHost(), anotherInterface, conSpeed); + connect(con,anotherInterface); + } + } + + /** + * Returns a string representation of the object. + * @return a string representation of the object. + */ + public String toString() { + return "SimpleBroadcastInterface " + super.toString(); + } + +} diff --git a/lib/DTNConsoleConnection.jar b/lib/DTNConsoleConnection.jar new file mode 100644 index 000000000..04040c4a0 Binary files /dev/null and b/lib/DTNConsoleConnection.jar differ diff --git a/lib/ECLA.jar b/lib/ECLA.jar new file mode 100644 index 000000000..78f17e499 Binary files /dev/null and b/lib/ECLA.jar differ diff --git a/movement/BusControlSystem.java b/movement/BusControlSystem.java new file mode 100644 index 000000000..9e94031ff --- /dev/null +++ b/movement/BusControlSystem.java @@ -0,0 +1,144 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import movement.map.SimMap; +import core.Coord; +import core.DTNSim; + +/** + * This class controls busses and passengers that can use the bus. + * There can be many bus BusControlSystems, but a bus or passenger can only + * belong to one system. + * + * @author Frans Ekman + */ +public class BusControlSystem { + public static final String BUS_CONTROL_SYSTEM_NR = "busControlSystemNr"; + + private static HashMap systems; + + private HashMap busses; + private HashMap travellers; + private List busStops; + + private SimMap simMap; + + static { + DTNSim.registerForReset(BusControlSystem.class.getCanonicalName()); + reset(); + } + + /** + * Creates a new instance of BusControlSystem without any travelers or + * busses + * @param systemID The unique ID of this system. + */ + private BusControlSystem(int systemID) { + busses = new HashMap(); + travellers = new HashMap(); + } + + public static void reset() { + systems = new HashMap(); + } + + /** + * Called by busses belonging to this system every time the bus has stopped. + * It calls every passengers enterBus() method so that the passengers can + * enter the bus if they want to. + * @param busID Unique identifier of the bus + * @param busStop Coordinates of the bus stop + * @param nextPath The path to the next stop + */ + public void busHasStopped(int busID, Coord busStop, Path nextPath) { + Iterator iterator = travellers.values(). + iterator(); + while (iterator.hasNext()) { + BusTravellerMovement traveller = (BusTravellerMovement)iterator. + next(); + if (traveller.getLocation() != null) { + if ((traveller.getLocation()).equals(busStop)) { + if (traveller.getState() == BusTravellerMovement. + STATE_WAITING_FOR_BUS) { + Path path = new Path(nextPath); + traveller.enterBus(path); + } + } + } + } + } + + /** + * Returns a reference to a BusControlSystem with ID provided as parameter. + * If a system does not already exist with the requested ID, a new one is + * created. + * @param systemID unique ID of the system + * @return The bus control system with the provided ID + */ + public static BusControlSystem getBusControlSystem(int systemID) { + Integer id = new Integer(systemID); + + if (systems.containsKey(id)) { + return systems.get(id); + } else { + BusControlSystem bcs = new BusControlSystem(systemID); + systems.put(id, bcs); + return bcs; + } + } + + /** + * Registers a bus to be part of a bus control system + * @param bus The bus to register + */ + public void registerBus(BusMovement bus) { + busses.put(bus.getID(), bus); + } + + /** + * Registers a traveller/passenger to be part of a bus control system + * @param traveller The traveller to register + */ + public void registerTraveller(BusTravellerMovement traveller) { + travellers.put(traveller.getID(), traveller); + } + + /** + * Provide the system with the map + * @param map + */ + public void setMap(SimMap map) { + this.simMap = map; + } + + /** + * Get the underlying map of the system + * @return The map + */ + public SimMap getMap() { + return this.simMap; + } + + /** + * @return A list of all bus stops belonging to this system + */ + public List getBusStops() { + return busStops; + } + + /** + * Set the bus stops that belong to this system + * @param busStops + */ + public void setBusStops(List busStops) { + this.busStops = busStops; + } + +} diff --git a/movement/BusMovement.java b/movement/BusMovement.java new file mode 100644 index 000000000..d8a63a481 --- /dev/null +++ b/movement/BusMovement.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.LinkedList; +import java.util.List; + +import movement.map.MapNode; +import core.Coord; +import core.Settings; + +/** + * This class controls the movement of busses. It informs the bus control system + * the bus is registered with every time the bus stops. + * + * @author Frans Ekman + */ +public class BusMovement extends MapRouteMovement { + + private BusControlSystem controlSystem; + private int id; + private static int nextID = 0; + private boolean startMode; + private List stops; + + /** + * Creates a new instance of BusMovement + * @param settings + */ + public BusMovement(Settings settings) { + super(settings); + int bcs = settings.getInt(BusControlSystem.BUS_CONTROL_SYSTEM_NR); + controlSystem = BusControlSystem.getBusControlSystem(bcs); + controlSystem.setMap(super.getMap()); + this.id = nextID++; + controlSystem.registerBus(this); + startMode = true; + stops = new LinkedList(); + List stopNodes = super.getStops(); + for (MapNode node : stopNodes) { + stops.add(node.getLocation().clone()); + } + controlSystem.setBusStops(stops); + } + + /** + * Create a new instance from a prototype + * @param proto + */ + public BusMovement(BusMovement proto) { + super(proto); + this.controlSystem = proto.controlSystem; + this.id = nextID++; + controlSystem.registerBus(this); + startMode = true; + } + + @Override + public Coord getInitialLocation() { + return (super.getInitialLocation()).clone(); + } + + @Override + public Path getPath() { + Coord lastLocation = (super.getLastLocation()).clone(); + Path path = super.getPath(); + if (!startMode) { + controlSystem.busHasStopped(id, lastLocation, path); + } + startMode = false; + return path; + } + + @Override + public BusMovement replicate() { + return new BusMovement(this); + } + + /** + * Returns unique ID of the bus + * @return unique ID of the bus + */ + public int getID() { + return id; + } + +} diff --git a/movement/BusTravellerMovement.java b/movement/BusTravellerMovement.java new file mode 100644 index 000000000..51b8b8bdc --- /dev/null +++ b/movement/BusTravellerMovement.java @@ -0,0 +1,357 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.List; +import java.util.Random; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; + +/** + * + * This class controls the movement of bus travellers. A bus traveller belongs + * to a bus control system. A bus traveller has a destination and a start + * location. If the direct path to the destination is longer than the path the + * node would have to walk if it would take the bus, the node uses the bus. If + * the destination is not provided, the node will pass a random number of stops + * determined by Markov chains (defined in settings). + * + * @author Frans Ekman + * + */ +public class BusTravellerMovement extends MapBasedMovement implements + SwitchableMovement, TransportMovement { + + public static final String PROBABILITIES_STRING = "probs"; + public static final String PROBABILITY_TAKE_OTHER_BUS = "probTakeOtherBus"; + + public static final int STATE_WAITING_FOR_BUS = 0; + public static final int STATE_DECIDED_TO_ENTER_A_BUS = 1; + public static final int STATE_TRAVELLING_ON_BUS = 2; + public static final int STATE_WALKING_ELSEWHERE = 3; + + private int state; + private Path nextPath; + private Coord location; + private Coord latestBusStop; + private BusControlSystem controlSystem; + private int id; + private ContinueBusTripDecider cbtd; + private double[] probabilities; + private double probTakeOtherBus; + private DijkstraPathFinder pathFinder; + + private Coord startBusStop; + private Coord endBusStop; + + private boolean takeBus; + + private static int nextID = 0; + + /** + * Creates a BusTravellerModel + * @param settings + */ + public BusTravellerMovement(Settings settings) { + super(settings); + int bcs = settings.getInt(BusControlSystem.BUS_CONTROL_SYSTEM_NR); + controlSystem = BusControlSystem.getBusControlSystem(bcs); + id = nextID++; + controlSystem.registerTraveller(this); + nextPath = new Path(); + state = STATE_WALKING_ELSEWHERE; + if (settings.contains(PROBABILITIES_STRING)) { + probabilities = settings.getCsvDoubles(PROBABILITIES_STRING); + } + if (settings.contains(PROBABILITY_TAKE_OTHER_BUS)) { + probTakeOtherBus = settings.getDouble(PROBABILITY_TAKE_OTHER_BUS); + } + cbtd = new ContinueBusTripDecider(rng, probabilities); + pathFinder = new DijkstraPathFinder(null); + takeBus = true; + } + + /** + * Creates a BusTravellerModel from a prototype + * @param proto + */ + public BusTravellerMovement(BusTravellerMovement proto) { + super(proto); + state = proto.state; + controlSystem = proto.controlSystem; + if (proto.location != null) { + location = proto.location.clone(); + } + nextPath = proto.nextPath; + id = nextID++; + controlSystem.registerTraveller(this); + probabilities = proto.probabilities; + cbtd = new ContinueBusTripDecider(rng, probabilities); + pathFinder = proto.pathFinder; + this.probTakeOtherBus = proto.probTakeOtherBus; + takeBus = true; + } + + @Override + public Coord getInitialLocation() { + + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int index = rng.nextInt(mapNodes.length - 1); + location = mapNodes[index].getLocation().clone(); + + List allStops = controlSystem.getBusStops(); + Coord closestToNode = getClosestCoordinate(allStops, location.clone()); + latestBusStop = closestToNode.clone(); + + return location.clone(); + } + + @Override + public Path getPath() { + if (!takeBus) { + return null; + } + if (state == STATE_WAITING_FOR_BUS) { + return null; + } else if (state == STATE_DECIDED_TO_ENTER_A_BUS) { + state = STATE_TRAVELLING_ON_BUS; + List coords = nextPath.getCoords(); + location = (coords.get(coords.size() - 1)).clone(); + return nextPath; + } else if (state == STATE_WALKING_ELSEWHERE) { + // Try to find back to the bus stop + SimMap map = controlSystem.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(location); + MapNode destinationNode = map.getNodeByCoord(latestBusStop); + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + location = latestBusStop.clone(); + return path; + } + + return null; + } + + /** + * Switches state between getPath() calls + * @return Always 0 + */ + protected double generateWaitTime() { + if (state == STATE_WALKING_ELSEWHERE) { + if (location.equals(latestBusStop)) { + state = STATE_WAITING_FOR_BUS; + } + } + if (state == STATE_TRAVELLING_ON_BUS) { + state = STATE_WAITING_FOR_BUS; + } + return 0; + } + + @Override + public MapBasedMovement replicate() { + return new BusTravellerMovement(this); + } + + public int getState() { + return state; + } + + /** + * Get the location where the bus is located when it has moved its path + * @return The end point of the last path returned + */ + public Coord getLocation() { + if (location == null) { + return null; + } + return location.clone(); + } + + /** + * Notifies the node at the bus stop that a bus is there. Nodes inside + * busses are also notified. + * @param nextPath The next path the bus is going to take + */ + public void enterBus(Path nextPath) { + + if (startBusStop != null && endBusStop != null) { + if (location.equals(endBusStop)) { + state = STATE_WALKING_ELSEWHERE; + latestBusStop = location.clone(); + } else { + state = STATE_DECIDED_TO_ENTER_A_BUS; + this.nextPath = nextPath; + } + return; + } + + if (!cbtd.continueTrip()) { + state = STATE_WAITING_FOR_BUS; + this.nextPath = null; + /* It might decide not to start walking somewhere and wait + for the next bus */ + if (rng.nextDouble() > probTakeOtherBus) { + state = STATE_WALKING_ELSEWHERE; + latestBusStop = location.clone(); + } + } else { + state = STATE_DECIDED_TO_ENTER_A_BUS; + this.nextPath = nextPath; + } + } + + public int getID() { + return id; + } + + + /** + * Small class to help nodes decide if they should continue the bus trip. + * Keeps the state of nodes, i.e. how many stops they have passed so far. + * Markov chain probabilities for the decisions. + * + * NOT USED BY THE WORKING DAY MOVEMENT MODEL + * + * @author Frans Ekman + */ + class ContinueBusTripDecider { + + private double[] probabilities; // Probability to travel with bus + private int state; + private Random rng; + + public ContinueBusTripDecider(Random rng, double[] probabilities) { + this.rng = rng; + this.probabilities = probabilities; + state = 0; + } + + /** + * + * @return true if node should continue + */ + public boolean continueTrip() { + double rand = rng.nextDouble(); + if (rand < probabilities[state]) { + incState(); + return true; + } else { + resetState(); + return false; + } + } + + /** + * Call when a stop has been passed + */ + private void incState() { + if (state < probabilities.length - 1) { + state++; + } + } + + /** + * Call when node has finished it's trip + */ + private void resetState() { + state = 0; + } + } + + /** + * Help method to find the closest coordinate from a list of coordinates, + * to a specific location + * @param allCoords list of coordinates to compare + * @param coord destination node + * @return closest to the destination + */ + private static Coord getClosestCoordinate(List allCoords, + Coord coord) { + Coord closestCoord = null; + double minDistance = Double.POSITIVE_INFINITY; + for (Coord temp : allCoords) { + double distance = temp.distance(coord); + if (distance < minDistance) { + minDistance = distance; + closestCoord = temp; + } + } + return closestCoord.clone(); + } + + /** + * Sets the next route for the traveller, so that it can decide wether it + * should take the bus or not. + * @param nodeLocation + * @param nodeDestination + */ + public void setNextRoute(Coord nodeLocation, Coord nodeDestination) { + + // Find closest stops to current location and destination + List allStops = controlSystem.getBusStops(); + + Coord closestToNode = getClosestCoordinate(allStops, nodeLocation); + Coord closestToDestination = getClosestCoordinate(allStops, + nodeDestination); + + // Check if it is shorter to walk than take the bus + double directDistance = nodeLocation.distance(nodeDestination); + double busDistance = nodeLocation.distance(closestToNode) + + nodeDestination.distance(closestToDestination); + + if (directDistance < busDistance) { + takeBus = false; + } else { + takeBus = true; + } + + this.startBusStop = closestToNode; + this.endBusStop = closestToDestination; + this.latestBusStop = startBusStop.clone(); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return location.clone(); + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + location = lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + if (state == STATE_WALKING_ELSEWHERE) { + return true; + } else { + return false; + } + } + + public static void reset() { + nextID = 0; + } + +} diff --git a/movement/CarMovement.java b/movement/CarMovement.java new file mode 100644 index 000000000..19518ef33 --- /dev/null +++ b/movement/CarMovement.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.List; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import core.Coord; +import core.Settings; + +/** + * The CarMovement class representing the car movement submodel + * + * @author Frans Ekman + */ +public class CarMovement extends MapBasedMovement implements + SwitchableMovement, TransportMovement { + + private Coord from; + private Coord to; + + private DijkstraPathFinder pathFinder; + + /** + * Car movement constructor + * @param settings + */ + public CarMovement(Settings settings) { + super(settings); + pathFinder = new DijkstraPathFinder(getOkMapNodeTypes()); + } + + /** + * Construct a new CarMovement instance from a prototype + * @param proto + */ + public CarMovement(CarMovement proto) { + super(proto); + this.pathFinder = proto.pathFinder; + } + + /** + * Sets the next route to be taken + * @param nodeLocation + * @param nodeDestination + */ + public void setNextRoute(Coord nodeLocation, Coord nodeDestination) { + from = nodeLocation.clone(); + to = nodeDestination.clone(); + } + + @Override + public Path getPath() { + Path path = new Path(generateSpeed()); + + MapNode fromNode = getMap().getNodeByCoord(from); + MapNode toNode = getMap().getNodeByCoord(to); + + List nodePath = pathFinder.getShortestPath(fromNode, toNode); + + for (MapNode node : nodePath) { // create a Path from the shortest path + path.addWaypoint(node.getLocation()); + } + + lastMapNode = toNode; + + return path; + } + + /** + * @see SwitchableMovement + * @return true + */ + public boolean isReady() { + return true; + } +} diff --git a/movement/ClusterMovement.java b/movement/ClusterMovement.java new file mode 100644 index 000000000..c4d666303 --- /dev/null +++ b/movement/ClusterMovement.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +/** + * Random waypoint movement where the coordinates are restricted to circular + * area defined by a central point and range. + * @author teemuk + */ +package movement; + +import core.Coord; +import core.Settings; + +public class ClusterMovement extends RandomWaypoint { + /** Range of the cluster */ + public static final String CLUSTER_RANGE = "clusterRange"; + /** Center point of the cluster */ + public static final String CLUSTER_CENTER = "clusterCenter"; + + private int p_x_center = 100, p_y_center = 100; + private double p_range = 100.0; + + public ClusterMovement(Settings s) { + super(s); + + if (s.contains(CLUSTER_RANGE)){ + this.p_range = s.getDouble(CLUSTER_RANGE); + } + if (s.contains(CLUSTER_CENTER)){ + int[] center = s.getCsvInts(CLUSTER_CENTER,2); + this.p_x_center = center[0]; + this.p_y_center = center[1]; + } + } + + private ClusterMovement(ClusterMovement cmv) { + super(cmv); + this.p_range = cmv.p_range; + this.p_x_center = cmv.p_x_center; + this.p_y_center = cmv.p_y_center; + } + + @Override + protected Coord randomCoord() { + double x = (rng.nextDouble()*2 - 1)*this.p_range; + double y = (rng.nextDouble()*2 - 1)*this.p_range; + while (x*x + y*y>this.p_range*this.p_range) { + x = (rng.nextDouble()*2 - 1)*this.p_range; + y = (rng.nextDouble()*2 - 1)*this.p_range; + } + x += this.p_x_center; + y += this.p_y_center; + return new Coord(x,y); + } + + @Override + public int getMaxX() { + return (int)Math.ceil(this.p_x_center + this.p_range); + } + + @Override + public int getMaxY() { + return (int)Math.ceil(this.p_y_center + this.p_range); + } + + @Override + public ClusterMovement replicate() { + return new ClusterMovement(this); + } +} diff --git a/movement/EveningActivityControlSystem.java b/movement/EveningActivityControlSystem.java new file mode 100644 index 000000000..f8fc1042e --- /dev/null +++ b/movement/EveningActivityControlSystem.java @@ -0,0 +1,140 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +import core.Coord; +import core.DTNSim; + +/** + * This class controls the group mobility of the people meeting their friends in + * the evening + * + * @author Frans Ekman + */ +public class EveningActivityControlSystem { + + private HashMap eveningActivityNodes; + private List meetingSpots; + private EveningTrip[] nextTrips; + + private Random rng; + + private static HashMap + controlSystems; + + static { + DTNSim.registerForReset(EveningActivityControlSystem.class. + getCanonicalName()); + reset(); + } + + /** + * Creates a new instance of EveningActivityControlSystem without any nodes + * or meeting spots, with the ID given as parameter + * @param id + */ + private EveningActivityControlSystem(int id) { + eveningActivityNodes = new HashMap(); + } + + public static void reset() { + controlSystems = new HashMap(); + } + + /** + * Register a evening activity node with the system + * @param eveningMovement activity movement + */ + public void addEveningActivityNode(EveningActivityMovement eveningMovement) { + eveningActivityNodes.put(new Integer(eveningMovement.getID()), + eveningMovement); + } + + /** + * Sets the meeting locations the nodes can choose among + * @param meetingSpots + */ + public void setMeetingSpots(List meetingSpots) { + this.meetingSpots = meetingSpots; + this.nextTrips = new EveningTrip[meetingSpots.size()]; + } + + /** + * This method gets the instruction for a node, i.e. When/where and with + * whom to go. + * @param eveningActivityNodeID unique ID of the node + * @return Instructions object + */ + public EveningTrip getEveningInstructions(int eveningActivityNodeID) { + EveningActivityMovement eveningMovement = eveningActivityNodes.get( + new Integer(eveningActivityNodeID)); + if (eveningMovement != null) { + int index = eveningActivityNodeID % meetingSpots.size(); + if (nextTrips[index] == null) { + int nrOfEveningMovementNodes = (int)(eveningMovement. + getMinGroupSize() + + (double)(eveningMovement.getMaxGroupSize() - + eveningMovement.getMinGroupSize()) * + rng.nextDouble()); + Coord loc = meetingSpots.get(index).clone(); + nextTrips[index] = new EveningTrip(nrOfEveningMovementNodes, + loc); + } + nextTrips[index].addNode(eveningMovement); + if (nextTrips[index].isFull()) { + EveningTrip temp = nextTrips[index]; + nextTrips[index] = null; + return temp; + } else { + return nextTrips[index]; + } + } + return null; + } + + /** + * Get the meeting spot for the node + * @param id + * @return Coordinates of the spot + */ + public Coord getMeetingSpotForID(int id) { + int index = id % meetingSpots.size(); + Coord loc = meetingSpots.get(index).clone(); + return loc; + } + + + /** + * Sets the random number generator to be used + * @param rand + */ + public void setRandomNumberGenerator(Random rand) { + this.rng = rand; + } + + /** + * Returns a reference to a EveningActivityControlSystem with ID provided as + * parameter. If a system does not already exist with the requested ID, a + * new one is created. + * @param id unique ID of the EveningActivityControlSystem + * @return The EveningActivityControlSystem with the provided ID + */ + public static EveningActivityControlSystem getEveningActivityControlSystem( + int id) { + if (controlSystems.containsKey(new Integer(id))) { + return controlSystems.get(new Integer(id)); + } else { + EveningActivityControlSystem scs = + new EveningActivityControlSystem(id); + controlSystems.put(new Integer(id), scs); + return scs; + } + } + +} diff --git a/movement/EveningActivityMovement.java b/movement/EveningActivityMovement.java new file mode 100644 index 000000000..60fbf6074 --- /dev/null +++ b/movement/EveningActivityMovement.java @@ -0,0 +1,299 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.WKTReader; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; + +/** + * A Class to model movement when people are out shopping or doing other + * activities with friends. If the node happens to be at some other location + * than the place where the shopping starts (where it meets its friends), it + * first travels to the destination along the shortest path. + * + * @author Frans Ekman + */ +public class EveningActivityMovement extends MapBasedMovement + implements SwitchableMovement { + + private static final int WALKING_TO_MEETING_SPOT_MODE = 0; + private static final int EVENING_ACTIVITY_MODE = 1; + + public static final String NR_OF_MEETING_SPOTS_SETTING = "nrOfMeetingSpots"; + public static final String EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING = + "shoppingControlSystemNr"; + + public static final String MEETING_SPOTS_FILE_SETTING = "meetingSpotsFile"; + + public static final String MIN_GROUP_SIZE_SETTING = "minGroupSize"; + public static final String MAX_GROUP_SIZE_SETTING = "maxGroupSize"; + + public static final String MIN_WAIT_TIME_SETTING = + "minAfterShoppingStopTime"; + public static final String MAX_WAIT_TIME_SETTING = + "maxAfterShoppingStopTime"; + + private static int nrOfMeetingSpots = 10; + + private int mode; + private boolean ready; + private DijkstraPathFinder pathFinder; + + private Coord lastWaypoint; + private Coord startAtLocation; + + private EveningActivityControlSystem scs; + private EveningTrip trip; + + private boolean readyToShop; + + private int id; + + private static int nextID = 0; + + private int minGroupSize; + private int maxGroupSize; + + /** + * Creates a new instance of EveningActivityMovement + * @param settings + */ + public EveningActivityMovement(Settings settings) { + super(settings); + super.backAllowed = false; + pathFinder = new DijkstraPathFinder(null); + mode = WALKING_TO_MEETING_SPOT_MODE; + + nrOfMeetingSpots = settings.getInt(NR_OF_MEETING_SPOTS_SETTING); + + minGroupSize = settings.getInt(MIN_GROUP_SIZE_SETTING); + maxGroupSize = settings.getInt(MAX_GROUP_SIZE_SETTING); + + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + + String shoppingSpotsFile = null; + try { + shoppingSpotsFile = settings.getSetting(MEETING_SPOTS_FILE_SETTING); + } catch (Throwable t) { + // Do nothing; + } + + List meetingSpotLocations = null; + + if (shoppingSpotsFile == null) { + meetingSpotLocations = new LinkedList(); + for (int i=0; i(); + List locationsRead = (new WKTReader()).readPoints( + new File(shoppingSpotsFile)); + for (Coord coord : locationsRead) { + SimMap map = getMap(); + Coord offset = map.getOffset(); + // mirror points if map data is mirrored + if (map.isMirrored()) { + coord.setLocation(coord.getX(), -coord.getY()); + } + coord.translate(offset.getX(), offset.getY()); + meetingSpotLocations.add(coord); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + this.id = nextID++; + + int scsID = settings.getInt(EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING); + + scs = EveningActivityControlSystem.getEveningActivityControlSystem(scsID); + scs.setRandomNumberGenerator(rng); + scs.addEveningActivityNode(this); + scs.setMeetingSpots(meetingSpotLocations); + + maxPathLength = 100; + minPathLength = 10; + + maxWaitTime = settings.getInt(MAX_WAIT_TIME_SETTING); + minWaitTime = settings.getInt(MIN_WAIT_TIME_SETTING); + } + + /** + * Creates a new instance of EveningActivityMovement from a prototype + * @param proto + */ + public EveningActivityMovement(EveningActivityMovement proto) { + super(proto); + this.pathFinder = proto.pathFinder; + this.mode = proto.mode; + this.id = nextID++; + scs = proto.scs; + scs.addEveningActivityNode(this); + this.setMinGroupSize(proto.getMinGroupSize()); + this.setMaxGroupSize(proto.getMaxGroupSize()); + } + + /** + * @return Unique ID of the shopper + */ + public int getID() { + return this.id; + } + + @Override + public Coord getInitialLocation() { + + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int index = rng.nextInt(mapNodes.length - 1); + lastWaypoint = mapNodes[index].getLocation().clone(); + return lastWaypoint.clone(); + } + + @Override + public Path getPath() { + if (mode == WALKING_TO_MEETING_SPOT_MODE) { + // Try to find to the shopping center + SimMap map = super.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(lastWaypoint); + MapNode destinationNode = map.getNodeByCoord(startAtLocation); + + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + lastWaypoint = startAtLocation.clone(); + mode = EVENING_ACTIVITY_MODE; + return path; + } else if (mode == EVENING_ACTIVITY_MODE) { + readyToShop = true; + if (trip.allMembersPresent()) { + Path path = trip.getPath(); + if (path == null) { + super.lastMapNode = super.getMap(). + getNodeByCoord(lastWaypoint); + path = super.getPath(); // TODO Create levy walk path + lastWaypoint = super.lastMapNode.getLocation(); + trip.setPath(path); + double waitTimeAtEnd = (maxWaitTime - minWaitTime) * + rng.nextDouble() + minWaitTime; + trip.setWaitTimeAtEnd(waitTimeAtEnd); + trip.setDestination(lastWaypoint); + } + lastWaypoint = trip.getDestination(); + ready = true; + return path; + } + } + + return null; + } + + @Override + protected double generateWaitTime() { + if (ready) { + double wait = trip.getWaitTimeAtEnd(); + return wait; + } else { + return 0; + } + } + + @Override + public MapBasedMovement replicate() { + return new EveningActivityMovement(this); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + return ready; + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + this.lastWaypoint = lastWaypoint.clone(); + ready = false; + mode = WALKING_TO_MEETING_SPOT_MODE; + } + + /** + * Sets the node ready to start a shopping trip. + * @return The coordinate of the place where the shopping trip starts + */ + public Coord getShoppingLocationAndGetReady() { + readyToShop = false; // New shopping round starts + trip = scs.getEveningInstructions(id); + startAtLocation = trip.getLocation().clone(); + return startAtLocation.clone(); + } + + + public Coord getShoppingLocation() { + return scs.getMeetingSpotForID(id).clone(); + } + + + /** + * Checks if a node is at the correct place where the shopping begins + * @return true if node is ready and waiting for the rest of the group to + * arrive + */ + public boolean isReadyToShop() { + return readyToShop; + } + + public static void reset() { + nextID = 0; + } + + public int getMinGroupSize() { + return minGroupSize; + } + + public void setMinGroupSize(int minGroupSize) { + this.minGroupSize = minGroupSize; + } + + public int getMaxGroupSize() { + return maxGroupSize; + } + + public void setMaxGroupSize(int maxGroupSize) { + this.maxGroupSize = maxGroupSize; + } + +} diff --git a/movement/EveningTrip.java b/movement/EveningTrip.java new file mode 100644 index 000000000..8e34e3825 --- /dev/null +++ b/movement/EveningTrip.java @@ -0,0 +1,128 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; + +/** + * A class to encapsulate information about a shopping trip + * 1. Where the trip begins + * 2. Where it ends + * 3. The path + * 4. All nodes in the group + * + * @author Frans Ekman + */ +public class EveningTrip { + private EveningActivityMovement[] eveningActivityNodes; + private int eveningActivityNodesInBuffer; + private Path path; + private Coord location; + private Coord destination; + private double waitTimeAtEnd; + + /** + * Create a new instance of a EveningTrip + * @param nrOfeveningActivityNodes The number of shoppers in the group + * @param location Where the trip starts + */ + public EveningTrip(int nrOfeveningActivityNodes, Coord location) { + eveningActivityNodes = + new EveningActivityMovement[nrOfeveningActivityNodes]; + this.location = location; + eveningActivityNodesInBuffer = 0; + } + + /** + * Add an evening activity node to the group + * @param eveningActivityNode + * @return true if there was room in the group + */ + public boolean addNode(EveningActivityMovement eveningActivityNode) { + if (isFull()) { + return false; + } else { + eveningActivityNodes[eveningActivityNodesInBuffer] = + eveningActivityNode; + eveningActivityNodesInBuffer++; + return true; + } + } + + /** + * Sets the shopping path for the group + * @param path + */ + public void setPath(Path path) { + this.path = new Path(path); + } + + /** + * @return The shopping trip path + */ + public Path getPath() { + if (path != null) { + return new Path(this.path); + } else { + return null; + } + } + + /** + * @return The location where the shopping trip starts + */ + public Coord getLocation() { + return location; + } + + /** + * @return true if the group is full + */ + public boolean isFull() { + return eveningActivityNodesInBuffer >= eveningActivityNodes.length; + } + + /** + * Checks if all members of the group have found their way to the meeting + * point + * @return true if all nodes are there + */ + public boolean allMembersPresent() { + if (!isFull()) { + return false; + } + for (int i=0; i idMapping; + /** initial locations for nodes */ + private static List> initLocations; + /** time of the very first location data */ + private static double initTime; + /** sampling interval (seconds) of the location data */ + private static double samplingInterval; + /** last read time stamp after preloading */ + private static double lastPreloadTime; + /** how many time intervals to load on every preload run */ + private static double nrofPreload = 10; + /** minimum number intervals that should be preloaded ahead of sim time */ + private static final double MIN_AHEAD_INTERVALS = 2; + + /** the very first location of the node */ + private Coord intialLocation; + /** queue of path-start-time, path tuples */ + private Queue> pathQueue; + + /** when was the path currently under construction started */ + private double latestPathStartTime; + /** the last location of path waypoint */ + private Coord latestLocation; + /** the path currently under construction */ + private Path latestPath; + + /** is this node active */ + private boolean isActive; + + static { + DTNSim.registerForReset(ExternalMovement.class.getCanonicalName()); + reset(); + } + + /** + * Constructor for the prototype. Run once per group. + * @param settings Where settings are read from + */ + public ExternalMovement(Settings settings) { + super(settings); + + if (idMapping == null) { + // run these the first time object is created or after reset call + Settings s = new Settings(EXTERNAL_MOVEMENT_NS); + idMapping = new HashMap(); + inputFileName = s.getSetting(MOVEMENT_FILE_S); + reader = new ExternalMovementReader(inputFileName); + + initLocations = reader.readNextMovements(); + initTime = reader.getLastTimeStamp(); + samplingInterval = -1; + lastPreloadTime = -1; + + s.setNameSpace(EXTERNAL_MOVEMENT_NS); + if (s.contains(NROF_PRELOAD_S)) { + nrofPreload = s.getInt(NROF_PRELOAD_S); + if (nrofPreload <= 0) { + nrofPreload = 1; + } + } + } + } + + /** + * Copy constructor. Gives out location data for the new node from + * location queue. + * @param mm The movement model to copy from + */ + private ExternalMovement(MovementModel mm) { + super(mm); + + pathQueue = new LinkedList>(); + latestPath = null; + + if (initLocations.size() > 0) { // we have location data left + // gets a new location from the list + Tuple initLoc = initLocations.remove(0); + this.intialLocation = this.latestLocation = initLoc.getValue(); + this.latestPathStartTime = initTime; + + // puts the new model to model map for later updates + idMapping.put(initLoc.getKey(), this); + isActive = true; + } + else { + // no more location data left for the new node -> set inactive + this.intialLocation = DEF_INIT_LOC; + isActive = false; + } + } + + /** + * Checks if more paths should be preloaded and preloads them if + * needed. + */ + private static void checkPathNeed() { + if (samplingInterval == -1) { // first preload + lastPreloadTime = readMorePaths(); + } + + if (!Double.isNaN(lastPreloadTime) && SimClock.getTime() >= + lastPreloadTime - (samplingInterval * MIN_AHEAD_INTERVALS) ) { + for (int i=0; i < nrofPreload && + !Double.isNaN(lastPreloadTime); i++) { + lastPreloadTime = readMorePaths(); + } + } + } + + @Override + public Coord getInitialLocation() { + return this.intialLocation; + } + + @Override + public boolean isActive() { + return isActive; + } + + /** + * Adds a new location with a time to this model's move pattern. If the + * node stayed stationary during the update, the current path is put to the + * queue and a new path is started once the node starts moving. + * @param loc The location + * @param time When should the node be there + */ + private void addLocation(Coord loc, double time) { + assert samplingInterval > 0 : "Non-positive sampling interval!"; + + if (loc.equals(latestLocation)) { // node didn't move + if (latestPath != null) { + // constructing path -> end constructing and put it in the queue + pathQueue.add(new Tuple + (latestPathStartTime, latestPath)); + latestPath = null; + } + + this.latestPathStartTime = time; + return; + } + + if (latestPath == null) { + latestPath = new Path(); + } + + double speed = loc.distance(this.latestLocation) / samplingInterval; + latestPath.addWaypoint(loc, speed); + + this.latestLocation = loc; + } + + /** + * Returns a sim time when the next path is available. + * @return The sim time when node should ask the next time for a path + */ + @Override + public double nextPathAvailable() { + if (pathQueue.size() == 0) { + return latestPathStartTime; + } + else { + return pathQueue.element().getKey(); + } + } + + @Override + public Path getPath() { + Path p; + + checkPathNeed(); // check if we should preload more paths + + if (SimClock.getTime() < this.nextPathAvailable()) { + return null; + } + + if (pathQueue.size() == 0) { // nothing in the queue, return latest + p = latestPath; + latestPath = null; + } + else { // return first path in the queue + p = pathQueue.remove().getValue(); + } + + return p; + } + + @Override + public int getMaxX() { + return (int)(reader.getMaxX() - reader.getMinX()) + 1; + } + + @Override + public int getMaxY() { + return (int)(reader.getMaxY() - reader.getMinY()) + 1; + } + + + @Override + public MovementModel replicate() { + return new ExternalMovement(this); + } + + /** + * Reads paths for the next time instance from the reader + * @return The time stamp of the reading or Double.NaN if no movements + * were read. + */ + private static double readMorePaths() { + List> list = reader.readNextMovements(); + double time = reader.getLastTimeStamp(); + + if (samplingInterval == -1) { + samplingInterval = time - initTime; + } + + for (Tuple t : list) { + ExternalMovement em = idMapping.get(t.getKey()); + if (em != null) { // skip unknown IDs, i.e. IDs not mentioned in... + // ...init phase or if there are more IDs than nodes + em.addLocation(t.getValue(), time); + } + } + + if (list.size() > 0) { + return time; + } + else { + return Double.NaN; + } + } + + /** + * Reset state so that next instance will have a fresh state + */ + public static void reset() { + idMapping = null; + } + +} diff --git a/movement/ExternalPathMovement.java b/movement/ExternalPathMovement.java new file mode 100644 index 000000000..bdc9e34f4 --- /dev/null +++ b/movement/ExternalPathMovement.java @@ -0,0 +1,162 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.ExternalPathMovementReader; + +import java.util.List; + +import core.Coord; +import core.DTNHost; +import core.Settings; +import core.SimClock; + +/** + * External movement trace reader for traces that are in path format. + * See ExternalPathMovementReader for details. + * + * @author teemuk + * + */ +public class ExternalPathMovement extends MovementModel { + /** external locations file's path -setting id ({@value})*/ + public static final String MOVEMENT_FILE_S = "traceFile"; + /** activity file's path -setting id ({@value})*/ + public static final String ACTIVITY_FILE_S = "activeFile"; + + // Settings + private String traceFile; + private String activeFile; + + // Node's paths + private List> paths; + private int curPath=0; + private List active; + + public ExternalPathMovement(Settings settings) { + this.traceFile = settings.getSetting(MOVEMENT_FILE_S); + this.activeFile = settings.getSetting(ACTIVITY_FILE_S); + } + + /** + * Copy-constructor. + * + * @param mm + */ + public ExternalPathMovement(ExternalPathMovement mm) { + this.traceFile = mm.traceFile; + this.activeFile = mm.activeFile; + } + + /** + * Initializes the movement model. Uses a reader to get the paths for this + * host. + */ + private void init() { + // Get paths for this node + ExternalPathMovementReader reader = + ExternalPathMovementReader.getInstance(this.traceFile, + this.activeFile); + this.paths = reader.getPaths(getHost().getAddress()); + this.active = reader.getActive(getHost().getAddress()); + } + + @Override + public void setHost(DTNHost host) { + super.setHost(host); + this.init(); // Can only initialize after the host has been set + } + + @Override + public boolean isActive() { + double t = SimClock.getTime(); + + // Check whether the current time falls in one of the active periods + for (ExternalPathMovementReader.ActiveTime a : this.active) { + if (t >= a.start && t <= a.end) return true; + } + + return false; + } + + @Override + public Path getPath() { + // Make sure to not give out paths when the node is not active + if (!this.isActive()) { + return null; + } + + // Check whether we're moving or waiting for the next path to start + double t = SimClock.getTime(); + if (t < this.paths.get(this.curPath).get(0).time) { + return null; + } + + // Get the path + List path = + this.paths.get(this.curPath); + this.curPath++; + + // Drop the node to the the beginning of the new path in case the + // previous path ended somewhere else. + Coord curPos = super.getHost().getLocation(); + ExternalPathMovementReader.Entry pathStart = path.get(0); + if (curPos.getX() != pathStart.x || + curPos.getY() != pathStart.y) { + Coord c = new Coord(pathStart.x, pathStart.y); + super.getHost().setLocation(c); + } + + // If this is a stationary path, return only the fist point + if (path.size() == 1) { + Path p = new Path(0); + ExternalPathMovementReader.Entry e = path.get(0); + Coord c = new Coord(e.x, e.y); + p.addWaypoint(c); + return p; + } + + // Build and return the whole path at once + Path p = new Path(); + for (int i=1; i < path.size(); i++) { + ExternalPathMovementReader.Entry e = path.get(i); + ExternalPathMovementReader.Entry e2 = path.get(i-1); + Coord c = new Coord(e.x, e.y); + double dt = e.time - e2.time; + double ds = Math.sqrt( (e.x - e2.x) * (e.x - e2.x) + + (e.y - e2.y) * (e.y - e2.y)); + double v = ds/dt; + p.addWaypoint(c, v); + } + + return p; + } + + @Override + public Coord getInitialLocation() { + // Return the first point of the first path + if (this.paths.size() > 0 && + this.paths.get(0).size() > 0) { + ExternalPathMovementReader.Entry e = this.paths.get(0).get(0); + Coord c = new Coord(e.x, e.y); + return c; + } + return new Coord(0.0, 0.0); + } + + @Override + public MovementModel replicate() { + ExternalPathMovement mm = new ExternalPathMovement(this); + return mm; + } + + @Override + public double nextPathAvailable() { + if (this.curPath < this.paths.size()) + return this.paths.get(this.curPath).get(0).time; + else + return Double.MAX_VALUE; + } +} diff --git a/movement/GridLocation.java b/movement/GridLocation.java new file mode 100644 index 000000000..629bb3ab7 --- /dev/null +++ b/movement/GridLocation.java @@ -0,0 +1,107 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; +import core.SimScenario; + +/** + * Location (movement) model that sets the nodes in a grid formation + */ +public class GridLocation extends MovementModel { + /** Sub name space for the grid location settings ({@value}) */ + public static final String GRIDLOC_NS = "GridLocation"; + /** How many rows of nodes there are -setting ({@value}). + * Number of columns is calculated from the node count. */ + public static final String ROWS_S = "rows"; + /** Space between the nodes -setting ({@value}) */ + public static final String SPACING_S = "spacing"; + /** Maximum random offset for the location of the nodes + * -setting ({@value}). Default = 0. */ + public static final String OFFSET_S = "randomOffset"; + /** Location of the first node (grid's upper left corner) + * -setting ({@value}). Two values: x,y */ + public static final String LOCATION_S = "location"; + + private double startCoords[]; + private int rows; + private int cols; + private double spacing; + private double offset; + private int nodeCount; + private Coord loc; + + /** + * Creates a new movement model based on a Settings object's settings. + * @param s The Settings object where the settings are read from + */ + public GridLocation(Settings s) { + super(s); + int nodeCount = s.getInt(SimScenario.NROF_HOSTS_S); + + s.setSubNameSpace(GRIDLOC_NS); + + this.rows = s.getInt(ROWS_S); + this.cols = (nodeCount / this.rows); + this.startCoords = s.getCsvDoubles(LOCATION_S,2); + this.spacing = s.getInt(SPACING_S); + this.offset = s.getDouble(OFFSET_S, 0); + + s.restoreSubNameSpace(); + } + + /** + * Copy constructor. + * @param proto The movement model prototype + */ + public GridLocation(GridLocation proto) { + super(proto); + double x,y; + + x = proto.startCoords[0] + + ((proto.nodeCount) % proto.cols) * proto.spacing; + x += rng.nextDouble() * proto.offset; + + y = proto.startCoords[1] + + ((proto.nodeCount) / proto.cols) * proto.spacing; + y += rng.nextDouble() * proto.offset; + + this.loc = new Coord(x,y); + + proto.nodeCount++; + } + + /** + * Returns the only location of this movement model + * @return the only location of this movement model + */ + @Override + public Coord getInitialLocation() { + return loc; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public GridLocation replicate() { + return new GridLocation(this); + } + +} diff --git a/movement/HomeActivityMovement.java b/movement/HomeActivityMovement.java new file mode 100644 index 000000000..ba666af6d --- /dev/null +++ b/movement/HomeActivityMovement.java @@ -0,0 +1,249 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.WKTReader; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; +import core.SimClock; + +/** + * A Class to model movement at home. If the node happens to be at some other + * location than its home, it first walks the shortest path home location and + * then stays there until morning. A node has only one home + * + * @author Frans Ekman + */ +public class HomeActivityMovement extends MapBasedMovement + implements SwitchableMovement { + + private static final int WALKING_HOME_MODE = 0; + private static final int AT_HOME_MODE = 1; + private static final int READY_MODE = 2; + + private static final int DAY_LENGTH = 86000; + + public static final String HOME_LOCATIONS_FILE_SETTING = "homeLocationsFile"; + + public static final String STD_FOR_TIME_DIFF_SETTING = "timeDiffSTD"; + + private int mode; + private DijkstraPathFinder pathFinder; + + private int distance; + + private Coord lastWaypoint; + private Coord homeLocation; + + private List allHomes; + + private int timeDiffSTD; + private int timeDifference; + + /** + * Creates a new instance of HomeActivityMovement + * @param settings + */ + public HomeActivityMovement(Settings settings) { + super(settings); + distance = 100; + pathFinder = new DijkstraPathFinder(null); + mode = WALKING_HOME_MODE; + + String homeLocationsFile = null; + try { + homeLocationsFile = settings.getSetting(HOME_LOCATIONS_FILE_SETTING); + } catch (Throwable t) { + // Do nothing; + } + + timeDiffSTD = settings.getInt(STD_FOR_TIME_DIFF_SETTING); + + if (homeLocationsFile == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int homeIndex = rng.nextInt(mapNodes.length - 1); + homeLocation = mapNodes[homeIndex].getLocation().clone(); + } else { + try { + allHomes = new LinkedList(); + List locationsRead = (new WKTReader()).readPoints( + new File(homeLocationsFile)); + for (Coord coord : locationsRead) { + SimMap map = getMap(); + Coord offset = map.getOffset(); + // mirror points if map data is mirrored + if (map.isMirrored()) { + coord.setLocation(coord.getX(), -coord.getY()); + } + coord.translate(offset.getX(), offset.getY()); + allHomes.add(coord); + } + homeLocation = allHomes.get(rng.nextInt(allHomes.size())).clone(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (timeDiffSTD == -1) { + timeDifference = rng.nextInt(DAY_LENGTH) - DAY_LENGTH/2; + } else if (timeDiffSTD == 0) { + timeDifference = 0; + } else { + timeDifference = (int)Math.min( + Math.max( + (rng.nextGaussian() * timeDiffSTD), + -DAY_LENGTH/2 + ), + DAY_LENGTH/2 + ); + } + } + + /** + * Creates a new instance of HomeActivityMovement from a prototype + * @param proto + */ + public HomeActivityMovement(HomeActivityMovement proto) { + super(proto); + this.distance = proto.distance; + this.pathFinder = proto.pathFinder; + this.mode = proto.mode; + + this.timeDiffSTD = proto.timeDiffSTD; + + if (proto.allHomes == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int homeIndex = rng.nextInt(mapNodes.length - 1); + homeLocation = mapNodes[homeIndex].getLocation().clone(); + } else { + this.allHomes = proto.allHomes; + homeLocation = allHomes.get(rng.nextInt(allHomes.size())).clone(); + } + + if (timeDiffSTD == -1) { + timeDifference = rng.nextInt(DAY_LENGTH) - DAY_LENGTH/2; + } else if (timeDiffSTD == 0) { + timeDifference = 0; + } else { + timeDifference = (int)Math.min( + Math.max( + (rng.nextGaussian() * timeDiffSTD), + -DAY_LENGTH/2 + ), + DAY_LENGTH/2 + ); + } + } + + @Override + public Coord getInitialLocation() { + double x = rng.nextDouble() * getMaxX(); + double y = rng.nextDouble() * getMaxY(); + Coord c = new Coord(x,y); + + this.lastWaypoint = c; + return c.clone(); + } + + @Override + public Path getPath() { + if (mode == WALKING_HOME_MODE) { + // Try to find home + SimMap map = super.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(lastWaypoint); + MapNode destinationNode = map.getNodeByCoord(homeLocation); + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + lastWaypoint = homeLocation.clone(); + mode = AT_HOME_MODE; + + double newX = lastWaypoint.getX() + (rng.nextDouble() - 0.5) * + distance; + if (newX > getMaxX()) { + newX = getMaxX(); + } else if (newX < 0) { + newX = 0; + } + double newY = lastWaypoint.getY() + (rng.nextDouble() - 0.5) * + distance; + if (newY > getMaxY()) { + newY = getMaxY(); + } else if (newY < 0) { + newY = 0; + } + Coord c = new Coord(newX, newY); + path.addWaypoint(c); + return path; + } else { + Path path = new Path(1); + path.addWaypoint(lastWaypoint.clone()); + mode = READY_MODE; + return path; + } + + } + + @Override + protected double generateWaitTime() { + if (mode == AT_HOME_MODE) { + return DAY_LENGTH - ((SimClock.getIntTime() + DAY_LENGTH + + timeDifference) % DAY_LENGTH); + } else { + return 0; + } + } + + @Override + public MapBasedMovement replicate() { + return new HomeActivityMovement(this); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + return mode == READY_MODE; + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + this.lastWaypoint = lastWaypoint.clone(); + mode = WALKING_HOME_MODE; + } + + /** + * @return Home location of the node + */ + public Coord getHomeLocation() { + return homeLocation.clone(); + } + +} diff --git a/movement/LinearFormation.java b/movement/LinearFormation.java new file mode 100644 index 000000000..241e65ced --- /dev/null +++ b/movement/LinearFormation.java @@ -0,0 +1,116 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; +import movement.MovementModel; +import movement.Path; + +/** + * A stationary "movement" model where nodes do not move but are in linear + * formation (i.e., in a line). + */ +public class LinearFormation extends MovementModel { + /** Name space of the settings (append to group name space) */ + public static final String LINEAR_FORMATION_NS = "LinearFormation."; + /** Per node group setting for defining the start coordinates of + * the line ({@value}) */ + public static final String START_LOCATION_S = "startLocation"; + /** Per node group setting for defining the end coordinates of + * the line ({@value}) */ + public static final String END_LOCATION_S = "endLocation"; + + /* values for the prototype */ + private Coord startLoc; /** The start location of the line */ + private Coord endLoc; /** The start location of the line */ + private int nodeCount; /** how many nodes in this formation */ + private int lastIndex; /** index of the previous node */ + + /* values for the per-node models */ + private Coord loc; + + /** + * Creates a new movement model based on a Settings object's settings. + * @param s The Settings object where the settings are read from + */ + public LinearFormation(Settings s) { + super(s); + int coords[]; + + coords = s.getCsvInts(LINEAR_FORMATION_NS + START_LOCATION_S, 2); + this.startLoc = new Coord(coords[0], coords[1]); + coords = s.getCsvInts(LINEAR_FORMATION_NS + END_LOCATION_S, 2); + this.endLoc = new Coord(coords[0], coords[1]); + + this.nodeCount = s.getInt(core.SimScenario.NROF_HOSTS_S); + this.lastIndex = 0; + } + + /** + * Copy constructor. + * @param lf The LinearFormation prototype + */ + public LinearFormation(LinearFormation lf) { + super(lf); + this.loc = calculateInitLocation(lf); + } + + /** + * Calculates and returns the location of this node in the formation + * @param proto The movement model prototype + * @return the location of the node + */ + private Coord calculateInitLocation(LinearFormation proto) { + double dx, dy; + double placementFraction; + int formationIndex = proto.lastIndex++; + + Coord c = proto.startLoc.clone(); + + placementFraction = (1.0 * formationIndex / proto.nodeCount); + dx = placementFraction * + (proto.endLoc.getX() - proto.startLoc.getX()); + dy = placementFraction * + (proto.endLoc.getY() - proto.startLoc.getY()); + c.translate(dx, dy); + + return c; + } + + /** + * Returns the the location of the node in the formation + * @return the the location of the node in the formation + */ + @Override + public Coord getInitialLocation() { + return loc; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + + /** + * Returns Double.MAX_VALUE (no paths available) + */ + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public LinearFormation replicate() { + return new LinearFormation(this); + } + +} diff --git a/movement/LinearMovement.java b/movement/LinearMovement.java new file mode 100644 index 000000000..4320390ab --- /dev/null +++ b/movement/LinearMovement.java @@ -0,0 +1,180 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; +import movement.MovementModel; +import movement.Path; + +/** + * Movement model where all nodes move on a line + * (work in progress) + */ +public class LinearMovement extends MovementModel { + /** Name space of the settings (append to group name space) */ + public static final String LINEAR_MOVEMENT_NS = "LinearMovement."; + /** Per node group setting for defining the start coordinates of + * the line ({@value}) */ + public static final String START_LOCATION_S = "startLocation"; + /** Per node group setting for defining the end coordinates of + * the line ({@value}) */ + public static final String END_LOCATION_S = "endLocation"; + + /** + * Nodes' initial location type + *

  • 0: random (evenly distributed) + *
  • 1: evenly spaced + *
+ */ + public static final String INIT_LOC_S = "initLocType"; + /** + * Nodes' target (where they're heading) type + *
  • 0: random point on the line + *
  • 1: far-end of the line + *
+ */ + public static final String TARGET_S = "targetType"; + + /* values for the prototype */ + private Coord startLoc; /** The start location of the line */ + private Coord endLoc; /** The start location of the line */ + private int initLocType; + private int targetType; + private int nodeCount; /** how many nodes in this formation */ + private int lastIndex; /** index of the previous node */ + + /* values for the per-node models */ + private Path nextPath; + private Coord initLoc; + + /** + * Creates a new movement model based on a Settings object's settings. + * @param s The Settings object where the settings are read from + */ + public LinearMovement(Settings s) { + super(s); + int coords[]; + + coords = s.getCsvInts(LINEAR_MOVEMENT_NS + START_LOCATION_S, 2); + this.startLoc = new Coord(coords[0], coords[1]); + coords = s.getCsvInts(LINEAR_MOVEMENT_NS + END_LOCATION_S, 2); + this.endLoc = new Coord(coords[0], coords[1]); + this.initLocType = s.getInt(LINEAR_MOVEMENT_NS + INIT_LOC_S); + this.targetType = s.getInt(LINEAR_MOVEMENT_NS + TARGET_S); + this.nodeCount = s.getInt(core.SimScenario.NROF_HOSTS_S); + + this.lastIndex = 0; + } + + /** + * Copy constructor. + * @param lf The LinearFormation prototype + */ + public LinearMovement(LinearMovement ilm) { + super(ilm); + this.initLoc = calculateLocation(ilm, (ilm.initLocType == 1)); + this.nextPath = new Path(generateSpeed()); + this.nextPath.addWaypoint(initLoc); + + if (ilm.targetType == 0) { /* random target */ + this.nextPath.addWaypoint(calculateLocation(ilm, true)); + } else { + this.nextPath.addWaypoint(calculateEndTarget(ilm, initLoc)); + } + + ilm.lastIndex++; + } + + /** + * Calculates and returns a location in the line + * @param proto The movement model prototype + * @param isEven Is the distribution evenly spaced (false for random) + * @return a location on the line + */ + private Coord calculateLocation(LinearMovement proto, boolean isEven) { + double dx = 0; + double dy = 0; + double placementFraction; + + double xDiff = (proto.endLoc.getX() - proto.startLoc.getX()); + double yDiff = (proto.endLoc.getY() - proto.startLoc.getY()); + Coord c = proto.startLoc.clone(); + + if (isEven) { + placementFraction = (1.0 * proto.lastIndex / proto.nodeCount); + dx = placementFraction * xDiff; + dy = placementFraction * yDiff; + } else { /* random */ + dx = rng.nextDouble() * xDiff; + dy = rng.nextDouble() * yDiff; + } + + c.translate(dx, dy); + return c; + } + + /** + * Calculates and returns the far-end of the line + * @param proto The movement model prototype + * @param initLoc The initial location + * @return the coordinates for the far-end of the line + */ + private Coord calculateEndTarget(LinearMovement proto, Coord initLoc) { + return (proto.startLoc.distance(initLoc) > + proto.endLoc.distance(initLoc) ? proto.startLoc: proto.endLoc); + } + + /** + * Returns the the location of the node in the formation + * @return the the location of the node in the formation + */ + @Override + public Coord getInitialLocation() { + return this.initLoc; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = nextPath; + this.nextPath = null; + return p; + } + + /** + * Returns Double.MAX_VALUE (no paths available) + */ + @Override + public double nextPathAvailable() { + if (nextPath == null) { + return Double.MAX_VALUE; // no new paths available + } else { + return 0; + } + } + + @Override + public int getMaxX() { + return (int)(endLoc.getX() > startLoc.getX() ? endLoc.getX() : + startLoc.getX()); + } + + @Override + public int getMaxY() { + return (int)(endLoc.getY() > startLoc.getY() ? endLoc.getY() : + startLoc.getY()); + } + + + @Override + public LinearMovement replicate() { + return new LinearMovement(this); + } + +} diff --git a/movement/MapBasedMovement.java b/movement/MapBasedMovement.java new file mode 100644 index 000000000..652047f02 --- /dev/null +++ b/movement/MapBasedMovement.java @@ -0,0 +1,432 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.WKTMapReader; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.Vector; + +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; +import core.SettingsError; +import core.SimError; + +/** + * Map based movement model which gives out Paths that use the + * roads of a SimMap. + */ +public class MapBasedMovement extends MovementModel implements SwitchableMovement { + /** sim map for the model */ + private SimMap map = null; + /** node where the last path ended or node next to initial placement */ + protected MapNode lastMapNode; + /** max nrof map nodes to travel/path */ + protected int maxPathLength = 100; + /** min nrof map nodes to travel/path */ + protected int minPathLength = 10; + /** May a node choose to move back the same way it came at a crossing */ + protected boolean backAllowed; + /** map based movement model's settings namespace ({@value})*/ + public static final String MAP_BASE_MOVEMENT_NS = "MapBasedMovement"; + /** number of map files -setting id ({@value})*/ + public static final String NROF_FILES_S = "nrofMapFiles"; + /** map file -setting id ({@value})*/ + public static final String FILE_S = "mapFile"; + + /** + * Per node group setting for selecting map node types that are OK for + * this node group to traverse trough. Value must be a comma separated list + * of integers in range of [1,31]. Values reference to map file indexes + * (see {@link #FILE_S}). If setting is not defined, all map nodes are + * considered OK. + */ + public static final String MAP_SELECT_S = "okMaps"; + + /** the indexes of the OK map files or null if all maps are OK */ + private int [] okMapNodeTypes; + + /** how many map files are read */ + private int nrofMapFilesRead = 0; + /** map cache -- in case last mm read the same map, use it without loading*/ + private static SimMap cachedMap = null; + /** names of the previously cached map's files (for hit comparison) */ + private static List cachedMapFiles = null; + + /** + * Creates a new MapBasedMovement based on a Settings object's settings. + * @param settings The Settings object where the settings are read from + */ + public MapBasedMovement(Settings settings) { + super(settings); + map = readMap(); + readOkMapNodeTypes(settings); + maxPathLength = 100; + minPathLength = 10; + backAllowed = false; + } + + /** + * Creates a new MapBasedMovement based on a Settings object's settings + * but with different SimMap + * @param settings The Settings object where the settings are read from + * @param newMap The SimMap to use + * @param nrofMaps How many map "files" are in the map + */ + public MapBasedMovement(Settings settings, SimMap newMap, int nrofMaps) { + super(settings); + map = newMap; + this.nrofMapFilesRead = nrofMaps; + readOkMapNodeTypes(settings); + maxPathLength = 100; + minPathLength = 10; + backAllowed = false; + } + + /** + * Reads the OK map node types from settings + * @param settings The settings where the types are read + */ + private void readOkMapNodeTypes(Settings settings) { + if (settings.contains(MAP_SELECT_S)) { + this.okMapNodeTypes = settings.getCsvInts(MAP_SELECT_S); + for (int i : okMapNodeTypes) { + if (i < MapNode.MIN_TYPE || i > MapNode.MAX_TYPE) { + throw new SettingsError("Map type selection '" + i + + "' is out of range for setting " + + settings.getFullPropertyName(MAP_SELECT_S)); + } + if (i > nrofMapFilesRead) { + throw new SettingsError("Can't use map type selection '" + i + + "' for setting " + + settings.getFullPropertyName(MAP_SELECT_S) + + " because only " + nrofMapFilesRead + + " map files are read"); + } + } + } + else { + this.okMapNodeTypes = null; + } + } + + /** + * Copyconstructor. + * @param mbm The MapBasedMovement object to base the new object to + */ + protected MapBasedMovement(MapBasedMovement mbm) { + super(mbm); + this.okMapNodeTypes = mbm.okMapNodeTypes; + this.map = mbm.map; + this.minPathLength = mbm.minPathLength; + this.maxPathLength = mbm.maxPathLength; + this.backAllowed = mbm.backAllowed; + } + + /** + * Returns a (random) coordinate that is between two adjacent MapNodes + */ + @Override + public Coord getInitialLocation() { + List nodes = map.getNodes(); + MapNode n,n2; + Coord n2Location, nLocation, placement; + double dx, dy; + double rnd = rng.nextDouble(); + + // choose a random node (from OK types if such are defined) + do { + n = nodes.get(rng.nextInt(nodes.size())); + } while (okMapNodeTypes != null && !n.isType(okMapNodeTypes)); + + // choose a random neighbor of the selected node + n2 = n.getNeighbors().get(rng.nextInt(n.getNeighbors().size())); + + nLocation = n.getLocation(); + n2Location = n2.getLocation(); + + placement = n.getLocation().clone(); + + dx = rnd * (n2Location.getX() - nLocation.getX()); + dy = rnd * (n2Location.getY() - nLocation.getY()); + + placement.translate(dx, dy); // move coord from n towards n2 + + this.lastMapNode = n; + return placement; + } + + /** + * Returns map node types that are OK for this movement model in an array + * or null if all values are considered ok + * @return map node types that are OK for this movement model in an array + */ + protected int[] getOkMapNodeTypes() { + return okMapNodeTypes; + } + + @Override + public Path getPath() { + Path p = new Path(generateSpeed()); + MapNode curNode = lastMapNode; + MapNode prevNode = lastMapNode; + MapNode nextNode = null; + List neighbors; + Coord nextCoord; + + assert lastMapNode != null: "Tried to get a path before placement"; + + // start paths from current node + p.addWaypoint(curNode.getLocation()); + + int pathLength = rng.nextInt(maxPathLength-minPathLength) + + minPathLength; + + for (int i=0; i n2 = new Vector(neighbors); + if (!this.backAllowed) { + n2.remove(prevNode); // to prevent going back + } + + if (okMapNodeTypes != null) { //remove neighbor nodes that aren't ok + for (int j=0; j < n2.size(); ){ + if (!n2.get(j).isType(okMapNodeTypes)) { + n2.remove(j); + } + else { + j++; + } + } + } + + if (n2.size() == 0) { // only option is to go back + nextNode = prevNode; + } + else { // choose a random node from remaining neighbors + nextNode = n2.get(rng.nextInt(n2.size())); + } + + prevNode = curNode; + + nextCoord = nextNode.getLocation(); + curNode = nextNode; + + p.addWaypoint(nextCoord); + } + + lastMapNode = curNode; + + return p; + } + + /** + * Selects and returns a random node that is OK from a list of nodes. + * Whether node is OK, is determined by the okMapNodeTypes list. + * If okMapNodeTypes are defined, the given list must + * contain at least one OK node to prevent infinite looping. + * @param nodes The list of nodes to choose from. + * @return A random node from the list (that is OK if ok list is defined) + */ + protected MapNode selectRandomOkNode(List nodes) { + MapNode n; + do { + n = nodes.get(rng.nextInt(nodes.size())); + } while (okMapNodeTypes != null && !n.isType(okMapNodeTypes)); + + return n; + } + + /** + * Returns the SimMap this movement model uses + * @return The SimMap this movement model uses + */ + public SimMap getMap() { + return map; + } + + /** + * Reads a sim map from location set to the settings, mirrors the map and + * moves its upper left corner to origo. + * @return A new SimMap based on the settings + */ + private SimMap readMap() { + SimMap simMap; + Settings settings = new Settings(MAP_BASE_MOVEMENT_NS); + WKTMapReader r = new WKTMapReader(true); + + if (cachedMap == null) { + cachedMapFiles = new ArrayList(); // no cache present + } + else { // something in cache + // check out if previously asked map was asked again + SimMap cached = checkCache(settings); + if (cached != null) { + nrofMapFilesRead = cachedMapFiles.size(); + return cached; // we had right map cached -> return it + } + else { // no hit -> reset cache + cachedMapFiles = new ArrayList(); + cachedMap = null; + } + } + + try { + int nrofMapFiles = settings.getInt(NROF_FILES_S); + + for (int i = 1; i <= nrofMapFiles; i++ ) { + String pathFile = settings.getSetting(FILE_S + i); + cachedMapFiles.add(pathFile); + r.addPaths(new File(pathFile), i); + } + + nrofMapFilesRead = nrofMapFiles; + } catch (IOException e) { + throw new SimError(e.toString(),e); + } + + simMap = r.getMap(); + checkMapConnectedness(simMap.getNodes()); + // mirrors the map (y' = -y) and moves its upper left corner to origo + simMap.mirror(); + Coord offset = simMap.getMinBound().clone(); + simMap.translate(-offset.getX(), -offset.getY()); + checkCoordValidity(simMap.getNodes()); + + cachedMap = simMap; + return simMap; + } + + /** + * Checks that all map nodes can be reached from all other map nodes + * @param nodes The list of nodes to check + * @throws SettingsError if all map nodes are not connected + */ + private void checkMapConnectedness(List nodes) { + Set visited = new HashSet(); + Queue unvisited = new LinkedList(); + MapNode firstNode; + MapNode next = null; + + if (nodes.size() == 0) { + throw new SimError("No map nodes in the given map"); + } + + firstNode = nodes.get(0); + + visited.add(firstNode); + unvisited.addAll(firstNode.getNeighbors()); + + while ((next = unvisited.poll()) != null) { + visited.add(next); + for (MapNode n: next.getNeighbors()) { + if (!visited.contains(n) && ! unvisited.contains(n)) { + unvisited.add(n); + } + } + } + + if (visited.size() != nodes.size()) { // some node couldn't be reached + MapNode disconnected = null; + for (MapNode n : nodes) { // find an example node + if (!visited.contains(n)) { + disconnected = n; + break; + } + } + throw new SettingsError("SimMap is not fully connected. Only " + + visited.size() + " out of " + nodes.size() + " map nodes " + + "can be reached from " + firstNode + ". E.g. " + + disconnected + " can't be reached"); + } + } + + /** + * Checks that all coordinates of map nodes are within the min&max limits + * of the movement model + * @param nodes The list of nodes to check + * @throws SettingsError if some map node is out of bounds + */ + private void checkCoordValidity(List nodes) { + // Check that all map nodes are within world limits + for (MapNode n : nodes) { + double x = n.getLocation().getX(); + double y = n.getLocation().getY(); + if (x < 0 || x > getMaxX() || y < 0 || y > getMaxY()) { + throw new SettingsError("Map node " + n.getLocation() + + " is out of world bounds "+ + "(x: 0..." + getMaxX() + " y: 0..." + getMaxY() + ")"); + } + } + } + + /** + * Checks map cache if the requested map file(s) match to the cached + * sim map + * @param settings The Settings where map file names are found + * @return A cached map or null if the cached map didn't match + */ + private SimMap checkCache(Settings settings) { + int nrofMapFiles = settings.getInt(NROF_FILES_S); + + if (nrofMapFiles != cachedMapFiles.size() || cachedMap == null) { + return null; // wrong number of files + } + + for (int i = 1; i <= nrofMapFiles; i++ ) { + String pathFile = settings.getSetting(FILE_S + i); + if (!pathFile.equals(cachedMapFiles.get(i-1))) { + return null; // found wrong file name + } + } + + // all files matched -> return cached map + return cachedMap; + } + + @Override + public MapBasedMovement replicate() { + return new MapBasedMovement(this); + } + + public Coord getLastLocation() { + if (lastMapNode != null) { + return lastMapNode.getLocation(); + } else { + return null; + } + } + + public void setLocation(Coord lastWaypoint) { + // TODO: This should be optimized + MapNode nearest = null; + double minDistance = Double.MAX_VALUE; + Iterator iterator = getMap().getNodes().iterator(); + while (iterator.hasNext()) { + MapNode temp = iterator.next(); + double distance = temp.getLocation().distance(lastWaypoint); + if (distance < minDistance) { + minDistance = distance; + nearest = temp; + } + } + lastMapNode = nearest; + } + + public boolean isReady() { + return true; + } + +} diff --git a/movement/MapRouteMovement.java b/movement/MapRouteMovement.java new file mode 100644 index 000000000..da50422a7 --- /dev/null +++ b/movement/MapRouteMovement.java @@ -0,0 +1,159 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.List; + +import core.SettingsError; +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.MapRoute; +import core.Coord; +import core.Settings; + +/** + * Map based movement model that uses predetermined paths within the map area. + * Nodes using this model (can) stop on every route waypoint and find their + * way to next waypoint using {@link DijkstraPathFinder}. There can be + * different type of routes; see {@link #ROUTE_TYPE_S}. + */ +public class MapRouteMovement extends MapBasedMovement implements + SwitchableMovement { + + /** Per node group setting used for selecting a route file ({@value}) */ + public static final String ROUTE_FILE_S = "routeFile"; + /** + * Per node group setting used for selecting a route's type ({@value}). + * Integer value from {@link MapRoute} class. + */ + public static final String ROUTE_TYPE_S = "routeType"; + + /** + * Per node group setting for selecting which stop (counting from 0 from + * the start of the route) should be the first one. By default, or if a + * negative value is given, a random stop is selected. + */ + public static final String ROUTE_FIRST_STOP_S = "routeFirstStop"; + + /** the Dijkstra shortest path finder */ + private DijkstraPathFinder pathFinder; + + /** Prototype's reference to all routes read for the group */ + private List allRoutes = null; + /** next route's index to give by prototype */ + private Integer nextRouteIndex = null; + /** Index of the first stop for a group of nodes (or -1 for random) */ + private int firstStopIndex = -1; + + /** Route of the movement model's instance */ + private MapRoute route; + + /** + * Creates a new movement model based on a Settings object's settings. + * @param settings The Settings object where the settings are read from + */ + public MapRouteMovement(Settings settings) { + super(settings); + String fileName = settings.getSetting(ROUTE_FILE_S); + int type = settings.getInt(ROUTE_TYPE_S); + allRoutes = MapRoute.readRoutes(fileName, type, getMap()); + nextRouteIndex = 0; + pathFinder = new DijkstraPathFinder(getOkMapNodeTypes()); + this.route = this.allRoutes.get(this.nextRouteIndex).replicate(); + if (this.nextRouteIndex >= this.allRoutes.size()) { + this.nextRouteIndex = 0; + } + + if (settings.contains(ROUTE_FIRST_STOP_S)) { + this.firstStopIndex = settings.getInt(ROUTE_FIRST_STOP_S); + if (this.firstStopIndex >= this.route.getNrofStops()) { + throw new SettingsError("Too high first stop's index (" + + this.firstStopIndex + ") for route with only " + + this.route.getNrofStops() + " stops"); + } + } + } + + /** + * Copyconstructor. Gives a route to the new movement model from the + * list of routes and randomizes the starting position. + * @param proto The MapRouteMovement prototype + */ + protected MapRouteMovement(MapRouteMovement proto) { + super(proto); + this.route = proto.allRoutes.get(proto.nextRouteIndex).replicate(); + this.firstStopIndex = proto.firstStopIndex; + + if (firstStopIndex < 0) { + /* set a random starting position on the route */ + this.route.setNextIndex(rng.nextInt(route.getNrofStops()-1)); + } else { + /* use the one defined in the config file */ + this.route.setNextIndex(this.firstStopIndex); + } + + this.pathFinder = proto.pathFinder; + + proto.nextRouteIndex++; // give routes in order + if (proto.nextRouteIndex >= proto.allRoutes.size()) { + proto.nextRouteIndex = 0; + } + } + + @Override + public Path getPath() { + Path p = new Path(generateSpeed()); + MapNode to = route.nextStop(); + + List nodePath = pathFinder.getShortestPath(lastMapNode, to); + + // this assertion should never fire if the map is checked in read phase + assert nodePath.size() > 0 : "No path from " + lastMapNode + " to " + + to + ". The simulation map isn't fully connected"; + + for (MapNode node : nodePath) { // create a Path from the shortest path + p.addWaypoint(node.getLocation()); + } + + lastMapNode = to; + + return p; + } + + /** + * Returns the first stop on the route + */ + @Override + public Coord getInitialLocation() { + if (lastMapNode == null) { + lastMapNode = route.nextStop(); + } + + return lastMapNode.getLocation().clone(); + } + + @Override + public Coord getLastLocation() { + if (lastMapNode != null) { + return lastMapNode.getLocation().clone(); + } else { + return null; + } + } + + + @Override + public MapRouteMovement replicate() { + return new MapRouteMovement(this); + } + + /** + * Returns the list of stops on the route + * @return The list of stops + */ + public List getStops() { + return route.getStops(); + } +} diff --git a/movement/ModifiedRandomDirection.java b/movement/ModifiedRandomDirection.java new file mode 100644 index 000000000..54eaecf4f --- /dev/null +++ b/movement/ModifiedRandomDirection.java @@ -0,0 +1,44 @@ +package movement; + +import core.Settings; + +/** + *

+ * Modified Random Direction movement model as described in: + * Elizabeth M. Royer, P. Michael Melliar-Smith, and Louise E. Moser, + * "An Analysis of the Optimum Node Density for Ad hoc Mobile Networks" + *

+ * + *

+ * Similar to {@link RandomDirection}, except nodes will not move all the way + * to the edge. Instead they will pick a random direction and move in that + * direction for a random distance before pausing and picking another + * direction. + *

+ * + * @author teemuk + */ +public class ModifiedRandomDirection +extends RandomDirection { + + public ModifiedRandomDirection( Settings settings ) { + super( settings ); + } + + public ModifiedRandomDirection( ModifiedRandomDirection other ) { + super( other ); + } + + @Override + protected double getTravelFraction() { + // Move a random fraction in the picked direction instead of all the + // way to the edge. + return MovementModel.rng.nextDouble(); + } + + @Override + public MovementModel replicate() { + return new ModifiedRandomDirection( this ); + } + +} diff --git a/movement/MovementModel.java b/movement/MovementModel.java new file mode 100644 index 000000000..5c2968079 --- /dev/null +++ b/movement/MovementModel.java @@ -0,0 +1,288 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.Random; + +import util.ActivenessHandler; + +import core.Coord; +import core.DTNHost; +import core.DTNSim; +import core.ModuleCommunicationBus; +import core.Settings; +import core.SimClock; +import core.SimError; + +/** + *

Superclass for all movement models. All subclasses must contain at least a + * constructor with one {@link Settings} parameter and also a copy-constructor. + * They must also implement the {@link #replicate()} method, which should return + * an instance of the movement model class with same parameters as the object + * (immutable fields can be shared, but mutable fields must be copied).

+ *

To make a new movement model do something useful, also at least + * {@link #getInitialLocation()} and {@link #getPath()} are worthwhile to + * override.

+ */ +public abstract class MovementModel { + /** node's speed CSV (min, max) -setting id ({@value})*/ + public static final String SPEED = "speed"; + /** node's wait time CSV (min, max) -setting id ({@value})*/ + public static final String WAIT_TIME = "waitTime"; + + /** default setting for speed distribution */ + public static final double[] DEF_SPEEDS = {1,1}; + /** default setting for wait time distribution */ + public static final double[] DEF_WAIT_TIMES = {0,0}; + + /** MovementModel namespace (where world size and rng seed settings + * are looked from ({@value})*/ + public static final String MOVEMENT_MODEL_NS = "MovementModel"; + /** world's size CSV (width, height) -setting id ({@value})*/ + public static final String WORLD_SIZE = "worldSize"; + /** movement models' rng seed -setting id ({@value})*/ + public static final String RNG_SEED = "rngSeed"; + + /** common rng for all movement models in the simulation */ + protected static Random rng; + + /** DTNHost to which this movement model is attached */ + protected DTNHost host; + + private ActivenessHandler ah; + + protected double minSpeed; + protected double maxSpeed; + protected double minWaitTime; + protected double maxWaitTime; + + private int maxX; + private int maxY; + + protected ModuleCommunicationBus comBus; + + // static initialization of all movement models' random number generator + static { + DTNSim.registerForReset(MovementModel.class.getCanonicalName()); + reset(); + } + + /** + * Checks that the minimum setting is not bigger than the maximum and + * that both are positive + * @param name Name of the setting + * @param min The minimum setting + * @param max The maximum setting + */ + private static void checkMinAndMaxSetting(String name, + double min, double max) { + if (min < 0 || max < 0) { + throw new SimError("MovementModel." + name + " (in Settings)" + + " has a value less than zero ("+min+", "+max+")"); + } + if (min > max) { + throw new SimError("MovementModel." + name + " (in Settings)" + + " min is bigger than max ("+min+", "+max+")"); + } + } + + /** + * Empty constructor for testing purposes. + */ + public MovementModel() { + super(); + } + + /** + * Creates a new MovementModel based on a Settings object's settings. + * @param settings The Settings object where the settings are read from + */ + public MovementModel(Settings settings) { + double[] speeds; + double[] times; + + ah = new ActivenessHandler(settings); + + if (settings.contains(SPEED)) { + speeds = settings.getCsvDoubles(SPEED, 2); + } + else { + speeds = DEF_SPEEDS; + } + + minSpeed = speeds[0]; + maxSpeed = speeds[1]; + checkMinAndMaxSetting(SPEED,minSpeed,maxSpeed); + + if(settings.contains(WAIT_TIME)) { + times = settings.getCsvDoubles(WAIT_TIME, 2); + } + else { + times = DEF_WAIT_TIMES; + } + + minWaitTime = times[0]; + maxWaitTime = times[1]; + checkMinAndMaxSetting(WAIT_TIME,minWaitTime,maxWaitTime); + + settings.setNameSpace(MOVEMENT_MODEL_NS); + int [] worldSize = settings.getCsvInts(WORLD_SIZE,2); + this.maxX = worldSize[0]; + this.maxY = worldSize[1]; + + settings.restoreNameSpace(); + } + + /** + * Copyconstructor. Creates a new MovementModel based on the given + * prototype. + * @param mm The MovementModel prototype to base the new object to + */ + public MovementModel(MovementModel mm) { + this.maxSpeed = mm.maxSpeed; + this.minSpeed = mm.minSpeed; + this.maxWaitTime = mm.maxWaitTime; + this.minWaitTime = mm.minWaitTime; + this.maxX = mm.maxX; + this.maxY = mm.maxY; + this.ah = mm.ah; + this.comBus = null; + } + + /** + * Returns the largest X coordinate value this model uses + * @return Maximum of X coordinate values + */ + public int getMaxX() { + return this.maxX; + } + + /** + * Returns the largest Y coordinate value this model uses + * @return Maximum of Y coordinate values + */ + public int getMaxY() { + return this.maxY; + } + + + /** + * Generates and returns a speed value between min and max of the + * {@link #WAIT_TIME} setting. + * @return A new speed between min and max values + */ + protected double generateSpeed() { + if (rng == null) { + return 1; + } + return (maxSpeed - minSpeed) * rng.nextDouble() + minSpeed; + } + + /** + * Generates and returns a suitable waiting time at the end of a path. + * (i.e. random variable whose value is between min and max of the + * {@link #WAIT_TIME} setting). + * @return The time as a double + */ + protected double generateWaitTime() { + if (rng == null) { + return 0; + } + return (maxWaitTime - minWaitTime) * rng.nextDouble() + + minWaitTime; + } + + /** + * Returns a new path by this movement model or null if no new path could + * be constructed at the moment (node should wait where it is). A new + * path should not be requested before the destination of the previous + * path has been reached. + * @return A new path or null + */ + public abstract Path getPath(); + + /** + * Returns a new initial placement for a node + * @return The initial coordinates for a node + */ + public abstract Coord getInitialLocation(); + + /** + * @return the host + */ + public DTNHost getHost() { + return host; + } + + /** + * @param host the host to set + */ + public void setHost(DTNHost host) { + this.host = host; + } + + /** + * Returns true if this node is active at the moment (false if not) + * @return true if this node is active (false if not) + */ + public boolean isActive() { + /* TODO: add offset support */ + return ah.isActive(); + } + + /** + * Returns a sim time when the next path is available. This implementation + * returns a random time in future that is {@link #WAIT_TIME} from now. + * @return The sim time when node should ask the next time for a path + */ + public double nextPathAvailable() { + return SimClock.getTime() + generateWaitTime(); + } + + /** + * Sets the module communication bus for this movement model + * @param comBus The communications bus to set + */ + public void setComBus(ModuleCommunicationBus comBus) { + this.comBus = comBus; + } + + /** + * Returns the module communication bus of this movement model (if any) + * @return The communications bus or null if one is not set + */ + public ModuleCommunicationBus getComBus() { + return this.comBus; + } + + /** + * Returns simply the name of the movement model class + * @return the name of the movement model class + */ + public String toString() { + return this.getClass().getSimpleName(); + } + + /** + * Creates a replicate of the movement model. + * @return A new movement model with the same settings as this model + */ + public abstract MovementModel replicate(); + + /** + * Resets all static fields to default values + */ + public static void reset() { + Settings s = new Settings(MOVEMENT_MODEL_NS); + if (s.contains(RNG_SEED)) { + int seed = s.getInt(RNG_SEED); + rng = new Random(seed); + } + else { + rng = new Random(0); + } + } + +} diff --git a/movement/OfficeActivityMovement.java b/movement/OfficeActivityMovement.java new file mode 100644 index 000000000..1365d6ac7 --- /dev/null +++ b/movement/OfficeActivityMovement.java @@ -0,0 +1,286 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import input.WKTReader; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; + +import util.ParetoRNG; + +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import movement.map.SimMap; +import core.Coord; +import core.Settings; +import core.SimClock; + +/** + * This class models movement at an office. If the node happens to be at some + * other location than the office, it first walks the shortest path to the + * office and then stays there until the end of the work day. A node has only + * works at one office. + * + * @author Frans Ekman + * + */ +public class OfficeActivityMovement extends MapBasedMovement implements + SwitchableMovement { + + private static final int WALKING_TO_OFFICE_MODE = 0; + private static final int AT_OFFICE_MODE = 1; + + public static final String WORK_DAY_LENGTH_SETTING = "workDayLength"; + public static final String NR_OF_OFFICES_SETTING = "nrOfOffices"; + + public static final String OFFICE_SIZE_SETTING = "officeSize"; + public static final String OFFICE_WAIT_TIME_PARETO_COEFF_SETTING = + "officeWaitTimeParetoCoeff"; + public static final String OFFICE_MIN_WAIT_TIME_SETTING = + "officeMinWaitTime"; + public static final String OFFICE_MAX_WAIT_TIME_SETTING = + "officeMaxWaitTime"; + public static final String OFFICE_LOCATIONS_FILE_SETTING = + "officeLocationsFile"; + + private static int nrOfOffices = 50; + + private int mode; + private int workDayLength; + private int startedWorkingTime; + private boolean ready;; + private DijkstraPathFinder pathFinder; + + private ParetoRNG paretoRNG; + + private int distance; + private double officeWaitTimeParetoCoeff; + private double officeMinWaitTime; + private double officeMaxWaitTime; + + private List allOffices; + + private Coord lastWaypoint; + private Coord officeLocation; + private Coord deskLocation; + + private boolean sittingAtDesk; + + /** + * OfficeActivityMovement constructor + * @param settings + */ + public OfficeActivityMovement(Settings settings) { + super(settings); + + workDayLength = settings.getInt(WORK_DAY_LENGTH_SETTING); + nrOfOffices = settings.getInt(NR_OF_OFFICES_SETTING); + + distance = settings.getInt(OFFICE_SIZE_SETTING); + officeWaitTimeParetoCoeff = settings.getDouble( + OFFICE_WAIT_TIME_PARETO_COEFF_SETTING); + officeMinWaitTime = settings.getDouble(OFFICE_MIN_WAIT_TIME_SETTING); + officeMaxWaitTime = settings.getDouble(OFFICE_MAX_WAIT_TIME_SETTING); + + startedWorkingTime = -1; + pathFinder = new DijkstraPathFinder(null); + mode = WALKING_TO_OFFICE_MODE; + + String officeLocationsFile = null; + try { + officeLocationsFile = settings.getSetting( + OFFICE_LOCATIONS_FILE_SETTING); + } catch (Throwable t) { + // Do nothing; + } + + if (officeLocationsFile == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int officeIndex = rng.nextInt(mapNodes.length - 1) / + (mapNodes.length/nrOfOffices); + officeLocation = mapNodes[officeIndex].getLocation().clone(); + } else { + try { + allOffices = new LinkedList(); + List locationsRead = (new WKTReader()). + readPoints(new File(officeLocationsFile)); + for (Coord coord : locationsRead) { + SimMap map = getMap(); + Coord offset = map.getOffset(); + // mirror points if map data is mirrored + if (map.isMirrored()) { + coord.setLocation(coord.getX(), -coord.getY()); + } + coord.translate(offset.getX(), offset.getY()); + allOffices.add(coord); + } + officeLocation = allOffices.get( + rng.nextInt(allOffices.size())).clone(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + deskLocation = getRandomCoorinateInsideOffice(); + paretoRNG = new ParetoRNG(rng, officeWaitTimeParetoCoeff, + officeMinWaitTime, officeMaxWaitTime); + } + + /** + * Copyconstructor + * @param proto + */ + public OfficeActivityMovement(OfficeActivityMovement proto) { + super(proto); + this.workDayLength = proto.workDayLength; + startedWorkingTime = -1; + this.distance = proto.distance; + this.pathFinder = proto.pathFinder; + this.mode = proto.mode; + + if (proto.allOffices == null) { + MapNode[] mapNodes = (MapNode[])getMap().getNodes(). + toArray(new MapNode[0]); + int officeIndex = rng.nextInt(mapNodes.length - 1) / + (mapNodes.length/nrOfOffices); + officeLocation = mapNodes[officeIndex].getLocation().clone(); + } else { + this.allOffices = proto.allOffices; + officeLocation = allOffices.get( + rng.nextInt(allOffices.size())).clone(); + } + + officeWaitTimeParetoCoeff = proto.officeWaitTimeParetoCoeff; + officeMinWaitTime = proto.officeMinWaitTime; + officeMaxWaitTime = proto.officeMaxWaitTime; + + deskLocation = getRandomCoorinateInsideOffice(); + this.paretoRNG = proto.paretoRNG; + } + + public Coord getRandomCoorinateInsideOffice() { + double x_coord = officeLocation.getX() + + (0.5 - rng.nextDouble()) * distance; + if (x_coord > getMaxX()) { + x_coord = getMaxX(); + } else if (x_coord < 0) { + x_coord = 0; + } + double y_coord = officeLocation.getY() + + (0.5 - rng.nextDouble()) * distance; + if (y_coord > getMaxY()) { + y_coord = getMaxY(); + } else if (y_coord < 0) { + y_coord = 0; + } + return new Coord(x_coord, y_coord); + } + + @Override + public Coord getInitialLocation() { + double x = rng.nextDouble() * getMaxX(); + double y = rng.nextDouble() * getMaxY(); + Coord c = new Coord(x,y); + + this.lastWaypoint = c; + return c.clone(); + } + + @Override + public Path getPath() { + if (mode == WALKING_TO_OFFICE_MODE) { + // Try to find to the office + SimMap map = super.getMap(); + if (map == null) { + return null; + } + MapNode thisNode = map.getNodeByCoord(lastWaypoint); + MapNode destinationNode = map.getNodeByCoord(officeLocation); + List nodes = pathFinder.getShortestPath(thisNode, + destinationNode); + Path path = new Path(generateSpeed()); + for (MapNode node : nodes) { + path.addWaypoint(node.getLocation()); + } + lastWaypoint = officeLocation.clone(); + mode = AT_OFFICE_MODE; + return path; + } + + if (startedWorkingTime == -1) { + startedWorkingTime = SimClock.getIntTime(); + } + if (SimClock.getIntTime() - startedWorkingTime >= workDayLength) { + Path path = new Path(1); + path.addWaypoint(lastWaypoint.clone()); + ready = true; + return path; + } + Coord c; + if (sittingAtDesk) { + c = getRandomCoorinateInsideOffice(); + sittingAtDesk = false; + } else { + c = deskLocation.clone(); + sittingAtDesk = true; + } + + Path path = new Path(1); + path.addWaypoint(c); + return path; + } + + @Override + protected double generateWaitTime() { + int timeLeft = workDayLength - + (SimClock.getIntTime() - startedWorkingTime); + + int waitTime = (int)paretoRNG.getDouble(); + if (waitTime > timeLeft) { + return timeLeft; + } + return waitTime; + } + + @Override + public MapBasedMovement replicate() { + return new OfficeActivityMovement(this); + } + + /** + * @see SwitchableMovement + */ + public Coord getLastLocation() { + return lastWaypoint.clone(); + } + + /** + * @see SwitchableMovement + */ + public boolean isReady() { + return ready; + } + + /** + * @see SwitchableMovement + */ + public void setLocation(Coord lastWaypoint) { + this.lastWaypoint = lastWaypoint.clone(); + startedWorkingTime = -1; + ready = false; + mode = WALKING_TO_OFFICE_MODE; + } + + /** + * @return The location of the office + */ + public Coord getOfficeLocation() { + return officeLocation.clone(); + } + +} diff --git a/movement/Path.java b/movement/Path.java new file mode 100644 index 000000000..1fc715dd3 --- /dev/null +++ b/movement/Path.java @@ -0,0 +1,141 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import java.util.ArrayList; +import java.util.List; + +import core.Coord; + +/** + * A Path between multiple Coordinates. + */ +public class Path { + /** coordinates of the path */ + private List coords; + /** speeds in the path legs */ + private List speeds; + private int nextWpIndex; + + /** + * Creates a path with zero speed. + */ + public Path() { + this.nextWpIndex = 0; + this.coords = new ArrayList(); + this.speeds = new ArrayList(1); + } + + /** + * Copy constructor. Creates a copy of this path with a shallow copy of + * the coordinates and speeds. + * @param path The path to create the copy from + */ + public Path(Path path) { + this.nextWpIndex = path.nextWpIndex; + this.coords = new ArrayList((ArrayList)path.coords); + this.speeds = new ArrayList((ArrayList)path.speeds); + } + + /** + * Creates a path with constant speed + * @param speed The speed on the path + */ + public Path(double speed) { + this(); + setSpeed(speed); + } + + /** + * Sets a constant speed for the whole path. Any previously set speed(s) + * is discarded. + */ + public void setSpeed(double speed) { + this.speeds = new ArrayList(1); + speeds.add(speed); + } + + /** + * Returns a reference to the coordinates of this path + * @return coordinates of the path + */ + public List getCoords() { + return this.coords; + } + + /** + * Adds a new waypoint to the end of the path. + * @param wp The waypoint to add + */ + public void addWaypoint(Coord wp) { + assert this.speeds.size() <= 1 : "This method should be used only for" + + " paths with constant speed"; + this.coords.add(wp); + } + + /** + * Adds a new waypoint with a speed towards that waypoint + * @param wp The waypoint + * @param speed The speed towards that waypoint + */ + public void addWaypoint(Coord wp, double speed) { + this.coords.add(wp); + this.speeds.add(speed); + } + + /** + * Returns the next waypoint on this path + * @return the next waypoint + */ + public Coord getNextWaypoint() { + assert hasNext() : "Path didn't have " + (nextWpIndex+1) + ". waypoint"; + return coords.get(nextWpIndex++); + } + + /** + * Returns true if the path has more waypoints, false if not + * @return true if the path has more waypoints, false if not + */ + public boolean hasNext() { + return nextWpIndex < this.coords.size(); + } + + /** + * Returns the speed towards the next waypoint (asked with + * {@link #getNextWaypoint()}. + * @return the speed towards the next waypoint + */ + public double getSpeed() { + assert speeds.size() != 0 : "No speed set"; + assert nextWpIndex != 0 : "No waypoint asked"; + + if (speeds.size() == 1) { + return speeds.get(0); + } + else { + return speeds.get(nextWpIndex-1); + } + } + + /** + * Returns a string presentation of the path's coordinates + * @return Path as a string + */ + public String toString() { + String s =""; + for (int i=0, n=coords.size(); i 1) { + s += String.format("@%.2f ",speeds.get(i)); + } + } + return s; + } + + public List getSpeeds() { + return this.speeds; + } +} diff --git a/movement/RandomDirection.java b/movement/RandomDirection.java new file mode 100644 index 000000000..747dc0aaa --- /dev/null +++ b/movement/RandomDirection.java @@ -0,0 +1,219 @@ +package movement; + +import core.Coord; +import core.Settings; + +/** + *

+ * Random Direction movement model as described in: + * Elizabeth M. Royer, P. Michael Melliar-Smith, and Louise E. Moser, + * "An Analysis of the Optimum Node Density for Ad hoc Mobile Networks" + *

+ * + *

+ * Nodes will start at a random place on the simulation area and pick a random + * direction and follow it to the edge of the simulation area. They will then + * pause and pick another direction to go in until they hit the edge again. + *

+ * + * @author teemuk + */ +public class RandomDirection +extends MovementModel { + + private Coord lastWaypoint; + + //========================================================================// + // MovementModel implementation + //========================================================================// + public RandomDirection( Settings settings ) { + super( settings ); + } + + public RandomDirection( RandomDirection other ) { + super( other ); + } + + @Override + public Path getPath() { + Path p; + p = new Path( super.generateSpeed() ); + p.addWaypoint( this.lastWaypoint.clone() ); + Coord next = this.getRandomWaypoint( this.lastWaypoint.getX(), + this.lastWaypoint.getY() ); + p.addWaypoint( next ); + + this.lastWaypoint = next; + + return p; + } + + @Override + public Coord getInitialLocation() { + Coord c + = new Coord( MovementModel.rng.nextDouble() * super.getMaxX(), + MovementModel.rng.nextDouble() * super.getMaxY() ); + this.lastWaypoint = c; + + return c; + } + + @Override + public MovementModel replicate() { + return new RandomDirection( this ); + } + //========================================================================// + + + //========================================================================// + // Sub-classable + //========================================================================// + /** + * Returns the fraction of the path to follow towards the edge. This is + * called after the direction of travel has been picked and the path + * towards the edge calculated. Returning {@code 1.0} causes the node to + * travel all the way to the edge, returning {@code 0.5} would cause the + * node to travel half way, etc. + * + * @return the fraction of the path to follow towards the edge of the + * simulation area + */ + protected double getTravelFraction() { + return 1.0; + } + //========================================================================// + + + + //========================================================================// + // Calculations for selecting the next waypoint. + //------------------------------------------------------------------------// + // Solves the intersection of the path defined by: + // (x,y) = (x0,y0) + tp * (cos(angle), sin(angle)) + // And the simulation area bounds + // (x,y) = t1 * (1,0) + // (x,y) = t2 * (0,1) + // (x,y) = (0,areaHeight) + t3 * (1,0) + // (x,y) = (areaWidth,0) + t4 * (0,1) + //========================================================================// + private Coord getRandomWaypoint( double x0, double y0 ) { + double[] params = null; + double angle; + boolean done; + + // 1. Pick a random direction + // 2. Solve the intersection of the path with the bounds + // 3. Pick the right solution + // 4. Calculate the coordinate + do { + done = true; + + angle = MovementModel.rng.nextDouble() * 2 * Math.PI - Math.PI; + + double[] bottomParams + = this.getBottomParams( x0, y0, angle ); + double[] leftParams + = this.getLeftParams( x0, y0, angle ); + double[] topParams + = this.getTopParams( x0, y0, angle, super.getMaxY() ); + double[] rightParams + = this.getRightParams( x0, y0, angle, super.getMaxY() ); + + if ( this.hitTestBottom( bottomParams, super.getMaxX() ) ) { + params = bottomParams; + } else if ( this.hitTestLeft( leftParams, super.getMaxY() ) ) { + params = leftParams; + } else if ( this.hitTestTop( topParams, super.getMaxX() ) ) { + params = topParams; + } else if ( this.hitTestRight( rightParams, super.getMaxY() ) ) { + params = rightParams; + } else { + // Hit test can fail if we are already on the edge and picked + // direction outwards + done = false; + } + } while ( !done ); + + double t = this.getTravelFraction() * params[ 1 ]; + + double x = x0 + t * Math.cos( angle ); + double y = y0 + t * Math.sin( angle ); + + return new Coord( x, y ); + } + + private double[] getBottomParams( final double x0, final double y0, + final double angle ) { + double t1 = x0 - y0 * Math.cos( angle ) / Math.sin( angle ); + double tp = -1.0 * y0 / Math.sin( angle ); + + double[] ret = new double[ 2 ]; + ret[ 0 ] = t1; + ret[ 1 ] = tp; + + return ret; + } + + private double[] getLeftParams( final double x0, final double y0, + final double angle ) { + double t2 = y0 - x0 * Math.sin( angle ) / Math.cos( angle ); + double tp = -1.0 * x0 / Math.cos( angle ); + + double[] ret = new double[ 2 ]; + ret[ 0 ] = t2; + ret[ 1 ] = tp; + + return ret; + } + + private double[] getTopParams( final double x0, final double y0, + final double angle, + final double areaHeight ) { + double t3 = x0 + ( areaHeight - y0 ) * + Math.cos( angle ) / Math.sin( angle ); + double tp = ( areaHeight - y0 ) / Math.sin( angle ); + + double[] ret = new double[ 2 ]; + ret[ 0 ] = t3; + ret[ 1 ] = tp; + + return ret; + } + + private double[] getRightParams( final double x0, final double y0, + final double angle, + final double areaWidth ) { + double t4 = y0 + ( areaWidth - x0 ) * + Math.sin( angle ) / Math.cos( angle ); + double tp = ( areaWidth - x0 ) / Math.cos( angle ); + + double[] ret = new double[ 2 ]; + ret[ 0 ] = t4; + ret[ 1 ] = tp; + + return ret; + } + + private boolean hitTestBottom( final double[] t, + final double areaWidth ) { + return ( 0 <= t[ 0 ] && t[ 0 ] <= areaWidth ) && + ( t[ 1 ] > 0.0 ); + } + + private boolean hitTestLeft( final double[] t, + final double areaHeight ) { + return ( 0 <= t[ 0 ] && t[ 0 ] <= areaHeight ) && + ( t[ 1 ] > 0.0 ); + } + + private boolean hitTestTop( final double[] t, final double areaWidth ) { + return ( 0 <= t[ 0 ] && t[ 0 ] <= areaWidth ) && + ( t[ 1 ] > 0.0 ); + } + + private boolean hitTestRight( final double[] t, double areaHeight ) { + return ( 0 <= t[ 0 ] && t[ 0 ] <= areaHeight ) && + ( t[ 1 ] > 0 ); + } + //========================================================================// +} diff --git a/movement/RandomWalk.java b/movement/RandomWalk.java new file mode 100644 index 000000000..9566b2472 --- /dev/null +++ b/movement/RandomWalk.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; + +/** + * Random Walk movement model + * + * @author Frans Ekman + */ +public class RandomWalk extends MovementModel implements SwitchableMovement { + + private Coord lastWaypoint; + private double minDistance; + private double maxDistance; + + public RandomWalk(Settings settings) { + super(settings); + minDistance = 0; + maxDistance = 50; + } + + private RandomWalk(RandomWalk rwp) { + super(rwp); + minDistance = rwp.minDistance; + maxDistance = rwp.maxDistance; + } + + /** + * Returns a possible (random) placement for a host + * @return Random position on the map + */ + @Override + public Coord getInitialLocation() { + assert rng != null : "MovementModel not initialized!"; + double x = rng.nextDouble() * getMaxX(); + double y = rng.nextDouble() * getMaxY(); + Coord c = new Coord(x,y); + + this.lastWaypoint = c; + return c; + } + + @Override + public Path getPath() { + Path p; + p = new Path(generateSpeed()); + p.addWaypoint(lastWaypoint.clone()); + double maxX = getMaxX(); + double maxY = getMaxY(); + + Coord c = null; + while (true) { + + double angle = rng.nextDouble() * 2 * Math.PI; + double distance = minDistance + rng.nextDouble() * + (maxDistance - minDistance); + + double x = lastWaypoint.getX() + distance * Math.cos(angle); + double y = lastWaypoint.getY() + distance * Math.sin(angle); + + c = new Coord(x,y); + + if (x > 0 && y > 0 && x < maxX && y < maxY) { + break; + } + } + + p.addWaypoint(c); + + this.lastWaypoint = c; + return p; + } + + @Override + public RandomWalk replicate() { + return new RandomWalk(this); + } + + public Coord getLastLocation() { + return lastWaypoint; + } + + public void setLocation(Coord lastWaypoint) { + this.lastWaypoint = lastWaypoint; + } + + public boolean isReady() { + return true; + } +} diff --git a/movement/RandomWaypoint.java b/movement/RandomWaypoint.java new file mode 100644 index 000000000..e213e45a1 --- /dev/null +++ b/movement/RandomWaypoint.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; + +/** + * Random waypoint movement model. Creates zig-zag paths within the + * simulation area. + */ +public class RandomWaypoint extends MovementModel { + /** how many waypoints should there be per path */ + private static final int PATH_LENGTH = 1; + private Coord lastWaypoint; + + public RandomWaypoint(Settings settings) { + super(settings); + } + + protected RandomWaypoint(RandomWaypoint rwp) { + super(rwp); + } + + /** + * Returns a possible (random) placement for a host + * @return Random position on the map + */ + @Override + public Coord getInitialLocation() { + assert rng != null : "MovementModel not initialized!"; + Coord c = randomCoord(); + + this.lastWaypoint = c; + return c; + } + + @Override + public Path getPath() { + Path p; + p = new Path(generateSpeed()); + p.addWaypoint(lastWaypoint.clone()); + Coord c = lastWaypoint; + + for (int i=0; i nodePath = pathFinder.getShortestPath(lastMapNode, to); + + // this assertion should never fire if the map is checked in read phase + assert nodePath.size() > 0 : "No path from " + lastMapNode + " to " + + to + ". The simulation map isn't fully connected"; + + for (MapNode node : nodePath) { // create a Path from the shortest path + p.addWaypoint(node.getLocation()); + } + + lastMapNode = to; + + return p; + } + + @Override + public ShortestPathMapBasedMovement replicate() { + return new ShortestPathMapBasedMovement(this); + } + +} diff --git a/movement/StationaryMovement.java b/movement/StationaryMovement.java new file mode 100644 index 000000000..d56c64bca --- /dev/null +++ b/movement/StationaryMovement.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; + +/** + * A dummy stationary "movement" model where nodes do not move. + * Might be useful for simulations with only external connection events. + */ +public class StationaryMovement extends MovementModel { + /** Per node group setting for setting the location ({@value}) */ + public static final String LOCATION_S = "nodeLocation"; + private Coord loc; /** The location of the nodes */ + + /** + * Creates a new movement model based on a Settings object's settings. + * @param s The Settings object where the settings are read from + */ + public StationaryMovement(Settings s) { + super(s); + int coords[]; + + coords = s.getCsvInts(LOCATION_S, 2); + this.loc = new Coord(coords[0],coords[1]); + } + + /** + * Copy constructor. + * @param sm The StationaryMovement prototype + */ + public StationaryMovement(StationaryMovement sm) { + super(sm); + this.loc = sm.loc; + } + + /** + * Returns the only location of this movement model + * @return the only location of this movement model + */ + @Override + public Coord getInitialLocation() { + return loc; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public StationaryMovement replicate() { + return new StationaryMovement(this); + } + +} diff --git a/movement/SwitchableMovement.java b/movement/SwitchableMovement.java new file mode 100644 index 000000000..ea92ca5f3 --- /dev/null +++ b/movement/SwitchableMovement.java @@ -0,0 +1,37 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; + +/** + + * Movement models to be used by ExtendedMovementModels should implement this + * interface + * + * @author Frans Ekman + */ +public interface SwitchableMovement { + + /** + * Tell the movement model what its current location is + * @param lastWaypoint + */ + public void setLocation(Coord lastWaypoint); + + /** + * Get the last location the getPath() of this movement model has returned + * @return the last location + */ + public Coord getLastLocation(); + + /** + * Checks if the movement model is finished doing its task and it's time to + * switch to the next movement model. The method should be called between + * getPath() calls. + * @return true if ready + */ + public boolean isReady(); +} diff --git a/movement/TransportMovement.java b/movement/TransportMovement.java new file mode 100644 index 000000000..372f99b1f --- /dev/null +++ b/movement/TransportMovement.java @@ -0,0 +1,18 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; + +/** + * MovementModels used for transportation should implement this interface + * + * @author Frans Ekman + */ +public interface TransportMovement extends SwitchableMovement { + + public void setNextRoute(Coord nodeLocation, Coord nodeDestination); + +} diff --git a/movement/WorkingDayMovement.java b/movement/WorkingDayMovement.java new file mode 100644 index 000000000..c6c56e738 --- /dev/null +++ b/movement/WorkingDayMovement.java @@ -0,0 +1,180 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement; + +import core.Coord; +import core.Settings; + +/** + * + * This movement model makes use of several other movement models to simulate + * movement with daily routines. People wake up in the morning, go to work, + * go shopping or similar activities in the evening and finally go home to + * sleep. + * + * @author Frans Ekman + */ +public class WorkingDayMovement extends ExtendedMovementModel { + + public static final String PROBABILITY_TO_OWN_CAR_SETTING = "ownCarProb"; + public static final String PROBABILITY_TO_GO_SHOPPING_SETTING = + "probGoShoppingAfterWork"; + + private BusTravellerMovement busTravellerMM; + private OfficeActivityMovement workerMM; + private HomeActivityMovement homeMM; + private EveningActivityMovement eveningActivityMovement; + private CarMovement carMM; + + private TransportMovement movementUsedForTransfers; + + private static final int BUS_TO_WORK_MODE = 0; + private static final int BUS_TO_HOME_MODE = 1; + private static final int BUS_TO_EVENING_ACTIVITY_MODE = 2; + + private static final int WORK_MODE = 3; + private static final int HOME_MODE = 4; + private static final int EVENING_ACTIVITY_MODE = 5; + + private int mode; + + private double ownCarProb; + private double doEveningActivityProb; + + /** + * Creates a new instance of WorkingDayMovement + * @param settings + */ + public WorkingDayMovement(Settings settings) { + super(settings); + busTravellerMM = new BusTravellerMovement(settings); + workerMM = new OfficeActivityMovement(settings); + homeMM = new HomeActivityMovement(settings); + eveningActivityMovement = new EveningActivityMovement(settings); + carMM = new CarMovement(settings); + ownCarProb = settings.getDouble(PROBABILITY_TO_OWN_CAR_SETTING); + if (rng.nextDouble() < ownCarProb) { + movementUsedForTransfers = carMM; + } else { + movementUsedForTransfers = busTravellerMM; + } + doEveningActivityProb = settings.getDouble( + PROBABILITY_TO_GO_SHOPPING_SETTING); + + setCurrentMovementModel(homeMM); + mode = HOME_MODE; + } + + /** + * Creates a new instance of WorkingDayMovement from a prototype + * @param proto + */ + public WorkingDayMovement(WorkingDayMovement proto) { + super(proto); + busTravellerMM = new BusTravellerMovement(proto.busTravellerMM); + workerMM = new OfficeActivityMovement(proto.workerMM); + homeMM = new HomeActivityMovement(proto.homeMM); + eveningActivityMovement = new EveningActivityMovement( + proto.eveningActivityMovement); + carMM = new CarMovement(proto.carMM); + + ownCarProb = proto.ownCarProb; + if (rng.nextDouble() < ownCarProb) { + movementUsedForTransfers = carMM; + } else { + movementUsedForTransfers = busTravellerMM; + } + doEveningActivityProb = proto.doEveningActivityProb; + + setCurrentMovementModel(homeMM); + mode = proto.mode; + } + + @Override + public boolean newOrders() { + switch (mode) { + case WORK_MODE: + if (workerMM.isReady()) { + setCurrentMovementModel(movementUsedForTransfers); + if (doEveningActivityProb > rng.nextDouble()) { + movementUsedForTransfers.setNextRoute( + workerMM.getOfficeLocation(), + eveningActivityMovement. + getShoppingLocationAndGetReady()); + mode = BUS_TO_EVENING_ACTIVITY_MODE; + } else { + movementUsedForTransfers.setNextRoute( + workerMM.getOfficeLocation(), + homeMM.getHomeLocation()); + mode = BUS_TO_HOME_MODE; + } + } + break; + case HOME_MODE: + if (homeMM.isReady()) { + setCurrentMovementModel(movementUsedForTransfers); + movementUsedForTransfers.setNextRoute(homeMM.getHomeLocation(), + workerMM.getOfficeLocation()); + mode = BUS_TO_WORK_MODE; + } + break; + case EVENING_ACTIVITY_MODE: + if (eveningActivityMovement.isReady()) { + setCurrentMovementModel(movementUsedForTransfers); + movementUsedForTransfers.setNextRoute(eveningActivityMovement. + getLastLocation(), homeMM.getHomeLocation()); + mode = BUS_TO_HOME_MODE; + } + break; + case BUS_TO_WORK_MODE: + if (movementUsedForTransfers.isReady()) { + setCurrentMovementModel(workerMM); + mode = WORK_MODE; + } + break; + case BUS_TO_HOME_MODE: + if (movementUsedForTransfers.isReady()) { + setCurrentMovementModel(homeMM); + mode = HOME_MODE; + } + break; + case BUS_TO_EVENING_ACTIVITY_MODE: + if (movementUsedForTransfers.isReady()) { + setCurrentMovementModel(eveningActivityMovement); + mode = EVENING_ACTIVITY_MODE; + } + break; + default: + break; + } + return true; + } + + @Override + public Coord getInitialLocation() { + Coord homeLoc = homeMM.getHomeLocation().clone(); + homeMM.setLocation(homeLoc); + return homeLoc; + } + + @Override + public MovementModel replicate() { + return new WorkingDayMovement(this); + } + + + public Coord getOfficeLocation() { + return workerMM.getOfficeLocation().clone(); + } + + public Coord getHomeLocation() { + return homeMM.getHomeLocation().clone(); + } + + public Coord getShoppingLocation() { + return eveningActivityMovement.getShoppingLocation().clone(); + } + +} diff --git a/movement/map/DijkstraPathFinder.java b/movement/map/DijkstraPathFinder.java new file mode 100644 index 000000000..d9ec88ee8 --- /dev/null +++ b/movement/map/DijkstraPathFinder.java @@ -0,0 +1,228 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement.map; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Set; + +/** + * Implementation of the Dijkstra's shortest path algorithm. + */ +public class DijkstraPathFinder { + /** Value for infinite distance */ + private static final Double INFINITY = Double.MAX_VALUE; + /** Initial size of the priority queue */ + private static final int PQ_INIT_SIZE = 11; + + /** Map of node distances from the source node */ + private DistanceMap distances; + /** Set of already visited nodes (where the shortest path is known) */ + private Set visited; + /** Priority queue of unvisited nodes discovered so far */ + private Queue unvisited; + /** Map of previous nodes on the shortest path(s) */ + private Map prevNodes; + + private int [] okMapNodes; + + /** + * Constructor. + * @param okMapNodes The map node types that are OK for paths or null if + * all nodes are OK + */ + public DijkstraPathFinder(int [] okMapNodes) { + super(); + this.okMapNodes = okMapNodes; + } + + /** + * Initializes a new search with a source node + * @param node The path's source node + */ + private void initWith(MapNode node) { + assert (okMapNodes != null ? node.isType(okMapNodes) : true); + + // create needed data structures + this.unvisited = new PriorityQueue(PQ_INIT_SIZE, + new DistanceComparator()); + this.visited = new HashSet(); + this.prevNodes = new HashMap(); + this.distances = new DistanceMap(); + + // set distance to source 0 and initialize unvisited queue + this.distances.put(node, 0); + this.unvisited.add(node); + } + + /** + * Finds and returns a shortest path between two map nodes + * @param from The source of the path + * @param to The destination of the path + * @return a shortest path between the source and destination nodes in + * a list of MapNodes or an empty list if such path is not available + */ + public List getShortestPath(MapNode from, MapNode to) { + List path = new LinkedList(); + + if (from.compareTo(to) == 0) { // source and destination are the same + path.add(from); // return a list containing only source node + return path; + } + + initWith(from); + MapNode node = null; + + // always take the node with shortest distance + while ((node = unvisited.poll()) != null) { + if (node == to) { + break; // we found the destination -> no need to search further + } + + visited.add(node); // mark the node as visited + relax(node); // add/update neighbor nodes' distances + } + + // now we either have the path or such path wasn't available + if (node == to) { // found a path + path.add(0,to); + MapNode prev = prevNodes.get(to); + while (prev != from) { + path.add(0, prev); // always put previous node to beginning + prev = prevNodes.get(prev); + } + + path.add(0, from); // finally put the source node to first node + } + + return path; + } + + /** + * Relaxes the neighbors of a node (updates the shortest distances). + * @param node The node whose neighbors are relaxed + */ + private void relax(MapNode node) { + double nodeDist = distances.get(node); + for (MapNode n : node.getNeighbors()) { + if (visited.contains(n)) { + continue; // skip visited nodes + } + + if (okMapNodes != null && !n.isType(okMapNodes)) { + continue; // skip nodes that are not OK + } + + // n node's distance from path's source node + double nDist = nodeDist + getDistance(node, n); + + if (distances.get(n) > nDist) { // stored distance > found dist? + prevNodes.put(n, node); + setDistance(n, nDist); + } + } + } + + /** + * Sets the distance from source node to a node + * @param n The node whose distance is set + * @param distance The distance of the node from the source node + */ + private void setDistance(MapNode n, double distance) { + unvisited.remove(n); // remove node from old place in the queue + distances.put(n, distance); // update distance + unvisited.add(n); // insert node to the new place in the queue + } + + /** + * Returns the (euclidean) distance between the two map nodes + * @param from The first node + * @param to The second node + * @return Euclidean distance between the two map nodes + */ + private double getDistance(MapNode from, MapNode to) { + return from.getLocation().distance(to.getLocation()); + } + + /** + * Comparator that compares two map nodes by their distance from + * the source node. + */ + private class DistanceComparator implements Comparator { + + /** + * Compares two map nodes by their distance from the source node + * @return -1, 0 or 1 if node1's distance is smaller, equal to, or + * bigger than node2's distance + */ + public int compare(MapNode node1, MapNode node2) { + double dist1 = distances.get(node1); + double dist2 = distances.get(node2); + + if (dist1 > dist2) { + return 1; + } + else if (dist1 < dist2) { + return -1; + } + else { + return node1.compareTo(node2); + } + } + } + + /** + * Simple Map implementation for storing distances. + */ + private class DistanceMap { + private HashMap map; + + /** + * Constructor. Creates an empty distance map + */ + public DistanceMap() { + this.map = new HashMap(); + } + + /** + * Returns the distance to a node. If no distance value + * is found, returns {@link DijkstraPathFinder#INFINITY} as the value. + * @param node The node whose distance is requested + * @return The distance to that node + */ + public double get(MapNode node) { + Double value = map.get(node); + if (value != null) { + return value; + } + else { + return INFINITY; + } + } + + /** + * Puts a new distance value for a map node + * @param node The node + * @param distance Distance to that node + */ + public void put(MapNode node, double distance) { + map.put(node, distance); + } + + /** + * Returns a string representation of the map's contents + * @return a string representation of the map's contents + */ + public String toString() { + return map.toString(); + } + } +} \ No newline at end of file diff --git a/movement/map/MapNode.java b/movement/map/MapNode.java new file mode 100644 index 000000000..c0f1f25d8 --- /dev/null +++ b/movement/map/MapNode.java @@ -0,0 +1,146 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement.map; + +import java.util.List; +import java.util.Vector; + +import core.Coord; +import core.SettingsError; + +/** + * A node in a SimMap. Node has a location, 0-n neighbors that it is + * connected to and possibly a type identifier. + */ +public class MapNode implements Comparable { + /** Smallest valid type of a node: {@value}*/ + public static final int MIN_TYPE = 1; + /** Biggest valid type of a node: {@value} */ + public static final int MAX_TYPE = 31; + + + private Coord location; + private Vector neighbors; + // bit mask of map node's types or 0 if no type's are defined + private int type; + + /** + * Constructor. Creates a map node to a location. + * @param location The location of the node. + */ + public MapNode(Coord location) { + this.location = location; + this.neighbors = new Vector(); + type = 0; + } + + /** + * Adds a type indicator to this node + * @param type An integer from range [{@value MIN_TYPE}, {@value MAX_TYPE}] + */ + public void addType(int type) { + this.type |= typeToBitMask(type); + } + + /** + * Returns true if this node is of given type, false if none of node's + * type(s) match to given type or node doesn't have type at all + * @param type The type (integer from range [{@value MIN_TYPE}, + * {@value MAX_TYPE}]) + * @return True if this node is of given type + */ + public boolean isType(int type) { + if (this.type == 0) { + return false; + } + + return (this.type & typeToBitMask(type)) != 0; + } + + /** + * Returns true if the node's types match any of the given types + * @param types The types to check (array of values in range + * [{@value MIN_TYPE}, {@value MAX_TYPE}]) + * @return True if at least one of the types matched, false if none of the + * types matched + * @see #isType(int) + */ + public boolean isType(int[] types) { + for (int type : types) { + if (isType(type)) { + return true; + } + } + + return false; + } + + /** + * Converts type integer to a bit mask for setting & checking type + * @param type The type to convert + * @return A bit mask for the given type + * @throws SettingsError if the type is out of range + */ + private int typeToBitMask(int type) { + assert type >= MIN_TYPE && type <= MAX_TYPE : "Invalid node type "+type; + return 1 << type; // create the mask by bitwise shift + } + + /** + * Adds the node as this node's neighbour (unless the node is null) + * @param node The node to add or null for no action + */ + public void addNeighbor(MapNode node) { + if (node == null) { + return; + } + + addToList(node); // add the node to list + } + + /** + * Adds the node to list of neighbours unless it is already there or + * "neighbour" is this node + * @param node + */ + private void addToList(MapNode node) { + if (!this.neighbors.contains(node) && node != this) { + this.neighbors.add(node); + } + } + + /** + * Returns the location of the node + * @return the location of the node + */ + public Coord getLocation() { + return location; + } + + /** + * Returns the neighbors of this node. + * @return the neighbors in a list + */ + public List getNeighbors() { + return neighbors; + } + + /** + * Returns a String representation of the map node + * @return a String representation of the map node + */ + public String toString() { + return "N" + (type != 0 ? "t"+type : "") + "@"+this.location.toString(); + } + + /** + * Compares two map nodes by their coordinates + * @param o The other MapNode + */ + public int compareTo(MapNode o) { + return this.getLocation().compareTo((o).getLocation()); + } + +} diff --git a/movement/map/MapRoute.java b/movement/map/MapRoute.java new file mode 100644 index 000000000..3c51fcf1f --- /dev/null +++ b/movement/map/MapRoute.java @@ -0,0 +1,175 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement.map; + +import input.WKTReader; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import core.Coord; +import core.SettingsError; + +/** + * A route that consists of map nodes. There can be different kind of routes + * and the type is determined by the type parameter ({@value #CIRCULAR} + * or {@value #PINGPONG}). + */ +public class MapRoute { + /** Type of the route ID: circular ({@value}). + * After reaching the last node on path, the next node is the first node */ + public static final int CIRCULAR = 1; + /** Type of the route ID: ping-pong ({@value}). + * After last node on path, the direction on path is reversed */ + public static final int PINGPONG = 2; + + + private List stops; + private int type; // type of the route + private int index; // index of the previous returned map node + private boolean comingBack; + + /** + * Creates a new map route + * @param stops The stops of this route in a list + * @param type Type of the route (e.g. CIRCULAR or PINGPONG) + */ + public MapRoute(int type, List stops) { + assert stops.size() > 0 : "Route needs stops"; + this.type = type; + this.stops = stops; + this.index = 0; + this.comingBack = false; + } + + /** + * Sets the next index for this route + * @param index The index to set + */ + public void setNextIndex(int index) { + if (index > stops.size()) { + index = stops.size(); + } + + this.index = index; + } + + /** + * Returns the number of stops on this route + * @return the number of stops on this route + */ + public int getNrofStops() { + return stops.size(); + } + + public List getStops() { + return this.stops; + } + + /** + * Returns the next stop on the route (depending on the route mode) + * @return the next stop on the route + */ + public MapNode nextStop() { + MapNode next = stops.get(index); + + if (comingBack) { + index--; // ping-pong coming back + } + else { + index++; + } + + if (index < 0) { // returned to beginning in ping-pong + comingBack = false; // start next round + index = 1; + } + + if (index >= stops.size()) { // reached last stop + if (type == PINGPONG) { + comingBack = true; + index = stops.size() - 1; // go next to prev to last stop + } + else { + index = 0; // circular goes back to square one + } + } + + return next; + } + + /** + * Returns a new route with the same settings + * @return a replicate of this route + */ + public MapRoute replicate() { + return new MapRoute(type, stops); + } + + public String toString() { + return ((type == CIRCULAR) ? "Circular" : "Ping-pong") + " route with "+ + getNrofStops() + " stops"; + } + + /** + * Reads routes from files defined in Settings + * @param fileName name of the file where to read routes + * @param type Type of the route + * @param map SimMap where corresponding map nodes are found + * @return A list of MapRoutes that were read + */ + public static List readRoutes(String fileName, int type, + SimMap map) { + List routes = new ArrayList(); + WKTReader reader = new WKTReader(); + List> coords; + File routeFile = null; + boolean mirror = map.isMirrored(); + double xOffset = map.getOffset().getX(); + double yOffset = map.getOffset().getY(); + + if (type != CIRCULAR && type != PINGPONG) { + throw new SettingsError("Invalid route type (" + type + ")"); + } + + try { + routeFile = new File(fileName); + coords = reader.readLines(routeFile); + } + catch (IOException ioe){ + throw new SettingsError("Couldn't read MapRoute-data file " + + fileName + " (cause: " + ioe.getMessage() + ")"); + } + + for (List l : coords) { + List nodes = new ArrayList(); + for (Coord c : l) { + // make coordinates match sim map data + if (mirror) { + c.setLocation(c.getX(), -c.getY()); + } + c.translate(xOffset, yOffset); + + MapNode node = map.getNodeByCoord(c); + if (node == null) { + Coord orig = c.clone(); + orig.translate(-xOffset, -yOffset); + orig.setLocation(orig.getX(), -orig.getY()); + + throw new SettingsError("MapRoute in file " + routeFile + + " contained invalid coordinate " + c + " orig: " + + orig); + } + nodes.add(node); + } + + routes.add(new MapRoute(type, nodes)); + } + + return routes; + } +} diff --git a/movement/map/PointsOfInterest.java b/movement/map/PointsOfInterest.java new file mode 100644 index 000000000..925abc404 --- /dev/null +++ b/movement/map/PointsOfInterest.java @@ -0,0 +1,223 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement.map; + +import input.WKTReader; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +import util.Tuple; + +import core.Coord; +import core.Settings; +import core.SettingsError; + +/** + * Handler for points of interest data. + */ +public class PointsOfInterest { + /** Points Of Interest settings namespace ({@value})*/ + public static final String POI_NS = "PointsOfInterest"; + /** Points Of Interest file path -prefix id ({@value})*/ + public static final String POI_FILE_S = "poiFile"; + + /** + * Per node group setting used for selecting POI groups and their + * probabilities ({@value}).
Syntax: + * poiGroupIndex1, groupSelectionProbability1, groupIndex2, prob2, + * etc...
+ * Sum of probabilities must be less than or equal to one (1.0). If the sum + * is less than one, chance of getting a random MapPoint is + * 1-sum. + */ + public static final String POI_SELECT_S = "pois"; + /** map whose points all POIs are */ + private SimMap map; + /** map node types that are OK to visit */ + private int [] okMapNodeTypes; + /** list of all this POI instance's POI lists */ + private ArrayList> poiLists; + /** list of probabilites of choosing a POI group */ + private List> poiProbs; + /** (pseudo) random number generator */ + private Random rng; + + /** + * Constructor. + * @param parentMap The map whose MapNodes' subset the POIs are + * @param okMapNodeTypes Array of map node types that are OK to visit or + * null if all nodes are OK + * @param settings The Settings object where settings are read from + * @param rng The random number generator to use + */ + public PointsOfInterest(SimMap parentMap, int [] okMapNodeTypes, + Settings settings, Random rng) { + this.poiLists = new ArrayList>(); + this.poiProbs = new LinkedList>(); + this.map = parentMap; + this.okMapNodeTypes = okMapNodeTypes; + this.rng = rng; + readPois(settings); + } + + /** + * Selects a random destination from POIs or all MapNodes. Selecting among + * POI groups is done by their probabilities. If sum of their probabilities + * is less than 1.0 and the drawn random probability is bigger than the sum, + * a random MapNode is selected from the SimMap. + * @return A destination among POIs or all MapNodes + */ + public MapNode selectDestination() { + double random = rng.nextDouble(); + double acc = 0; + + for (Tuple t : poiProbs) { + acc += t.getKey(); + + if (acc > random) { + // get the lucky POI group + List pois = poiLists.get(t.getValue()); + // return a random POI from that group + return pois.get(rng.nextInt(pois.size())); + } + } + + // random was bigger than sum of probs -> return a random map node + // that is still OK (if OK node types are defined) + List allNodes = map.getNodes(); + MapNode node; + do { + node = allNodes.get(rng.nextInt(allNodes.size())); + } while (okMapNodeTypes != null && !node.isType(okMapNodeTypes)); + + return node; + } + + /** + * Reads POI selections and their probabilities from given Settings and + * stores them to poiLists and poiProbs. + * @param s The settings file where group specific settings are read + * @throws Settings error if there was an error while reading the file or + * some of the settings had invalid value(s). + */ + private void readPois(Settings s) { + Coord offset = map.getOffset(); + if (!s.contains(POI_SELECT_S)) { + return; // no POIs for this group + } + double[] groupPois = s.getCsvDoubles(POI_SELECT_S); + + // fully qualified setting name for error messages + String fqSetting = s.getFullPropertyName(POI_SELECT_S); + + if (groupPois.length % 2 != 0) { + throw new SettingsError("Invalid amount of POI selection-"+ + "probability values (" + groupPois.length + "). Must be " + + "divisable by 2 in " + fqSetting); + } + + // read POIs from the requested indexes and assign defined probabilites + for (int i=0; i 1.0) { + throw new SettingsError("Invalid probability value (" + prob + + ") for POI at index " + index + " in " + fqSetting); + } + + // check that there's no list of POIs for that index yet + if (index < poiLists.size() && poiLists.get(index) != null) { + throw new SettingsError("Duplicate definition for POI index " + + index + " in " + fqSetting); + } + + List nodes = readPoisOf(index, offset); + if (poiLists.size() <= index) { + // list too small -> fill with nulls up to index + for (int j = poiLists.size(); j <= index; j++) { + poiLists.add(j,null); + } + } + poiLists.set(index, nodes); + poiProbs.add(new Tuple(groupPois[i+1], index)); + } + + // check the sum of probabilites + double probSum = 0; + for (Tuple t : poiProbs) { + probSum += t.getKey(); + } + if (probSum > 1.0) { + throw new SettingsError("Sum of POI probabilities (" + + String.format("%.2f", probSum) + + ") exceeds 1.0 in " + fqSetting); + } + + } + + /** + * Reads POIs from a file {@value POI_FILE_S} + index defined + * in Settings' namespace {@value POI_NS}. + * @param index The index of the POI file + * @param offset Offset of map data + * @return A list of MapNodes read from the POI file + * @throws Settings error if there was an error while reading the file + * or some coordinate in POI-file didn't match any MapNode in the SimMap + */ + private List readPoisOf(int index, Coord offset) { + List nodes = new ArrayList(); + Settings fileSettings = new Settings(POI_NS); + WKTReader reader = new WKTReader(); + + File poiFile = null; + List coords = null; + try { + poiFile = new File(fileSettings.getSetting(POI_FILE_S + index)); + coords = reader.readPoints(poiFile); + } + catch (IOException ioe){ + throw new SettingsError("Couldn't read POI-data from file '" + + poiFile + "' defined in setting " + + fileSettings.getFullPropertyName(POI_FILE_S + index) + + " (cause: " + ioe.getMessage() + ")"); + } + + if (coords.size() == 0) { + throw new SettingsError("Read a POI group of size 0 from "+poiFile); + } + + for (Coord c : coords) { + if (map.isMirrored()) { // mirror POIs if map data is also mirrored + c.setLocation(c.getX(), -c.getY()); // flip around X axis + } + + // translate to match map data + c.translate(offset.getX(), offset.getY()); + + + MapNode node = map.getNodeByCoord(c); + if (node != null) { + if (okMapNodeTypes != null && !node.isType(okMapNodeTypes)) { + throw new SettingsError("POI " + node + " from file " + + poiFile + " is on a part of the map that is not "+ + "allowed for this movement model"); + } + nodes.add(node); + } + else { + throw new SettingsError("No MapNode in SimMap at location " + + c + " (after translation) from file " + poiFile); + } + } + + return nodes; + } +} diff --git a/movement/map/SimMap.java b/movement/map/SimMap.java new file mode 100644 index 000000000..6dcf26697 --- /dev/null +++ b/movement/map/SimMap.java @@ -0,0 +1,167 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package movement.map; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import core.Coord; + +/** + * A simulation map for node movement. + */ +public class SimMap implements Serializable { + private Coord minBound; + private Coord maxBound; + /** list representation of the map for efficient list-returning */ + private ArrayList nodes; + /** hash map presentation of the map for efficient finding node by coord */ + private Map nodesMap; + /** offset of map translations */ + private Coord offset; + /** is this map data mirrored after reading */ + private boolean isMirrored; + + /** is re-hash needed before using hash mode (some coordinates changed) */ + private boolean needsRehash = false; + + public SimMap(Map nodes) { + this.offset = new Coord(0,0); + this.nodes = new ArrayList(nodes.values()); + this.nodesMap = nodes; + this.isMirrored = false; + setBounds(); + } + + /** + * Returns all the map nodes in a list + * @return all the map nodes in a list + */ + public List getNodes() { + return this.nodes; + } + + /** + * Returns a MapNode at given coordinates or null if there's no MapNode + * in the location of the coordinate + * @param c The coordinate + * @return The map node in that location or null if it doesn't exist + */ + public MapNode getNodeByCoord(Coord c) { + if (needsRehash) { // some coordinates have changed after creating hash + nodesMap.clear(); + for (MapNode node : getNodes()) { + nodesMap.put(node.getLocation(), node); // re-hash + } + } + + return nodesMap.get(c); + } + + /** + * Returns the upper left corner coordinate of the map + * @return the upper left corner coordinate of the map + */ + public Coord getMinBound() { + return this.minBound; + } + + /** + * Returns the lower right corner coordinate of the map + * @return the lower right corner coordinate of the map + */ + public Coord getMaxBound() { + return this.maxBound; + } + + /** + * Returns the offset that has been caused by translates made to + * this map (does NOT take into account mirroring). + * @return The current offset + */ + public Coord getOffset() { + return this.offset; + } + + /** + * Returns true if this map has been mirrored after reading + * @return true if this map has been mirrored after reading + * @see #mirror() + */ + public boolean isMirrored() { + return this.isMirrored; + } + + /** + * Translate whole map by dx and dy + * @param dx The amount to translate X coordinates + * @param dy the amount to translate Y coordinates + */ + public void translate(double dx, double dy) { + for (MapNode n : nodes) { + n.getLocation().translate(dx, dy); + } + + minBound.translate(dx, dy); + maxBound.translate(dx, dy); + offset.translate(dx, dy); + + needsRehash = true; + } + + /** + * Mirrors all map coordinates around X axis (x'=x, y'=-y). + */ + public void mirror() { + assert !isMirrored : "Map data already mirrored"; + + Coord c; + for (MapNode n : nodes) { + c=n.getLocation(); + c.setLocation(c.getX(), -c.getY()); + } + setBounds(); + this.isMirrored = true; + needsRehash = true; + } + + /** + * Updates the min & max bounds to conform to the values of the map nodes. + */ + private void setBounds() { + double minX, minY, maxX, maxY; + Coord c; + minX = minY = Double.MAX_VALUE; + maxX = maxY = -Double.MAX_VALUE; + + for (MapNode n : nodes) { + c = n.getLocation(); + if (c.getX() < minX) { + minX = c.getX(); + } + if (c.getX() > maxX) { + maxX = c.getX(); + } + if (c.getY() < minY) { + minY = c.getY(); + } + if (c.getY() > maxY) { + maxY = c.getY(); + } + } + minBound = new Coord(minX, minY); + maxBound = new Coord(maxX, maxY); + } + + /** + * Returns a String representation of the map + * @return a String representation of the map + */ + public String toString() { + return this.nodes.toString(); + } +} \ No newline at end of file diff --git a/movement/map/package.html b/movement/map/package.html new file mode 100644 index 000000000..379663b48 --- /dev/null +++ b/movement/map/package.html @@ -0,0 +1,9 @@ + + + + +Sub package for MapBasedMovement movement model's (and its sub classes) +helper classes. + + + \ No newline at end of file diff --git a/movement/package.html b/movement/package.html new file mode 100644 index 000000000..8ca20683a --- /dev/null +++ b/movement/package.html @@ -0,0 +1,18 @@ + + + + +Contains different movement models and related classes for the simulator. +All movement models have to be in this package and must extend the +{@link movement.MovementModel} class so they can be dynamically +loaded to the simulator. The classes to load can be specified trough +{@link core.Settings} class' settings source. See MovementModel class and +classes extending it for details about the settings. + + +Complex movement models can store their other +classes (the ones that don't extend MovementModel class) to sub packages. + + + + \ No newline at end of file diff --git a/one.bat b/one.bat new file mode 100644 index 000000000..9c6afb2d2 --- /dev/null +++ b/one.bat @@ -0,0 +1 @@ +java -Xmx512M -cp .;lib/ECLA.jar;lib/DTNConsoleConnection.jar core.DTNSim %* \ No newline at end of file diff --git a/one.sh b/one.sh new file mode 100755 index 000000000..865616e3c --- /dev/null +++ b/one.sh @@ -0,0 +1,2 @@ +#! /bin/sh +java -Xmx512M -cp .:lib/ECLA.jar:lib/DTNConsoleConnection.jar core.DTNSim $* diff --git a/report/AdjacencyGraphvizReport.java b/report/AdjacencyGraphvizReport.java new file mode 100644 index 000000000..9e7afd1d0 --- /dev/null +++ b/report/AdjacencyGraphvizReport.java @@ -0,0 +1,121 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.Collection; +import java.util.HashMap; + +import core.ConnectionListener; +import core.DTNHost; + +/** + * Generates Graphviz compatible graph from connections. + * Connections that happen during the warm up period are ignored. + */ +public class AdjacencyGraphvizReport extends Report implements ConnectionListener { + /** Name of the graphviz report ({@value})*/ + public static final String GRAPH_NAME = "adjgraph"; + + private String HOST_DELIM = "<->"; // used in toString() + private HashMap cons; + private Collection allHosts; + + /** + * Constructor. + */ + public AdjacencyGraphvizReport() { + this.allHosts = null; + init(); + } + + protected void init() { + super.init(); + this.cons = new HashMap(); + } + + + public void hostsConnected(DTNHost host1, DTNHost host2) { + if (isWarmup()) { + return; + } + + newEvent(); + ConnectionInfo ci = cons.get(host1+HOST_DELIM+host2); + + if (ci == null) { + cons.put(host1+HOST_DELIM+host2, new ConnectionInfo(host1,host2)); + } + else { + ci.nrofConnections++; + } + } + + // Nothing to do here.. + public void hostsDisconnected(DTNHost host1, DTNHost host2) {} + + /** + * Sets all hosts that should be in the graph at least once + * @param hosts Collection of hosts + */ + public void setAllHosts(Collection hosts) { + this.allHosts = hosts; + } + + public void done() { + write("graph " + GRAPH_NAME + " {"); + setPrefix("\t"); // indent following lines by one tab + + for (ConnectionInfo ci : cons.values()) { + int weight = ci.nrofConnections; + write(ci.h1 + "--" + ci.h2 + " [weight=" + weight + "];"); + } + + // mention all hosts in the graph at least once + if (this.allHosts != null) { + for (DTNHost h : allHosts) { + write(h+ ";"); + } + } + + setPrefix(""); // don't indent anymore + write("}"); + + super.done(); + } + + /** + * Private class stores information of the connected hosts + * and nrof times they have connected. + */ + private class ConnectionInfo { + private DTNHost h1; + private DTNHost h2; + private int nrofConnections; + + public ConnectionInfo(DTNHost h1, DTNHost h2) { + this.h1 = h1; + this.h2 = h2; + this.nrofConnections = 1; + } + + public boolean equals(Object o) { + if (o == null) return false; + return o.toString().equals(this.toString()); + } + + public int hashCode() { + return toString().hashCode(); + } + + public String toString() { + return h1+HOST_DELIM+h2; + } + + public int compareTo(Object o) { + return nrofConnections - ((ConnectionInfo)o).nrofConnections; + } + } + +} diff --git a/report/BufferOccupancyReport.java b/report/BufferOccupancyReport.java new file mode 100644 index 000000000..1ce28d5ce --- /dev/null +++ b/report/BufferOccupancyReport.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2012 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +/** + * Records the average buffer occupancy and its variance with format: + *

+ * [Simulation time] [average buffer occupancy % [0..100] ] [variance] + *

+ * + *

+ * The occupancy is calculated as an instantaneous snapshot every nth second + * as defined by the occupancyInterval setting, not as an + * average over time. + *

+ * + * @author teemuk + */ +import java.util.List; + +import core.DTNHost; +import core.Settings; +import core.SimClock; +import core.UpdateListener; + +public class BufferOccupancyReport extends Report implements UpdateListener { + + /** + * Record occupancy every nth second -setting id ({@value}). + * Defines the interval how often (seconds) a new snapshot of buffer + * occupancy is taken + */ + public static final String BUFFER_REPORT_INTERVAL = "occupancyInterval"; + /** Default value for the snapshot interval */ + public static final int DEFAULT_BUFFER_REPORT_INTERVAL = 5; + + private double lastRecord = Double.MIN_VALUE; + private int interval; + + /** + * Creates a new BufferOccupancyReport instance. + */ + public BufferOccupancyReport() { + super(); + + Settings settings = getSettings(); + if (settings.contains(BUFFER_REPORT_INTERVAL)) { + interval = settings.getInt(BUFFER_REPORT_INTERVAL); + } else { + interval = -1; /* not found; use default */ + } + + if (interval < 0) { /* not found or invalid value -> use default */ + interval = DEFAULT_BUFFER_REPORT_INTERVAL; + } + } + + public void updated(List hosts) { + if (SimClock.getTime() - lastRecord >= interval) { + lastRecord = SimClock.getTime(); + printLine(hosts); + } + } + + /** + * Prints a snapshot of the average buffer occupancy + * @param hosts The list of hosts in the simulation + */ + private void printLine(List hosts) { + double bufferOccupancy = 0.0; + double bo2 = 0.0; + + for (DTNHost h : hosts) { + double tmp = h.getBufferOccupancy(); + tmp = (tmp<=100.0)?(tmp):(100.0); + bufferOccupancy += tmp; + bo2 += (tmp*tmp)/100.0; + } + + double E_X = bufferOccupancy / hosts.size(); + double Var_X = bo2 / hosts.size() - (E_X*E_X)/100.0; + + String output = format(SimClock.getTime()) + " " + format(E_X) + " " + + format(Var_X); + write(output); + } + +} diff --git a/report/ConnectivityDtnsim2Report.java b/report/ConnectivityDtnsim2Report.java new file mode 100644 index 000000000..d1c429c27 --- /dev/null +++ b/report/ConnectivityDtnsim2Report.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.ConnectionListener; +import core.DTNHost; + +/** + * Link connectivity report generator for DTNSim2 input. + * Connections that start during the warm up period are ignored. + */ +public class ConnectivityDtnsim2Report extends Report + implements ConnectionListener { + + /** + * Constructor. + */ + public ConnectivityDtnsim2Report() { + init(); + } + + public void hostsConnected(DTNHost h1, DTNHost h2) { + if (isWarmup()) { + addWarmupID(connectionString(h1, h2)); + return; + } + + newEvent(); + write(createTimeStamp() + " " + connectionString(h1, h2) + " up"); + } + + public void hostsDisconnected(DTNHost h1, DTNHost h2) { + String conString = connectionString(h1, h2); + + if (isWarmup() || isWarmupID(conString)) { + removeWarmupID(conString); + return; + } + + newEvent(); + write(createTimeStamp() + " " + conString + " down"); + } + + /** + * Creates and returns a "@" prefixed time stamp of the current simulation + * time + * @return time stamp of the current simulation time + */ + private String createTimeStamp() { + return String.format("@%.2f", getSimTime()); + } + + /** + * Creates and returns a String presentation of the connection where the + * node with the lower network address is first + * @param h1 The other node of the connection + * @param h2 The other node of the connection + * @return String presentation of the connection + */ + private String connectionString(DTNHost h1, DTNHost h2) { + if (h1.getAddress() < h2.getAddress()) { + return h1 + " <-> " + h2; + } + else { + return h2 + " <-> " + h1; + } + } + +} diff --git a/report/ConnectivityONEReport.java b/report/ConnectivityONEReport.java new file mode 100644 index 000000000..899c6e91a --- /dev/null +++ b/report/ConnectivityONEReport.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.ConnectionListener; +import core.DTNHost; + +/** + * Link connectivity report generator for ONE StandardEventsReader input. + * Connections that start during the warm up period are ignored. + */ +public class ConnectivityONEReport extends Report + implements ConnectionListener { + + /** + * Constructor. + */ + public ConnectivityONEReport() { + init(); + } + + public void hostsConnected(DTNHost h1, DTNHost h2) { + if (isWarmup()) { + addWarmupID(connectionString(h1, h2)); + return; + } + newEvent(); + write(createTimeStamp() + " CONN " + connectionString(h1, h2) + " up"); + } + + public void hostsDisconnected(DTNHost h1, DTNHost h2) { + String conString = connectionString(h1, h2); + + if (isWarmup() || isWarmupID(conString)) { + removeWarmupID(conString); + return; + } + + write(createTimeStamp() + " CONN " + conString + " down"); + } + + /** + * Creates and returns a "@" prefixed time stamp of the current simulation + * time + * @return time stamp of the current simulation time + */ + private String createTimeStamp() { + return String.format("%.2f", getSimTime()); + } + + /** + * Creates and returns a String presentation of the connection where the + * node with the lower network address is first + * @param h1 The other node of the connection + * @param h2 The other node of the connection + * @return String presentation of the connection + */ + private String connectionString(DTNHost h1, DTNHost h2) { + if (h1.getAddress() < h2.getAddress()) { + return h1.getAddress() + " " + h2.getAddress(); + } + else { + return h2.getAddress() + " " + h1.getAddress(); + } + } + +} diff --git a/report/ContactTimesReport.java b/report/ContactTimesReport.java new file mode 100644 index 000000000..8f1ca5178 --- /dev/null +++ b/report/ContactTimesReport.java @@ -0,0 +1,213 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.HashMap; +import java.util.Vector; + +import core.ConnectionListener; +import core.DTNHost; +import core.Settings; + +/** + * Reports the node contact time (i.e., how long they were in the range + * of each other) distribution. Report file contains the count of connections + * that lasted for certain amount of time. Syntax:
+ * time nrofContacts + */ +public class ContactTimesReport extends Report implements ConnectionListener { + protected HashMap connections; + private Vector nrofContacts; + + /** Granularity -setting id ({@value}). Defines how many simulated seconds + * are grouped in one reported interval. */ + public static final String GRANULARITY = "granularity"; + /** How many seconds are grouped in one group */ + protected double granularity; + + /** + * Constructor. + */ + public ContactTimesReport() { + Settings settings = getSettings(); + if (settings.contains(GRANULARITY)) { + this.granularity = settings.getDouble(GRANULARITY); + } + else { + this.granularity = 1.0; + } + + init(); + } + + @Override + protected void init() { + super.init(); + this.connections = new HashMap(); + this.nrofContacts = new Vector(); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + if (isWarmup()) { + return; + } + addConnection(host1, host2); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + newEvent(); + ConnectionInfo ci = removeConnection(host1, host2); + + if (ci == null) { + return; /* the connection was started during the warm up period */ + } + + ci.connectionEnd(); + increaseTimeCount(ci.getConnectionTime()); + } + + protected void addConnection(DTNHost host1, DTNHost host2) { + ConnectionInfo ci = new ConnectionInfo(host1, host2); + + assert !connections.containsKey(ci) : "Already contained "+ + " a connection of " + host1 + " and " + host2; + + connections.put(ci,ci); + } + + protected ConnectionInfo removeConnection(DTNHost host1, DTNHost host2) { + ConnectionInfo ci = new ConnectionInfo(host1, host2); + ci = connections.remove(ci); + return ci; + } + + /** + * Increases the amount of times a certain time value has been seen. + * @param time The time value that was seen + */ + protected void increaseTimeCount(double time) { + int index = (int)(time/this.granularity); + + if (index >= this.nrofContacts.size()) { + /* if biggest index so far, fill array with nulls up to + index+2 to keep the last time count always zero */ + this.nrofContacts.setSize(index + 2); + } + + Integer curValue = this.nrofContacts.get(index); + if (curValue == null) { // no value found -> put the first + this.nrofContacts.set(index, 1); + } + else { // value found -> increase the number by one + this.nrofContacts.set(index, curValue+1); + } + } + + @Override + public void done() { + + for (int i=0, n=this.nrofContacts.size(); i" + this.h2 + " [" + this.startTime + +"-"+ (this.endTime >0 ? this.endTime : "n/a") + "]"; + } + } +} diff --git a/report/ContactsDuringAnICTReport.java b/report/ContactsDuringAnICTReport.java new file mode 100644 index 000000000..d6b291c6b --- /dev/null +++ b/report/ContactsDuringAnICTReport.java @@ -0,0 +1,115 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import core.ConnectionListener; +import core.DTNHost; +import core.UpdateListener; + +/** + * The number of contacts during an inter-contact time metric is similar to + * the inter-contact times metric, except that instead of measuring the time + * until a node meets again, we count the number of other nodes both of the + * nodes meet separately. In contrast to the inter-contact times, the number + * of contacts during an inter-contact is not symmetric, i.e. during an + * inter-contact both nodes wait the exact same time but will meet a different + * number of nodes. + * + * @author Frans Ekman + */ +public class ContactsDuringAnICTReport extends Report + implements ConnectionListener, UpdateListener { + + private boolean[][] areDisconnected; + private int[][] contactCount; + private LinkedList contactsDuringIC; + + private boolean updateHasBeenCalled; + + public ContactsDuringAnICTReport() { + super(); + init(); + } + + + @Override + protected void init() { + super.init(); + contactsDuringIC = new LinkedList(); + } + + + public void hostsConnected(DTNHost host1, DTNHost host2) { + if (!updateHasBeenCalled) { + return; + } + int id1 = host1.getAddress(); + int id2 = host2.getAddress(); + if (areDisconnected[id1][id2]) { + areDisconnected[id1][id2] = false; + areDisconnected[id2][id1] = false; + contactsDuringIC.add(new Integer(contactCount[id1][id2])); + contactsDuringIC.add(new Integer(contactCount[id2][id1])); + contactCount[id1][id2] = 0; + contactCount[id2][id1] = 0; + } + + incContactForAllDisconnectedNodes(host1); + incContactForAllDisconnectedNodes(host2); + + } + + private void incContactForAllDisconnectedNodes(DTNHost host) { + int id = host.getAddress(); + for (int i=0; i hosts) { + if (areDisconnected == null || contactCount == null) { + areDisconnected = new boolean[hosts.size()][hosts.size()]; + contactCount = new int[hosts.size()][hosts.size()]; + } + updateHasBeenCalled = true; + } + + @Override + public void done() { + Integer[] contacts = (Integer[])contactsDuringIC.toArray(new Integer[0]); + Arrays.sort(contacts); + + int count = 0; + int last = 0; + for (int i=0; i contactCounts; + private int currentHourCount; + private int currentHour; + + public ContactsPerHourReport() { + init(); + } + + @Override + public void init() { + super.init(); + contactCounts = new LinkedList(); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + int time = SimClock.getIntTime() / 3600; + while (Math.floor(time) > currentHour) { + contactCounts.add(new Integer(currentHourCount)); + currentHourCount = 0; + currentHour++; + } + + currentHourCount++; + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + // Do nothing + } + + public void done() { + Iterator iterator = contactCounts.iterator(); + int hour = 0; + while (iterator.hasNext()) { + Integer count = (Integer)iterator.next(); + write(hour + "\t" + count); + hour++; + } + super.done(); + } + +} diff --git a/report/CreatedMessagesReport.java b/report/CreatedMessagesReport.java new file mode 100644 index 000000000..6630e61f0 --- /dev/null +++ b/report/CreatedMessagesReport.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Reports information about all created messages. Messages created during + * the warm up period are ignored. + * For output syntax, see {@link #HEADER}. + */ +public class CreatedMessagesReport extends Report implements MessageListener { + public static String HEADER = "# time ID size fromHost toHost TTL " + + "isResponse"; + + /** + * Constructor. + */ + public CreatedMessagesReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + } + + + public void newMessage(Message m) { + if (isWarmup()) { + return; + } + + int ttl = m.getTtl(); + write(format(getSimTime()) + " " + m.getId() + " " + + m.getSize() + " " + m.getFrom() + " " + m.getTo() + " " + + (ttl != Integer.MAX_VALUE ? ttl : "n/a") + + (m.isResponse() ? " Y " : " N ")); + } + + // nothing to implement for the rest + public void messageTransferred(Message m, DTNHost f, DTNHost t,boolean b) {} + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} + + @Override + public void done() { + super.done(); + } +} diff --git a/report/DTN2Reporter.java b/report/DTN2Reporter.java new file mode 100644 index 000000000..887c45d94 --- /dev/null +++ b/report/DTN2Reporter.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package report; + +import core.DTN2Manager; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import fi.tkk.netlab.dtn.ecla.CLAParser; + +/** + * The DTN2Reporter class is responsible for delivering bundles from + * The ONE to dtnd. To enable DTN2 connectivity, the class must be + * specified in the configuration file as a report class. + * @author teemuk + */ +public class DTN2Reporter extends Report implements MessageListener { + /** + * Creates a new reporter object. + */ + public DTN2Reporter() { + super.init(); + DTN2Manager.setReporter(this); + } + + // Implement MessageListener + /** + * Method is called when a new message is created + * @param m Message that was created + */ + public void newMessage(Message m) {} + + /** + * Method is called when a message's transfer is started + * @param m The message that is going to be transferred + * @param from Node where the message is transferred from + * @param to Node where the message is transferred to + */ + public void messageTransferStarted(Message m, DTNHost from, DTNHost to){} + + /** + * Method is called when a message is deleted + * @param m The message that was deleted + * @param where The host where the message was deleted + * @param dropped True if the message was dropped, false if removed + */ + public void messageDeleted(Message m, DTNHost where, boolean dropped){} + + /** + * Method is called when a message's transfer was aborted before + * it finished + * @param m The message that was being transferred + * @param from Node where the message was being transferred from + * @param to Node where the message was being transferred to + */ + public void messageTransferAborted(Message m, DTNHost from, DTNHost to){} + + /** + * Method is called when a message is successfully transferred from + * a node to another. + * @param m The message that was transferred + * @param from Node where the message was transferred from + * @param to Node where the message was transferred to + * @param firstDelivery Was the target node final destination of the message + * and received this message for the first time. + */ + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery) { + // We received a BundleMessage that should be passed to dtnd + CLAParser p = DTN2Manager.getParser(to); + if (p != null) { // Check that there's a CLA connected to this node + p.sendBundle( (DTN2Manager.getBundle(m.getId())).file ); + } + } + } +} diff --git a/report/DeliveredMessagesReport.java b/report/DeliveredMessagesReport.java new file mode 100644 index 000000000..d79c68e02 --- /dev/null +++ b/report/DeliveredMessagesReport.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.List; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Report information about all delivered messages. Messages created during + * the warm up period are ignored. + * For output syntax, see {@link #HEADER}. + */ +public class DeliveredMessagesReport extends Report implements MessageListener { + public static String HEADER = "# time ID size hopcount deliveryTime " + + "fromHost toHost remainingTtl isResponse path"; + + /** + * Constructor. + */ + public DeliveredMessagesReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + } + + /** + * Returns the given messages hop path as a string + * @param m The message + * @return hop path as a string + */ + private String getPathString(Message m) { + List hops = m.getHops(); + String str = m.getFrom().toString(); + + for (int i=1; i creationInfos; + + /** + * Constructor. + */ + public DistanceDelayReport() { + init(); + } + + @Override + protected void init() { + super.init(); + this.creationInfos = new HashMap(); + printHeader(); + } + + /** + * This is called when a message is transferred between nodes + */ + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (isWarmupID(m.getId()) || !firstDelivery) { + return; // report is only interested of first deliveries + } + + InfoTuple info = this.creationInfos.remove(m.getId()); + if (info == null) { + return; /* message was created before the warm up period */ + } + + report(m.getId(), info.getLoc1().distance(info.getLoc2()), + getSimTime() - info.getTime(), m.getHops().size()-1); + } + + /** + * This is called when a new message is created + */ + public void newMessage(Message m) { + if (isWarmup()) { + addWarmupID(m.getId()); + return; + } + + this.creationInfos.put( m.getId(), + new InfoTuple(getSimTime(), + m.getFrom().getLocation().clone(), + m.getTo().getLocation().clone()) ); + } + + /** + * Writes an informative header in the beginning of the file + */ + private void printHeader() { + write("# Scenario " + getScenarioName()); + write("# " + SYNTAX); + } + + /** + * Writes a report line + * @param id Id of the message + * @param startDistance Distance of the nodes when the message was creted + * @param time Time it took for the message to be delivered + * @param hopCount The amount of hops it took to deliver the message + */ + private void report(String id, double startDistance, double time, + int hopCount) { + write(format(startDistance) + " " + format(time) + " " + hopCount + + " " + id); + } + + /* nothing to implement for the rest */ + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + + public void done() { + // report rest of the messages as 'not delivered' (time == -1) + for (String id : creationInfos.keySet()) { + InfoTuple info = creationInfos.get(id); + report(id, info.getLoc1().distance(info.getLoc2()), -1, -1); + } + + super.done(); + } + + /** + * Private class that encapsulates time and location related information + */ + private class InfoTuple { + private double time; + private Coord loc1; + private Coord loc2; + + public InfoTuple(double time, Coord loc1, Coord loc2) { + this.time = time; + this.loc1 = loc1; + this.loc2 = loc2; + } + + public Coord getLoc1() { + return loc1; + } + + public Coord getLoc2() { + return loc2; + } + + public double getTime() { + return time; + } + } + +} diff --git a/report/EncountersVSUniqueEncountersReport.java b/report/EncountersVSUniqueEncountersReport.java new file mode 100644 index 000000000..45522ebe7 --- /dev/null +++ b/report/EncountersVSUniqueEncountersReport.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.List; + +import core.ConnectionListener; +import core.DTNHost; +import core.UpdateListener; + +/** + * The total- vs. the unique encounters for each node + * + * @author Frans Ekman + */ +public class EncountersVSUniqueEncountersReport extends Report + implements ConnectionListener, UpdateListener { + + private TotalEncountersReport totalEncountersReport; + private UniqueEncountersReport uniqueEncountersReport; + + public EncountersVSUniqueEncountersReport() { + totalEncountersReport = new TotalEncountersReport(); + uniqueEncountersReport = new UniqueEncountersReport(); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + totalEncountersReport.hostsConnected(host1, host2); + uniqueEncountersReport.hostsConnected(host1, host2); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + totalEncountersReport.hostsDisconnected(host1, host2); + uniqueEncountersReport.hostsDisconnected(host1, host2); + } + + public void updated(List hosts) { + totalEncountersReport.updated(hosts); + uniqueEncountersReport.updated(hosts); + } + + @Override + public void done() { + int[] totalEncounters = totalEncountersReport.getEncounters(); + int[][] nodeRelationships = uniqueEncountersReport.getNodeRelationships(); + + for (int i=0; i 0) { + count++; + } + } + row += count; + write(row); + } + + super.done(); + } +} diff --git a/report/EnergyLevelReport.java b/report/EnergyLevelReport.java new file mode 100644 index 000000000..b8b05fa26 --- /dev/null +++ b/report/EnergyLevelReport.java @@ -0,0 +1,96 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.HashSet; +import java.util.List; + +import core.DTNHost; +import core.Settings; +import core.SimError; +import core.UpdateListener; + +/** + * Node energy level report. Reports the energy level of all (or only some) + * nodes every configurable-amount-of seconds. Writes reports only after + * the warmup period. + */ +public class EnergyLevelReport extends Report implements UpdateListener { + /** Reporting granularity -setting id ({@value}). + * Defines the interval how often (seconds) a new snapshot of energy levels + * is created */ + public static final String GRANULARITY = "granularity"; + /** Optional reported nodes (comma separated list of network addresses). + * By default all nodes are reported. */ + public static final String REPORTED_NODES = "nodes"; + /** value of the granularity setting */ + protected final int granularity; + /** time of last update*/ + protected double lastUpdate; + /** Networks addresses (integers) of the nodes which are reported */ + protected HashSet reportedNodes; + + /** + * Constructor. Reads the settings and initializes the report module. + */ + public EnergyLevelReport() { + Settings settings = getSettings(); + this.lastUpdate = 0; + this.granularity = settings.getInt(GRANULARITY); + + if (settings.contains(REPORTED_NODES)) { + this.reportedNodes = new HashSet(); + for (Integer nodeId : settings.getCsvInts(REPORTED_NODES)) { + this.reportedNodes.add(nodeId); + } + } + else { + this.reportedNodes = null; + } + + init(); + } + + /** + * Creates a new snapshot of the energy levels if "granularity" + * seconds have passed since the last snapshot. + * @param hosts All the hosts in the world + */ + public void updated(List hosts) { + double simTime = getSimTime(); + if (isWarmup()) { + return; /* warmup period is on */ + } + /* creates a snapshot once every granularity seconds */ + if (simTime - lastUpdate >= granularity) { + createSnapshot(hosts); + this.lastUpdate = simTime - simTime % granularity; + } + } + + /** + * Creates a snapshot of energy levels + * @param hosts The list of hosts in the world + */ + private void createSnapshot(List hosts) { + write ("[" + (int)getSimTime() + "]"); /* simulation time stamp */ + for (DTNHost h : hosts) { + if (this.reportedNodes != null && + !this.reportedNodes.contains(h.getAddress())) { + continue; /* node not in the list */ + } + Double value = (Double)h.getComBus(). + getProperty(routing.util.EnergyModel.ENERGY_VALUE_ID); + if (value == null) { + throw new SimError("Host " + h + + " is not using energy model"); + } + + write(h.toString() + " " + format(value)); + } + + } + +} diff --git a/report/EventLogReport.java b/report/EventLogReport.java new file mode 100644 index 000000000..1fb6d7184 --- /dev/null +++ b/report/EventLogReport.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.ConnectionListener; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import input.StandardEventsReader; + +/** + * Report that creates same output as the GUI's event log panel but formatted + * like {@link input.StandardEventsReader} input. Message relying event has + * extra one-letter identifier to tell whether that message was delivered to + * final destination, delivered there again, or just normally relayed + * (see the public constants). + */ +public class EventLogReport extends Report + implements ConnectionListener, MessageListener { + + /** Extra info for message relayed event ("relayed"): {@value} */ + public static final String MESSAGE_TRANS_RELAYED = "R"; + /** Extra info for message relayed event ("delivered"): {@value} */ + public static final String MESSAGE_TRANS_DELIVERED = "D"; + /** Extra info for message relayed event ("delivered again"): {@value} */ + public static final String MESSAGE_TRANS_DELIVERED_AGAIN = "A"; + + /** + * Processes a log event by writing a line to the report file + * @param action The action as a string + * @param host1 First host involved in the event (if any, or null) + * @param host2 Second host involved in the event (if any, or null) + * @param message The message involved in the event (if any, or null) + * @param extra Extra info to append in the end of line (if any, or null) + */ + private void processEvent(final String action, final DTNHost host1, + final DTNHost host2, final Message message, final String extra) { + write(getSimTime() + " " + action + " " + (host1 != null ? host1 : "") + + (host2 != null ? (" " + host2) : "") + + (message != null ? " " + message : "") + + (extra != null ? " " + extra : "")); + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + processEvent(StandardEventsReader.CONNECTION, host1, host2, null, + StandardEventsReader.CONNECTION_UP); + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + processEvent(StandardEventsReader.CONNECTION, host1, host2, null, + StandardEventsReader.CONNECTION_DOWN); + } + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + processEvent((dropped ? StandardEventsReader.DROP : + StandardEventsReader.REMOVE), where, null, m, null); + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + String extra; + if (firstDelivery) { + extra = MESSAGE_TRANS_DELIVERED; + } + else if (to == m.getTo()) { + extra = MESSAGE_TRANS_DELIVERED_AGAIN; + } + else { + extra = MESSAGE_TRANS_RELAYED; + } + + processEvent(StandardEventsReader.DELIVERED, from, to, m, extra); + } + + public void newMessage(Message m) { + processEvent(StandardEventsReader.CREATE, m.getFrom(), null, m, null); + } + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + processEvent(StandardEventsReader.ABORT, from, to, m, null); + } + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + processEvent(StandardEventsReader.SEND, from, to, m, null); + } +} \ No newline at end of file diff --git a/report/InterContactTimesReport.java b/report/InterContactTimesReport.java new file mode 100644 index 000000000..98ead3b36 --- /dev/null +++ b/report/InterContactTimesReport.java @@ -0,0 +1,35 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.DTNHost; + +/** + * Reports the inter-contact time (i.e., the time between the end of previous + * contact and the beginning of a new contact between two hosts) distribution. + * The syntax of the report file is the same as in {@link ContactTimesReport}. + */ +public class InterContactTimesReport extends ContactTimesReport { + + @Override + public void hostsConnected(DTNHost host1, DTNHost host2) { + ConnectionInfo ci = this.removeConnection(host1, host2); + + if (ci != null) { // connected again + newEvent(); + ci.connectionEnd(); + increaseTimeCount(ci.getConnectionTime()); + } + } + + @Override + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + if (isWarmup()) { + return; + } + // start counting time to next connection + this.addConnection(host1, host2); + } +} diff --git a/report/MessageAvailabilityReport.java b/report/MessageAvailabilityReport.java new file mode 100644 index 000000000..6715a5c48 --- /dev/null +++ b/report/MessageAvailabilityReport.java @@ -0,0 +1,116 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SettingsError; + +/** + * Reports which messages are available (either in the buffer or at one + * of the connected hosts' buffer) for certain, randomly selected, + * tracked hosts. Supports the same settings as the + * {@link MessageLocationReport} + */ +public class MessageAvailabilityReport extends MessageLocationReport { + + /** Number of tracked hosts -setting id ({@value}). Defines how many + * hosts are selected for sampling message availability */ + public static final String NROF_HOSTS_S = "nrofHosts"; + + private int nrofHosts; + private Set trackedHosts; + private Random rng; + + public MessageAvailabilityReport() { + super(); + Settings s = getSettings(); + nrofHosts = s.getInt(NROF_HOSTS_S, -1); + this.rng = new Random(nrofHosts); + + this.trackedHosts = null; + } + + /** + * Randomly selects the hosts to track + * @param allHosts All hosts in the scenario + * @return The set of tracked hosts + */ + private Set selectTrackedHosts(List allHosts) { + Set trackedHosts = new HashSet(); + + if (this.nrofHosts > allHosts.size()) { + throw new SettingsError("Can't use more hosts than there are " + + "in the simulation scenario"); + } + + + for (int i=0; i hosts) { + write("[" + (int) getSimTime() + "]"); /* write sim time stamp */ + + if (this.trackedHosts == null) { + this.trackedHosts = selectTrackedHosts(hosts); + } + + for (DTNHost host : hosts) { + Set msgIds = null; + String idString = ""; + + if (! this.trackedHosts.contains(host)) { + continue; + } + + msgIds = new HashSet(); + + /* add own messages */ + for (Message m : host.getMessageCollection()) { + if (!isTracked(m)) { + continue; + } + msgIds.add(m.getId()); + } + /* add all peer messages */ + for (Connection c : host.getConnections()) { + DTNHost peer = c.getOtherNode(host); + for (Message m : peer.getMessageCollection()) { + if (!isTracked(m)) { + continue; + } + msgIds.add(m.getId()); + } + } + + for (String id : msgIds) { + idString += " " + id; + } + + write(host + idString); + } + } +} \ No newline at end of file diff --git a/report/MessageCopyCountReport.java b/report/MessageCopyCountReport.java new file mode 100644 index 000000000..b5d8b081b --- /dev/null +++ b/report/MessageCopyCountReport.java @@ -0,0 +1,52 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import core.DTNHost; +import core.Message; + +/** + * Reports the amount of messages in the system at each time interval. Uses the + * same settings as the {@link MessageLocationReport} + */ +public class MessageCopyCountReport extends MessageLocationReport { + + /** + * Creates a snapshot of message counts + * @param hosts The list of hosts in the world + */ + @Override + protected void createSnapshot(List hosts) { + Map counts = new HashMap(); + write("[" + (int) getSimTime() + "]"); /* write sim time stamp */ + ArrayList keys; + + for (DTNHost host : hosts) { + for (Message m : host.getMessageCollection()) { + Integer oldCount; + if (!isTracked(m)) { + continue; + } + oldCount = counts.get(m.getId()); + counts.put(m.getId(), (oldCount == null ? 1 : oldCount + 1)); + } + } + + keys = new ArrayList(counts.keySet()); + Collections.sort(keys); + + for (String key : keys) { + write(key + " " + counts.get(key)); + } + + } + +} diff --git a/report/MessageDelayReport.java b/report/MessageDelayReport.java new file mode 100644 index 000000000..abb729872 --- /dev/null +++ b/report/MessageDelayReport.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.ArrayList; +import java.util.List; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Reports delivered messages' delays (one line per delivered message) + * and cumulative delivery probability sorted by message delays. + * Ignores the messages that were created during the warm up period. + */ +public class MessageDelayReport extends Report implements MessageListener { + public static final String HEADER = + "# messageDelay cumulativeProbability"; + /** all message delays */ + private List delays; + private int nrofCreated; + + /** + * Constructor. + */ + public MessageDelayReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + this.delays = new ArrayList(); + this.nrofCreated = 0; + } + + public void newMessage(Message m) { + if (isWarmup()) { + addWarmupID(m.getId()); + } + else { + this.nrofCreated++; + } + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery && !isWarmupID(m.getId())) { + this.delays.add(getSimTime() - m.getCreationTime()); + } + + } + + @Override + public void done() { + if (delays.size() == 0) { + write("# no messages delivered in sim time "+format(getSimTime())); + super.done(); + return; + } + double cumProb = 0; // cumulative probability + + java.util.Collections.sort(delays); + + for (int i=0; i < delays.size(); i++) { + cumProb += 1.0/nrofCreated; + write(format(delays.get(i)) + " " + format(cumProb)); + } + super.done(); + } + + // nothing to implement for the rest + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} + +} diff --git a/report/MessageDeliveryReport.java b/report/MessageDeliveryReport.java new file mode 100644 index 000000000..acafecf58 --- /dev/null +++ b/report/MessageDeliveryReport.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Report for of amount of messages delivered vs. time. A new report line + * is created every time when either a message is created or delivered. + * Messages created during the warm up period are ignored. + * For output syntax, see {@link #HEADER}. + */ +public class MessageDeliveryReport extends Report implements MessageListener { + public static String HEADER="# time created delivered delivered/created"; + private int created; + private int delivered; + + /** + * Constructor. + */ + public MessageDeliveryReport() { + init(); + } + + @Override + public void init() { + super.init(); + created = 0; + delivered = 0; + write(HEADER); + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery && !isWarmup() && !isWarmupID(m.getId())) { + delivered++; + reportValues(); + } + } + + public void newMessage(Message m) { + if (isWarmup()) { + addWarmupID(m.getId()); + return; + } + created++; + reportValues(); + } + + /** + * Writes the current values to report file + */ + private void reportValues() { + double prob = (1.0 * delivered) / created; + write(format(getSimTime()) + " " + created + " " + delivered + + " " + format(prob)); + } + + // nothing to implement for the rest + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} + + @Override + public void done() { + super.done(); + } +} diff --git a/report/MessageGraphvizReport.java b/report/MessageGraphvizReport.java new file mode 100644 index 000000000..51066ad7b --- /dev/null +++ b/report/MessageGraphvizReport.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.List; +import java.util.Vector; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Creates a graphviz compatible graph of messages that were passed. + * Messages created during the warm up period are ignored. + */ +public class MessageGraphvizReport extends Report implements MessageListener { + /** Name of the graphviz report ({@value})*/ + public static final String GRAPH_NAME = "msggraph"; + private Vector deliveredMessages; + + /** + * Constructor. + */ + public MessageGraphvizReport() { + init(); + } + + protected void init() { + super.init(); + this.deliveredMessages = new Vector(); + } + + public void newMessage(Message m) { + if (isWarmup()) { + addWarmupID(m.getId()); + } + } + + public void messageTransferred(Message m, DTNHost from, + DTNHost to, boolean firstDelivery) { + if (firstDelivery && !isWarmupID(m.getId())) { + newEvent(); + this.deliveredMessages.add(m); + } + } + + /* nothing to implement for these */ + public void messageDeleted(Message m, DTNHost where, boolean dropped) { } + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} + + @Override + public void done() { + write("/* scenario " + getScenarioName() + "\n" + + deliveredMessages.size() + " messages delivered at " + + "sim time " + getSimTime() + " */") ; + write("digraph " + GRAPH_NAME + " {"); + setPrefix("\t"); // indent following lines by one tab + + for (Message m : deliveredMessages) { + List path = m.getHops(); + String pathString = path.remove(0).toString(); // start node + + for (DTNHost next : path) { + pathString += "->" + next.toString(); + } + + write (pathString + ";"); + } + + setPrefix(""); // don't indent anymore + write("}"); + + super.done(); + } + +} diff --git a/report/MessageLocationReport.java b/report/MessageLocationReport.java new file mode 100644 index 000000000..d1d266586 --- /dev/null +++ b/report/MessageLocationReport.java @@ -0,0 +1,108 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.HashSet; +import java.util.List; + +import core.DTNHost; +import core.Message; +import core.Settings; +import core.UpdateListener; + + +/** + * Message location report. Reports the location (coordinates) of messages. + * The messages that are reported and the reporting interval can be configured. + */ +public class MessageLocationReport extends Report implements UpdateListener { + /** Reporting granularity -setting id ({@value}). + * Defines the interval how often (seconds) a new snapshot of message + * locations is created */ + public static final String GRANULARITY = "granularity"; + /** Reported messages -setting id ({@value}). + * Defines the IDs of the messages that are reported + * (comma separated list). Unless defined, all messages are reported. */ + public static final String REPORTED_MESSAGES = "messages"; + /** value of the granularity setting */ + protected final int granularity; + /** time of last update*/ + protected double lastUpdate; + /** Identifiers of the message which are reported */ + protected HashSet reportedMessages; + + /** + * Constructor. Reads the settings and initializes the report module. + */ + public MessageLocationReport() { + Settings settings = getSettings(); + this.lastUpdate = 0; + this.granularity = settings.getInt(GRANULARITY); + + if (settings.contains(REPORTED_MESSAGES)) { + this.reportedMessages = new HashSet(); + for (String msgId : settings.getCsvSetting(REPORTED_MESSAGES)) { + this.reportedMessages.add(msgId); + } + } else { + this.reportedMessages = null; /* all messages */ + } + + init(); + } + + /** + * Creates a new snapshot of the message locations if "granularity" + * seconds have passed since the last snapshot. + * @param hosts All the hosts in the world + */ + public void updated(List hosts) { + double simTime = getSimTime(); + /* creates a snapshot once every granularity seconds */ + if (simTime - lastUpdate >= granularity) { + createSnapshot(hosts); + this.lastUpdate = simTime - simTime % granularity; + } + } + + /** + * Returns true if the given message is tracked by the report + * @param m The message + * @return True if the message is tracked, false if not + */ + protected boolean isTracked(Message m) { + return (this.reportedMessages == null || + this.reportedMessages.contains(m.getId())); + } + + /** + * Creates a snapshot of message locations + * @param hosts The list of hosts in the world + */ + protected void createSnapshot(List hosts) { + boolean isFirstMessage; + String reportLine; + + write ("[" + (int)getSimTime() + "]"); /* write sim time stamp */ + + for (DTNHost host : hosts) { + isFirstMessage = true; + reportLine = ""; + for (Message m : host.getMessageCollection()) { + if (isTracked(m)) { + if (isFirstMessage) { + reportLine = host.getLocation().toString(); + isFirstMessage = false; + } + reportLine += " " + m.getId(); + } + } + if (reportLine.length() > 0) { + write(reportLine); /* write coordinate and message IDs */ + } + } + } + +} diff --git a/report/MessageReport.java b/report/MessageReport.java new file mode 100644 index 000000000..afb373c29 --- /dev/null +++ b/report/MessageReport.java @@ -0,0 +1,61 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Reports delivered messages + * report: + * message_id creation_time deliver_time (duplicate) + */ +public class MessageReport extends Report implements MessageListener { + public static final String HEADER = + "# messages: ID, start time, end time"; + /** all message delays */ + + /** + * Constructor. + */ + public MessageReport() { + init(); + } + + @Override + public void init() { + super.init(); + write(HEADER); + } + + public void newMessage(Message m) {} + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + if (firstDelivery) { + write(m.getId() + " " + + format(m.getCreationTime()) + " " + + format(getSimTime())); + } else { + if (to.getAddress() == m.getTo().getAddress()) { + write(m.getId() + " " + + format(m.getCreationTime()) + " " + + format(getSimTime()) + " duplicate"); + } + } + } + + @Override + public void done() { + super.done(); + } + + // nothing to implement for the rest + public void messageDeleted(Message m, DTNHost where, boolean dropped) {} + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) {} + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) {} + +} diff --git a/report/MessageStatsReport.java b/report/MessageStatsReport.java new file mode 100644 index 000000000..33fe2d863 --- /dev/null +++ b/report/MessageStatsReport.java @@ -0,0 +1,182 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Report for generating different kind of total statistics about message + * relaying performance. Messages that were created during the warm up period + * are ignored. + *

Note: if some statistics could not be created (e.g. + * overhead ratio if no messages were delivered) "NaN" is reported for + * double values and zero for integer median(s). + */ +public class MessageStatsReport extends Report implements MessageListener { + private Map creationTimes; + private List latencies; + private List hopCounts; + private List msgBufferTime; + private List rtt; // round trip times + + private int nrofDropped; + private int nrofRemoved; + private int nrofStarted; + private int nrofAborted; + private int nrofRelayed; + private int nrofCreated; + private int nrofResponseReqCreated; + private int nrofResponseDelivered; + private int nrofDelivered; + + /** + * Constructor. + */ + public MessageStatsReport() { + init(); + } + + @Override + protected void init() { + super.init(); + this.creationTimes = new HashMap(); + this.latencies = new ArrayList(); + this.msgBufferTime = new ArrayList(); + this.hopCounts = new ArrayList(); + this.rtt = new ArrayList(); + + this.nrofDropped = 0; + this.nrofRemoved = 0; + this.nrofStarted = 0; + this.nrofAborted = 0; + this.nrofRelayed = 0; + this.nrofCreated = 0; + this.nrofResponseReqCreated = 0; + this.nrofResponseDelivered = 0; + this.nrofDelivered = 0; + } + + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + if (isWarmupID(m.getId())) { + return; + } + + if (dropped) { + this.nrofDropped++; + } + else { + this.nrofRemoved++; + } + + this.msgBufferTime.add(getSimTime() - m.getReceiveTime()); + } + + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + if (isWarmupID(m.getId())) { + return; + } + + this.nrofAborted++; + } + + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean finalTarget) { + if (isWarmupID(m.getId())) { + return; + } + + this.nrofRelayed++; + if (finalTarget) { + this.latencies.add(getSimTime() - + this.creationTimes.get(m.getId()) ); + this.nrofDelivered++; + this.hopCounts.add(m.getHops().size() - 1); + + if (m.isResponse()) { + this.rtt.add(getSimTime() - m.getRequest().getCreationTime()); + this.nrofResponseDelivered++; + } + } + } + + + public void newMessage(Message m) { + if (isWarmup()) { + addWarmupID(m.getId()); + return; + } + + this.creationTimes.put(m.getId(), getSimTime()); + this.nrofCreated++; + if (m.getResponseSize() > 0) { + this.nrofResponseReqCreated++; + } + } + + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + if (isWarmupID(m.getId())) { + return; + } + + this.nrofStarted++; + } + + + @Override + public void done() { + write("Message stats for scenario " + getScenarioName() + + "\nsim_time: " + format(getSimTime())); + double deliveryProb = 0; // delivery probability + double responseProb = 0; // request-response success probability + double overHead = Double.NaN; // overhead ratio + + if (this.nrofCreated > 0) { + deliveryProb = (1.0 * this.nrofDelivered) / this.nrofCreated; + } + if (this.nrofDelivered > 0) { + overHead = (1.0 * (this.nrofRelayed - this.nrofDelivered)) / + this.nrofDelivered; + } + if (this.nrofResponseReqCreated > 0) { + responseProb = (1.0* this.nrofResponseDelivered) / + this.nrofResponseReqCreated; + } + + String statsText = "created: " + this.nrofCreated + + "\nstarted: " + this.nrofStarted + + "\nrelayed: " + this.nrofRelayed + + "\naborted: " + this.nrofAborted + + "\ndropped: " + this.nrofDropped + + "\nremoved: " + this.nrofRemoved + + "\ndelivered: " + this.nrofDelivered + + "\ndelivery_prob: " + format(deliveryProb) + + "\nresponse_prob: " + format(responseProb) + + "\noverhead_ratio: " + format(overHead) + + "\nlatency_avg: " + getAverage(this.latencies) + + "\nlatency_med: " + getMedian(this.latencies) + + "\nhopcount_avg: " + getIntAverage(this.hopCounts) + + "\nhopcount_med: " + getIntMedian(this.hopCounts) + + "\nbuffertime_avg: " + getAverage(this.msgBufferTime) + + "\nbuffertime_med: " + getMedian(this.msgBufferTime) + + "\nrtt_avg: " + getAverage(this.rtt) + + "\nrtt_med: " + getMedian(this.rtt) + ; + + write(statsText); + super.done(); + } + +} diff --git a/report/MovementNs2Report.java b/report/MovementNs2Report.java new file mode 100644 index 000000000..7286eaec0 --- /dev/null +++ b/report/MovementNs2Report.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import core.Coord; +import core.DTNHost; +import core.MovementListener; +import core.Settings; + +/** + * Movement report that generates suitable movement data for ns-2 simulator + * as described in + * http://www.isi.edu/nsnam/ns/doc/node174.html. + * This report ignores the warm up settings. + */ +public class MovementNs2Report extends Report implements MovementListener { + /** node array's name -setting id ({@value})*/ + public static final String NODE_ARR_S = "nodeArray"; + /** ns command -setting id ({@value}) */ + public static final String NS_CMD_S = "nsCmd"; + /** default value for the array name ({@value})*/ + public static final String DEF_NODE_ARRAY = "$node_"; + /** default value for the ns command ({@value})*/ + public static final String DEF_NS_CMD = "$ns_"; + + /** a value "close enough" to zero ({@value}). Used for fixing zero values*/ + public static final double EPSILON = 0.00001; + /** formatting string for coordinate values ({@value})*/ + public static final String COORD_FORMAT = "%.5f"; + + private String nodeArray; + private String nsCmd; + + /** + * Constructor. Reads {@link #NODE_ARR_S} and {@link #NS_CMD_S} settings + * and uses those values as the name of the node array and ns command. + * If the values aren't present, default values of + * {@value DEF_NODE_ARRAY} and + * {@value DEF_NS_CMD} are used. + */ + public MovementNs2Report() { + Settings settings = getSettings(); + + if (settings.contains(NODE_ARR_S)) { + nodeArray = settings.getSetting(NODE_ARR_S); + } + else { + nodeArray = DEF_NODE_ARRAY; + } + if (settings.contains(NS_CMD_S)) { + nsCmd = settings.getSetting(NS_CMD_S); + } + else { + nsCmd = DEF_NS_CMD; + } + + init(); + } + + public void initialLocation(DTNHost host, Coord location) { + int index = host.getAddress(); + write(nodeArray + "("+ index + ") set X_ " + fix(location.getX())); + write(nodeArray + "("+ index + ") set Y_ " + fix(location.getY())); + write(nodeArray + "("+ index + ") set Z_ 0"); + } + + public void newDestination(DTNHost host, Coord dst, double speed) { + int index = host.getAddress(); + double time = getSimTime(); + + write(nsCmd + " at " + time + " \"\\" + nodeArray + "(" + index + ")" + + " setdest " + fix(dst.getX()) + " " + fix(dst.getY()) + + " " + speed + "\""); + } + + /** + * Fixes and formats coordinate values suitable for Ns2 module. + * I.e. converts zero-values to {@value EPSILON} and formats values + * with {@link #COORD_FORMAT}. + * @param val The value to fix + * @return The fixed value + */ + private String fix(double val) { + val = val == 0 ? EPSILON : val; + return String.format(COORD_FORMAT, val); + } +} diff --git a/report/PingAppReporter.java b/report/PingAppReporter.java new file mode 100644 index 000000000..ad780a34f --- /dev/null +++ b/report/PingAppReporter.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package report; + +import applications.PingApplication; +import core.Application; +import core.ApplicationListener; +import core.DTNHost; + +/** + * Reporter for the PingApplication. Counts the number of pings + * and pongs sent and received. Calculates success probabilities. + * + * @author teemuk + */ +public class PingAppReporter extends Report implements ApplicationListener { + + private int pingsSent=0, pingsReceived=0; + private int pongsSent=0, pongsReceived=0; + + public void gotEvent(String event, Object params, Application app, + DTNHost host) { + // Check that the event is sent by correct application type + if (!(app instanceof PingApplication)) return; + + // Increment the counters based on the event type + if (event.equalsIgnoreCase("GotPing")) { + pingsReceived++; + } + if (event.equalsIgnoreCase("SentPong")) { + pongsSent++; + } + if (event.equalsIgnoreCase("GotPong")) { + pongsReceived++; + } + if (event.equalsIgnoreCase("SentPing")) { + pingsSent++; + } + + } + + + @Override + public void done() { + write("Ping stats for scenario " + getScenarioName() + + "\nsim_time: " + format(getSimTime())); + double pingProb = 0; // ping probability + double pongProb = 0; // pong probability + double successProb = 0; // success probability + + if (this.pingsSent > 0) { + pingProb = (1.0 * this.pingsReceived) / this.pingsSent; + } + if (this.pongsSent > 0) { + pongProb = (1.0 * this.pongsReceived) / this.pongsSent; + } + if (this.pingsSent > 0) { + successProb = (1.0 * this.pongsReceived) / this.pingsSent; + } + + String statsText = "pings sent: " + this.pingsSent + + "\npings received: " + this.pingsReceived + + "\npongs sent: " + this.pongsSent + + "\npongs received: " + this.pongsReceived + + "\nping delivery prob: " + format(pingProb) + + "\npong delivery prob: " + format(pongProb) + + "\nping/pong success prob: " + format(successProb) + ; + + write(statsText); + super.done(); + } +} diff --git a/report/Report.java b/report/Report.java new file mode 100644 index 000000000..209fec126 --- /dev/null +++ b/report/Report.java @@ -0,0 +1,420 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import core.Settings; +import core.SimClock; +import core.SimError; +import core.SimScenario; + +/** + * Abstract superclass for all reports. All settings defined in this class + * can be used for all Report classes. Some reports don't implement intervalled + * reports ({@link #INTERVAL_SETTING}) and will ignore that setting. Most of + * the reports implement warm up feature ({@link #WARMUP_S}) but the + * implementations are always report specific. + */ +public abstract class Report { + /** Name space of the settings that are common to all reports ({@value}). */ + public static final String REPORT_NS = "Report"; + /** The interval (simulated seconds) of creating new settings files + * -setting id ({@value}) */ + public static final String INTERVAL_SETTING = "interval"; + /** The output file path of the report -setting id ({@value})*/ + public static final String OUTPUT_SETTING = "output"; + /** Precision of formatted double values - setting id ({@value}). + * Defines the amount of decimals shown in formatted double values. + * Default value is {@value #DEF_PRECISION}. */ + public static final String PRECISION_SETTING = "precision"; + /** Default precision of formatted double values */ + public static final int DEF_PRECISION = 4; + /** The default output directory of reports (can be overridden per report + * with {@link Report#OUTPUT_SETTING}) -setting id ({@value})*/ + public static final String REPORTDIR_SETTING = "Report.reportDir"; + /** Warm up period -setting id ({@value}). Defines how many seconds from + * the beginning of the simulation should not be included in the reports. + * Implementation of the feature is report specific, so check out the + * respective report classes for details. Default is 0. Must be a positive + * integer or 0. */ + public static final String WARMUP_S = "warmup"; + /** Suffix of report files without explicit output */ + public static final String OUT_SUFFIX = ".txt"; + /** Suffix for reports that are created on n second intervals */ + public static final String INTERVALLED_FORMAT ="%04d" + OUT_SUFFIX; + /** The print writer used to write output. See {@link #write(String)} */ + protected PrintWriter out; + /** String value for values that could not be calculated */ + public static final String NAN = "NaN"; + private String prefix = ""; + private int precision; + protected int warmupTime; + protected Set warmupIDs; + + private int lastOutputSuffix; + private double outputInterval; + private double lastReportTime; + private String outFileName; + private String scenarioName; + + /** + * Constructor. + * Looks for a className.output setting in the Settings and + * if such is found, uses that as the output file name. Otherwise + * scenarioname_classname.txt is used as the file name. + */ + public Report(){ + this.lastOutputSuffix = 0; + this.outputInterval = -1; + this.warmupIDs = null; + + Settings settings = new Settings(); + scenarioName = settings.valueFillString(settings.getSetting( + SimScenario.SCENARIO_NS + "." + SimScenario.NAME_S)); + + settings = getSettings(); + + if (settings.contains(INTERVAL_SETTING)) { + outputInterval = settings.getDouble(INTERVAL_SETTING); + } + + if (settings.contains(WARMUP_S)) { + this.warmupTime = settings.getInt(WARMUP_S); + } + else { + this.warmupTime = 0; + } + + + if (settings.contains(PRECISION_SETTING)) { + precision = settings.getInt(PRECISION_SETTING); + if (precision < 0) { + precision = 0; + } + } + else { + precision = DEF_PRECISION; + } + + if (settings.contains(OUTPUT_SETTING)) { + outFileName = settings.getSetting(OUTPUT_SETTING); + // fill value place holders in the name + outFileName = settings.valueFillString(outFileName); + } + else { + // no output name define -> construct one from report class' name + settings.setNameSpace(null); + String outDir = settings.getSetting(REPORTDIR_SETTING); + if (!outDir.endsWith("/")) { + outDir += "/"; // make sure dir ends with directory delimiter + } + outFileName = outDir + scenarioName + + "_" + this.getClass().getSimpleName(); + if (outputInterval == -1) { + outFileName += OUT_SUFFIX; // no intervalled reports + } + + } + + checkDirExistence(outFileName); + } + + /** + * Checks that a directory for a file exists or creates the directory + * if it didn't exist. + * @param outFileName Name of the file + */ + private void checkDirExistence(String outFileName) { + File outFile = new File(outFileName); + File outDir = outFile.getParentFile(); + + if (outDir != null && !outDir.exists()) { + if (!createDirs(outDir)) { + throw new SimError("Couldn't create report directory '" + + outDir.getAbsolutePath()+"'"); + } + } + } + + /** + * Recursively creates a directory structure + * @param directory The directory to create + * @return True if the creation succeeded, false if not + */ + private boolean createDirs(File directory) { + if (directory==null) { + return true; + } + if (directory.exists()) { + return true; + } else { + if (!createDirs(directory.getParentFile())) { + return false; + } + if (!directory.mkdir()) { + return false; + } else { + return true; + } + } + } + + /** + * Initializes the report output. Method is called in the beginning of + * every new report file. Subclasses must call this method first in their + * own implementations of init(). + */ + protected void init() { + this.lastReportTime = getSimTime(); + + if (outputInterval > 0) { + createSuffixedOutput(outFileName); + } + else { + createOutput(outFileName); + } + } + + /** + * Creates a new output file + * @param outFileName Name (&path) of the file to create + */ + private void createOutput(String outFileName) { + try { + this.out = new PrintWriter(new FileWriter(outFileName)); + } catch (IOException e) { + throw new SimError("Couldn't open file '" + outFileName + + "' for report output\n" + e.getMessage(), e); + } + } + + /** + * Creates a number-suffixed output file with increasing number suffix + * @param outFileName Prefix of the output file's name + */ + private void createSuffixedOutput(String outFileName) { + String suffix = String.format(INTERVALLED_FORMAT, + this.lastOutputSuffix); + createOutput(outFileName+suffix); + this.lastOutputSuffix++; + } + + /** + * This method should be called before every new (complete) event the + * report logs. If the report has no meaningful use for multiple reports, + * the call can be omitted (then only single output file will be generated) + */ + protected void newEvent() { + if (this.outputInterval <= 0) { + return; + } + + if (getSimTime() > this.lastReportTime + this.outputInterval) { + done(); // finalize the old file + init(); // init the new file + } + } + + /** + * Writes a line to report using defined prefix and {@link #out} writer. + * @param txt Line to write + * @see #setPrefix(String) + */ + protected void write(String txt) { + if (out == null) { + init(); + } + out.println(prefix + txt); + } + + /** + * Formats a double value according to current precision setting (see + * {@link #PRECISION_SETTING}) and returns it in a string. + * @param value The value to format + * @return Formatted value in a string + */ + protected String format(double value) { + return String.format("%." + precision + "f", value); + } + + /** + * Sets a prefix that will be inserted before every line in the report + * @param txt Text to use as the prefix + */ + protected void setPrefix(String txt) { + this.prefix = txt; + } + + /** + * Returns the name of the scenario as read from the settings + * @return the name of the scenario as read from the settings + */ + protected String getScenarioName() { + return this.scenarioName; + } + + /** + * Returns the current simulation time from the SimClock + * @return the current simulation time from the SimClock + */ + protected double getSimTime() { + return SimClock.getTime(); + } + + /** + * Returns true if the warm up period is still ongoing (simTime < warmup) + * @return true if the warm up period is still ongoing, false if not + */ + protected boolean isWarmup() { + return this.warmupTime > SimClock.getTime(); + } + + /** + * Adds a new ID to the warm up ID set + * @param id The ID + */ + protected void addWarmupID(String id) { + if (this.warmupIDs == null) { // lazy creation of the Set + this.warmupIDs = new HashSet(); + } + + this.warmupIDs.add(id); + } + + /** + * Removes a warm up ID from the warm up ID set + * @param id The ID to remove + */ + protected void removeWarmupID(String id) { + this.warmupIDs.remove(id); + } + + /** + * Returns true if the given ID is in the warm up ID set + * @param id The ID + * @return true if the given ID is in the warm up ID set + */ + protected boolean isWarmupID(String id) { + if (this.warmupIDs == null || this.warmupIDs.size() == 0) { + return false; + } + + return this.warmupIDs.contains(id); + } + + /** + * Returns a Settings object initialized for the report class' name space + * that uses {@value REPORT_NS} as the secondary name space. + * @return a Settings object initialized for the report class' name space + */ + protected Settings getSettings() { + Settings s = new Settings(this.getClass().getSimpleName()); + s.setSecondaryNamespace(REPORT_NS); + return s; + } + + /** + * Called when the simulation is done, user requested + * premature termination or intervalled report generating decided + * that it's time for the next report. + */ + public void done() { + if (out != null) { + out.close(); + } + } + + /** + * Returns the average of double values stored in a List or "NaN" for + * empty lists. + * @param values The list of double values + * @return average of double values stored in the List in a formatted String + */ + public String getAverage(List values) { + double sum = 0; + if (values.size() == 0) { + return NAN; + } + + for (double dValue : values) { + sum += dValue; + } + + return format(sum / values.size()); + } + + /** + * Returns the average of integer values stored in a List + * @param values The list of values + * @return average of integer values stored in the List or "NaN" for + * empty lists. + */ + public String getIntAverage(List values) { + List dValues = new ArrayList(values.size()); + for (int i : values) { + dValues.add((double)i); + } + return getAverage(dValues); + } + + /** + * Returns the median of double values stored in a List + * @param values The list of double values + * @return median of double values stored in the List or "NaN" for + * empty lists. + */ + public String getMedian(List values) { + if (values.size() == 0) { + return NAN; + } + + Collections.sort(values); + return format(values.get(values.size()/2)); + } + + /** + * Returns the median of integer values stored in a List + * @param values The list of values + * @return median of integer values stored in the List or 0 for + * empty lists. + */ + public int getIntMedian(List values) { + if (values.size() == 0) { + return 0; + } + + Collections.sort(values); + return values.get(values.size()/2); + } + + /** + * Returns the variance of the values in the List. + * + * @param values The list of values + * @return The variance of the values in the list or "NaN" if the list is + * empty. + */ + public String getVariance(List values) { + if (values.size()==0) return "NaN"; + double E_X; + double sum=0, sum2=0; + for (double dValue : values) { + sum += dValue; + sum2 += dValue*dValue; + } + E_X = sum / values.size(); + return format(sum2/values.size() - (E_X*E_X)); + } + +} diff --git a/report/TotalContactTimeReport.java b/report/TotalContactTimeReport.java new file mode 100644 index 000000000..526074591 --- /dev/null +++ b/report/TotalContactTimeReport.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.List; + +import core.DTNHost; +import core.UpdateListener; + +/** + * Report for total amount of contact times among hosts. Reports how long all + * nodes have been in contact with some other node. Supports + * {@link ContactTimesReport#GRANULARITY} setting. If update interval is + * smaller than 1.0 seconds, time stamps may start to drift. Reported values + * still correspond to reported times. Connections that started during the + * warmup period are ignored. + */ +public class TotalContactTimeReport extends ContactTimesReport implements + UpdateListener { + + /** The header of every report file */ + public static final String HEADER = "# time totalContactTime"; + /** cumulative contact times of all disconnected contacts */ + private double oldContactTimes; + /** sim time of last report writing */ + private double lastWrite; + /** last reported time count (to suppress duplicates) */ + private double lastReportedTime; + + public void init() { + super.init(); + write(HEADER); + this.oldContactTimes = 0; + this.lastReportedTime = 0; + this.lastWrite = getSimTime(); + } + + @Override + public void hostsDisconnected(DTNHost host1, DTNHost host2) { + newEvent(); + ConnectionInfo ci = removeConnection(host1, host2); + + if (ci == null) { + return; // connection started during the warm up period + } + + oldContactTimes += ci.getConnectionTime(); + } + + /** + * Reports total contact time if more time than defined with setting + * {@link ContactTimesReport#GRANULARITY} has passed. Method is called + * on every update cycle. + */ + public void updated(List hosts) { + double simTime = getSimTime(); + if (simTime - lastWrite < granularity || isWarmup()) { + return; // shouldn't report yet + } + lastWrite = simTime; + + // count also the times for connections that are still up + double othersTime = 0; + for (ConnectionInfo oth : this.connections.values()) { + othersTime += oth.getConnectionTime(); + } + + double totalTime = oldContactTimes + othersTime; + + if (lastReportedTime == totalTime) { + return; // don't report duplicate times + } + + write(format(simTime) + " " + format(totalTime)); + lastReportedTime = totalTime; + } +} diff --git a/report/TotalEncountersReport.java b/report/TotalEncountersReport.java new file mode 100644 index 000000000..dbcba20b9 --- /dev/null +++ b/report/TotalEncountersReport.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package report; + +import java.util.List; + +import core.ConnectionListener; +import core.DTNHost; +import core.UpdateListener; + +/** + * A report of the distribution of how many encounters (contacts) a node has had + * + * @author Frans Ekman + */ +public class TotalEncountersReport extends Report implements ConnectionListener, + UpdateListener { + + private int[] encounters; + + public TotalEncountersReport() { + + } + + public void hostsConnected(DTNHost host1, DTNHost host2) { + if (encounters == null) { + return; + } + encounters[host1.getAddress()]++; + encounters[host2.getAddress()]++; + } + + public void hostsDisconnected(DTNHost host1, DTNHost host2) {} + + public void updated(List hosts) { + if (encounters == null) { + encounters = new int[hosts.size()]; + } + } + + @Override + public void done() { + + int maxEncounters = -1; + for (int i=0; i maxEncounters) { + maxEncounters = encounters[i]; + } + } + + int[] distribution = new int[maxEncounters + 1]; + + for (int i=0; i hosts) { + if (nodeRelationships == null) { + nodeRelationships = new int[hosts.size()][hosts.size()]; + } + } + + @Override + public void done() { + int[] distribution = new int[1000]; + + for (int i=0; i 0) { + count++; + } + } + + int promille = (count * 1000)/nodeRelationships.length; + distribution[promille]++; + } + + // print distribution + for (int i=0; i + + + +Contains all the report classes. Reports can be used to create e.g. statistics +and visualizations of the simulation. All report classes must be in this +package and must extend the {@link report.Report} class so they can be +dynamically loaded to the simulator. The classes to load can be specified +trough {@link core.Settings} class' settings source. See Report class and +classes extending it for details about the settings. + + + \ No newline at end of file diff --git a/routing/ActiveRouter.java b/routing/ActiveRouter.java new file mode 100644 index 000000000..e42605b9c --- /dev/null +++ b/routing/ActiveRouter.java @@ -0,0 +1,660 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +import routing.util.EnergyModel; +import routing.util.MessageTransferAcceptPolicy; +import routing.util.RoutingInfo; +import util.Tuple; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import core.NetworkInterface; +import core.Settings; +import core.SimClock; + +/** + * Superclass of active routers. Contains convenience methods (e.g. + * {@link #getNextMessageToRemove(boolean)}) and watching of sending connections (see + * {@link #update()}). + */ +public abstract class ActiveRouter extends MessageRouter { + /** Delete delivered messages -setting id ({@value}). Boolean valued. + * If set to true and final recipient of a message rejects it because it + * already has it, the message is deleted from buffer. Default=false. */ + public static final String DELETE_DELIVERED_S = "deleteDelivered"; + /** should messages that final recipient marks as delivered be deleted + * from message buffer */ + protected boolean deleteDelivered; + + /** prefix of all response message IDs */ + public static final String RESPONSE_PREFIX = "R_"; + /** how often TTL check (discarding old messages) is performed */ + public static int TTL_CHECK_INTERVAL = 60; + /** connection(s) that are currently used for sending */ + protected ArrayList sendingConnections; + /** sim time when the last TTL check was done */ + private double lastTtlCheck; + + private MessageTransferAcceptPolicy policy; + private EnergyModel energy; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ActiveRouter(Settings s) { + super(s); + + this.policy = new MessageTransferAcceptPolicy(s); + + this.deleteDelivered = s.getBoolean(DELETE_DELIVERED_S, false); + + if (s.contains(EnergyModel.INIT_ENERGY_S)) { + this.energy = new EnergyModel(s); + } else { + this.energy = null; /* no energy model */ + } + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected ActiveRouter(ActiveRouter r) { + super(r); + this.deleteDelivered = r.deleteDelivered; + this.policy = r.policy; + this.energy = (r.energy != null ? r.energy.replicate() : null); + } + + @Override + public void init(DTNHost host, List mListeners) { + super.init(host, mListeners); + this.sendingConnections = new ArrayList(1); + this.lastTtlCheck = 0; + } + + /** + * Called when a connection's state changes. If energy modeling is enabled, + * and a new connection is created to this node, reduces the energy for the + * device discovery (scan response) amount + * @param @con The connection whose state changed + */ + @Override + public void changedConnection(Connection con) { + if (this.energy != null && con.isUp() && !con.isInitiator(getHost())) { + this.energy.reduceDiscoveryEnergy(); + } + } + + @Override + public boolean requestDeliverableMessages(Connection con) { + if (isTransferring()) { + return false; + } + + DTNHost other = con.getOtherNode(getHost()); + /* do a copy to avoid concurrent modification exceptions + * (startTransfer may remove messages) */ + ArrayList temp = + new ArrayList(this.getMessageCollection()); + for (Message m : temp) { + if (other == m.getTo()) { + if (startTransfer(m, con) == RCV_OK) { + return true; + } + } + } + return false; + } + + @Override + public boolean createNewMessage(Message m) { + makeRoomForNewMessage(m.getSize()); + return super.createNewMessage(m); + } + + @Override + public int receiveMessage(Message m, DTNHost from) { + int recvCheck = checkReceiving(m, from); + if (recvCheck != RCV_OK) { + return recvCheck; + } + + // seems OK, start receiving the message + return super.receiveMessage(m, from); + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + Message m = super.messageTransferred(id, from); + + /** + * N.B. With application support the following if-block + * becomes obsolete, and the response size should be configured + * to zero. + */ + // check if msg was for this host and a response was requested + if (m.getTo() == getHost() && m.getResponseSize() > 0) { + // generate a response message + Message res = new Message(this.getHost(),m.getFrom(), + RESPONSE_PREFIX+m.getId(), m.getResponseSize()); + this.createNewMessage(res); + this.getMessage(RESPONSE_PREFIX+m.getId()).setRequest(m); + } + + return m; + } + + /** + * Returns a list of connections this host currently has with other hosts. + * @return a list of connections this host currently has with other hosts + */ + protected List getConnections() { + return getHost().getConnections(); + } + + /** + * Tries to start a transfer of message using a connection. Is starting + * succeeds, the connection is added to the watch list of active connections + * @param m The message to transfer + * @param con The connection to use + * @return the value returned by + * {@link Connection#startTransfer(DTNHost, Message)} + */ + protected int startTransfer(Message m, Connection con) { + int retVal; + + if (!con.isReadyForTransfer()) { + return TRY_LATER_BUSY; + } + + if (!policy.acceptSending(getHost(), + con.getOtherNode(getHost()), con, m)) { + return MessageRouter.DENIED_POLICY; + } + + retVal = con.startTransfer(getHost(), m); + if (retVal == RCV_OK) { // started transfer + addToSendingConnections(con); + } + else if (deleteDelivered && retVal == DENIED_OLD && + m.getTo() == con.getOtherNode(this.getHost())) { + /* final recipient has already received the msg -> delete it */ + this.deleteMessage(m.getId(), false); + } + + return retVal; + } + + /** + * Makes rudimentary checks (that we have at least one message and one + * connection) about can this router start transfer. + * @return True if router can start transfer, false if not + */ + protected boolean canStartTransfer() { + if (this.getNrofMessages() == 0) { + return false; + } + if (this.getConnections().size() == 0) { + return false; + } + + return true; + } + + /** + * Checks if router "wants" to start receiving message (i.e. router + * isn't transferring, doesn't have the message and has room for it). + * @param m The message to check + * @return A return code similar to + * {@link MessageRouter#receiveMessage(Message, DTNHost)}, i.e. + * {@link MessageRouter#RCV_OK} if receiving seems to be OK, + * TRY_LATER_BUSY if router is transferring, DENIED_OLD if the router + * is already carrying the message or it has been delivered to + * this router (as final recipient), or DENIED_NO_SPACE if the message + * does not fit into buffer + */ + protected int checkReceiving(Message m, DTNHost from) { + if (isTransferring()) { + return TRY_LATER_BUSY; // only one connection at a time + } + + if ( hasMessage(m.getId()) || isDeliveredMessage(m) || + super.isBlacklistedMessage(m.getId())) { + return DENIED_OLD; // already seen this message -> reject it + } + + if (m.getTtl() <= 0 && m.getTo() != getHost()) { + /* TTL has expired and this host is not the final recipient */ + return DENIED_TTL; + } + + if (energy != null && energy.getEnergy() <= 0) { + return MessageRouter.DENIED_LOW_RESOURCES; + } + + if (!policy.acceptReceiving(from, getHost(), m)) { + return MessageRouter.DENIED_POLICY; + } + + /* remove oldest messages but not the ones being sent */ + if (!makeRoomForMessage(m.getSize())) { + return DENIED_NO_SPACE; // couldn't fit into buffer -> reject + } + + return RCV_OK; + } + + /** + * Removes messages from the buffer (oldest first) until + * there's enough space for the new message. + * @param size Size of the new message + * transferred, the transfer is aborted before message is removed + * @return True if enough space could be freed, false if not + */ + protected boolean makeRoomForMessage(int size){ + if (size > this.getBufferSize()) { + return false; // message too big for the buffer + } + + int freeBuffer = this.getFreeBufferSize(); + /* delete messages from the buffer until there's enough space */ + while (freeBuffer < size) { + Message m = getNextMessageToRemove(true); // don't remove msgs being sent + + if (m == null) { + return false; // couldn't remove any more messages + } + + /* delete message from the buffer as "drop" */ + deleteMessage(m.getId(), true); + freeBuffer += m.getSize(); + } + + return true; + } + + /** + * Drops messages whose TTL is less than zero. + */ + protected void dropExpiredMessages() { + Message[] messages = getMessageCollection().toArray(new Message[0]); + for (int i=0; i messages = this.getMessageCollection(); + Message oldest = null; + for (Message m : messages) { + + if (excludeMsgBeingSent && isSending(m.getId())) { + continue; // skip the message(s) that router is sending + } + + if (oldest == null ) { + oldest = m; + } + else if (oldest.getReceiveTime() > m.getReceiveTime()) { + oldest = m; + } + } + + return oldest; + } + + /** + * Returns a list of message-connections tuples of the messages whose + * recipient is some host that we're connected to at the moment. + * @return a list of message-connections tuples + */ + protected List> getMessagesForConnected() { + if (getNrofMessages() == 0 || getConnections().size() == 0) { + /* no messages -> empty list */ + return new ArrayList>(0); + } + + List> forTuples = + new ArrayList>(); + for (Message m : getMessageCollection()) { + for (Connection con : getConnections()) { + DTNHost to = con.getOtherNode(getHost()); + if (m.getTo() == to) { + forTuples.add(new Tuple(m,con)); + } + } + } + + return forTuples; + } + + /** + * Tries to send messages for the connections that are mentioned + * in the Tuples in the order they are in the list until one of + * the connections starts transferring or all tuples have been tried. + * @param tuples The tuples to try + * @return The tuple whose connection accepted the message or null if + * none of the connections accepted the message that was meant for them. + */ + protected Tuple tryMessagesForConnected( + List> tuples) { + if (tuples.size() == 0) { + return null; + } + + for (Tuple t : tuples) { + Message m = t.getKey(); + Connection con = t.getValue(); + if (startTransfer(m, con) == RCV_OK) { + return t; + } + } + + return null; + } + + /** + * Goes trough the messages until the other node accepts one + * for receiving (or doesn't accept any). If a transfer is started, the + * connection is included in the list of sending connections. + * @param con Connection trough which the messages are sent + * @param messages A list of messages to try + * @return The message whose transfer was started or null if no + * transfer was started. + */ + protected Message tryAllMessages(Connection con, List messages) { + for (Message m : messages) { + int retVal = startTransfer(m, con); + if (retVal == RCV_OK) { + return m; // accepted a message, don't try others + } + else if (retVal > 0) { + return null; // should try later -> don't bother trying others + } + } + + return null; // no message was accepted + } + + /** + * Tries to send all given messages to all given connections. Connections + * are first iterated in the order they are in the list and for every + * connection, the messages are tried in the order they are in the list. + * Once an accepting connection is found, no other connections or messages + * are tried. + * @param messages The list of Messages to try + * @param connections The list of Connections to try + * @return The connections that started a transfer or null if no connection + * accepted a message. + */ + protected Connection tryMessagesToConnections(List messages, + List connections) { + for (int i=0, n=connections.size(); i connections = getConnections(); + if (connections.size() == 0 || this.getNrofMessages() == 0) { + return null; + } + + List messages = + new ArrayList(this.getMessageCollection()); + this.sortByQueueMode(messages); + + return tryMessagesToConnections(messages, connections); + } + + /** + * Exchanges deliverable (to final recipient) messages between this host + * and all hosts this host is currently connected to. First all messages + * from this host are checked and then all other hosts are asked for + * messages to this host. If a transfer is started, the search ends. + * @return A connection that started a transfer or null if no transfer + * was started + */ + protected Connection exchangeDeliverableMessages() { + List connections = getConnections(); + + if (connections.size() == 0) { + return null; + } + + @SuppressWarnings(value = "unchecked") + Tuple t = + tryMessagesForConnected(sortByQueueMode(getMessagesForConnected())); + + if (t != null) { + return t.getValue(); // started transfer + } + + // didn't start transfer to any node -> ask messages from connected + for (Connection con : connections) { + if (con.getOtherNode(getHost()).requestDeliverableMessages(con)) { + return con; + } + } + + return null; + } + + + + /** + * Shuffles a messages list so the messages are in random order. + * @param messages The list to sort and shuffle + */ + protected void shuffleMessages(List messages) { + if (messages.size() <= 1) { + return; // nothing to shuffle + } + + Random rng = new Random(SimClock.getIntTime()); + Collections.shuffle(messages, rng); + } + + /** + * Adds a connections to sending connections which are monitored in + * the update. + * @see #update() + * @param con The connection to add + */ + protected void addToSendingConnections(Connection con) { + this.sendingConnections.add(con); + } + + /** + * Returns true if this router is transferring something at the moment or + * some transfer has not been finalized. + * @return true if this router is transferring something + */ + public boolean isTransferring() { + if (this.sendingConnections.size() > 0) { + return true; // sending something + } + + List connections = getConnections(); + + if (connections.size() == 0) { + return false; // not connected + } + + for (int i=0, n=connections.size(); imsgId. + * @param msgId The ID of the message + * @return True if the message is being sent false if not + */ + public boolean isSending(String msgId) { + for (Connection con : this.sendingConnections) { + if (con.getMessage() == null) { + continue; // transmission is finalized + } + if (con.getMessage().getId().equals(msgId)) { + return true; + } + } + return false; + } + + /** + * Returns true if the node has energy left (i.e., energy modeling is + * enabled OR (is enabled and model has energy left)) + * @return has the node energy + */ + public boolean hasEnergy() { + return this.energy == null || this.energy.getEnergy() > 0; + } + + /** + * Checks out all sending connections to finalize the ready ones + * and abort those whose connection went down. Also drops messages + * whose TTL <= 0 (checking every one simulated minute). + * @see #addToSendingConnections(Connection) + */ + @Override + public void update() { + super.update(); + + /* in theory we can have multiple sending connections even though + currently all routers allow only one concurrent sending connection */ + for (int i=0; i= TTL_CHECK_INTERVAL && + sendingConnections.size() == 0) { + dropExpiredMessages(); + lastTtlCheck = SimClock.getTime(); + } + + if (energy != null) { + /* TODO: add support for other interfaces */ + NetworkInterface iface = getHost().getInterface(1); + energy.update(iface, getHost().getComBus()); + } + } + + /** + * Method is called just before a transfer is aborted at {@link #update()} + * due connection going down. This happens on the sending host. + * Subclasses that are interested of the event may want to override this. + * @param con The connection whose transfer was aborted + */ + protected void transferAborted(Connection con) { } + + /** + * Method is called just before a transfer is finalized + * at {@link #update()}. + * Subclasses that are interested of the event may want to override this. + * @param con The connection whose transfer was finalized + */ + protected void transferDone(Connection con) { } + + @Override + public RoutingInfo getRoutingInfo() { + RoutingInfo top = super.getRoutingInfo(); + if (energy != null) { + top.addMoreInfo(new RoutingInfo("Energy level: " + + String.format("%.2f mAh", energy.getEnergy() / 3600))); + } + return top; + } + +} diff --git a/routing/DirectDeliveryRouter.java b/routing/DirectDeliveryRouter.java new file mode 100644 index 000000000..2bfb107e7 --- /dev/null +++ b/routing/DirectDeliveryRouter.java @@ -0,0 +1,39 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import core.Settings; + +/** + * Router that will deliver messages only to the final recipient. + */ +public class DirectDeliveryRouter extends ActiveRouter { + + public DirectDeliveryRouter(Settings s) { + super(s); + } + + protected DirectDeliveryRouter(DirectDeliveryRouter r) { + super(r); + } + + @Override + public void update() { + super.update(); + if (isTransferring() || !canStartTransfer()) { + return; // can't start a new transfer + } + + // Try only the messages that can be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; // started a transfer + } + } + + @Override + public DirectDeliveryRouter replicate() { + return new DirectDeliveryRouter(this); + } +} diff --git a/routing/EpidemicOracleRouter.java b/routing/EpidemicOracleRouter.java new file mode 100644 index 000000000..875f852d2 --- /dev/null +++ b/routing/EpidemicOracleRouter.java @@ -0,0 +1,181 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.List; + +import core.*; + +/** + *

+ * Epidemic message router with an oracle that tells when a message is delivered + * and that message is then removed from all nodes that use this routing module. + * This router also ignores message size and all messages are delivered + * immediately.

+ * Note: This router module also bypasses ActiveRouter.update() + */ +public class EpidemicOracleRouter extends ActiveRouter { + + /** List of all routers in this node group */ + private static List allRouters; + + static { + DTNSim.registerForReset(EpidemicOracleRouter.class.getCanonicalName()); + reset(); + } + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public EpidemicOracleRouter(Settings s) { + super(s); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected EpidemicOracleRouter(EpidemicOracleRouter r) { + super(r); + allRouters.add(this); + } + + @Override + public void changedConnection(Connection con) { + super.changedConnection(con); + + if (con.isUp()) { + DTNHost peer = con.getOtherNode(getHost()); + List newMessages = new ArrayList(); + + for (Message m : peer.getMessageCollection()) { + if (!this.hasMessage(m.getId())) { + newMessages.add(m); + } + } + for (Message m : newMessages) { + /* try to start transfer from peer */ + if (con.startTransfer(peer, m) == RCV_OK) { + con.finalizeTransfer(); /* and finalize it right away */ + } + } + } + } + + private void sendMessageToConnected(Message m) { + DTNHost host = getHost(); + + for (Connection c : getConnections()) { + if (c.isReadyForTransfer() && c.startTransfer(host, m) == RCV_OK) { + c.finalizeTransfer(); /* and finalize it right away */ + } + } + } + + public boolean createNewMessage(Message m) { + boolean ok = super.createNewMessage(m); + + if (!ok) { + throw new SimError("Can't create message " + m); + } + + sendMessageToConnected(m); + + return true; + } + + /** + * Removes the message with the given ID from this router, if the router + * has that message; otherwise does nothing. If the router was transferring + * the message, the transfer is aborted. + * @param id ID of the message to be removed + */ + public void removeDeliveredMessage(String id) { + if (this.hasMessage(id)) { + for (Connection c : this.sendingConnections) { + /* if sending the message-to-be-removed, cancel transfer */ + if (c.getMessage().getId().equals(id)) { + c.abortTransfer(); + } + } + this.deleteMessage(id, false); + } + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + Message m = super.messageTransferred(id, from); + + if (m.getTo() == this.getHost()) { + for (EpidemicOracleRouter r : allRouters) { + if (r != this && r != from.getRouter()) { + r.removeDeliveredMessage(id); + } + } + } else { + sendMessageToConnected(m); + } + + return m; + } + + protected int checkReceiving(Message m) { + if ( isIncomingMessage(m.getId()) || hasMessage(m.getId()) || + isDeliveredMessage(m) ){ + return DENIED_OLD; // already seen this message -> reject it + } + + if (m.getTtl() <= 0 && m.getTo() != getHost()) { + /* TTL has expired and this host is not the final recipient */ + return DENIED_TTL; + } + + /* remove oldest messages but not the ones being sent */ + if (!makeRoomForMessage(m.getSize())) { + return DENIED_NO_SPACE; // couldn't fit into buffer -> reject + } + + return RCV_OK; + } + + @Override + protected void transferDone(Connection con) { + Message m = con.getMessage(); + + if (m == null) { + core.Debug.p("Null message for con " + con); + return; + } + + /* was the message delivered to the final recipient? */ + if (m.getTo() == con.getOtherNode(getHost())) { + this.deleteMessage(m.getId(), false); + } + } + + @Override + public void update() { + /* nothing to do; all transfers are started only when new connections + are created or new messages are created or received, and transfers + are finalized immediately */ + } + + + @Override + public EpidemicOracleRouter replicate() { + return new EpidemicOracleRouter(this); + } + + /** + * Resets the static router list + */ + public static void reset() { + allRouters = new ArrayList(); + } + +} \ No newline at end of file diff --git a/routing/EpidemicRouter.java b/routing/EpidemicRouter.java new file mode 100644 index 000000000..f2a696890 --- /dev/null +++ b/routing/EpidemicRouter.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import core.Settings; + +/** + * Epidemic message router with drop-oldest buffer and only single transferring + * connections at a time. + */ +public class EpidemicRouter extends ActiveRouter { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public EpidemicRouter(Settings s) { + super(s); + //TODO: read&use epidemic router specific settings (if any) + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected EpidemicRouter(EpidemicRouter r) { + super(r); + //TODO: copy epidemic settings here (if any) + } + + @Override + public void update() { + super.update(); + if (isTransferring() || !canStartTransfer()) { + return; // transferring, don't try other connections yet + } + + // Try first the messages that can be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; // started a transfer, don't try others (yet) + } + + // then try any/all message to any/all connection + this.tryAllMessagesToAllConnections(); + } + + + @Override + public EpidemicRouter replicate() { + return new EpidemicRouter(this); + } + +} \ No newline at end of file diff --git a/routing/FirstContactRouter.java b/routing/FirstContactRouter.java new file mode 100644 index 000000000..f48fe7365 --- /dev/null +++ b/routing/FirstContactRouter.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; + +/** + * First contact router which uses only a single copy of the message + * (or fragments) and forwards it to the first available contact. + */ +public class FirstContactRouter extends ActiveRouter { + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public FirstContactRouter(Settings s) { + super(s); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected FirstContactRouter(FirstContactRouter r) { + super(r); + } + + @Override + protected int checkReceiving(Message m, DTNHost from) { + int recvCheck = super.checkReceiving(m, from); + + if (recvCheck == RCV_OK) { + /* don't accept a message that has already traversed this node */ + if (m.getHops().contains(getHost())) { + recvCheck = DENIED_OLD; + } + } + + return recvCheck; + } + + @Override + public void update() { + super.update(); + if (isTransferring() || !canStartTransfer()) { + return; + } + + if (exchangeDeliverableMessages() != null) { + return; + } + + tryAllMessagesToAllConnections(); + } + + @Override + protected void transferDone(Connection con) { + /* don't leave a copy for the sender */ + this.deleteMessage(con.getMessage().getId(), false); + } + + @Override + public FirstContactRouter replicate() { + return new FirstContactRouter(this); + } + +} \ No newline at end of file diff --git a/routing/LifeRouter.java b/routing/LifeRouter.java new file mode 100644 index 000000000..8cb17a3d8 --- /dev/null +++ b/routing/LifeRouter.java @@ -0,0 +1,115 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.Vector; + +import core.DTNHost; +import core.Message; +import core.Settings; +import core.Connection; + +/** + * Router module mimicking the game-of-life behavior + */ +public class LifeRouter extends ActiveRouter { + + /** + * Neighboring message count -setting id ({@value}). Two comma + * separated values: min and max. Only if the amount of connected nodes + * with the given message is between the min and max value, the message + * is accepted for transfer and kept in the buffer. + */ + public static final String NM_COUNT_S = "nmcount"; + private int countRange[]; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public LifeRouter(Settings s) { + super(s); + countRange = s.getCsvInts(NM_COUNT_S, 2); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected LifeRouter(LifeRouter r) { + super(r); + this.countRange = r.countRange; + } + + /** + * Counts how many of the connected peers have the given message + * @param m The message to check + * @return Amount of connected peers with the message + */ + private int getPeerMessageCount(Message m) { + DTNHost me = getHost(); + String id = m.getId(); + int peerMsgCount = 0; + + for (Connection c : getConnections()) { + if (c.getOtherNode(me).getRouter().hasMessage(id)) { + peerMsgCount++; + } + } + + return peerMsgCount; + } + + @Override + protected int checkReceiving(Message m, DTNHost from) { + int peerMsgCount = getPeerMessageCount(m); + + if (peerMsgCount < this.countRange[0] || + peerMsgCount > this.countRange[1]) { + return DENIED_POLICY; + } + + /* peer message count check OK; receive based on other checks */ + return super.checkReceiving(m, from); + } + + @Override + public void update() { + int peerMsgCount; + Vector messagesToDelete = new Vector(); + super.update(); + + if (isTransferring() || !canStartTransfer()) { + return; /* transferring, don't try other connections yet */ + } + + /* Try first the messages that can be delivered to final recipient */ + if (exchangeDeliverableMessages() != null) { + return; + } + this.tryAllMessagesToAllConnections(); + + /* see if need to drop some messages... */ + for (Message m : getMessageCollection()) { + peerMsgCount = getPeerMessageCount(m); + if (peerMsgCount < this.countRange[0] || + peerMsgCount > this.countRange[1]) { + messagesToDelete.add(m.getId()); + } + } + for (String id : messagesToDelete) { /* ...and drop them */ + this.deleteMessage(id, true); + } + + } + + + @Override + public LifeRouter replicate() { + return new LifeRouter(this); + } + +} \ No newline at end of file diff --git a/routing/MaxPropRouter.java b/routing/MaxPropRouter.java new file mode 100644 index 000000000..c71d8a652 --- /dev/null +++ b/routing/MaxPropRouter.java @@ -0,0 +1,600 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import routing.maxprop.MaxPropDijkstra; +import routing.maxprop.MeetingProbabilitySet; +import routing.util.RoutingInfo; +import util.Tuple; +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; + +/** + * Implementation of MaxProp router as described in + * MaxProp: Routing for Vehicle-Based Disruption-Tolerant Networks by + * John Burgess et al. + * @version 1.0 + * + * Extension of the protocol by adding a parameter alpha (default 1) + * By new connection, the delivery likelihood is increased by alpha + * and divided by 1+alpha. Using the default results in the original + * algorithm. Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing + * Protocols Chants, 2008 + */ +public class MaxPropRouter extends ActiveRouter { + /** Router's setting namespace ({@value})*/ + public static final String MAXPROP_NS = "MaxPropRouter"; + /** + * Meeting probability set maximum size -setting id ({@value}). + * The maximum amount of meeting probabilities to store. */ + public static final String PROB_SET_MAX_SIZE_S = "probSetMaxSize"; + /** Default value for the meeting probability set maximum size ({@value}).*/ + public static final int DEFAULT_PROB_SET_MAX_SIZE = 50; + private static int probSetMaxSize; + + /** probabilities of meeting hosts */ + private MeetingProbabilitySet probs; + /** meeting probabilities of all hosts from this host's point of view + * mapped using host's network address */ + private Map allProbs; + /** the cost-to-node calculator */ + private MaxPropDijkstra dijkstra; + /** IDs of the messages that are known to have reached the final dst */ + private Set ackedMessageIds; + /** mapping of the current costs for all messages. This should be set to + * null always when the costs should be updated (a host is met or a new + * message is received) */ + private Map costsForMessages; + /** From host of the last cost calculation */ + private DTNHost lastCostFrom; + + /** Map of which messages have been sent to which hosts from this host */ + private Map> sentMessages; + + /** Over how many samples the "average number of bytes transferred per + * transfer opportunity" is taken */ + public static int BYTES_TRANSFERRED_AVG_SAMPLES = 10; + private int[] avgSamples; + private int nextSampleIndex = 0; + /** current value for the "avg number of bytes transferred per transfer + * opportunity" */ + private int avgTransferredBytes = 0; + + /** The alpha parameter string*/ + public static final String ALPHA_S = "alpha"; + + /** The alpha variable, default = 1;*/ + private double alpha; + + /** The default value for alpha */ + public static final double DEFAULT_ALPHA = 1.0; + + /** + * Constructor. Creates a new prototype router based on the settings in + * the given Settings object. + * @param settings The settings object + */ + public MaxPropRouter(Settings settings) { + super(settings); + Settings maxPropSettings = new Settings(MAXPROP_NS); + if (maxPropSettings.contains(ALPHA_S)) { + alpha = maxPropSettings.getDouble(ALPHA_S); + } else { + alpha = DEFAULT_ALPHA; + } + + Settings mpSettings = new Settings(MAXPROP_NS); + if (mpSettings.contains(PROB_SET_MAX_SIZE_S)) { + probSetMaxSize = mpSettings.getInt(PROB_SET_MAX_SIZE_S); + } else { + probSetMaxSize = DEFAULT_PROB_SET_MAX_SIZE; + } + } + + /** + * Copy constructor. Creates a new router based on the given prototype. + * @param r The router prototype where setting values are copied from + */ + protected MaxPropRouter(MaxPropRouter r) { + super(r); + this.alpha = r.alpha; + this.probs = new MeetingProbabilitySet(probSetMaxSize, this.alpha); + this.allProbs = new HashMap(); + this.dijkstra = new MaxPropDijkstra(this.allProbs); + this.ackedMessageIds = new HashSet(); + this.avgSamples = new int[BYTES_TRANSFERRED_AVG_SAMPLES]; + this.sentMessages = new HashMap>(); + } + + @Override + public void changedConnection(Connection con) { + super.changedConnection(con); + + if (con.isUp()) { // new connection + this.costsForMessages = null; // invalidate old cost estimates + + if (con.isInitiator(getHost())) { + /* initiator performs all the actions on behalf of the + * other node too (so that the meeting probs are updated + * for both before exchanging them) */ + DTNHost otherHost = con.getOtherNode(getHost()); + MessageRouter mRouter = otherHost.getRouter(); + + assert mRouter instanceof MaxPropRouter : "MaxProp only works "+ + " with other routers of same type"; + MaxPropRouter otherRouter = (MaxPropRouter)mRouter; + + /* exchange ACKed message data */ + this.ackedMessageIds.addAll(otherRouter.ackedMessageIds); + otherRouter.ackedMessageIds.addAll(this.ackedMessageIds); + deleteAckedMessages(); + otherRouter.deleteAckedMessages(); + + /* update both meeting probabilities */ + probs.updateMeetingProbFor(otherHost.getAddress()); + otherRouter.probs.updateMeetingProbFor(getHost().getAddress()); + + /* exchange the transitive probabilities */ + this.updateTransitiveProbs(otherRouter.allProbs); + otherRouter.updateTransitiveProbs(this.allProbs); + this.allProbs.put(otherHost.getAddress(), + otherRouter.probs.replicate()); + otherRouter.allProbs.put(getHost().getAddress(), + this.probs.replicate()); + } + } + else { + /* connection went down, update transferred bytes average */ + updateTransferredBytesAvg(con.getTotalBytesTransferred()); + } + } + + /** + * Updates transitive probability values by replacing the current + * MeetingProbabilitySets with the values from the given mapping + * if the given sets have more recent updates. + * @param p Mapping of the values of the other host + */ + private void updateTransitiveProbs(Map p) { + for (Map.Entry e : p.entrySet()) { + MeetingProbabilitySet myMps = this.allProbs.get(e.getKey()); + if (myMps == null || + e.getValue().getLastUpdateTime() > myMps.getLastUpdateTime() ) { + this.allProbs.put(e.getKey(), e.getValue().replicate()); + } + } + } + + /** + * Deletes the messages from the message buffer that are known to be ACKed + */ + private void deleteAckedMessages() { + for (String id : this.ackedMessageIds) { + if (this.hasMessage(id) && !isSending(id)) { + this.deleteMessage(id, false); + } + } + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + this.costsForMessages = null; // new message -> invalidate costs + Message m = super.messageTransferred(id, from); + /* was this node the final recipient of the message? */ + if (isDeliveredMessage(m)) { + this.ackedMessageIds.add(id); + } + return m; + } + + /** + * Method is called just before a transfer is finalized + * at {@link ActiveRouter#update()}. MaxProp makes book keeping of the + * delivered messages so their IDs are stored. + * @param con The connection whose transfer was finalized + */ + @Override + protected void transferDone(Connection con) { + Message m = con.getMessage(); + String id = m.getId(); + DTNHost recipient = con.getOtherNode(getHost()); + Set sentMsgIds = this.sentMessages.get(recipient); + + /* was the message delivered to the final recipient? */ + if (m.getTo() == recipient) { + this.ackedMessageIds.add(m.getId()); // yes, add to ACKed messages + this.deleteMessage(m.getId(), false); // delete from buffer + } + + /* update the map of where each message is already sent */ + if (sentMsgIds == null) { + sentMsgIds = new HashSet(); + this.sentMessages.put(recipient, sentMsgIds); + } + sentMsgIds.add(id); + } + + /** + * Updates the average estimate of the number of bytes transferred per + * transfer opportunity. + * @param newValue The new value to add to the estimate + */ + private void updateTransferredBytesAvg(int newValue) { + int realCount = 0; + int sum = 0; + + this.avgSamples[this.nextSampleIndex++] = newValue; + if(this.nextSampleIndex >= BYTES_TRANSFERRED_AVG_SAMPLES) { + this.nextSampleIndex = 0; + } + + for (int i=0; i < BYTES_TRANSFERRED_AVG_SAMPLES; i++) { + if (this.avgSamples[i] > 0) { // only values above zero count + realCount++; + sum += this.avgSamples[i]; + } + } + + if (realCount > 0) { + this.avgTransferredBytes = sum / realCount; + } + else { // no samples or all samples are zero + this.avgTransferredBytes = 0; + } + } + + /** + * Returns the next message that should be dropped, according to MaxProp's + * message ordering scheme (see {@link MaxPropTupleComparator}). + * @param excludeMsgBeingSent If true, excludes message(s) that are + * being sent from the next-to-be-dropped check (i.e., if next message to + * drop is being sent, the following message is returned) + * @return The oldest message or null if no message could be returned + * (no messages in buffer or all messages in buffer are being sent and + * exludeMsgBeingSent is true) + */ + @Override + protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) { + Collection messages = this.getMessageCollection(); + List validMessages = new ArrayList(); + + for (Message m : messages) { + if (excludeMsgBeingSent && isSending(m.getId())) { + continue; // skip the message(s) that router is sending + } + validMessages.add(m); + } + + Collections.sort(validMessages, + new MaxPropComparator(this.calcThreshold())); + + return validMessages.get(validMessages.size()-1); // return last message + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Returns the message delivery cost between two hosts from this host's + * point of view. If there is no path between "from" and "to" host, + * Double.MAX_VALUE is returned. Paths are calculated only to hosts + * that this host has messages to. + * @param from The host where a message is coming from + * @param to The host where a message would be destined to + * @return The cost of the cheapest path to the destination or + * Double.MAX_VALUE if such a path doesn't exist + */ + public double getCost(DTNHost from, DTNHost to) { + /* check if the cached values are OK */ + if (this.costsForMessages == null || lastCostFrom != from) { + /* cached costs are invalid -> calculate new costs */ + this.allProbs.put(getHost().getAddress(), this.probs); + int fromIndex = from.getAddress(); + + /* calculate paths only to nodes we have messages to + * (optimization) */ + Set toSet = new HashSet(); + for (Message m : getMessageCollection()) { + toSet.add(m.getTo().getAddress()); + } + + this.costsForMessages = dijkstra.getCosts(fromIndex, toSet); + this.lastCostFrom = from; // store source host for caching checks + } + + if (costsForMessages.containsKey(to.getAddress())) { + return costsForMessages.get(to.getAddress()); + } + else { + /* there's no known path to the given host */ + return Double.MAX_VALUE; + } + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * hop counts and their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts that are not transferring at the moment, + * collect all the messages that could be sent */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + MaxPropRouter othRouter = (MaxPropRouter)other.getRouter(); + Set sentMsgIds = this.sentMessages.get(other); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + /* skip messages that the other host has or that have + * passed the other host */ + if (othRouter.hasMessage(m.getId()) || + m.getHops().contains(other)) { + continue; + } + /* skip message if this host has already sent it to the other + host (regardless of if the other host still has it) */ + if (sentMsgIds != null && sentMsgIds.contains(m.getId())) { + continue; + } + /* message was a good candidate for sending */ + messages.add(new Tuple(m,con)); + } + } + + if (messages.size() == 0) { + return null; + } + + /* sort the message-connection tuples according to the criteria + * defined in MaxPropTupleComparator */ + Collections.sort(messages, new MaxPropTupleComparator(calcThreshold())); + return tryMessagesForConnected(messages); + } + + /** + * Calculates and returns the current threshold value for the buffer's split + * based on the average number of bytes transferred per transfer opportunity + * and the hop counts of the messages in the buffer. Method is public only + * to make testing easier. + * @return current threshold value (hop count) for the buffer's split + */ + public int calcThreshold() { + /* b, x and p refer to respective variables in the paper's equations */ + int b = this.getBufferSize(); + int x = this.avgTransferredBytes; + int p; + + if (x == 0) { + /* can't calc the threshold because there's no transfer data */ + return 0; + } + + /* calculates the portion (bytes) of the buffer selected for priority */ + if (x < b/2) { + p = x; + } + else if (b/2 <= x && x < b) { + p = Math.min(x, b-x); + } + else { + return 0; // no need for the threshold + } + + /* creates a copy of the messages list, sorted by hop count */ + ArrayList msgs = new ArrayList(); + msgs.addAll(getMessageCollection()); + if (msgs.size() == 0) { + return 0; // no messages -> no need for threshold + } + /* anonymous comparator class for hop count comparison */ + Comparator hopCountComparator = new Comparator() { + public int compare(Message m1, Message m2) { + return m1.getHopCount() - m2.getHopCount(); + } + }; + Collections.sort(msgs, hopCountComparator); + + /* finds the first message that is beyond the calculated portion */ + int i=0; + for (int n=msgs.size(); i0; i++) { + p -= msgs.get(i).getSize(); + } + + i--; // the last round moved i one index too far + if (i < 0) { + return 0; + } + + /* now i points to the first packet that exceeds portion p; + * the threshold is that packet's hop count + 1 (so that packet and + * perhaps some more are included in the priority part) */ + return msgs.get(i).getHopCount() + 1; + } + + /** + * Message comparator for the MaxProp routing module. + * Messages that have a hop count smaller than the given + * threshold are given priority and they are ordered by their hop count. + * Other messages are ordered by their delivery cost. + */ + private class MaxPropComparator implements Comparator { + private int threshold; + private DTNHost from1; + private DTNHost from2; + + /** + * Constructor. Assumes that the host where all the costs are calculated + * from is this router's host. + * @param treshold Messages with the hop count smaller than this + * value are transferred first (and ordered by the hop count) + */ + public MaxPropComparator(int treshold) { + this.threshold = treshold; + this.from1 = this.from2 = getHost(); + } + + /** + * Constructor. + * @param treshold Messages with the hop count smaller than this + * value are transferred first (and ordered by the hop count) + * @param from1 The host where the cost of msg1 is calculated from + * @param from2 The host where the cost of msg2 is calculated from + */ + public MaxPropComparator(int treshold, DTNHost from1, DTNHost from2) { + this.threshold = treshold; + this.from1 = from1; + this.from2 = from2; + } + + /** + * Compares two messages and returns -1 if the first given message + * should be first in order, 1 if the second message should be first + * or 0 if message order can't be decided. If both messages' hop count + * is less than the threshold, messages are compared by their hop count + * (smaller is first). If only other's hop count is below the threshold, + * that comes first. If both messages are below the threshold, the one + * with smaller cost (determined by + * {@link MaxPropRouter#getCost(DTNHost, DTNHost)}) is first. + */ + public int compare(Message msg1, Message msg2) { + double p1, p2; + int hopc1 = msg1.getHopCount(); + int hopc2 = msg2.getHopCount(); + + if (msg1 == msg2) { + return 0; + } + + /* if one message's hop count is above and the other one's below the + * threshold, the one below should be sent first */ + if (hopc1 < threshold && hopc2 >= threshold) { + return -1; // message1 should be first + } + else if (hopc2 < threshold && hopc1 >= threshold) { + return 1; // message2 -"- + } + + /* if both are below the threshold, one with lower hop count should + * be sent first */ + if (hopc1 < threshold && hopc2 < threshold) { + return hopc1 - hopc2; + } + + /* both messages have more than threshold hops -> cost of the + * message path is used for ordering */ + p1 = getCost(from1, msg1.getTo()); + p2 = getCost(from2, msg2.getTo()); + + /* the one with lower cost should be sent first */ + if (p1-p2 == 0) { + /* if costs are equal, hop count breaks ties. If even hop counts + are equal, the queue ordering is used */ + if (hopc1 == hopc2) { + return compareByQueueMode(msg1, msg2); + } + else { + return hopc1 - hopc2; + } + } + else if (p1-p2 < 0) { + return -1; // msg1 had the smaller cost + } + else { + return 1; // msg2 had the smaller cost + } + } + } + + /** + * Message-Connection tuple comparator for the MaxProp routing + * module. Uses {@link MaxPropComparator} on the messages of the tuples + * setting the "from" host for that message to be the one in the connection + * tuple (i.e., path is calculated starting from the host on the other end + * of the connection). + */ + private class MaxPropTupleComparator + implements Comparator > { + private int threshold; + + public MaxPropTupleComparator(int threshold) { + this.threshold = threshold; + } + + /** + * Compares two message-connection tuples using the + * {@link MaxPropComparator#compare(Message, Message)}. + */ + public int compare(Tuple tuple1, + Tuple tuple2) { + MaxPropComparator comp; + DTNHost from1 = tuple1.getValue().getOtherNode(getHost()); + DTNHost from2 = tuple2.getValue().getOtherNode(getHost()); + + comp = new MaxPropComparator(threshold, from1, from2); + return comp.compare(tuple1.getKey(), tuple2.getKey()); + } + } + + + @Override + public RoutingInfo getRoutingInfo() { + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(probs.getAllProbs().size() + + " meeting probabilities"); + + /* show meeting probabilities for this host */ + for (Map.Entry e : probs.getAllProbs().entrySet()) { + Integer host = e.getKey(); + Double value = e.getValue(); + ri.addMoreInfo(new RoutingInfo(String.format("host %d : %.6f", + host, value))); + } + + top.addMoreInfo(ri); + top.addMoreInfo(new RoutingInfo("Avg transferred bytes: " + + this.avgTransferredBytes)); + + return top; + } + + @Override + public MessageRouter replicate() { + MaxPropRouter r = new MaxPropRouter(this); + return r; + } +} \ No newline at end of file diff --git a/routing/MaxPropRouterWithEstimation.java b/routing/MaxPropRouterWithEstimation.java new file mode 100644 index 000000000..8f5094bf2 --- /dev/null +++ b/routing/MaxPropRouterWithEstimation.java @@ -0,0 +1,722 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import routing.maxprop.MaxPropDijkstra; +import routing.maxprop.MeetingProbabilitySet; +import routing.util.RoutingInfo; +import util.Tuple; +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimClock; + +/** + * Implementation of MaxProp router as described in + * MaxProp: Routing for Vehicle-Based Disruption-Tolerant Networks by + * John Burgess et al. + * + * but with parameter estimation for finding an alpha based on timescale + * definition: + * + * Extension of the protocol by adding a parameter alpha (default 1) + * By new connection, the delivery likelihood is increased by alpha + * and divided by 1+alpha. Using the default results in the original + * algorithm. Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing + * Protocols Chants, 2008 + * + * This version tries to estimate a good value of alpha from a timescale parameter + * given by the user, and from the encounters the node sees during simulation. + * + * @version 1.0 + */ +public class MaxPropRouterWithEstimation extends ActiveRouter { + /** probabilities of meeting hosts */ + private MeetingProbabilitySet probs; + /** meeting probabilities of all hosts from this host's point of view + * mapped using host's network address */ + private Map allProbs; + /** the cost-to-node calculator */ + private MaxPropDijkstra dijkstra; + /** IDs of the messages that are known to have reached the final dst */ + private Set ackedMessageIds; + /** mapping of the current costs for all messages. This should be set to + * null always when the costs should be updated (a host is met or a new + * message is received) */ + private Map costsForMessages; + /** From host of the last cost calculation */ + private DTNHost lastCostFrom; + + /** Over how many samples the "average number of bytes transferred per + * transfer opportunity" is taken */ + public static int BYTES_TRANSFERRED_AVG_SAMPLES = 10; + private int[] avgSamples; + private int nextSampleIndex = 0; + /** current value for the "avg number of bytes transferred per transfer + * opportunity" */ + private int avgTransferredBytes = 0; + + /** MaxPROP router's setting namespace ({@value})*/ + public static final String MAXPROP_NS = "MaxPropRouterWithEstimation"; + + /* Number of seconds in time scale.*/ + public static final String TIME_SCALE_S ="timeScale"; + + /** The alpha variable, default = 1; + */ + private double alpha; + + /** The default value for alpha + */ + public static final double DEFAULT_ALPHA = 1.0; + + /** value of time scale variable */ + private int timescale; + + /** last meeting time with a node */ + private Map meetings; + private int nrofSamplesIET; + private double meanIET; + + /** number of encounters between encounters */ + private Map encounters; + private int nrofSamplesENC; + private double meanENC; + private int nrofTotENC; + + /** + * Constructor. Creates a new prototype router based on the settings in + * the given Settings object. + * @param settings The settings object + */ + public MaxPropRouterWithEstimation(Settings settings) { + super(settings); + Settings maxPropSettings = new Settings(MAXPROP_NS); + alpha = DEFAULT_ALPHA; + timescale = maxPropSettings.getInt(TIME_SCALE_S); + initMeetings(); + } + + /** + * Copy constructor. Creates a new router based on the given prototype. + * @param r The router prototype where setting values are copied from + */ + protected MaxPropRouterWithEstimation(MaxPropRouterWithEstimation r) { + super(r); + this.alpha = r.alpha; + this.timescale = r.timescale; + this.probs = new MeetingProbabilitySet( + MeetingProbabilitySet.INFINITE_SET_SIZE, this.alpha); + this.allProbs = new HashMap(); + this.dijkstra = new MaxPropDijkstra(this.allProbs); + this.ackedMessageIds = new HashSet(); + this.avgSamples = new int[BYTES_TRANSFERRED_AVG_SAMPLES]; + initMeetings(); + } + + /** + * Initializes interencounter estimators + */ + private void initMeetings() { + this.meetings = new HashMap(); + this.encounters = new HashMap(); + this.meanIET = 0; + this.nrofSamplesIET = 0; + this.meanENC = 0; + this.nrofSamplesENC = 0; + this.nrofTotENC = 0; + } + + @Override + public void changedConnection(Connection con) { + super.changedConnection(con); + + if (con.isUp()) { // new connection + this.costsForMessages = null; // invalidate old cost estimates + + if (con.isInitiator(getHost())) { + /* initiator performs all the actions on behalf of the + * other node too (so that the meeting probs are updated + * for both before exchanging them) */ + DTNHost otherHost = con.getOtherNode(getHost()); + MessageRouter mRouter = otherHost.getRouter(); + + assert mRouter instanceof MaxPropRouterWithEstimation : "MaxProp only works "+ + " with other routers of same type"; + MaxPropRouterWithEstimation otherRouter = (MaxPropRouterWithEstimation)mRouter; + + /* update the estimators */ + if (this.updateEstimators(otherHost)) { + this.updateParam(); + } + if (otherRouter.updateEstimators(getHost())) { + otherRouter.updateParam(); + } + + /* exchange ACKed message data */ + this.ackedMessageIds.addAll(otherRouter.ackedMessageIds); + otherRouter.ackedMessageIds.addAll(this.ackedMessageIds); + deleteAckedMessages(); + otherRouter.deleteAckedMessages(); + + /* update both meeting probabilities */ + probs.updateMeetingProbFor(otherHost.getAddress()); + otherRouter.probs.updateMeetingProbFor(getHost().getAddress()); + + /* exchange the transitive probabilities */ + this.updateTransitiveProbs(otherRouter.allProbs); + otherRouter.updateTransitiveProbs(this.allProbs); + this.allProbs.put(otherHost.getAddress(), + otherRouter.probs.replicate()); + otherRouter.allProbs.put(getHost().getAddress(), + this.probs.replicate()); + } + } + else { + /* connection went down, update transferred bytes average */ + updateTransferredBytesAvg(con.getTotalBytesTransferred()); + } + } + + /** + * Updates transitive probability values by replacing the current + * MeetingProbabilitySets with the values from the given mapping + * if the given sets have more recent updates. + * @param p Mapping of the values of the other host + */ + private void updateTransitiveProbs(Map p) { + for (Map.Entry e : p.entrySet()) { + MeetingProbabilitySet myMps = this.allProbs.get(e.getKey()); + if (myMps == null || + e.getValue().getLastUpdateTime() > myMps.getLastUpdateTime() ) { + this.allProbs.put(e.getKey(), e.getValue().replicate()); + } + } + } + + /** + * Updates the MaxPROP estimators + * @param host + */ + protected boolean updateEstimators(DTNHost host) { + /* First estimate the mean InterEncounter Time */ + double currentTime = SimClock.getTime(); + if (meetings.containsKey(host)) { + double timeDiff = currentTime - meetings.get(host); + // System.out.printf("current time: %f\t last time: %f\n",currentTime,meetings.get(host)); + + nrofSamplesIET++; + meanIET = (((double)nrofSamplesIET -1) / (double)nrofSamplesIET) * meanIET + + (1 / (double)nrofSamplesIET) * timeDiff; + meetings.put(host, currentTime); + } else { + /* nothing to update */ + meetings.put(host,currentTime); + } + /* Then estimate the number of encounters + * + */ + nrofTotENC++; // the number of encounter + if (encounters.containsKey(host)) { + int encounterNro = nrofTotENC - encounters.get(host); + // System.out.printf("current time: %f\t last time: %f\n",currentTime,meetings.get(host)); + + nrofSamplesENC++; + meanENC = (((double)nrofSamplesENC -1) / (double)nrofSamplesENC) * meanENC + + (1 / (double)nrofSamplesENC) * (double)encounterNro; + encounters.put(host,nrofTotENC); + return true; + } else { + /* nothing to update */ + encounters.put(host,nrofTotENC); + return false; + } + } + + /** + * update the alpha parameter based on the estimators + */ + protected void updateParam() + { + double err = .01; + double ntarg = Math.ceil(timescale/meanIET); + double ee = 1; + double alphadiff = .1; + int ob = 0; + double fstable; + double fnzero; + double fnone; + double eezero; + double eeone; + double A; + + /* + * the estimation algorith does not work for timescales + * shorter than the mean IET - so use defaults + */ + if (meanIET > (double)timescale) { + System.out.printf("meanIET %f > %d timescale\n",meanIET,timescale); + return; + } + + if (meanIET == 0) { + System.out.printf("Mean IET == 0\n"); + return; + } + + if (meanENC == 0) { + System.out.printf("Mean ENC == 0\n"); + return; + } + + while (ee != err) { + A = Math.pow(1+alpha,meanENC+1); + fstable = alpha/(A-1); + fnzero = (alpha/A)*(1-Math.pow(A,-ntarg))/(1-1/A); + fnone = fnzero + 1/(Math.pow(A,ntarg)); + eezero = Math.abs(fnzero-fstable); + eeone = Math.abs(fnone -fstable); + ee = Math.max(eezero,eeone); + + if (ee > err ) { + if (ob == 2) { + alphadiff = alphadiff / 2.0; + } + ob = 1; + alpha = alpha+alphadiff; + } else { + if (ee < (err-err*0.001)) { + if (ob == 1) { + alphadiff = alphadiff / 2.0; + } + ob = 2; + alpha = alpha - alphadiff; + + // double precision floating makes problems... + if ((alpha <= 0) | (((1 + alpha) - 1) == 0)) { + alpha = alphadiff; + alphadiff = alphadiff / 2.0; + ob = 0; + } + } else { + ee = err; + } + } + } + probs.setAlpha(alpha); + } + + /** + * Deletes the messages from the message buffer that are known to be ACKed + */ + private void deleteAckedMessages() { + for (String id : this.ackedMessageIds) { + if (this.hasMessage(id) && !isSending(id)) { + this.deleteMessage(id, false); + } + } + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + this.costsForMessages = null; // new message -> invalidate costs + Message m = super.messageTransferred(id, from); + /* was this node the final recipient of the message? */ + if (isDeliveredMessage(m)) { + this.ackedMessageIds.add(id); + } + return m; + } + + /** + * Method is called just before a transfer is finalized + * at {@link ActiveRouter#update()}. MaxProp makes book keeping of the + * delivered messages so their IDs are stored. + * @param con The connection whose transfer was finalized + */ + @Override + protected void transferDone(Connection con) { + Message m = con.getMessage(); + /* was the message delivered to the final recipient? */ + if (m.getTo() == con.getOtherNode(getHost())) { + this.ackedMessageIds.add(m.getId()); // yes, add to ACKed messages + this.deleteMessage(m.getId(), false); // delete from buffer + } + } + + /** + * Updates the average estimate of the number of bytes transferred per + * transfer opportunity. + * @param newValue The new value to add to the estimate + */ + private void updateTransferredBytesAvg(int newValue) { + int realCount = 0; + int sum = 0; + + this.avgSamples[this.nextSampleIndex++] = newValue; + if(this.nextSampleIndex >= BYTES_TRANSFERRED_AVG_SAMPLES) { + this.nextSampleIndex = 0; + } + + for (int i=0; i < BYTES_TRANSFERRED_AVG_SAMPLES; i++) { + if (this.avgSamples[i] > 0) { // only values above zero count + realCount++; + sum += this.avgSamples[i]; + } + } + + if (realCount > 0) { + this.avgTransferredBytes = sum / realCount; + } + else { // no samples or all samples are zero + this.avgTransferredBytes = 0; + } + } + + /** + * Returns the next message that should be dropped, according to MaxProp's + * message ordering scheme (see {@link MaxPropTupleComparator}). + * @param excludeMsgBeingSent If true, excludes message(s) that are + * being sent from the next-to-be-dropped check (i.e., if next message to + * drop is being sent, the following message is returned) + * @return The oldest message or null if no message could be returned + * (no messages in buffer or all messages in buffer are being sent and + * exludeMsgBeingSent is true) + */ + protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) { + Collection messages = this.getMessageCollection(); + List validMessages = new ArrayList(); + + for (Message m : messages) { + if (excludeMsgBeingSent && isSending(m.getId())) { + continue; // skip the message(s) that router is sending + } + validMessages.add(m); + } + + Collections.sort(validMessages, + new MaxPropComparator(this.calcThreshold())); + + return validMessages.get(validMessages.size()-1); // return last message + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Returns the message delivery cost between two hosts from this host's + * point of view. If there is no path between "from" and "to" host, + * Double.MAX_VALUE is returned. Paths are calculated only to hosts + * that this host has messages to. + * @param from The host where a message is coming from + * @param to The host where a message would be destined to + * @return The cost of the cheapest path to the destination or + * Double.MAX_VALUE if such a path doesn't exist + */ + public double getCost(DTNHost from, DTNHost to) { + /* check if the cached values are OK */ + if (this.costsForMessages == null || lastCostFrom != from) { + /* cached costs are invalid -> calculate new costs */ + this.allProbs.put(getHost().getAddress(), this.probs); + int fromIndex = from.getAddress(); + + /* calculate paths only to nodes we have messages to + * (optimization) */ + Set toSet = new HashSet(); + for (Message m : getMessageCollection()) { + toSet.add(m.getTo().getAddress()); + } + + this.costsForMessages = dijkstra.getCosts(fromIndex, toSet); + this.lastCostFrom = from; // store source host for caching checks + } + + if (costsForMessages.containsKey(to.getAddress())) { + return costsForMessages.get(to.getAddress()); + } + else { + /* there's no known path to the given host */ + return Double.MAX_VALUE; + } + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * hop counts and their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts that are not transferring at the moment, + * collect all the messages that could be sent */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + MaxPropRouterWithEstimation othRouter = (MaxPropRouterWithEstimation)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + /* skip messages that the other host has or that have + * passed the other host */ + if (othRouter.hasMessage(m.getId()) || + m.getHops().contains(other)) { + continue; + } + messages.add(new Tuple(m,con)); + } + } + + if (messages.size() == 0) { + return null; + } + + /* sort the message-connection tuples according to the criteria + * defined in MaxPropTupleComparator */ + Collections.sort(messages, new MaxPropTupleComparator(calcThreshold())); + return tryMessagesForConnected(messages); + } + + /** + * Calculates and returns the current threshold value for the buffer's split + * based on the average number of bytes transferred per transfer opportunity + * and the hop counts of the messages in the buffer. Method is public only + * to make testing easier. + * @return current threshold value (hop count) for the buffer's split + */ + public int calcThreshold() { + /* b, x and p refer to respective variables in the paper's equations */ + int b = this.getBufferSize(); + int x = this.avgTransferredBytes; + int p; + + if (x == 0) { + /* can't calc the threshold because there's no transfer data */ + return 0; + } + + /* calculates the portion (bytes) of the buffer selected for priority */ + if (x < b/2) { + p = x; + } + else if (b/2 <= x && x < b) { + p = Math.min(x, b-x); + } + else { + return 0; // no need for the threshold + } + + /* creates a copy of the messages list, sorted by hop count */ + ArrayList msgs = new ArrayList(); + msgs.addAll(getMessageCollection()); + if (msgs.size() == 0) { + return 0; // no messages -> no need for threshold + } + /* anonymous comparator class for hop count comparison */ + Comparator hopCountComparator = new Comparator() { + public int compare(Message m1, Message m2) { + return m1.getHopCount() - m2.getHopCount(); + } + }; + Collections.sort(msgs, hopCountComparator); + + /* finds the first message that is beyond the calculated portion */ + int i=0; + for (int n=msgs.size(); i0; i++) { + p -= msgs.get(i).getSize(); + } + + i--; // the last round moved i one index too far + + /* now i points to the first packet that exceeds portion p; + * the threshold is that packet's hop count + 1 (so that packet and + * perhaps some more are included in the priority part) */ + return msgs.get(i).getHopCount() + 1; + } + + /** + * Message comparator for the MaxProp routing module. + * Messages that have a hop count smaller than the given + * threshold are given priority and they are ordered by their hop count. + * Other messages are ordered by their delivery cost. + */ + private class MaxPropComparator implements Comparator { + private int threshold; + private DTNHost from1; + private DTNHost from2; + + /** + * Constructor. Assumes that the host where all the costs are calculated + * from is this router's host. + * @param treshold Messages with the hop count smaller than this + * value are transferred first (and ordered by the hop count) + */ + public MaxPropComparator(int treshold) { + this.threshold = treshold; + this.from1 = this.from2 = getHost(); + } + + /** + * Constructor. + * @param treshold Messages with the hop count smaller than this + * value are transferred first (and ordered by the hop count) + * @param from1 The host where the cost of msg1 is calculated from + * @param from2 The host where the cost of msg2 is calculated from + */ + public MaxPropComparator(int treshold, DTNHost from1, DTNHost from2) { + this.threshold = treshold; + this.from1 = from1; + this.from2 = from2; + } + + /** + * Compares two messages and returns -1 if the first given message + * should be first in order, 1 if the second message should be first + * or 0 if message order can't be decided. If both messages' hop count + * is less than the threshold, messages are compared by their hop count + * (smaller is first). If only other's hop count is below the threshold, + * that comes first. If both messages are below the threshold, the one + * with smaller cost (determined by + * {@link MaxPropRouterWithEstimation#getCost(DTNHost, DTNHost)}) is first. + */ + public int compare(Message msg1, Message msg2) { + double p1, p2; + int hopc1 = msg1.getHopCount(); + int hopc2 = msg2.getHopCount(); + + if (msg1 == msg2) { + return 0; + } + + /* if one message's hop count is above and the other one's below the + * threshold, the one below should be sent first */ + if (hopc1 < threshold && hopc2 >= threshold) { + return -1; // message1 should be first + } + else if (hopc2 < threshold && hopc1 >= threshold) { + return 1; // message2 -"- + } + + /* if both are below the threshold, one with lower hop count should + * be sent first */ + if (hopc1 < threshold && hopc2 < threshold) { + return hopc1 - hopc2; + } + + /* both messages have more than threshold hops -> cost of the + * message path is used for ordering */ + p1 = getCost(from1, msg1.getTo()); + p2 = getCost(from2, msg2.getTo()); + + /* the one with lower cost should be sent first */ + if (p1-p2 == 0) { + /* if costs are equal, hop count breaks ties. If even hop counts + are equal, the queue ordering is used */ + if (hopc1 == hopc2) { + return compareByQueueMode(msg1, msg2); + } + else { + return hopc1 - hopc2; + } + } + else if (p1-p2 < 0) { + return -1; // msg1 had the smaller cost + } + else { + return 1; // msg2 had the smaller cost + } + } + } + + /** + * Message-Connection tuple comparator for the MaxProp routing + * module. Uses {@link MaxPropComparator} on the messages of the tuples + * setting the "from" host for that message to be the one in the connection + * tuple (i.e., path is calculated starting from the host on the other end + * of the connection). + */ + private class MaxPropTupleComparator + implements Comparator > { + private int threshold; + + public MaxPropTupleComparator(int threshold) { + this.threshold = threshold; + } + + /** + * Compares two message-connection tuples using the + * {@link MaxPropComparator#compare(Message, Message)}. + */ + public int compare(Tuple tuple1, + Tuple tuple2) { + MaxPropComparator comp; + DTNHost from1 = tuple1.getValue().getOtherNode(getHost()); + DTNHost from2 = tuple2.getValue().getOtherNode(getHost()); + + comp = new MaxPropComparator(threshold, from1, from2); + return comp.compare(tuple1.getKey(), tuple2.getKey()); + } + } + + + @Override + public RoutingInfo getRoutingInfo() { + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(probs.getAllProbs().size() + + " meeting probabilities"); + + /* show meeting probabilities for this host */ + for (Map.Entry e : probs.getAllProbs().entrySet()) { + Integer host = e.getKey(); + Double value = e.getValue(); + ri.addMoreInfo(new RoutingInfo(String.format("host %d : %.6f", + host, value))); + } + + ri.addMoreInfo(new RoutingInfo(String.format("meanIET: %f\t from %d samples",meanIET,nrofSamplesIET))); + ri.addMoreInfo(new RoutingInfo(String.format("meanENC: %f\t from %d samples",meanENC,nrofSamplesENC))); + ri.addMoreInfo(new RoutingInfo(String.format("current alpha: %f",alpha))); + + top.addMoreInfo(ri); + top.addMoreInfo(new RoutingInfo("Avg transferred bytes: " + + this.avgTransferredBytes)); + + return top; + } + + @Override + public MessageRouter replicate() { + MaxPropRouterWithEstimation r = new MaxPropRouterWithEstimation(this); + return r; + } +} \ No newline at end of file diff --git a/routing/MessageRouter.java b/routing/MessageRouter.java new file mode 100644 index 000000000..4e6d2913c --- /dev/null +++ b/routing/MessageRouter.java @@ -0,0 +1,658 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +import routing.util.RoutingInfo; + +import util.Tuple; + +import core.Application; +import core.Connection; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import core.Settings; +import core.SettingsError; +import core.SimClock; +import core.SimError; + +/** + * Superclass for message routers. + */ +public abstract class MessageRouter { + /** Message buffer size -setting id ({@value}). Integer value in bytes.*/ + public static final String B_SIZE_S = "bufferSize"; + /** + * Message TTL -setting id ({@value}). Value is in minutes and must be + * an integer. + */ + public static final String MSG_TTL_S = "msgTtl"; + /** + * Message/fragment sending queue type -setting id ({@value}). + * This setting affects the order the messages and fragments are sent if the + * routing protocol doesn't define any particular order (e.g, if more than + * one message can be sent directly to the final recipient). + * Valid values are
+ *

    + *
  • 1 : random (message order is randomized every time; default option) + *
  • 2 : FIFO (most recently received messages are sent last) + *
+ */ + public static final String SEND_QUEUE_MODE_S = "sendQueue"; + + /** Setting value for random queue mode */ + public static final int Q_MODE_RANDOM = 1; + /** Setting value for FIFO queue mode */ + public static final int Q_MODE_FIFO = 2; + + /* Return values when asking to start a transmission: + * RCV_OK (0) means that the host accepts the message and transfer started, + * values < 0 mean that the receiving host will not accept this + * particular message (right now), + * values > 0 mean the host will not right now accept any message. + * Values in the range [-100, 100] are reserved for general return values + * (and specified here), values beyond that are free for use in + * implementation specific cases */ + /** Receive return value for OK */ + public static final int RCV_OK = 0; + /** Receive return value for busy receiver */ + public static final int TRY_LATER_BUSY = 1; + /** Receive return value for an old (already received) message */ + public static final int DENIED_OLD = -1; + /** Receive return value for not enough space in the buffer for the msg */ + public static final int DENIED_NO_SPACE = -2; + /** Receive return value for messages whose TTL has expired */ + public static final int DENIED_TTL = -3; + /** Receive return value for a node low on some resource(s) */ + public static final int DENIED_LOW_RESOURCES = -4; + /** Receive return value for a node low on some resource(s) */ + public static final int DENIED_POLICY = -5; + /** Receive return value for unspecified reason */ + public static final int DENIED_UNSPECIFIED = -99; + + private List mListeners; + /** The messages being transferred with msgID_hostName keys */ + private HashMap incomingMessages; + /** The messages this router is carrying */ + private HashMap messages; + /** The messages this router has received as the final recipient */ + private HashMap deliveredMessages; + /** The messages that Applications on this router have blacklisted */ + private HashMap blacklistedMessages; + /** Host where this router belongs to */ + private DTNHost host; + /** size of the buffer */ + private int bufferSize; + /** TTL for all messages */ + protected int msgTtl; + /** Queue mode for sending messages */ + private int sendQueueMode; + + /** applications attached to the host */ + private HashMap> applications = null; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. Size of the message buffer is read from + * {@link #B_SIZE_S} setting. Default value is Integer.MAX_VALUE. + * @param s The settings object + */ + public MessageRouter(Settings s) { + this.bufferSize = Integer.MAX_VALUE; // defaults to rather large buffer + this.msgTtl = Message.INFINITE_TTL; + this.applications = new HashMap>(); + + if (s.contains(B_SIZE_S)) { + this.bufferSize = s.getInt(B_SIZE_S); + } + if (s.contains(MSG_TTL_S)) { + this.msgTtl = s.getInt(MSG_TTL_S); + } + if (s.contains(SEND_QUEUE_MODE_S)) { + this.sendQueueMode = s.getInt(SEND_QUEUE_MODE_S); + if (sendQueueMode < 1 || sendQueueMode > 2) { + throw new SettingsError("Invalid value for " + + s.getFullPropertyName(SEND_QUEUE_MODE_S)); + } + } + else { + sendQueueMode = Q_MODE_RANDOM; + } + + } + + /** + * Initializes the router; i.e. sets the host this router is in and + * message listeners that need to be informed about message related + * events etc. + * @param host The host this router is in + * @param mListeners The message listeners + */ + public void init(DTNHost host, List mListeners) { + this.incomingMessages = new HashMap(); + this.messages = new HashMap(); + this.deliveredMessages = new HashMap(); + this.blacklistedMessages = new HashMap(); + this.mListeners = mListeners; + this.host = host; + } + + /** + * Copy-constructor. + * @param r Router to copy the settings from. + */ + protected MessageRouter(MessageRouter r) { + this.bufferSize = r.bufferSize; + this.msgTtl = r.msgTtl; + this.sendQueueMode = r.sendQueueMode; + + this.applications = new HashMap>(); + for (Collection apps : r.applications.values()) { + for (Application app : apps) { + addApplication(app.replicate()); + } + } + } + + /** + * Updates router. + * This method should be called (at least once) on every simulation + * interval to update the status of transfer(s). + */ + public void update(){ + for (Collection apps : this.applications.values()) { + for (Application app : apps) { + app.update(this.host); + } + } + } + + /** + * Informs the router about change in connections state. + * @param con The connection that changed + */ + public abstract void changedConnection(Connection con); + + /** + * Returns a message by ID. + * @param id ID of the message + * @return The message + */ + protected Message getMessage(String id) { + return this.messages.get(id); + } + + /** + * Checks if this router has a message with certain id buffered. + * @param id Identifier of the message + * @return True if the router has message with this id, false if not + */ + public boolean hasMessage(String id) { + return this.messages.containsKey(id); + } + + /** + * Returns true if a full message with same ID as the given message has been + * received by this host as the final recipient + * (at least once). + * @param m message we're interested of + * @return true if a message with the same ID has been received by + * this host as the final recipient. + */ + protected boolean isDeliveredMessage(Message m) { + return (this.deliveredMessages.containsKey(m.getId())); + } + + /** + * Returns true if the message has been blacklisted. Messages + * get blacklisted when an application running on the node wants to drop it. + * This ensures the peer doesn't try to constantly send the same message to + * this node, just to get dropped by an application every time. + * + * @param id id of the message + * @return true if blacklisted, false otherwise. + */ + protected boolean isBlacklistedMessage(String id) { + return this.blacklistedMessages.containsKey(id); + } + + /** + * Returns a reference to the messages of this router in collection. + * Note: If there's a chance that some message(s) from the collection + * could be deleted (or added) while iterating through the collection, a + * copy of the collection should be made to avoid concurrent modification + * exceptions. + * @return a reference to the messages of this router in collection + */ + public Collection getMessageCollection() { + return this.messages.values(); + } + + /** + * Returns the number of messages this router has + * @return How many messages this router has + */ + public int getNrofMessages() { + return this.messages.size(); + } + + /** + * Returns the size of the message buffer. + * @return The size or Integer.MAX_VALUE if the size isn't defined. + */ + public int getBufferSize() { + return this.bufferSize; + } + + /** + * Returns the amount of free space in the buffer. May return a negative + * value if there are more messages in the buffer than should fit there + * (because of creating new messages). + * @return The amount of free space (Integer.MAX_VALUE if the buffer + * size isn't defined) + */ + public int getFreeBufferSize() { + int occupancy = 0; + + if (this.getBufferSize() == Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + + for (Message m : getMessageCollection()) { + occupancy += m.getSize(); + } + + return this.getBufferSize() - occupancy; + } + + /** + * Returns the host this router is in + * @return The host object + */ + protected DTNHost getHost() { + return this.host; + } + + /** + * Start sending a message to another host. + * @param id Id of the message to send + * @param to The host to send the message to + */ + public void sendMessage(String id, DTNHost to) { + Message m = getMessage(id); + Message m2; + if (m == null) throw new SimError("no message for id " + + id + " to send at " + this.host); + + m2 = m.replicate(); // send a replicate of the message + to.receiveMessage(m2, this.host); + } + + /** + * Requests for deliverable message from this router to be sent trough a + * connection. + * @param con The connection to send the messages trough + * @return True if this router started a transfer, false if not + */ + public boolean requestDeliverableMessages(Connection con) { + return false; // default behavior is to not start -- subclasses override + } + + /** + * Try to start receiving a message from another host. + * @param m Message to put in the receiving buffer + * @param from Who the message is from + * @return Value zero if the node accepted the message (RCV_OK), value less + * than zero if node rejected the message (e.g. DENIED_OLD), value bigger + * than zero if the other node should try later (e.g. TRY_LATER_BUSY). + */ + public int receiveMessage(Message m, DTNHost from) { + Message newMessage = m.replicate(); + + this.putToIncomingBuffer(newMessage, from); + newMessage.addNodeOnPath(this.host); + + for (MessageListener ml : this.mListeners) { + ml.messageTransferStarted(newMessage, from, getHost()); + } + + return RCV_OK; // superclass always accepts messages + } + + /** + * This method should be called (on the receiving host) after a message + * was successfully transferred. The transferred message is put to the + * message buffer unless this host is the final recipient of the message. + * @param id Id of the transferred message + * @param from Host the message was from (previous hop) + * @return The message that this host received + */ + public Message messageTransferred(String id, DTNHost from) { + Message incoming = removeFromIncomingBuffer(id, from); + boolean isFinalRecipient; + boolean isFirstDelivery; // is this first delivered instance of the msg + + + if (incoming == null) { + throw new SimError("No message with ID " + id + " in the incoming "+ + "buffer of " + this.host); + } + + incoming.setReceiveTime(SimClock.getTime()); + + // Pass the message to the application (if any) and get outgoing message + Message outgoing = incoming; + for (Application app : getApplications(incoming.getAppID())) { + // Note that the order of applications is significant + // since the next one gets the output of the previous. + outgoing = app.handle(outgoing, this.host); + if (outgoing == null) break; // Some app wanted to drop the message + } + + Message aMessage = (outgoing==null)?(incoming):(outgoing); + // If the application re-targets the message (changes 'to') + // then the message is not considered as 'delivered' to this host. + isFinalRecipient = aMessage.getTo() == this.host; + isFirstDelivery = isFinalRecipient && + !isDeliveredMessage(aMessage); + + if (!isFinalRecipient && outgoing!=null) { + // not the final recipient and app doesn't want to drop the message + // -> put to buffer + addToMessages(aMessage, false); + } else if (isFirstDelivery) { + this.deliveredMessages.put(id, aMessage); + } else if (outgoing == null) { + // Blacklist messages that an app wants to drop. + // Otherwise the peer will just try to send it back again. + this.blacklistedMessages.put(id, null); + } + + for (MessageListener ml : this.mListeners) { + ml.messageTransferred(aMessage, from, this.host, + isFirstDelivery); + } + + return aMessage; + } + + /** + * Puts a message to incoming messages buffer. Two messages with the + * same ID are distinguished by the from host. + * @param m The message to put + * @param from Who the message was from (previous hop). + */ + protected void putToIncomingBuffer(Message m, DTNHost from) { + this.incomingMessages.put(m.getId() + "_" + from.toString(), m); + } + + /** + * Removes and returns a message with a certain ID from the incoming + * messages buffer or null if such message wasn't found. + * @param id ID of the message + * @param from The host that sent this message (previous hop) + * @return The found message or null if such message wasn't found + */ + protected Message removeFromIncomingBuffer(String id, DTNHost from) { + return this.incomingMessages.remove(id + "_" + from.toString()); + } + + /** + * Returns true if a message with the given ID is one of the + * currently incoming messages, false if not + * @param id ID of the message + * @return True if such message is incoming right now + */ + protected boolean isIncomingMessage(String id) { + return this.incomingMessages.containsKey(id); + } + + /** + * Adds a message to the message buffer and informs message listeners + * about new message (if requested). + * @param m The message to add + * @param newMessage If true, message listeners are informed about a new + * message, if false, nothing is informed. + */ + protected void addToMessages(Message m, boolean newMessage) { + this.messages.put(m.getId(), m); + + if (newMessage) { + for (MessageListener ml : this.mListeners) { + ml.newMessage(m); + } + } + } + + /** + * Removes and returns a message from the message buffer. + * @param id Identifier of the message to remove + * @return The removed message or null if message for the ID wasn't found + */ + protected Message removeFromMessages(String id) { + Message m = this.messages.remove(id); + return m; + } + + /** + * This method should be called (on the receiving host) when a message + * transfer was aborted. + * @param id Id of the message that was being transferred + * @param from Host the message was from (previous hop) + * @param bytesRemaining Nrof bytes that were left before the transfer + * would have been ready; or -1 if the number of bytes is not known + */ + public void messageAborted(String id, DTNHost from, int bytesRemaining) { + Message incoming = removeFromIncomingBuffer(id, from); + if (incoming == null) { + throw new SimError("No incoming message for id " + id + + " to abort in " + this.host); + } + + for (MessageListener ml : this.mListeners) { + ml.messageTransferAborted(incoming, from, this.host); + } + } + + /** + * Creates a new message to the router. + * @param m The message to create + * @return True if the creation succeeded, false if not (e.g. + * the message was too big for the buffer) + */ + public boolean createNewMessage(Message m) { + m.setTtl(this.msgTtl); + addToMessages(m, true); + return true; + } + + /** + * Deletes a message from the buffer and informs message listeners + * about the event + * @param id Identifier of the message to delete + * @param drop If the message is dropped (e.g. because of full buffer) this + * should be set to true. False value indicates e.g. remove of message + * because it was delivered to final destination. + */ + public void deleteMessage(String id, boolean drop) { + Message removed = removeFromMessages(id); + if (removed == null) throw new SimError("no message for id " + + id + " to remove at " + this.host); + + for (MessageListener ml : this.mListeners) { + ml.messageDeleted(removed, this.host, drop); + } + } + + /** + * Sorts/shuffles the given list according to the current sending queue + * mode. The list can contain either Message or Tuple + * objects. Other objects cause error. + * @param list The list to sort or shuffle + * @return The sorted/shuffled list + */ + @SuppressWarnings(value = "unchecked") /* ugly way to make this generic */ + protected List sortByQueueMode(List list) { + switch (sendQueueMode) { + case Q_MODE_RANDOM: + Collections.shuffle(list, new Random(SimClock.getIntTime())); + break; + case Q_MODE_FIFO: + Collections.sort(list, + new Comparator() { + /** Compares two tuples by their messages' receiving time */ + public int compare(Object o1, Object o2) { + double diff; + Message m1, m2; + + if (o1 instanceof Tuple) { + m1 = ((Tuple)o1).getKey(); + m2 = ((Tuple)o2).getKey(); + } + else if (o1 instanceof Message) { + m1 = (Message)o1; + m2 = (Message)o2; + } + else { + throw new SimError("Invalid type of objects in " + + "the list"); + } + + diff = m1.getReceiveTime() - m2.getReceiveTime(); + if (diff == 0) { + return 0; + } + return (diff < 0 ? -1 : 1); + } + }); + break; + /* add more queue modes here */ + default: + throw new SimError("Unknown queue mode " + sendQueueMode); + } + + return list; + } + + /** + * Gives the order of the two given messages as defined by the current + * queue mode + * @param m1 The first message + * @param m2 The second message + * @return -1 if the first message should come first, 1 if the second + * message should come first, or 0 if the ordering isn't defined + */ + protected int compareByQueueMode(Message m1, Message m2) { + switch (sendQueueMode) { + case Q_MODE_RANDOM: + /* return randomly (enough) but consistently -1, 0 or 1 */ + return (m1.hashCode()/2 + m2.hashCode()/2) % 3 - 1; + case Q_MODE_FIFO: + double diff = m1.getReceiveTime() - m2.getReceiveTime(); + if (diff == 0) { + return 0; + } + return (diff < 0 ? -1 : 1); + /* add more queue modes here */ + default: + throw new SimError("Unknown queue mode " + sendQueueMode); + } + } + + /** + * Returns routing information about this router. + * @return The routing information. + */ + public RoutingInfo getRoutingInfo() { + RoutingInfo ri = new RoutingInfo(this); + RoutingInfo incoming = new RoutingInfo(this.incomingMessages.size() + + " incoming message(s)"); + RoutingInfo delivered = new RoutingInfo(this.deliveredMessages.size() + + " delivered message(s)"); + + RoutingInfo cons = new RoutingInfo(host.getConnections().size() + + " connection(s)"); + + ri.addMoreInfo(incoming); + ri.addMoreInfo(delivered); + ri.addMoreInfo(cons); + + for (Message m : this.incomingMessages.values()) { + incoming.addMoreInfo(new RoutingInfo(m)); + } + + for (Message m : this.deliveredMessages.values()) { + delivered.addMoreInfo(new RoutingInfo(m + " path:" + m.getHops())); + } + + for (Connection c : host.getConnections()) { + cons.addMoreInfo(new RoutingInfo(c)); + } + + return ri; + } + + /** + * Adds an application to the attached applications list. + * + * @param app The application to attach to this router. + */ + public void addApplication(Application app) { + if (!this.applications.containsKey(app.getAppID())) { + this.applications.put(app.getAppID(), + new LinkedList()); + } + this.applications.get(app.getAppID()).add(app); + } + + /** + * Returns all the applications that want to receive messages for the given + * application ID. + * + * @param ID The application ID or null for all apps. + * @return A list of all applications that want to receive the message. + */ + public Collection getApplications(String ID) { + LinkedList apps = new LinkedList(); + // Applications that match + Collection tmp = this.applications.get(ID); + if (tmp != null) { + apps.addAll(tmp); + } + // Applications that want to look at all messages + if (ID != null) { + tmp = this.applications.get(null); + if (tmp != null) { + apps.addAll(tmp); + } + } + return apps; + } + + /** + * Creates a replicate of this router. The replicate has the same + * settings as this router but empty buffers and routing tables. + * @return The replicate + */ + public abstract MessageRouter replicate(); + + /** + * Returns a String presentation of this router + * @return A String presentation of this router + */ + public String toString() { + return getClass().getSimpleName() + " of " + + this.getHost().toString() + " with " + getNrofMessages() + + " messages"; + } +} diff --git a/routing/PassiveRouter.java b/routing/PassiveRouter.java new file mode 100644 index 000000000..d4c830abe --- /dev/null +++ b/routing/PassiveRouter.java @@ -0,0 +1,43 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import core.Connection; +import core.Settings; + +/** + * Passive router that doesn't send anything unless commanded. This is useful + * for external event -controlled routing or dummy nodes. + * For implementation specifics, see MessageRouter class. + */ +public class PassiveRouter extends MessageRouter { + + public PassiveRouter(Settings s) { + super(s); + } + + /** + * Copy-constructor. + * @param r Router to copy the settings from. + */ + protected PassiveRouter(PassiveRouter r) { + super(r); + } + + @Override + public void update() { + super.update(); + } + + @Override + public void changedConnection(Connection con) { + // -"- + } + + @Override + public MessageRouter replicate() { + return new PassiveRouter(this); + } +} diff --git a/routing/ProphetRouter.java b/routing/ProphetRouter.java new file mode 100644 index 000000000..3dda01446 --- /dev/null +++ b/routing/ProphetRouter.java @@ -0,0 +1,308 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import routing.util.RoutingInfo; + +import util.Tuple; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimClock; + +/** + * Implementation of PRoPHET router as described in + * Probabilistic routing in intermittently connected networks by + * Anders Lindgren et al. + */ +public class ProphetRouter extends ActiveRouter { + /** delivery predictability initialization constant*/ + public static final double P_INIT = 0.75; + /** delivery predictability transitivity scaling constant default value */ + public static final double DEFAULT_BETA = 0.25; + /** delivery predictability aging constant */ + public static final double GAMMA = 0.98; + + /** Prophet router's setting namespace ({@value})*/ + public static final String PROPHET_NS = "ProphetRouter"; + /** + * Number of seconds in time unit -setting id ({@value}). + * How many seconds one time unit is when calculating aging of + * delivery predictions. Should be tweaked for the scenario.*/ + public static final String SECONDS_IN_UNIT_S ="secondsInTimeUnit"; + + /** + * Transitivity scaling constant (beta) -setting id ({@value}). + * Default value for setting is {@link #DEFAULT_BETA}. + */ + public static final String BETA_S = "beta"; + + /** the value of nrof seconds in time unit -setting */ + private int secondsInTimeUnit; + /** value of beta setting */ + private double beta; + + /** delivery predictabilities */ + private Map preds; + /** last delivery predictability update (sim)time */ + private double lastAgeUpdate; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ProphetRouter(Settings s) { + super(s); + Settings prophetSettings = new Settings(PROPHET_NS); + secondsInTimeUnit = prophetSettings.getInt(SECONDS_IN_UNIT_S); + if (prophetSettings.contains(BETA_S)) { + beta = prophetSettings.getDouble(BETA_S); + } + else { + beta = DEFAULT_BETA; + } + + initPreds(); + } + + /** + * Copyconstructor. + * @param r The router prototype where setting values are copied from + */ + protected ProphetRouter(ProphetRouter r) { + super(r); + this.secondsInTimeUnit = r.secondsInTimeUnit; + this.beta = r.beta; + initPreds(); + } + + /** + * Initializes predictability hash + */ + private void initPreds() { + this.preds = new HashMap(); + } + + @Override + public void changedConnection(Connection con) { + super.changedConnection(con); + + if (con.isUp()) { + DTNHost otherHost = con.getOtherNode(getHost()); + updateDeliveryPredFor(otherHost); + updateTransitivePreds(otherHost); + } + } + + /** + * Updates delivery predictions for a host. + * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * P_INIT + * @param host The host we just met + */ + private void updateDeliveryPredFor(DTNHost host) { + double oldValue = getPredFor(host); + double newValue = oldValue + (1 - oldValue) * P_INIT; + preds.put(host, newValue); + } + + /** + * Returns the current prediction (P) value for a host or 0 if entry for + * the host doesn't exist. + * @param host The host to look the P for + * @return the current P value + */ + public double getPredFor(DTNHost host) { + ageDeliveryPreds(); // make sure preds are updated before getting + if (preds.containsKey(host)) { + return preds.get(host); + } + else { + return 0; + } + } + + /** + * Updates transitive (A->B->C) delivery predictions. + * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA + * + * @param host The B host who we just met + */ + private void updateTransitivePreds(DTNHost host) { + MessageRouter otherRouter = host.getRouter(); + assert otherRouter instanceof ProphetRouter : "PRoPHET only works " + + " with other routers of same type"; + + double pForHost = getPredFor(host); // P(a,b) + Map othersPreds = + ((ProphetRouter)otherRouter).getDeliveryPreds(); + + for (Map.Entry e : othersPreds.entrySet()) { + if (e.getKey() == getHost()) { + continue; // don't add yourself + } + + double pOld = getPredFor(e.getKey()); // P(a,c)_old + double pNew = pOld + ( 1 - pOld) * pForHost * e.getValue() * beta; + preds.put(e.getKey(), pNew); + } + } + + /** + * Ages all entries in the delivery predictions. + * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of + * time units that have elapsed since the last time the metric was aged. + * @see #SECONDS_IN_UNIT_S + */ + private void ageDeliveryPreds() { + double timeDiff = (SimClock.getTime() - this.lastAgeUpdate) / + secondsInTimeUnit; + + if (timeDiff == 0) { + return; + } + + double mult = Math.pow(GAMMA, timeDiff); + for (Map.Entry e : preds.entrySet()) { + e.setValue(e.getValue()*mult); + } + + this.lastAgeUpdate = SimClock.getTime(); + } + + /** + * Returns a map of this router's delivery predictions + * @return a map of this router's delivery predictions + */ + private Map getDeliveryPreds() { + ageDeliveryPreds(); // make sure the aging is done + return this.preds; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts collect all messages that have a higher + probability of delivery by the other host */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + ProphetRouter othRouter = (ProphetRouter)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + if (othRouter.hasMessage(m.getId())) { + continue; // skip messages that the other one has + } + if (othRouter.getPredFor(m.getTo()) > getPredFor(m.getTo())) { + // the other node has higher probability of delivery + messages.add(new Tuple(m,con)); + } + } + } + + if (messages.size() == 0) { + return null; + } + + // sort the message-connection tuples + Collections.sort(messages, new TupleComparator()); + return tryMessagesForConnected(messages); // try to send messages + } + + /** + * Comparator for Message-Connection-Tuples that orders the tuples by + * their delivery probability by the host on the other side of the + * connection (GRTRMax) + */ + private class TupleComparator implements Comparator + > { + + public int compare(Tuple tuple1, + Tuple tuple2) { + // delivery probability of tuple1's message with tuple1's connection + double p1 = ((ProphetRouter)tuple1.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple1.getKey().getTo()); + // -"- tuple2... + double p2 = ((ProphetRouter)tuple2.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple2.getKey().getTo()); + + // bigger probability should come first + if (p2-p1 == 0) { + /* equal probabilities -> let queue mode decide */ + return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); + } + else if (p2-p1 < 0) { + return -1; + } + else { + return 1; + } + } + } + + @Override + public RoutingInfo getRoutingInfo() { + ageDeliveryPreds(); + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(preds.size() + + " delivery prediction(s)"); + + for (Map.Entry e : preds.entrySet()) { + DTNHost host = e.getKey(); + Double value = e.getValue(); + + ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", + host, value))); + } + + top.addMoreInfo(ri); + return top; + } + + @Override + public MessageRouter replicate() { + ProphetRouter r = new ProphetRouter(this); + return r; + } + +} diff --git a/routing/ProphetRouterWithEstimation.java b/routing/ProphetRouterWithEstimation.java new file mode 100644 index 000000000..75c75984a --- /dev/null +++ b/routing/ProphetRouterWithEstimation.java @@ -0,0 +1,523 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import routing.util.RoutingInfo; + +import util.Tuple; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimClock; + +/** + * Implementation of PRoPHET router as described in + * Probabilistic routing in intermittently connected networks by + * Anders Lindgren et al. + * + * + * This version tries to estimate a good value of protocol parameters from + * a timescale parameter given by the user, and from the encounters the node + * sees during simulation. + * Refer to Karvo and Ott, Time Scales and Delay-Tolerant Routing + * Protocols Chants, 2008 + * + */ +public class ProphetRouterWithEstimation extends ActiveRouter { + /** delivery predictability initialization constant*/ + public static final double P_INIT = 0.75; + /** delivery predictability transitivity scaling constant default value */ + public static final double DEFAULT_BETA = 0.25; + /** delivery predictability aging constant */ + public static final double GAMMA = 0.98; + /** default P target */ + public static final double DEFAULT_PTARGET = .2; + + /** Prophet router's setting namespace ({@value})*/ + public static final String PROPHET_NS = "ProphetRouterWithEstimation"; + /** + * Number of seconds in time scale.*/ + public static final String TIME_SCALE_S ="timeScale"; + /** + * Target P_avg + * + */ + public static final String P_AVG_TARGET_S = "targetPavg"; + + /** + * Transitivity scaling constant (beta) -setting id ({@value}). + * Default value for setting is {@link #DEFAULT_BETA}. + */ + public static final String BETA_S = "beta"; + + /** values of parameter settings */ + private double beta; + private double gamma; + private double pinit; + + /** value of time scale variable */ + private int timescale; + private double ptavg; + + /** delivery predictabilities */ + private Map preds; + + /** last meeting time with a node */ + private Map meetings; + private int nrofSamples; + private double meanIET; + + /** last delivery predictability update (sim)time */ + private double lastAgeUpdate; + + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ProphetRouterWithEstimation(Settings s) { + super(s); + Settings prophetSettings = new Settings(PROPHET_NS); + timescale = prophetSettings.getInt(TIME_SCALE_S); + if (prophetSettings.contains(P_AVG_TARGET_S)) { + ptavg = prophetSettings.getDouble(P_AVG_TARGET_S); + } else { + ptavg = DEFAULT_PTARGET; + } + if (prophetSettings.contains(BETA_S)) { + beta = prophetSettings.getDouble(BETA_S); + } else { + beta = DEFAULT_BETA; + } + gamma = GAMMA; + pinit = P_INIT; + + initPreds(); + initMeetings(); + } + + /** + * Copyconstructor. + * @param r The router prototype where setting values are copied from + */ + protected ProphetRouterWithEstimation(ProphetRouterWithEstimation r) { + super(r); + this.timescale = r.timescale; + this.ptavg = r.ptavg; + this.beta = r.beta; + initPreds(); + initMeetings(); + } + + /** + * Initializes predictability hash + */ + private void initPreds() { + this.preds = new HashMap(); + } + + /** + * Initializes inter-encounter time estimator + */ + private void initMeetings() { + this.meetings = new HashMap(); + this.meanIET = 0; + this.nrofSamples = 0; + } + + @Override + public void changedConnection(Connection con) { + super.changedConnection(con); + + if (con.isUp()) { + DTNHost otherHost = con.getOtherNode(getHost()); + if (updateIET(otherHost)) { + updateParams(); + } + updateDeliveryPredFor(otherHost); + updateTransitivePreds(otherHost); + } + } + + /** + * Updates the interencounter time estimates + * @param host + */ + private boolean updateIET(DTNHost host) { + /* First estimate the mean InterEncounter Time */ + double currentTime = SimClock.getTime(); + if (meetings.containsKey(host)) { + double timeDiff = currentTime - meetings.get(host); + // System.out.printf("current time: %f\t last time: %f\n",currentTime,meetings.get(host)); + + nrofSamples++; + meanIET = (((double)nrofSamples -1) / (double)nrofSamples) * meanIET + + (1 / (double)nrofSamples) * timeDiff; + meetings.put(host, currentTime); + return true; + } else { + /* nothing to update */ + meetings.put(host,currentTime); + return false; + } + } + + /** + * update PROPHET parameters + * + */ + private void updateParams() + { + double b; + double zeta; + double err; + boolean cond; + int ntarg; + double zetadiff; + int ozeta; + double pstable; + double pavg; + double ee; + double bdiff; + int ob; + int zcount; + boolean bcheck; + double pnzero; + double pnone; + double eezero; + double eeone; + + /* + * the estimation algorith does not work for timescales + * shorter than the mean IET - so use defaults + */ + if (meanIET > (double)timescale) { + System.out.printf("meanIET %f > %d timescale\n",meanIET,timescale); + return; + } + + if (meanIET == 0) { + System.out.printf("Mean IET == 0\n"); + return; + } + + System.out.printf("prophetfindparams(%d,%f,%f);\n",timescale,ptavg,meanIET); + b = 1e-5; + zeta = .9; + err = 0.005; + zetadiff = .1; + ozeta = 0; + cond = false; + ntarg = (int)Math.ceil((double)timescale/(double)meanIET); + while (cond == false) { + pstable = (1-zeta)/(Math.exp(b*meanIET)-zeta); + pavg = (1/(b*meanIET)) * (1-zeta*(1-pstable)) * + (1- Math.exp( -b*meanIET)); + + if (Double.isNaN(pavg)) { + pavg = 1; + } + + if (pavg > ptavg) { + //System.out.printf("PAVG %f > %f PTAVG\n", pavg,ptavg); + if (ozeta == 2) { + zetadiff = zetadiff / 2.0; + } + ozeta = 1; + zeta = zeta + zetadiff; + if (zeta >= 1) { + zeta = 1-zetadiff; + zetadiff = zetadiff / 2.0; + ozeta = 0; + } + } else { + if (pavg < ptavg * (1-err)) { + // System.out.printf("PAVG %f < %f PTAVG\n", pavg,ptavg); + if (ozeta == 1) { + zetadiff = zetadiff / 2.0; + } + ozeta = 2; + zeta = zeta-zetadiff; + if (zeta <= 0) { + zeta = 0 + zetadiff; + zetadiff = zetadiff / 2.0; + ozeta = 0; + } + } else { + cond = true; + } + } + + //System.out.printf("Zeta: %f Zetadiff: %f\n",zeta,zetadiff); + ee = 1; + bdiff = .1; + ob = 0; + zcount = 0; // if 100 iterations won't help, lets increase zeta... + bcheck = false; + while (bcheck == false) { + + pstable = (1-zeta)/(Math.exp(b*meanIET)-zeta); + pnzero = Math.exp(-b*meanIET) * (1-zeta) * + ((1-Math.pow(zeta*Math.exp(-b*meanIET),ntarg-1))/ + (1-zeta*Math.exp(-b*meanIET))); + pnone = Math.pow(zeta*Math.exp(-b*meanIET),ntarg) + pnzero; + eezero = Math.abs(pnzero-pstable); + eeone = Math.abs(pnone -pstable); + ee = Math.max(eezero,eeone); + +// System.out.printf("Zeta: %f\n", zeta); + // System.out.printf("Ptarget: %f \t Pstable: %f\n",ptavg,pstable); + // System.out.printf("Pnzero: %f \tPnone: %f\n", pnzero,pnone); + // System.out.printf("eezero: %f\t eeone: %f\n", eezero, eeone); + + if (ee > err) { + if (ob == 2) { + bdiff = bdiff / 2.0; + } + ob = 1; + b = b+bdiff; + } else { + if (ee < (err*(1-err))) { + if (ob == 1) { + bdiff = bdiff / 2.0; + } + ob = 2; + b = b-bdiff; + if (b <= 0) { + b = 0 + bdiff; + bdiff = bdiff / 1.5; + ob = 0; + } + } else { + bcheck = true; +// System.out.println("******"); + } + } + +// System.out.printf("EE: %f B: %f Bdiff: %f\n",ee,b,bdiff); + zcount = zcount + 1; + if (zcount > 100) { + bcheck = true; + ozeta = 0; + } + } + } + gamma = Math.exp(-b); + pinit = 1-zeta; + } + + /** + * Updates delivery predictions for a host. + * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * P_INIT + * @param host The host we just met + */ + private void updateDeliveryPredFor(DTNHost host) { + double oldValue = getPredFor(host); + double newValue = oldValue + (1 - oldValue) * pinit; + preds.put(host, newValue); + } + + /** + * Returns the current prediction (P) value for a host or 0 if entry for + * the host doesn't exist. + * @param host The host to look the P for + * @return the current P value + */ + public double getPredFor(DTNHost host) { + ageDeliveryPreds(); // make sure preds are updated before getting + if (preds.containsKey(host)) { + return preds.get(host); + } + else { + return 0; + } + } + + /** + * Updates transitive (A->B->C) delivery predictions. + * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA + * + * @param host The B host who we just met + */ + private void updateTransitivePreds(DTNHost host) { + MessageRouter otherRouter = host.getRouter(); + assert otherRouter instanceof ProphetRouterWithEstimation : "PRoPHET only works " + + " with other routers of same type"; + + double pForHost = getPredFor(host); // P(a,b) + Map othersPreds = + ((ProphetRouterWithEstimation)otherRouter).getDeliveryPreds(); + + for (Map.Entry e : othersPreds.entrySet()) { + if (e.getKey() == getHost()) { + continue; // don't add yourself + } + + double pOld = getPredFor(e.getKey()); // P(a,c)_old + double pNew = pOld + ( 1 - pOld) * pForHost * e.getValue() * beta; + preds.put(e.getKey(), pNew); + } + } + + /** + * Ages all entries in the delivery predictions. + * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of + * time units that have elapsed since the last time the metric was aged. + * @see #SECONDS_IN_UNIT_S + */ + private void ageDeliveryPreds() { + double timeDiff = (SimClock.getTime() - this.lastAgeUpdate); + + if (timeDiff == 0) { + return; + } + + double mult = Math.pow(gamma, timeDiff); + for (Map.Entry e : preds.entrySet()) { + e.setValue(e.getValue()*mult); + } + + this.lastAgeUpdate = SimClock.getTime(); + } + + /** + * Returns a map of this router's delivery predictions + * @return a map of this router's delivery predictions + */ + private Map getDeliveryPreds() { + ageDeliveryPreds(); // make sure the aging is done + return this.preds; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts collect all messages that have a higher + probability of delivery by the other host */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + ProphetRouterWithEstimation othRouter = (ProphetRouterWithEstimation)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + if (othRouter.hasMessage(m.getId())) { + continue; // skip messages that the other one has + } + if (othRouter.getPredFor(m.getTo()) > getPredFor(m.getTo())) { + // the other node has higher probability of delivery + messages.add(new Tuple(m,con)); + } + } + } + + if (messages.size() == 0) { + return null; + } + + // sort the message-connection tuples + Collections.sort(messages, new TupleComparator()); + return tryMessagesForConnected(messages); // try to send messages + } + + /** + * Comparator for Message-Connection-Tuples that orders the tuples by + * their delivery probability by the host on the other side of the + * connection (GRTRMax) + */ + private class TupleComparator implements Comparator + > { + + public int compare(Tuple tuple1, + Tuple tuple2) { + // delivery probability of tuple1's message with tuple1's connection + double p1 = ((ProphetRouterWithEstimation)tuple1.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple1.getKey().getTo()); + // -"- tuple2... + double p2 = ((ProphetRouterWithEstimation)tuple2.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple2.getKey().getTo()); + + // bigger probability should come first + if (p2-p1 == 0) { + /* equal probabilities -> let queue mode decide */ + return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); + } + else if (p2-p1 < 0) { + return -1; + } + else { + return 1; + } + } + } + + @Override + public RoutingInfo getRoutingInfo() { + ageDeliveryPreds(); + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(preds.size() + + " delivery prediction(s)"); + + for (Map.Entry e : preds.entrySet()) { + DTNHost host = e.getKey(); + Double value = e.getValue(); + + ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", + host, value))); + } + + ri.addMoreInfo(new RoutingInfo(String.format("meanIET: %f\t from %d samples",meanIET,nrofSamples))); + ri.addMoreInfo(new RoutingInfo(String.format("current gamma: %f",gamma))); + ri.addMoreInfo(new RoutingInfo(String.format("current Pinit: %f",pinit))); + + top.addMoreInfo(ri); + return top; + } + + @Override + public MessageRouter replicate() { + ProphetRouterWithEstimation r = new ProphetRouterWithEstimation(this); + return r; + } + +} diff --git a/routing/ProphetV2Router.java b/routing/ProphetV2Router.java new file mode 100644 index 000000000..757debab0 --- /dev/null +++ b/routing/ProphetV2Router.java @@ -0,0 +1,361 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + * The Original PRoPHET code updated to PRoPHETv2 router + * by Samo Grasic(samo@grasic.net) - Jun 2011 + */ +package routing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import java.util.Random; + +import routing.util.RoutingInfo; + + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimClock; +import util.Tuple; + +/** + * Implementation of PRoPHETv2" router as described in + * http://tools.ietf.org/html/draft-irtf-dtnrg-prophet-09 + */ +public class ProphetV2Router extends ActiveRouter { + /** delivery predictability initialization constant*/ + public static final double PEncMax = 0.5; + /** typical interconnection time in seconds*/ + public static final double I_TYP = 1800; + /** delivery predictability transitivity scaling constant default value */ + public static final double DEFAULT_BETA = 0.9; + /** delivery predictability aging constant */ + public static final double GAMMA = 0.999885791; + Random randomGenerator = new Random(); + + /** Prophet router's setting namespace ({@value})*/ + public static final String PROPHET_NS = "ProphetV2Router"; + /** + * Number of seconds in time unit -setting id ({@value}). + * How many seconds one time unit is when calculating aging of + * delivery predictions. Should be tweaked for the scenario.*/ + public static final String SECONDS_IN_UNIT_S ="secondsInTimeUnit"; + + /** + * Transitivity scaling constant (beta) -setting id ({@value}). + * Default value for setting is {@link #DEFAULT_BETA}. + */ + public static final String BETA_S = "beta"; + + /** the value of nrof seconds in time unit -setting */ + private int secondsInTimeUnit; + /** value of beta setting */ + private double beta; + + /** delivery predictabilities */ + private Map preds; + + /** last encouter timestamp (sim)time */ + private Map lastEncouterTime; + + /** last delivery predictability update (sim)time */ + private double lastAgeUpdate; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public ProphetV2Router(Settings s) { + super(s); + Settings prophetSettings = new Settings(PROPHET_NS); + secondsInTimeUnit = prophetSettings.getInt(SECONDS_IN_UNIT_S); + if (prophetSettings.contains(BETA_S)) { + beta = prophetSettings.getDouble(BETA_S); + } + else { + beta = DEFAULT_BETA; + } + + initPreds(); + initEncTimes(); + + } + + /** + * Copyc onstructor. + * @param The router prototype where setting values are copied from + */ + protected ProphetV2Router(ProphetV2Router r) { + super(r); + this.secondsInTimeUnit = r.secondsInTimeUnit; + this.beta = r.beta; + initPreds(); + initEncTimes(); + } + + /** + * Initializes lastEncouterTime hash + */ + private void initEncTimes() { + this.lastEncouterTime = new HashMap(); + } + + /** + * Initializes predictability hash + */ + private void initPreds() { + this.preds = new HashMap(); + } + + @Override + public void changedConnection(Connection con) { + if (con.isUp()) { + DTNHost otherHost = con.getOtherNode(getHost()); + updateDeliveryPredFor(otherHost); + updateTransitivePreds(otherHost); + } + } + + /** + * Updates delivery predictions for a host. + * P(a,b) = P(a,b)_old + (1 - P(a,b)_old) * PEnc + * PEnc(intvl) = + * P_encounter_max * (intvl / I_typ) for 0<= intvl <= I_typ + * P_encounter_max for intvl > I_typ + * @param host The host we just met + */ + private void updateDeliveryPredFor(DTNHost host) { + double PEnc; + double simTime = SimClock.getTime(); + double lastEncTime=getEncTimeFor(host); + if(lastEncTime==0) + PEnc=PEncMax; + else + if((simTime-lastEncTime)B->C) delivery predictions. + * P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA + * + * @param host The B host who we just met + */ + private void updateTransitivePreds(DTNHost host) { + MessageRouter otherRouter = host.getRouter(); + assert otherRouter instanceof ProphetV2Router : + "PRoPHETv2 only works with other routers of same type"; + + double pForHost = getPredFor(host); // P(a,b) + Map othersPreds = + ((ProphetV2Router)otherRouter).getDeliveryPreds(); + + for (Map.Entry e : othersPreds.entrySet()) { + if (e.getKey() == getHost()) { + continue; // don't add yourself + } + +//ProphetV2 max(old,new) + double pOld = getPredFor(e.getKey()); // P(a,c)_old + double pNew = pForHost * e.getValue() * beta; + if(pNew>pOld) + preds.put(e.getKey(), pNew); + + } + } + + /** + * Ages all entries in the delivery predictions. + * P(a,b) = P(a,b)_old * (GAMMA ^ k), where k is number of + * time units that have elapsed since the last time the metric was aged. + * @see #SECONDS_IN_UNIT_S + */ + private void ageDeliveryPreds() { + double timeDiff = (SimClock.getTime() - this.lastAgeUpdate) / + secondsInTimeUnit; + + if (timeDiff == 0) { + return; + } + + double mult = Math.pow(GAMMA, timeDiff); + for (Map.Entry e : preds.entrySet()) { + e.setValue(e.getValue()*mult); + } + + this.lastAgeUpdate = SimClock.getTime(); + } + + /** + * Returns a map of this router's delivery predictions + * @return a map of this router's delivery predictions + */ + private Map getDeliveryPreds() { + ageDeliveryPreds(); // make sure the aging is done + return this.preds; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() ||isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + // try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Tries to send all other messages to all connected hosts ordered by + * their delivery probability + * @return The return value of {@link #tryMessagesForConnected(List)} + */ + private Tuple tryOtherMessages() { + List> messages = + new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /* for all connected hosts collect all messages that have a higher + probability of delivery by the other host */ + for (Connection con : getConnections()) { + DTNHost other = con.getOtherNode(getHost()); + ProphetV2Router othRouter = (ProphetV2Router)other.getRouter(); + + if (othRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + if (othRouter.hasMessage(m.getId())) { + continue; // skip messages that the other one has + } + if((othRouter.getPredFor(m.getTo()) >= getPredFor(m.getTo()))) + { + + messages.add(new Tuple(m,con)); + } + } + } + + if (messages.size() == 0) { + return null; + } + + // sort the message-connection tuples + Collections.sort(messages, new TupleComparator()); + return tryMessagesForConnected(messages); // try to send messages + } + + /** + * Comparator for Message-Connection-Tuples that orders the tuples by + * their delivery probability by the host on the other side of the + * connection (GRTRMax) + */ + private class TupleComparator implements Comparator + > { + + public int compare(Tuple tuple1, + Tuple tuple2) { + // delivery probability of tuple1's message with tuple1's connection + double p1 = ((ProphetV2Router)tuple1.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple1.getKey().getTo()); + // -"- tuple2... + double p2 = ((ProphetV2Router)tuple2.getValue(). + getOtherNode(getHost()).getRouter()).getPredFor( + tuple2.getKey().getTo()); + + // bigger probability should come first + if (p2-p1 == 0) { + /* equal probabilities -> let queue mode decide */ + return compareByQueueMode(tuple1.getKey(), tuple2.getKey()); + } + else if (p2-p1 < 0) { + return -1; + } + else { + return 1; + } + } + } + + @Override + public RoutingInfo getRoutingInfo() { + ageDeliveryPreds(); + RoutingInfo top = super.getRoutingInfo(); + RoutingInfo ri = new RoutingInfo(preds.size() + + " delivery prediction(s)"); + + for (Map.Entry e : preds.entrySet()) { + DTNHost host = e.getKey(); + Double value = e.getValue(); + + ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f", + host, value))); + } + + top.addMoreInfo(ri); + return top; + } + + @Override + public MessageRouter replicate() { + ProphetV2Router r = new ProphetV2Router(this); + return r; + } +} \ No newline at end of file diff --git a/routing/SprayAndWaitRouter.java b/routing/SprayAndWaitRouter.java new file mode 100644 index 000000000..07103a561 --- /dev/null +++ b/routing/SprayAndWaitRouter.java @@ -0,0 +1,163 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.ArrayList; +import java.util.List; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; + +/** + * Implementation of Spray and wait router as depicted in + * Spray and Wait: An Efficient Routing Scheme for Intermittently + * Connected Mobile Networks by Thrasyvoulos Spyropoulus et al. + * + */ +public class SprayAndWaitRouter extends ActiveRouter { + /** identifier for the initial number of copies setting ({@value})*/ + public static final String NROF_COPIES = "nrofCopies"; + /** identifier for the binary-mode setting ({@value})*/ + public static final String BINARY_MODE = "binaryMode"; + /** SprayAndWait router's settings name space ({@value})*/ + public static final String SPRAYANDWAIT_NS = "SprayAndWaitRouter"; + /** Message property key */ + public static final String MSG_COUNT_PROPERTY = SPRAYANDWAIT_NS + "." + + "copies"; + + protected int initialNrofCopies; + protected boolean isBinary; + + public SprayAndWaitRouter(Settings s) { + super(s); + Settings snwSettings = new Settings(SPRAYANDWAIT_NS); + + initialNrofCopies = snwSettings.getInt(NROF_COPIES); + isBinary = snwSettings.getBoolean( BINARY_MODE); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected SprayAndWaitRouter(SprayAndWaitRouter r) { + super(r); + this.initialNrofCopies = r.initialNrofCopies; + this.isBinary = r.isBinary; + } + + @Override + public int receiveMessage(Message m, DTNHost from) { + return super.receiveMessage(m, from); + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + Message msg = super.messageTransferred(id, from); + Integer nrofCopies = (Integer)msg.getProperty(MSG_COUNT_PROPERTY); + + assert nrofCopies != null : "Not a SnW message: " + msg; + + if (isBinary) { + /* in binary S'n'W the receiving node gets ceil(n/2) copies */ + nrofCopies = (int)Math.ceil(nrofCopies/2.0); + } + else { + /* in standard S'n'W the receiving node gets only single copy */ + nrofCopies = 1; + } + + msg.updateProperty(MSG_COUNT_PROPERTY, nrofCopies); + return msg; + } + + @Override + public boolean createNewMessage(Message msg) { + makeRoomForNewMessage(msg.getSize()); + + msg.setTtl(this.msgTtl); + msg.addProperty(MSG_COUNT_PROPERTY, new Integer(initialNrofCopies)); + addToMessages(msg, true); + return true; + } + + @Override + public void update() { + super.update(); + if (!canStartTransfer() || isTransferring()) { + return; // nothing to transfer or is currently transferring + } + + /* try messages that could be delivered to final recipient */ + if (exchangeDeliverableMessages() != null) { + return; + } + + /* create a list of SAWMessages that have copies left to distribute */ + @SuppressWarnings(value = "unchecked") + List copiesLeft = sortByQueueMode(getMessagesWithCopiesLeft()); + + if (copiesLeft.size() > 0) { + /* try to send those messages */ + this.tryMessagesToConnections(copiesLeft, getConnections()); + } + } + + /** + * Creates and returns a list of messages this router is currently + * carrying and still has copies left to distribute (nrof copies > 1). + * @return A list of messages that have copies left + */ + protected List getMessagesWithCopiesLeft() { + List list = new ArrayList(); + + for (Message m : getMessageCollection()) { + Integer nrofCopies = (Integer)m.getProperty(MSG_COUNT_PROPERTY); + assert nrofCopies != null : "SnW message " + m + " didn't have " + + "nrof copies property!"; + if (nrofCopies > 1) { + list.add(m); + } + } + + return list; + } + + /** + * Called just before a transfer is finalized (by + * {@link ActiveRouter#update()}). + * Reduces the number of copies we have left for a message. + * In binary Spray and Wait, sending host is left with floor(n/2) copies, + * but in standard mode, nrof copies left is reduced by one. + */ + @Override + protected void transferDone(Connection con) { + Integer nrofCopies; + String msgId = con.getMessage().getId(); + /* get this router's copy of the message */ + Message msg = getMessage(msgId); + + if (msg == null) { // message has been dropped from the buffer after.. + return; // ..start of transfer -> no need to reduce amount of copies + } + + /* reduce the amount of copies left */ + nrofCopies = (Integer)msg.getProperty(MSG_COUNT_PROPERTY); + if (isBinary) { + nrofCopies /= 2; + } + else { + nrofCopies--; + } + msg.updateProperty(MSG_COUNT_PROPERTY, nrofCopies); + } + + @Override + public SprayAndWaitRouter replicate() { + return new SprayAndWaitRouter(this); + } +} diff --git a/routing/WaveRouter.java b/routing/WaveRouter.java new file mode 100644 index 000000000..3854f67ae --- /dev/null +++ b/routing/WaveRouter.java @@ -0,0 +1,169 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import routing.util.RoutingInfo; + +import core.Connection; +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimClock; + +/** + * Epidemic-like message router making waves of messages. + * Work in progress. + */ +public class WaveRouter extends ActiveRouter { + + /** + * Immunity time -setting id ({@value}). Defines how long time a node + * will reject incoming messages it has already received + */ + public static final String IMMUNITY_S = "immunityTime"; + /** + * Custody fraction -setting id ({@value}). Defines how long (compared to + * immunity time) nodes accept custody for new incoming messages. + */ + public static final String CUSTODY_S = "custodyFraction"; + private double immunityTime; + private double custodyFraction; + /** map of recently received messages and their receive times */ + private Map recentMessages; + /** IDs of the messages this host has custody for */ + private Map custodyMessages; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public WaveRouter(Settings s) { + super(s); + this.immunityTime = s.getDouble(IMMUNITY_S); + this.custodyFraction = s.getDouble(CUSTODY_S); + } + + /** + * Copy constructor. + * @param r The router prototype where setting values are copied from + */ + protected WaveRouter(WaveRouter r) { + super(r); + recentMessages = new HashMap(); + this.immunityTime = r.immunityTime; + this.custodyFraction = r.custodyFraction; + this.custodyMessages = new HashMap(); + } + + @Override + protected int checkReceiving(Message m, DTNHost from) { + Double lastTime = this.recentMessages.get(m.getId()); + + if (lastTime != null) { + if (lastTime + this.immunityTime > SimClock.getTime()) { + return DENIED_POLICY; /* still immune to the message */ + } else { + /* immunity has passed; remove from recent */ + this.recentMessages.remove(m.getId()); + } + } + + /* no last time or immunity passed; receive based on other checks */ + return super.checkReceiving(m, from); + } + + /** + * Returns the oldest message that has been already sent forward + */ + @Override + protected Message getNextMessageToRemove(boolean excludeMsgBeingSent) { + Collection messages = this.getMessageCollection(); + Message oldest = null; + + for (Message m : messages) { + Double custodyStartTime = this.custodyMessages.get(m.getId()); + if (custodyStartTime != null) { + if (SimClock.getTime() > + custodyStartTime + immunityTime * custodyFraction) { + this.custodyMessages.remove(m.getId()); /* time passed */ + } else { + continue; /* skip messages that still have custody */ + } + } + + + if (excludeMsgBeingSent && isSending(m.getId())) { + continue; /* skip the message(s) that router is sending */ + } + + if (oldest == null ) { + oldest = m; + } + else if (oldest.getReceiveTime() > m.getReceiveTime()) { + oldest = m; + } + } + + return oldest; + } + + @Override + public void update() { + super.update(); + + if (isTransferring() || !canStartTransfer()) { + return; /* transferring, don't try other connections yet */ + } + + /* Try first the messages that can be delivered to final recipient */ + if (exchangeDeliverableMessages() != null) { + return; + } + this.tryAllMessagesToAllConnections(); + } + + @Override + public Message messageTransferred(String id, DTNHost from) { + Message m = super.messageTransferred(id, from); + /* store received message IDs for immunity */ + this.recentMessages.put(m.getId(), new Double(SimClock.getTime())); + this.custodyMessages.put(id, SimClock.getTime()); + return m; + } + + @Override + protected void transferDone(Connection con) { + /* remove from custody messages (if it was there) */ + this.custodyMessages.remove(con.getMessage().getId()); + } + + @Override + public RoutingInfo getRoutingInfo() { + RoutingInfo ri = super.getRoutingInfo(); + RoutingInfo immunity = new RoutingInfo("Immune to " + + this.recentMessages.size() + " messages"); + + for (String id : recentMessages.keySet()) { + RoutingInfo m = new RoutingInfo(id + " until " + + String.format("%.2f", + recentMessages.get(id) + this.immunityTime)); + immunity.addMoreInfo(m); + } + ri.addMoreInfo(immunity); + + return ri; + } + + @Override + public WaveRouter replicate() { + return new WaveRouter(this); + } + +} \ No newline at end of file diff --git a/routing/maxprop/MaxPropDijkstra.java b/routing/maxprop/MaxPropDijkstra.java new file mode 100644 index 000000000..d4c37c815 --- /dev/null +++ b/routing/maxprop/MaxPropDijkstra.java @@ -0,0 +1,224 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.maxprop; + +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Set; + +/** + * Dijkstra's shortest path implementation for MaxProp Router module. + */ +public class MaxPropDijkstra { + /** Value for infinite distance */ + private static final Double INFINITY = Double.MAX_VALUE; + /** Initial size of the priority queue */ + private static final int PQ_INIT_SIZE = 11; + + /** Map of node distances from the source node */ + private DistanceMap distancesFromStart; + /** Set of already visited nodes (where the shortest path is known) */ + private Set visited; + /** Priority queue of unvisited nodes discovered so far */ + private Queue unvisited; + /** Map of previous nodes on the shortest path(s) -- only used for + * debugging purposes */ + private Map prevNodes; + /** Mapping of to other nodes' (whom this node has met) probability sets */ + private Map probs; + + /** + * Constructor. + * @param probs A reference to the mapping of the known hosts meeting + * probability sets + */ + public MaxPropDijkstra(Map probs) { + this.probs = probs; + } + + /** + * Initializes a new search with the first hop router node + * @param firstHop The first hop router node + */ + private void initWith(Integer firstHop) { + this.unvisited = new PriorityQueue(PQ_INIT_SIZE, + new DistanceComparator()); + this.visited = new HashSet(); + this.prevNodes = new HashMap(); + this.distancesFromStart = new DistanceMap(); + + // set distance to source 0 and initialize unvisited queue + this.distancesFromStart.put(firstHop, 0); + this.unvisited.add(firstHop); + } + + /** + * Calculates total costs to the given set of target nodes. The cost to + * a node is the sum of complements of probabilities that all the links + * come up as the next contact of the nodes. + * @param from The index (address) of the start node + * @param to The address set of destination nodes + * @return A map of (destination node, cost) tuples + */ + public Map getCosts(Integer from, Set to) { + Map distMap = new HashMap(); + int nrofNodesToFind = to.size(); + + initWith(from); + Integer node = null; + + // always take the node with shortest distance + while ((node = unvisited.poll()) != null) { + if (to.contains(node)) { + // found one of the requested nodes + distMap.put(node, distancesFromStart.get(node)); + nrofNodesToFind--; + if (nrofNodesToFind == 0) { + break; // all requested nodes found + } + } + + visited.add(node); // mark the node as visited + relax(node); // add/update neighbor nodes' distances + } + + return distMap; + } + + /** + * Relaxes the neighbors of a node (updates the shortest distances). + * @param node The node whose neighbors are relaxed + */ + private void relax(Integer node) { + double nodeDist = distancesFromStart.get(node); + Collection neighbors; + + if (!this.probs.containsKey(node)) { + return; // node's neighbors are not known + } + + neighbors = this.probs.get(node).getAllProbs().keySet(); + + for (Integer n : neighbors) { + if (visited.contains(n)) { + continue; // skip visited nodes + } + + // n node's distance from path's source node + double nDist = nodeDist + getDistance(node, n); + + if (distancesFromStart.get(n) > nDist) { + // stored distance > found dist -> update + prevNodes.put(n, node); // for debugging + setDistance(n, nDist); + } + } + } + + /** + * Sets the distance from source node to a node + * @param n The node whose distance is set + * @param distance The distance of the node from the source node + */ + private void setDistance(Integer n, double distance) { + unvisited.remove(n); // remove node from old place in the queue + distancesFromStart.put(n, distance); // update distance + unvisited.add(n); // insert node to the new place in the queue + } + + /** + * Returns the "distance" between two nodes, i.e., the complement of the + * probability that the next node "from" meets is "to". Works only if there + * exist a probability value for "from" meeting "to". + * @param from The first node + * @param to The second node + * @return The distance between the two nodes + */ + private double getDistance(Integer from, Integer to) { + assert probs.containsKey(from) : "Node " + from + " has not met " + to + + " (it has met nodes " + probs.keySet() + ")"; + return ( 1 - probs.get(from).getProbFor(to) ); + } + + /** + * Comparator that compares two nodes by their distance from + * the source node. + */ + private class DistanceComparator implements + Comparator { + + /** + * Compares two map nodes by their distance from the source node + * @return -1, 0 or 1 if node1's distance is smaller, equal to, or + * bigger than node2's distance + */ + public int compare(Integer node1, Integer node2) { + double dist1 = distancesFromStart.get(node1); + double dist2 = distancesFromStart.get(node2); + + if (dist1 > dist2) { + return 1; + } + else if (dist1 < dist2) { + return -1; + } + else { + return node1.compareTo(node2); + } + } + } + + /** + * Simple Map implementation for storing distances. + */ + private class DistanceMap { + private HashMap map; + + /** + * Constructor. Creates an empty distance map + */ + public DistanceMap() { + this.map = new HashMap(); + } + + /** + * Returns the distance to a node. If no distance value + * is found, returns {@link MaxPropDijkstra#INFINITY} as the value. + * @param node The node whose distance is requested + * @return The distance to that node + */ + public double get(Integer node) { + Double value = map.get(node); + if (value != null) { + return value; + } + else { + return INFINITY; + } + } + + /** + * Puts a new distance value for a map node + * @param node The node + * @param distance Distance to that node + */ + public void put(Integer node, double distance) { + map.put(node, distance); + } + + /** + * Returns a string representation of the map's contents + * @return a string representation of the map's contents + */ + public String toString() { + return map.toString(); + } + } +} \ No newline at end of file diff --git a/routing/maxprop/MeetingProbabilitySet.java b/routing/maxprop/MeetingProbabilitySet.java new file mode 100644 index 000000000..022dd08f0 --- /dev/null +++ b/routing/maxprop/MeetingProbabilitySet.java @@ -0,0 +1,173 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.maxprop; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import core.SimClock; + +/** + * Class for storing and manipulating the meeting probabilities for the MaxProp + * router module. + */ +public class MeetingProbabilitySet { + public static final int INFINITE_SET_SIZE = Integer.MAX_VALUE; + /** meeting probabilities (probability that the next node one meets is X) */ + private Map probs; + /** the time when this MPS was last updated */ + private double lastUpdateTime; + /** the alpha parameter */ + private double alpha; + private int maxSetSize; + + /** + * Constructor. Creates a probability set with empty node-probability + * mapping. + * @param maxSetSize Maximum size of the probability set; when the set is + * full, smallest values are dropped when new are added + */ + public MeetingProbabilitySet(int maxSetSize, double alpha) { + this.alpha = alpha; + this.probs = new HashMap(); + if (maxSetSize == INFINITE_SET_SIZE || maxSetSize < 1) { + this.probs = new HashMap(); + this.maxSetSize = INFINITE_SET_SIZE; + } else { + this.probs = new HashMap(maxSetSize); + this.maxSetSize = maxSetSize; + } + this.lastUpdateTime = 0; + } + + /** + * Constructor. Creates a probability set with empty node-probability + * mapping and infinite set size + */ + public MeetingProbabilitySet() { + this(INFINITE_SET_SIZE, 1); + } + + /** + * Constructor. Creates a probability set with equal probability for + * all the given node indexes. + */ + public MeetingProbabilitySet(double alpha, + List initiallyKnownNodes) { + this(INFINITE_SET_SIZE, alpha); + double prob = 1.0/initiallyKnownNodes.size(); + for (Integer i : initiallyKnownNodes) { + this.probs.put(i, prob); + } + } + + /** + * Updates meeting probability for the given node index. + *
 P(b) = P(b)_old + alpha
+	 * Normalize{P}
+ * I.e., The probability of the given node index is increased by one and + * then all the probabilities are normalized so that their sum equals to 1. + * @param index The node index to update the probability for + */ + public void updateMeetingProbFor(Integer index) { + Map.Entry smallestEntry = null; + double smallestValue = Double.MAX_VALUE; + + this.lastUpdateTime = SimClock.getTime(); + + if (probs.size() == 0) { // first entry + probs.put(index, 1.0); + return; + } + + double newValue = getProbFor(index) + alpha; + probs.put(index, newValue); + + /* now the sum of all entries is 1+alpha; + * normalize to one by dividing all the entries by 1+alpha */ + for (Map.Entry entry : probs.entrySet()) { + entry.setValue(entry.getValue() / (1+alpha)); + if (entry.getValue() < smallestValue) { + smallestEntry = entry; + smallestValue = entry.getValue(); + } + + } + + if (probs.size() >= maxSetSize) { + core.Debug.p("Probsize: " + probs.size() + " dropping " + + probs.remove(smallestEntry.getKey())); + } + } + + public void updateMeetingProbFor(Integer index, double iet) { + probs.put(index, iet); + } + + /** + * Returns the current delivery probability value for the given node index + * @param index The index of the node to look the P for + * @return the current delivery probability value + */ + public double getProbFor(Integer index) { + if (probs.containsKey(index)) { + return probs.get(index); + } + else { + /* the node with the given index has not been met */ + return 0.0; + } + } + + /** + * Returns a reference to the probability map of this probability set + * @return a reference to the probability map of this probability set + */ + public Map getAllProbs() { + return this.probs; + } + + /** + * Returns the time when this probability set was last updated + * @return the time when this probability set was last updated + */ + public double getLastUpdateTime() { + return this.lastUpdateTime; + } + + /** + * Enables changing the alpha parameter dynamically + */ + public void setAlpha(double alpha) { + this.alpha = alpha; + } + + /** + * Returns a deep copy of the probability set + * @return a deep copy of the probability set + */ + public MeetingProbabilitySet replicate() { + MeetingProbabilitySet replica = new MeetingProbabilitySet( + this.maxSetSize, alpha); + + // do a deep copy + for (Map.Entry e : probs.entrySet()) { + replica.probs.put(e.getKey(), e.getValue().doubleValue()); + } + + replica.lastUpdateTime = this.lastUpdateTime; + return replica; + } + + /** + * Returns a String presentation of the probabilities + * @return a String presentation of the probabilities + */ + @Override + public String toString() { + return "probs: " + this.probs.toString(); + } +} \ No newline at end of file diff --git a/routing/maxprop/package.html b/routing/maxprop/package.html new file mode 100644 index 000000000..583c1fc11 --- /dev/null +++ b/routing/maxprop/package.html @@ -0,0 +1,8 @@ + + + + +Contains MaxProp routing module specific classes. + + + \ No newline at end of file diff --git a/routing/package.html b/routing/package.html new file mode 100644 index 000000000..4830dc966 --- /dev/null +++ b/routing/package.html @@ -0,0 +1,14 @@ + + + + +Contains all the router classes who decide how to handle the messages. +All router classes must be in this package and must extend the +{@link routing.MessageRouter} (when creating new routers, extending +{@link routing.ActiveRouter} might make sense) class so they can be +dynamically loaded to the simulator. The classes to load can be specified +through {@link core.Settings} class' settings source. See MessageRouter class +and classes extending it for details about the settings. + + + \ No newline at end of file diff --git a/routing/schedule/ScheduleDijkstra.java b/routing/schedule/ScheduleDijkstra.java new file mode 100644 index 000000000..fc7244173 --- /dev/null +++ b/routing/schedule/ScheduleDijkstra.java @@ -0,0 +1,211 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.schedule; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Set; + +/** + * Dijkstra's shortest path implementation for schedule data + */ +/* TODO: combine this with movement.map.DijkstraPathFinder? */ +public class ScheduleDijkstra { + /** Value for infinite distance */ + private static final Double INFINITY = Double.MAX_VALUE; + /** Initial size of the priority queue */ + private static final int PQ_INIT_SIZE = 11; + + /** Map of the times when one could be at certain node */ + private TimeMap times; + /** Set of already visited nodes (where the shortest path is known) */ + private Set visited; + /** Priority queue of unvisited nodes discovered so far */ + private Queue unvisited; + /** Map of previous schedule on the shortest path(s) */ + private Map prevHops; + /** Oracle that know all schedules */ + private ScheduleOracle oracle; + + /** + * Constructor. + * @param oracle The schedule oracle + * all nodes are OK + */ + public ScheduleDijkstra(ScheduleOracle oracle) { + this.oracle = oracle; + } + + /** + * Initializes a new search with a source node + * @param node The path's source node + * @param time The time when the path starts + */ + private void initWith(Integer node, double time) { + this.unvisited = new PriorityQueue(PQ_INIT_SIZE, + new DurationComparator()); + this.visited = new HashSet(); + this.prevHops = new HashMap(); + this.times = new TimeMap(); + + this.times.put(node, time); + this.unvisited.add(node); + } + + /** + * Finds and returns the fastest path between two destinations + * @param from The source of the path + * @param to The destination of the path + * @param time The time when the path starts + * @return a shortest path between the source and destination nodes in + * a list of Integers or an empty list if such path is not available + */ + public List getShortestPath(Integer from, Integer to, + double time){ + List path = new ArrayList(); + assert time >= 0.0 : "Can't use negative start time"; + + if (from.compareTo(to) == 0) { + return path; + } + + initWith(from, time); + Integer node = null; + + while ((node = unvisited.poll()) != null) { + if (node.equals(to)) { + break; + } + + visited.add(node); + relax(node); + } + + if (node != null) { // found a path + ScheduleEntry prev = prevHops.get(to); + while (prev.getFrom() != from) { + path.add(0, prev); + prev = prevHops.get(prev.getFrom()); + } + + path.add(0, prev); + } + + return path; + } + + /** + * Relaxes the neighbors of a node (updates the shortest distances). + * @param node The node whose neighbors are relaxed + */ + private void relax(Integer node) { + double timeNow = times.get(node); + int to; + double timeTo; + + for (ScheduleEntry se : oracle.getConnected(node, timeNow)) { + to = se.getTo(); + if (visited.contains(to)) { + continue; // skip visited nodes + } + + timeTo = se.getTime() + se.getDuration(); + + if (timeTo < times.get(to)) { + prevHops.put(to, se); + setTime(to, timeTo); + } + } + } + + /** + * Sets the time when at a node + * @param n The node whose time is set + * @param time The time when at given node + */ + private void setTime(Integer n, double time) { + unvisited.remove(n); + times.put(n, time); + unvisited.add(n); + } + + /** + * Comparator that compares two nodes by their journey duration + */ + private class DurationComparator implements Comparator { + + /** + * Compares two nodes by their time to get there + * @return -1, 0 or 1 if node1's time is smaller, equal to, or + * bigger than node2's + */ + public int compare(Integer node1, Integer node2) { + double time1 = times.get(node1); + double time2 = times.get(node2); + + if (time1 > time2) { + return 1; + } + else if (time1 < time2) { + return -1; + } + else { + return 0; + } + } + } + + private class TimeMap { + private HashMap map; + + /** + * Constructor. Creates an empty map + */ + public TimeMap() { + this.map = new HashMap(); + } + + /** + * Returns the currently known smallest time one has a path for to the + * given node. If no time value is found, returns + * {@link ScheduleDijkstra#INFINITY} as the value. + * @param node The node whose time is requested + * @return The time when one could be at that node + */ + public double get(Integer node) { + Double value = map.get(node); + if (value != null) { + return value; + } + else { + return INFINITY; + } + } + + /** + * Puts a new time value for a node + * @param node The node + * @param time Time at that node + */ + public void put(Integer node, double time) { + map.put(node, time); + } + + /** + * Returns a string representation of the map's contents + * @return a string representation of the map's contents + */ + public String toString() { + return map.toString(); + } + } +} \ No newline at end of file diff --git a/routing/schedule/ScheduleEntry.java b/routing/schedule/ScheduleEntry.java new file mode 100644 index 000000000..b1c0183cc --- /dev/null +++ b/routing/schedule/ScheduleEntry.java @@ -0,0 +1,111 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.schedule; + +import java.io.Serializable; + +public class ScheduleEntry implements Serializable { + private static final long serialVersionUID = 42L; + + private double time; + private int from; + private int to; + private int via; + private double delta; + private double duration; + private int usageCount; + + /** + * Constructor of new schedule entry + * @param time When the journey from "from" starts + * @param from The source + * @param via The node that takes us there (or -1 if n/a) + * @param to The destination + * @param duration Time it takes from the source to destination + */ + public ScheduleEntry(double time, int from, int via, int to, + double duration) { + this.time = time; + this.from = from; + this.via = via; + this.to = to; + this.duration = duration; + this.delta = 0; + this.usageCount = 0; + } + + /** + * Returns time + delta + * @return the time + */ + public double getTime() { + return time + delta; + } + + /** + * @return the destination + */ + public int getTo() { + return to; + } + + /** + * @return the source + */ + public int getFrom() { + return from; + } + + /** + * @return the via + */ + public int getVia() { + return via; + } + + /** + * Return the time it takes to get from source to destination + * @return the duration + */ + public double getDuration() { + return duration; + } + + public double getDestinationTime() { + return this.getTime() + this.getDuration(); + } + + /** + * @return the delta + */ + public double getDelta() { + return delta; + } + + /** + * @param delta the delta to set + */ + public void setDelta(double delta) { + this.delta = delta; + } + + /** + * @return the usageCount + */ + public int getUsageCount() { + return usageCount; + } + + public void increaseUsageCount() { + this.usageCount++; + } + + @Override + public String toString() { + return time + "(+" + delta + "): " + from + "->" + + (via > 0 ? via + "->" : "") + to + " (" + duration + ")"; + } + +} \ No newline at end of file diff --git a/routing/schedule/ScheduleOracle.java b/routing/schedule/ScheduleOracle.java new file mode 100644 index 000000000..f7125c691 --- /dev/null +++ b/routing/schedule/ScheduleOracle.java @@ -0,0 +1,91 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.schedule; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ScheduleOracle implements Serializable{ + private static final long serialVersionUID = 42L; + + Map> schedules; + + public ScheduleOracle() { + this.schedules = new HashMap>(); + } + + /** + * Adds a new schedule entry to the oracle + * @param start Start time + * @param from Source of the connection + * @param via The node that goes from "from" to "via" (or -1 for n/a) + * @param to Destination of the connection + * @param duration How long it takes to get to destination + */ + public void addEntry(double start, int from, int via, int to, + double duration) { + List list = schedules.get(from); + + if (list == null) { /* first entry for the from */ + list = new ArrayList(); + schedules.put(from, list); + } + + list.add(new ScheduleEntry(start, from, via, to, duration)); + } + + /** + * Adds a new schedule entry to the oracle + * @param start Start time + * @param from Source of the connection + * @param to Destination of the connection + * @param duration How long it takes to get to destination + */ + public void addEntry(double start, int from, int to,double duration) { + addEntry(start, from, -1, to, duration); + } + + /** + * Returns a list of schedule entries for nodes reachable after given time + * from the given node + * @param from The source node + * @param time Time to start + * @return List of reachable nodes + */ + public List getConnected(int from, double time) { + List connected = new ArrayList(); + List all = schedules.get(from); + + if (all == null) { + return connected; + } + + for (ScheduleEntry s : all) { + if (s.getTime() >= time) { + connected.add(s); + } + } + + return connected; + } + + /** + * Returns all schedule entries + * @return all schedule entries + */ + public List getEntries() { + List entries = new ArrayList(); + for (List list : schedules.values()) { + for (ScheduleEntry se : list) { + entries.add(se); + } + } + + return entries; + } +} \ No newline at end of file diff --git a/routing/util/EnergyModel.java b/routing/util/EnergyModel.java new file mode 100644 index 000000000..bb9213e3c --- /dev/null +++ b/routing/util/EnergyModel.java @@ -0,0 +1,211 @@ +/* + * Copyright 2011 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.util; + +import java.util.Random; + +import core.*; + +/** + * Energy model for routing modules. Handles power use from scanning (device + * discovery), scan responses, and data transmission. If scanning is done more + * often than 1/s, constant scanning is assumed (and power consumption does not + * increase from {@link #scanEnergy} value). + */ +public class EnergyModel implements ModuleCommunicationListener { + /** Initial units of energy -setting id ({@value}). Can be either a + * single value, or a range of two values. In the latter case, the used + * value is a uniformly distributed random value between the two values. */ + public static final String INIT_ENERGY_S = "initialEnergy"; + + /** Energy usage per scanning (device discovery) -setting id ({@value}). */ + public static final String SCAN_ENERGY_S = "scanEnergy"; + + /** Energy usage per scanning (device discovery) response -setting id + * ({@value}). */ + public static final String SCAN_RSP_ENERGY_S = "scanResponseEnergy"; + + /** Energy usage per second when sending -setting id ({@value}). */ + public static final String TRANSMIT_ENERGY_S = "transmitEnergy"; + + /** Base energy usage per second -setting id ({@value}). */ + public static final String BASE_ENERGY_S = "baseEnergy"; + + /** Energy update warmup period -setting id ({@value}). Defines the + * simulation time after which the energy level starts to decrease due to + * scanning, transmissions, etc. Default value = 0. If value of "-1" is + * defined, uses the value from the report warmup setting + * {@link report.Report#WARMUP_S} from the namespace + * {@value report.Report#REPORT_NS}. */ + public static final String WARMUP_S = "energyWarmup"; + + /** {@link ModuleCommunicationBus} identifier for the "current amount of + * energy left" variable. Value type: double */ + public static final String ENERGY_VALUE_ID = "Energy.value"; + + /** Initial energy levels from the settings */ + private final double[] initEnergy; + private double warmupTime; + /** current energy level */ + private double currentEnergy; + /** energy usage per scan */ + private double scanEnergy; + /** energy usage per transmitted byte */ + private double transmitEnergy; + /** energy usage per device discovery response */ + private double scanResponseEnergy; + /** sim time of the last energy updated */ + private double lastUpdate; + private ModuleCommunicationBus comBus; + private static Random rng = null; + + /** + * Constructor. Creates a new message router based on the settings in + * the given Settings object. + * @param s The settings object + */ + public EnergyModel(Settings s) { + this.initEnergy = s.getCsvDoubles(INIT_ENERGY_S); + + if (this.initEnergy.length != 1 && this.initEnergy.length != 2) { + throw new SettingsError(INIT_ENERGY_S + " setting must have " + + "either a single value or two comma separated values"); + } + + this.scanEnergy = s.getDouble(SCAN_ENERGY_S); + this.transmitEnergy = s.getDouble(TRANSMIT_ENERGY_S); + this.scanResponseEnergy = s.getDouble(SCAN_RSP_ENERGY_S); + + if (s.contains(WARMUP_S)) { + this.warmupTime = s.getInt(WARMUP_S); + if (this.warmupTime == -1) { + this.warmupTime = new Settings(report.Report.REPORT_NS). + getInt(report.Report.WARMUP_S); + } + } + else { + this.warmupTime = 0; + } + } + + /** + * Copy constructor. + * @param proto The model prototype where setting values are copied from + */ + protected EnergyModel(EnergyModel proto) { + this.initEnergy = proto.initEnergy; + setEnergy(this.initEnergy); + this.scanEnergy = proto.scanEnergy; + this.transmitEnergy = proto.transmitEnergy; + this.warmupTime = proto.warmupTime; + this.scanResponseEnergy = proto.scanResponseEnergy; + this.comBus = null; + this.lastUpdate = 0; + } + + public EnergyModel replicate() { + return new EnergyModel(this); + } + + /** + * Sets the current energy level into the given range using uniform + * random distribution. + * @param range The min and max values of the range, or if only one value + * is given, that is used as the energy level + */ + protected void setEnergy(double range[]) { + if (range.length == 1) { + this.currentEnergy = range[0]; + } + else { + if (rng == null) { + rng = new Random((int)(range[0] + range[1])); + } + this.currentEnergy = range[0] + + rng.nextDouble() * (range[1] - range[0]); + } + } + + /** + * Returns the current energy level + * @return the current energy level + */ + public double getEnergy() { + return this.currentEnergy; + } + + /** + * Updates the current energy so that the given amount is reduced from it. + * If the energy level goes below zero, sets the level to zero. + * Does nothing if the warmup time has not passed. + * @param amount The amount of energy to reduce + */ + protected void reduceEnergy(double amount) { + if (SimClock.getTime() < this.warmupTime) { + return; + } + + if (comBus == null) { + return; /* model not initialized (via update) yet */ + } + + if (amount >= this.currentEnergy) { + comBus.updateProperty(ENERGY_VALUE_ID, 0.0); + } else { + comBus.updateDouble(ENERGY_VALUE_ID, -amount); + } + + } + + /** + * Reduces the energy reserve for the amount that is used when another + * host connects (does device discovery) + */ + public void reduceDiscoveryEnergy() { + reduceEnergy(this.scanResponseEnergy); + } + + /** + * Reduces the energy reserve for the amount that is used by sending data + * and scanning for the other nodes. + */ + public void update(NetworkInterface iface, ModuleCommunicationBus comBus) { + double simTime = SimClock.getTime(); + double delta = simTime - this.lastUpdate; + + if (this.comBus == null) { + this.comBus = comBus; + this.comBus.addProperty(ENERGY_VALUE_ID, this.currentEnergy); + this.comBus.subscribe(ENERGY_VALUE_ID, this); + } + + if (simTime > this.lastUpdate && iface.isTransferring()) { + /* sending or receiving data */ + reduceEnergy(delta * this.transmitEnergy); + } + this.lastUpdate = simTime; + + if (iface.isScanning()) { + /* scanning at this update round */ + if (iface.getTransmitRange() > 0) { + if (delta < 1) { + reduceEnergy(this.scanEnergy * delta); + } else { + reduceEnergy(this.scanEnergy); + } + } + } + } + + /** + * Called by the combus if the energy value is changed + * @param key The energy ID + * @param newValue The new energy value + */ + public void moduleValueChanged(String key, Object newValue) { + this.currentEnergy = (Double)newValue; + } + +} \ No newline at end of file diff --git a/routing/util/MessageTransferAcceptPolicy.java b/routing/util/MessageTransferAcceptPolicy.java new file mode 100644 index 000000000..5541150f4 --- /dev/null +++ b/routing/util/MessageTransferAcceptPolicy.java @@ -0,0 +1,325 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.util; + +import java.util.ArrayList; + +import util.Range; +import util.Tuple; + +import core.ArithmeticCondition; +import core.Connection; +import core.DTNHost; +import core.Message; +import core.ModuleCommunicationBus; +import core.Settings; + +/** + *

Message transfer accepting policy module. Can be used to decide whether + * certain messages should be accepted or not. Shared by a whole node group, but + * uses the module communication bus of each node in question.

+ *

Supports 3 different modes: "simple policy", Hop Count, and + * ModuleCommunicationBus (MCB) values. With simple policy, hosts that are + * accepted as the source of a message (i.e., the original message sender) when + * receiving a message are listed (comma separated values) using the + * {@link #FROM_RPOLICY_S} setting + * (when sending, using {@link #FROM_SPOLICY_S}) and hosts that are accepted as + * the destination when receiving are listed using {@link #TO_RPOLICY_S} + * (and when sending, using {@link #TO_SPOLICY_S}). By default, any message is + * accepted.

+ * With ModuleCommunicationBus values, the amount of conditions is first defined + * with {@link #NROF_MCBCS_S} and sending/receiving conditions are defined + * as {@link ArithmeticCondition} with {@link #MCBACS_S} or {@link #MCBACR_S} + * and the ModuleCommuncationBus IDs where to get values from to use with the + * condition with {@link #MCBCVS_S} and {@link #MCBCVR_S}.

+ *

The MCB conditions are checked first, and if none of them match, + * simple policy conditions are checked. If they don't exists, + * or one of them matches, hop count policy is checked. If that doesn't exist + * or matches to message's hop count, transfer is accepted. Otherwise transfer + * is denied. + *

+ * @author Ari + */ +public class MessageTransferAcceptPolicy { + + /** Namespace for all "Message Transfer Accept policy" settings ({@value})*/ + public static final String MTA_POLICY_NS = "mtaPolicy"; + + /** Number of Module Communication Bus Conditions -setting id ({@value}). + * Two comma separated values. Defines the number of receiving and number of + * sending conditions to read from the settings. */ + public static final String NROF_MCBCS_S = "nrofMCBACs"; + + /** Module Communication Bus Arithmetic Condition for Receiving -setting id + * ({@value}). {@link ArithmeticCondition}. Defines one arithmetic condition + * to use for receiving messages. */ + public static final String MCBACR_S = "MCBRcondition"; + /** Module Communication Bus Arithmetic Condition for Sending -setting id + * ({@value}). {@link ArithmeticCondition}. */ + public static final String MCBACS_S = "MCBScondition"; + + /** Module Communication Bus Condition Value for Receiving -setting id + * ({@value}). String. Defines the ID to use with the receiving + * condition. */ + public static final String MCBCVR_S = "MCBRvalue"; + /** Module Communication Bus Condition Value for Sending -setting id + * ({@value}). String. Defines the ID to use with the sending + * condition. */ + public static final String MCBCVS_S = "MCBSvalue"; + + /** The valued used in to-policy to refer to this host ({@value}) */ + public static final int TO_ME_VALUE = -1; + + /** Simple-policy accept-to -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the destination of a + * message when receiving messages. Special value {@link #TO_ME_VALUE} + * refers to this host. */ + public static final String TO_RPOLICY_S = "toReceivePolicy"; + + /** Simple-policy accept-from -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the source of a + * message when receiving messages. Special value {@link #TO_ME_VALUE} + * refers to this host. */ + public static final String FROM_RPOLICY_S = "fromReceivePolicy"; + + /** Simple-policy accept-to -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the destination of a + * message when sending messages. Special value {@link #TO_ME_VALUE} refers + * to this host (but doesn't usually make much sense here). */ + public static final String TO_SPOLICY_S = "toSendPolicy"; + + /**

Simple-policy accept-from -setting id ({@value}). Integer list. + * Defines the addresses of the hosts accepted as the source of a + * message when sending messages. Special value {@link #TO_ME_VALUE} refers + * to this host.

+ *

Note: if this setting is defined and the {@link #TO_ME_VALUE} + * is NOT listed, the hosts own messages are not sent anywhere.

*/ + public static final String FROM_SPOLICY_S = "fromSendPolicy"; + + /** Hop count forwarding receive policy -setting id ({@value}). + * {@link ArithmeticCondition}. Defines condition for the message hop + * count; if the condition does not match, the message is rejected, + * unless it is destined to this node. */ + public static final String HOPCOUNT_RPOLICY_S = "hopCountReceivePolicy"; + /** Hop count forwarding send policy -setting id ({@value}). + * {@link ArithmeticCondition}. Defines condition for the message hop + * count; if the condition does not match, the message is not offered + * to other nodes, unless it would be delivered to the final destination. */ + public static final String HOPCOUNT_SPOLICY_S = "hopCountSendPolicy"; + + private ArrayList> recvConditions = null; + private ArrayList> sendConditions = null; + + private Range[] toSendPolicy = null; + private Range[] fromSendPolicy = null; + private Range[] toReceivePolicy = null; + private Range[] fromReceivePolicy = null; + private ArithmeticCondition hopCountSendPolicy = null; + private ArithmeticCondition hopCountReceivePolicy = null; + + public MessageTransferAcceptPolicy(Settings nsSettings) { + Settings s; + + if (! nsSettings.contains(MTA_POLICY_NS)) { + return; /* no (or "default") policy */ + } + + s = new Settings(nsSettings.getSetting(MTA_POLICY_NS)); + addMCBCs(s); + + if (s.contains(TO_SPOLICY_S)) { + this.toSendPolicy = s.getCsvRanges(TO_SPOLICY_S); + } + if (s.contains(FROM_SPOLICY_S)) { + this.fromSendPolicy = s.getCsvRanges(FROM_SPOLICY_S); + } + if (s.contains(TO_RPOLICY_S)) { + this.toReceivePolicy = s.getCsvRanges(TO_RPOLICY_S); + } + if (s.contains(FROM_RPOLICY_S)) { + this.fromReceivePolicy = s.getCsvRanges(FROM_RPOLICY_S); + } + if (s.contains(HOPCOUNT_SPOLICY_S)) { + hopCountSendPolicy = s.getCondition(HOPCOUNT_SPOLICY_S); + } + if (s.contains(HOPCOUNT_RPOLICY_S)) { + hopCountReceivePolicy = s.getCondition(HOPCOUNT_RPOLICY_S); + } + } + + /** + * Adds MessageCommunicationBus Conditions + * @param s Settings where the conditions are read from + */ + private void addMCBCs(Settings s) { + if (!s.contains(NROF_MCBCS_S)) { + return; /* no transfer policy defined */ + } + + int[] nrof = s.getCsvInts(NROF_MCBCS_S); + if (nrof[0] > 0) { /* create lists only if needed */ + this.recvConditions = + new ArrayList>(); + } + if (nrof[1] > 0) { + this.sendConditions = + new ArrayList>(); + } + + addConditions(s, MCBACR_S, MCBCVR_S, this.recvConditions, nrof[0]); + addConditions(s, MCBACS_S, MCBCVS_S, this.sendConditions, nrof[1]); + } + + /** + * Read conditions from the settings and add them to the given list + * @param s The settings object + * @param cPrefix Condition setting prefix + * @param vPrefix Value setting prefix + * @param list The list to add conditions + * @param nrof The number of settings to read + */ + private void addConditions(Settings s, String cPrefix, String vPrefix, + ArrayList> list, + int nrof) { + for (int i=1; i<=nrof; i++) { + ArithmeticCondition ac = s.getCondition(cPrefix + i); + String mcbValue = s.getSetting(vPrefix + i); + list.add(new Tuple(mcbValue, ac)); + } + } + + /** + * Checks all the Module Communication Bus conditions and returns false + * if at least one of them failed. + * @param mcb The module communication bus to use + * @param receiving Should check using the receiving conditions list; + * if false, the sending conditions list is used + * @return true if all conditions evaluated to true + */ + private boolean checkMcbConditions(ModuleCommunicationBus mcb, + boolean receiving) { + ArrayList> list = + (receiving ? this.recvConditions : this.sendConditions); + + if (list == null) { + return true; + } + + for (Tuple t : list) { + if (!mcb.containsProperty(t.getKey())) { + continue; /* no value in the bus; can't fail condition */ + } + if (t.getValue().isTrueFor(mcb.getDouble(t.getKey(), 0))){ + return false; + } + } + + return true; + } + + /** + * Checks if the host's address is contained in the policy list + * (or {@value #TO_ME_VALUE} is contained and the address matches to + * thisHost parameter) + * @param host The hosts whose address to check + * @param policy The list of accepted addresses + * @param thisHost The address of this host + * @return True if the address was in the policy list, or the policy list + * was null + */ + private boolean checkSimplePolicy(DTNHost host, Range [] policy, + int thisHost) { + int address; + + if (policy == null) { + return true; + } + + address = host.getAddress(); + + for (Range r : policy) { + if (r.isInRange(TO_ME_VALUE) && address == thisHost) { + return true; + } + else if (r.isInRange(address)) { + return true; + } + } + return false; + } + + /** + * Checks the given messages hop count against the given policy arithmetic + * condition + * @param m The message whose hop count is checked + * @param ac The policy arithmetic condition + * @return True if the condition is null or the hop count matches to the + * condition, false otherwise + */ + private boolean checkHopCountPolicy(Message m, ArithmeticCondition ac) { + if (ac == null) { + return true; + } else { + return ac.isTrueFor(m.getHopCount()); + } + } + + /** + * Returns true if the given message, using the given connection, is OK + * to send from "from" to "to" host. + * @param from The sending host + * @param to The receiving host + * @param con The connection used by the hosts + * @param m The message to transfer + * @return True if the message is OK to transfer, false is not + */ + public boolean acceptSending(DTNHost from, DTNHost to, Connection con, + Message m) { + if (!checkMcbConditions(from.getComBus(), false)) { + return false; + } + + int myAddr = from.getAddress(); + if (! (checkSimplePolicy(m.getTo(), this.toSendPolicy, myAddr) && + checkSimplePolicy(m.getFrom(), this.fromSendPolicy, myAddr)) ) { + return false; + } + + if (m.getTo() != to && + !checkHopCountPolicy(m, this.hopCountSendPolicy)){ + return false; + } + + return true; + } + + /** + * Returns true if the given message is OK to receive from "from" to + * "to" host. + * @param from The sending host + * @param to The receiving host + * @param m The message to transfer + * @return True if the message is OK to transfer, false is not + */ + public boolean acceptReceiving(DTNHost from, DTNHost to, Message m) { + if (! checkMcbConditions(to.getComBus(), true)) { + return false; + } + + int myAddr = to.getAddress(); + if (! (checkSimplePolicy(m.getTo(), this.toReceivePolicy,myAddr) && + checkSimplePolicy(m.getFrom(), this.fromReceivePolicy, myAddr)) ) { + return false; + } + + if (m.getTo() != to && + !checkHopCountPolicy(m, this.hopCountReceivePolicy)) { + return false; + } + + return true; + } + +} \ No newline at end of file diff --git a/routing/util/RoutingInfo.java b/routing/util/RoutingInfo.java new file mode 100644 index 000000000..00c35b35d --- /dev/null +++ b/routing/util/RoutingInfo.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class for storing routing related information in a tree form for + * user interface(s). + */ +public class RoutingInfo { + private String text; + private List moreInfo = null; + + /** + * Creates a routing info based on a text. + * @param infoText The text of the info + */ + public RoutingInfo(String infoText) { + this.text = infoText; + } + + /** + * Creates a routing info based on any object. Object's + * toString() method's output is used as the info text. + * @param o The object this info is based on + */ + public RoutingInfo(Object o) { + this.text = o.toString(); + } + + /** + * Adds child info object for this routing info. + * @param info The info object to add. + */ + public void addMoreInfo(RoutingInfo info) { + if (this.moreInfo == null) { // lazy creation + this.moreInfo = new ArrayList(); + } + this.moreInfo.add(info); + } + + /** + * Returns the child routing infos of this info. + * @return The children of this info or an empty list if this info + * doesn't have any children. + */ + public List getMoreInfo() { + if (this.moreInfo == null) { + return new ArrayList(0); + } + return this.moreInfo; + } + + /** + * Returns the info text of this routing info. + * @return The info text + */ + public String toString() { + return this.text; + } + +} diff --git a/test/AbstractRouterTest.java b/test/AbstractRouterTest.java new file mode 100644 index 000000000..59bd6ffae --- /dev/null +++ b/test/AbstractRouterTest.java @@ -0,0 +1,154 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import routing.MessageRouter; +import core.Coord; +import core.DTNHost; +import core.MessageListener; +import core.NetworkInterface; +import core.SimClock; + +/** + * Superclass for router tests. Sets up the environment by creating + * multiple hosts with router set by {@link #setRouterProto(MessageRouter)} + */ +public abstract class AbstractRouterTest extends TestCase { + protected MessageChecker mc; + protected TestUtils utils; + protected static TestSettings ts = new TestSettings(); + + protected static final int BUFFER_SIZE = 100; + protected static final int TRANSMIT_SPEED = 10; + protected SimClock clock; + + protected Coord c0 = new Coord(0,0); + protected Coord farAway = new Coord(100000,100000); + protected static final Coord disconnectLocation = new Coord(900000,900000); + protected DTNHost h0; + protected DTNHost h1; + protected DTNHost h2; + protected DTNHost h3; + protected DTNHost h4; + protected DTNHost h5; + protected DTNHost h6; + protected static final String msgId1 = "MSG_ID1"; + protected static final String msgId2 = "MSG_ID2"; + protected static final String msgId3 = "MSG_ID3"; + protected static final String msgId4 = "MSG_ID4"; + protected static final String msgId5 = "MSG_ID5"; + + protected MessageRouter routerProto; + + protected void setUp() throws Exception { + super.setUp(); + this.mc = new MessageChecker(); + mc.reset(); + this.clock = SimClock.getInstance(); + clock.setTime(0); + + List ml = new ArrayList(); + ml.add(mc); + + ts.setNameSpace(TestUtils.IFACE_NS); + ts.putSetting(NetworkInterface.TRANSMIT_SPEED_S, ""+TRANSMIT_SPEED); + + this.utils = new TestUtils(null,ml,ts); + this.utils.setMessageRouterProto(routerProto); + core.NetworkInterface.reset(); + core.DTNHost.reset(); + this.h0 = utils.createHost(c0, "h0"); + this.h1 = utils.createHost(c0, "h1"); + this.h2 = utils.createHost(c0, "h2"); + this.h3 = utils.createHost(c0, "h3"); + this.h4 = utils.createHost(c0, "h4"); + this.h5 = utils.createHost(c0, "h5"); + this.h6 = utils.createHost(c0, "h6"); + } + + protected void setRouterProto(MessageRouter r) { + this.routerProto = r; + } + + /** + * Checks that mc contains only nrof create-events and nothing else + * @param nrof how many creates to expect + */ + protected void checkCreates(int nrof) { + for (int i=0; i delete ACKed message + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(msgId, mc.getLastMsg().getId()); + assertEquals(from, mc.getLastFrom()); + } + + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); // finished transfer + assertEquals(msgId, mc.getLastMsg().getId()); + assertEquals(from, mc.getLastFrom()); + assertEquals(to, mc.getLastTo()); + + if (isFirstDelivery) { + assertTrue(mc.getLastFirstDelivery()); + } + } + + protected void deliverMessage(DTNHost from, DTNHost to, String msgId, + int msgSize, boolean firstDelivery) { + assertFalse("MC contained " + mc.getLastType(), mc.next()); + from.update(true); + to.update(true); + checkTransferStart(from, to, msgId); + clock.advance((1.0*msgSize)/TRANSMIT_SPEED); + from.update(true); + to.update(true); + checkDelivered(from, to, msgId, firstDelivery); + } + + /** + * Moves node to disconnectLocation (far away from c0), updates it and + * restores the node location + * @param node Node to disconnect + */ + protected static void disconnect(DTNHost node) { + Coord loc = node.getLocation(); + node.setLocation(disconnectLocation); + node.update(true); + node.setLocation(loc); + } + + public String toString() { + return "MC: " + mc.toString(); + } + +} diff --git a/test/ActivenessHandlerTest.java b/test/ActivenessHandlerTest.java new file mode 100644 index 000000000..a56488b9e --- /dev/null +++ b/test/ActivenessHandlerTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import util.ActivenessHandler; +import junit.framework.TestCase; +import core.SimClock; + +public class ActivenessHandlerTest extends TestCase { + private ActivenessHandler ah; + private SimClock clock; + private double in = 3.0; + private double out = 7.0; + + private String moreTimes = ", 100,110, 210,220, 350,400"; + + protected void setUp() throws Exception { + super.setUp(); + TestSettings ts = new TestSettings(); + + ts.putSetting(ActivenessHandler.ACTIVE_TIMES_S, in + "," + out + + moreTimes); + ah = new ActivenessHandler(ts); + clock = SimClock.getInstance(); + SimClock.reset(); + } + + public void testIsActive() { + assertFalse(ah.isActive()); + clock.setTime(in); + assertTrue(ah.isActive()); + clock.setTime(in + 0.1); + assertTrue(ah.isActive()); + clock.advance(1.0); + assertTrue(ah.isActive()); + clock.advance(10.0); + assertFalse(ah.isActive()); + } + + + public void testMoreTimes() { + // test second value tuple + clock.setTime(98); + assertFalse(ah.isActive()); + clock.setTime(100); + assertTrue(ah.isActive()); + clock.setTime(105); + assertTrue(ah.isActive()); + clock.setTime(112); + assertFalse(ah.isActive()); + + + // test zero ease + clock.setTime(209.9); + assertFalse(ah.isActive()); + clock.setTime(210); + assertTrue(ah.isActive()); + clock.setTime(220); + assertTrue(ah.isActive()); + clock.setTime(220.1); + assertFalse(ah.isActive()); + + // test last tuple + clock.setTime(360); + assertTrue(ah.isActive()); + clock.setTime(450); + assertFalse(ah.isActive()); + + } + +} + diff --git a/test/AdjacencyGraphvizReportTest.java b/test/AdjacencyGraphvizReportTest.java new file mode 100644 index 000000000..79049fd2d --- /dev/null +++ b/test/AdjacencyGraphvizReportTest.java @@ -0,0 +1,106 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Vector; + +import junit.framework.TestCase; +import report.AdjacencyGraphvizReport; +import core.ConnectionListener; +import core.Coord; +import core.DTNHost; + +public class AdjacencyGraphvizReportTest extends TestCase { + private File outFile; + private TestUtils utils; + private AdjacencyGraphvizReport r; + + private static final int NROF = 3; + + public void setUp() throws IOException { + TestSettings ts = new TestSettings(); + outFile = File.createTempFile("adjgvtest", ".tmp"); + outFile.deleteOnExit(); + + ts.putSetting("AdjacencyGraphvizReport.output", outFile.getAbsolutePath()); + ts.putSetting("AdjacencyGraphvizReport.interval" , ""); + r = new AdjacencyGraphvizReport(); + Vector cl = new Vector(); + cl.add(r); + + utils = new TestUtils(cl, null, ts); + } + + private void generateConnections() { + Coord c1 = new Coord(0,0); + Coord c2 = new Coord(1,0); + Coord c3 = new Coord(2,0); + Coord c4 = new Coord(0,2); + + utils.setTransmitRange(2); + DTNHost h1 = utils.createHost(c1,"h1"); + DTNHost h2 = utils.createHost(c2,"h2"); + DTNHost h3 = utils.createHost(c3,"h3"); + DTNHost h4 = utils.createHost(c4,"h4"); + + h1.connect(h2); + h2.connect(h3); + // h1--h2--h3 + + h2.setLocation(new Coord(1,10)); + h2.update(true); + // h2 + // h1 h3 + + h2.setLocation(c2); + h2.connect(h3); // reconnect + // h1 h2--h3 + + h1.connect(h4); + + c4.translate(-5, 0); + h1.update(true); // disconnect h1-h4 + c4.translate(5, 0); + h1.connect(h4); // reconnect h1-h4 + } + + public void testDone() throws IOException { + BufferedReader reader; + List lines = new ArrayList(); + + generateConnections(); + r.done(); + + reader = new BufferedReader(new FileReader(outFile)); + + // check the first line of output + assertEquals("graph " + AdjacencyGraphvizReport.GRAPH_NAME + + " {", reader.readLine()); + + for (int i=0; i li = new ArrayList(); + li.add(ni); + + ModuleCommunicationBus comBus = new ModuleCommunicationBus(); + h[i] = new TestDTNHost(li,comBus, testSettings); + m[i] = new Message(h[0], h[i],""+i, size[i]); + } + + con(h[0], h[1]); + con(h[0], h[2]); + con(h[1], h[3]); + con(h[2], h[4]); + con(h[3], h[4]); + + c[0].startTransfer(h[0], m[0]); + c[1].startTransfer(h[0], m[1]); + c[2].startTransfer(h[1], m[2]); + conCount = 3; + } + + private void con(DTNHost from, DTNHost to) { + c[index] = new CBRConnection(from, from.getInterfaces().get(0), to, to.getInterfaces().get(0), speed[index]); + index++; + } + + public void testIsInitiator() { + assertTrue(c[0].isInitiator(h[0])); + assertFalse(c[0].isInitiator(h[1])); + assertFalse(c[0].isInitiator(h[2])); + assertTrue(c[3].isInitiator(h[2])); + } + + public void testStartTransfer() { + assertTrue(h[1].recvFrom == h[0]); + assertTrue(h[1].recvMessage.getId().equals(m[0].getId())); + assertTrue(h[2].recvFrom == h[0]); + assertTrue(h[2].recvMessage.getId().equals(m[1].getId())); + } + + public void testAbortTransfer() { + assertTrue(h[1].abortedId == null); + assertFalse(c[0].isMessageTransferred()); + + c[0].abortTransfer(); + + assertTrue(h[1].abortedId != null); + assertTrue(h[1].abortedId.equals(m[0].getId())); + assertTrue(c[0].isMessageTransferred()); + } + + public void testGetTransferDoneTime() { + double doneTime; + + doneTime = START_TIME + (1.0 * m[0].getSize()) / speed[0]; + assertEquals(doneTime, c[0].getTransferDoneTime()); + + doneTime = START_TIME + (1.0 * m[1].getSize()) / speed[1]; + assertEquals(doneTime, c[1].getTransferDoneTime()); + } + + public void testGetRemainingByteCount() { + double STEP = 0.1; + int transferred; + + assertEquals(size[0], c[0].getRemainingByteCount()); + assertEquals(size[1], c[1].getRemainingByteCount()); + + clock.setTime(START_TIME + STEP); + for (int i=0; i cl = new Vector(); + cl.add(ctr); + cl.add(ictr); + + TestUtils utils = new TestUtils(cl, null, ts); + generateConnections(utils); + ctr.done(); + ictr.done(); + ctReader = new BufferedReader(new FileReader(outFile)); + ictReader = new BufferedReader(new FileReader(iOutFile)); + + } + + private void generateConnections(TestUtils utils) { + Coord c1 = new Coord(0,0); + Coord c2 = new Coord(1,0); + Coord c3 = new Coord(2,0); + + utils.setTransmitRange(3); // make sure everyone can connect + DTNHost h1 = utils.createHost(c1); + DTNHost h2 = utils.createHost(c2); + DTNHost h3 = utils.createHost(c3); + + h1.connect(h2); + + clock.advance(1.0); + h2.connect(h3); + + clock.advance(2.0); + h2.setLocation(new Coord(10,10)); + h1.update(true); // disconnect h1-h2 + h3.update(true); // disconnect h2-h3 (from h3) + + clock.advance(3.0); + h2.setLocation(c2); + h3.connect(h2); // reconnect the other way + h2.setLocation(new Coord(10,10)); + clock.advance(3.5); + h3.update(true); // disconnect + + clock.advance(10); + h3.setLocation(c2); + h3.connect(h1); // con h3--h1 + clock.advance(6); + h1.setLocation(new Coord(-10,0)); + h1.update(true); // disconnect 6 sec connection + } + + public void testReport() throws IOException { + String[] ctValues = {"0.0 0", "1.0 0", "2.0 1", "3.0 2", "4.0 0", + "5.0 0", "6.0 1", "7.0 0"}; + String[] ictValues = {"0.0 0", "1.0 0", "2.0 0", "3.0 1", + "4.0 0"}; + + this.setUpWithGranularity(1.0); + checkValues(ctValues, ictValues); + } + + private void checkValues(String[] ctValues, String[] ictValues) + throws IOException { + for (String value : ctValues) { + assertEquals(value,ctReader.readLine()); + } + assertEquals(null,ctReader.readLine()); // no more times left + + for (String value : ictValues) { + assertEquals(value,ictReader.readLine()); + } + assertEquals(null,ictReader.readLine()); + } + + public void testGranularity2() throws IOException { + String[] ctValues = {"0.0 0", "2.0 3", "4.0 0", + "6.0 1", "8.0 0"}; + String[] ictValues = {"0.0 0", "2.0 1", "4.0 0"}; + + this.setUpWithGranularity(2.0); + checkValues(ctValues, ictValues); + } + + + public void testGranularity10() throws IOException { + this.setUpWithGranularity(10.0); + + assertEquals("0.0 4",ctReader.readLine()); + assertEquals("10.0 0",ctReader.readLine()); + assertEquals(null,ctReader.readLine()); + } + + public void testGanularity05() throws IOException { + String[] ctValues = {"0.0 0", "0.5 0", "1.0 0", "1.5 0", + "2.0 1", "2.5 0", "3.0 1", "3.5 1", "4.0 0", + "4.5 0", "5.0 0", "5.5 0", "6.0 1", "6.5 0"}; + String[] ictValues = {"0.0 0", "0.5 0", "1.0 0", "1.5 0", + "2.0 0", "2.5 0", "3.0 1", "3.5 0"}; + + this.setUpWithGranularity(0.5); + checkValues(ctValues, ictValues); + } + +} diff --git a/test/CoordTest.java b/test/CoordTest.java new file mode 100644 index 000000000..593fb9dc9 --- /dev/null +++ b/test/CoordTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import junit.framework.TestCase; +import core.Coord; + +public class CoordTest extends TestCase { + + public void testHashCode() { + Coord c1 = new Coord(1,1); + Coord c2 = new Coord(1,1); + Coord c3 = new Coord(2,3); + Coord c4 = new Coord(3,2); + Coord c5 = new Coord(-2,-3); + Coord c6 = new Coord(-2,-3); + + assertTrue(c1.hashCode() == c2.hashCode()); + assertTrue(c1.hashCode() != c3.hashCode()); + assertTrue(c3.hashCode() != c4.hashCode()); + assertTrue(c5.hashCode() == c6.hashCode()); + assertTrue(c3.hashCode() != c5.hashCode()); + + c5.translate(1, 1); + assertTrue(c5.hashCode() != c6.hashCode()); + + } + +} diff --git a/test/DijkstraPathFinderTest.java b/test/DijkstraPathFinderTest.java new file mode 100644 index 000000000..41679a0d1 --- /dev/null +++ b/test/DijkstraPathFinderTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.util.List; + +import junit.framework.TestCase; +import movement.map.DijkstraPathFinder; +import movement.map.MapNode; +import core.Coord; + +public class DijkstraPathFinderTest extends TestCase { + private DijkstraPathFinder r; + + private final MapNode n1 = newNode(0,0); + private final MapNode n2 = newNode(10,0); + private final MapNode n3 = newNode(20,0); + private final MapNode n4 = newNode(0,10); + private final MapNode n5 = newNode(10,10); + private final MapNode n6 = newNode(15,10); + private final MapNode n7 = newNode(20,10); + private final MapNode n8 = newNode(25,10); + + protected void setUp() throws Exception { + super.setUp(); + r = new DijkstraPathFinder(null); + createTopology(); + } + + /** + * Creates a topology: + * + * n1-10-n2---10---n3 + * 10 10 / 10 + * n4-10-n5-5-n6-5-n7-5-n8 + */ + private void createTopology() { + n1.addNeighbor(n2); + n1.addNeighbor(n4); + n2.addNeighbor(n1); + n2.addNeighbor(n5); + n2.addNeighbor(n3); + n3.addNeighbor(n2); + n3.addNeighbor(n6); + n3.addNeighbor(n7); + n4.addNeighbor(n1); + n4.addNeighbor(n5); + n5.addNeighbor(n4); + n5.addNeighbor(n2); + n5.addNeighbor(n6); + n6.addNeighbor(n5); + n6.addNeighbor(n3); + n6.addNeighbor(n7); + n7.addNeighbor(n6); + n7.addNeighbor(n3); + n7.addNeighbor(n8); + n8.addNeighbor(n7); + } + + private MapNode newNode(double x, double y) { + return new MapNode(new Coord(x,y)); + } + + public void testPathFinding() { + checkPath(getPath(n1,n1), n1); + checkPath(getPath(n1,n3), n1, n2, n3); + checkPath(getPath(n1,n6), n1, n2, n5, n6); + checkPath(getPath(n5,n3), n5, n6, n3); + checkPath(getPath(n3,n5), n3, n6, n5); + checkPath(getPath(n4,n8), n4, n5, n6, n7, n8); + checkPath(getPath(n8,n4), n8, n7, n6, n5, n4); + } + + private void checkPath(List path, MapNode ... nodes) { + assertEquals(nodes.length,path.size()); + + for (int i=0; i< nodes.length; i++) { + assertEquals((i+1)+"th node was wrong",nodes[i],path.get(i)); + } + } + + private List getPath(MapNode from, MapNode to) { + List path = r.getShortestPath(from, to); + return path; + } + + +} diff --git a/test/DistanceDelayReportTest.java b/test/DistanceDelayReportTest.java new file mode 100644 index 000000000..7cb2fbc26 --- /dev/null +++ b/test/DistanceDelayReportTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Vector; + +import junit.framework.TestCase; +import report.DistanceDelayReport; +import core.Coord; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import core.SimClock; + +public class DistanceDelayReportTest extends TestCase { + private SimClock clock; + File outFile; + + private Vector ml; + private DistanceDelayReport r; + private TestUtils utils; + + public void setUp() throws IOException { + final String NS = "DistanceDelayReport."; + TestSettings ts = new TestSettings(); + outFile = File.createTempFile("ddrtest", ".tmp"); + outFile.deleteOnExit(); + + ts.putSetting(NS + "output", outFile.getAbsolutePath()); + ts.putSetting(NS + report.Report.PRECISION_SETTING, "1"); + clock = SimClock.getInstance(); + r = new DistanceDelayReport(); + ml = new Vector(); + ml.add(r); + this.utils = new TestUtils(null, ml, ts); + } + + + public void testMessageTransferred() throws IOException { + DTNHost h1 = utils.createHost(new Coord(0,0)); + DTNHost h2 = utils.createHost(new Coord(2,0)); + DTNHost h3 = utils.createHost(new Coord(0,5)); + BufferedReader reader; + + Message m1 = new Message(h1, h2, "tst1", 1); + h1.createNewMessage(m1); + clock.advance(1.5); + h1.sendMessage("tst1", h2); + h2.messageTransferred("tst1", h1); + + Message m2 = new Message(h2,h1, "tst2", 1); + h2.createNewMessage(m2); + clock.advance(0.5); + h2.sendMessage("tst2", h1); + h1.messageTransferred("tst2", h2); + + Message m3 = new Message(h1,h3, "tst3", 1); + h1.createNewMessage(m3); + clock.advance(1.0); + h1.sendMessage("tst3", h2); + h2.messageTransferred("tst3", h1); + h2.sendMessage("tst3", h3); + h3.messageTransferred("tst3", h2); + + r.done(); + + reader = new BufferedReader(new FileReader(outFile)); + + reader.readLine(); // skip headers + reader.readLine(); // skip headers + assertEquals("2.0 1.5 1 tst1",reader.readLine()); + assertEquals("2.0 0.5 1 tst2",reader.readLine()); + assertEquals("5.0 1.0 2 tst3",reader.readLine()); + + reader.close(); + } + + +} diff --git a/test/EpidemicRouterTest.java b/test/EpidemicRouterTest.java new file mode 100644 index 000000000..072fc1e71 --- /dev/null +++ b/test/EpidemicRouterTest.java @@ -0,0 +1,622 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import routing.EpidemicRouter; +import routing.MessageRouter; +import core.DTNHost; +import core.Message; + +/** + * Tests for EpidemicRouter and, due the simple nature of Epidemic router, + * also ActiveRouter in general. + */ +public class EpidemicRouterTest extends AbstractRouterTest { + + private static int TTL = 300; + + @Override + public void setUp() throws Exception { + ts.putSetting(MessageRouter.MSG_TTL_S, ""+TTL); + ts.putSetting(MessageRouter.B_SIZE_S, ""+BUFFER_SIZE); + setRouterProto(new EpidemicRouter(ts)); + super.setUp(); + } + + /** + * Tests routing messages between three hosts + */ + public void testRouter() { + // nothing should have happened so far + assertEquals(mc.TYPE_NONE, mc.getLastType()); + + Message m1 = new Message(h1, h3, msgId1, 1); + h1.createNewMessage(m1); + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertEquals(mc.getLastFrom(), h1); + assertEquals(mc.getLastTo(), h3); + + // connect h1-h2-h3 + h1.connect(h2); + h2.connect(h3); + + updateAllNodes(); + clock.advance(2); + updateAllNodes(); + + // should cause relay h1 -> h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertFalse(mc.getLastFirstDelivery()); + assertEquals(mc.getLastFrom(), h1); + assertEquals(mc.getLastTo(), h2); + + // should cause relay h2 -> h3 + clock.advance(1); + updateAllNodes(); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertTrue(mc.getLastFirstDelivery()); + assertEquals(mc.getLastFrom(), h2); + assertEquals(mc.getLastTo(), h3); + // message delivered to recipient + assertFalse(mc.next()); + + + // disconnect all nodes and try to other direction + disconnect(h2); + // create message while not connected + Message m2 = new Message(h3,h1, msgId2, 1); + h3.createNewMessage(m2); + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + + h1.connect(h2); // reconnect h1-h2 + clock.advance(10); + updateAllNodes(); + assertFalse(mc.next()); // nothing should have happened to messages + + h2.connect(h3); + updateAllNodes(); // now h3 should start forwarding msg to h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertFalse(mc.next()); + + clock.advance(10); + updateAllNodes(); // forwarding msg2 h3->h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertFalse(mc.next()); + + updateAllNodes(); // forwarding msg2 h2->h1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + + clock.advance(10); + updateAllNodes(); // forwarding msg2 h2->h1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h1, mc.getLastTo()); + assertEquals(h2, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertTrue(mc.getLastFirstDelivery()); // message delivered to recipient + assertFalse(mc.next()); + } + + /** + * Checks that delivering many messages in a row works + */ + public void testManyMessages() { + + Message m1 = new Message(h1,h2, msgId1, 1); + h1.createNewMessage(m1); + Message m2 = new Message(h1,h2, msgId2, 1); + h1.createNewMessage(m2); + mc.reset(); + + h1.connect(h2); + updateAllNodes(); // h1 should start transfer + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + + clock.advance(10); + updateAllNodes(); + + /* h1 should have delivered the msg & start next transfer */ + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); // nothing more happened so far + + clock.advance(10); + updateAllNodes(); // h1 should finish relaying the msg + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + + assertFalse(mc.next()); + } + + /** + * Tests that messages that can be delivered right a way are delivered first + */ + public void testDeliverableMessageExchange() { + Message m1 = new Message(h1,h3, "Dummy1", 1); + h1.createNewMessage(m1); + Message m2 = new Message(h1,h3, "A_Dummy2", 1); + h1.createNewMessage(m2); + Message m3 = new Message(h1,h2, msgId1, 1); + h1.createNewMessage(m3); + + Message m4 = new Message(h2,h3, "Dummy3", 1); + h2.createNewMessage(m4); + Message m5 = new Message(h2,h1, msgId2, 1); + h2.createNewMessage(m5); + Message m6 = new Message(h2,h3, "Dummy4", 1); + h2.createNewMessage(m6); + + checkCreates(6); + + h1.connect(h2); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); // starts h1->h2 msgId1 + assertEquals(h2, mc.getLastTo()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + clock.advance(10); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); // finished delivery + + // should also start delivery of msgId2 from h2 to h1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(msgId2, mc.getLastMsg().getId()); + assertEquals(h1, mc.getLastTo()); + + } + + /** + * Tests aborting transfer when connections is disconnected during the + * transfer + */ + public void testMessageRelayAbort() { + Message m1 = new Message(h1,h2, msgId1, BUFFER_SIZE); + h1.createNewMessage(m1); + checkCreates(1); + + h1.connect(h2); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + clock.advance(1); + updateAllNodes(); + assertFalse(mc.next()); + + h2.setLocation(farAway); + updateAllNodes(); // disconnect, still transferring + + assertTrue(mc.next()); + assertEquals(mc.TYPE_ABORT, mc.getLastType()); + assertEquals(h1, mc.getLastFrom()); + assertFalse(mc.next()); + } + + /** + * try disconnecting on the same update interval when a transfer should + * be finished -> should not cause abort (anymore) + */ + public void testAbortWhenReady() { + Message m1 = new Message(h2, h1, msgId2, 1); + h2.createNewMessage(m1); + checkCreates(1); + + h2.connect(h1); + updateAllNodes(); // should start transfer + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + + clock.advance(10); + h2.setLocation(farAway); + // transfer should have been finished even if nodes disconnected + updateAllNodes(); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastFrom()); + assertFalse(mc.next()); + } + + /** + * Test unexpected ordering of finalizations and message transfers. + */ + public void testDifferentOrdering() { + h1.connect(h2); + Message m1 = new Message(h1,h2, msgId1, 1); + h1.createNewMessage(m1); + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(mc.getLastFrom(),h1); + assertEquals(mc.getLastTo(),h2); + + clock.advance(10); + // h1 has transferred msg but not finalized transfer when h2 starts + Message m2 = new Message(h2,h1, msgId2, 1); + h2.createNewMessage(m2); + h2.update(true); // h2 and h1 are connected but this shouldn't start relay + + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertFalse(mc.next()); // shouldn't start transfer (prev not finalized) + + h1.update(true); // finalize the transfer of MSG2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + + // last transfer is finalized -> update should start transfer of msgId2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(h1, mc.getLastTo()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertFalse(mc.next()); + } + + /** + * Tests if rejecting already delivered message(s) work + */ + public void testDoubleDelivery() { + Message m1 = new Message(h1,h2, msgId1, 1); + h1.createNewMessage(m1); + + h1.connect(h2); + updateAllNodes(); // starts transfer h1 -> h2 + clock.advance(10); + mc.reset(); // discard create & start + updateAllNodes(); // msg delivered h1 -> h2 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h2, mc.getLastTo()); + + h1.connect(h3); + updateAllNodes(); // start transfer h1 -> h3 + assertTrue(mc.next()); + clock.advance(10); + updateAllNodes(); // msg transferred h1 -> h3 + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h3, mc.getLastTo()); + + h3.connect(h2); + updateAllNodes(); // should not start a new transfer (h1 -> h2) + clock.advance(10); + updateAllNodes(); // still shouldn't do anything + + assertFalse(mc.next()); + } + + /** + * Tests if the FIFO queue management works + */ + public void testQueueManagement() { + Message m1 = new Message(h1,h3, "dummy", BUFFER_SIZE-1); + h1.createNewMessage(m1); + assertEquals(1, h1.getNrofMessages()); + Message m2 = new Message(h1,h3, msgId1, BUFFER_SIZE/3); + h1.createNewMessage(m2); + assertEquals(1, h1.getNrofMessages()); // message should replace dummy + assertEquals(msgId1, h1.getMessageCollection().iterator().next().getId()); + + mc.reset(); + + clock.advance(10); + Message m3 = new Message(h1,h3, msgId2, BUFFER_SIZE/3); + h1.createNewMessage(m3); + clock.advance(10); + Message m4 = new Message(h1,h3, "newestMsg", BUFFER_SIZE/3); + h1.createNewMessage(m4); + + clock.advance(10); + Message m5 = new Message(h2,h3, "MSG_from_h2", BUFFER_SIZE/2); + h2.createNewMessage(m5); + + checkCreates(3); // remove 3 creates from mc + + h2.connect(h1); // h2 starts transfer of message -> h1 makes room + h2.update(true); + // h1 should drop first msgId1 and then msgId2 (older first) + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h1, mc.getLastFrom()); + assertEquals(msgId1, mc.getLastMsg().getId()); + assertTrue(mc.getLastDropped()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertEquals(1, h1.getNrofMessages()); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); // h2 should start + assertEquals(h2, mc.getLastFrom()); + assertFalse(mc.next()); + + clock.advance(10); + updateAllNodes(); // h2 should finish transfer + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(h1, mc.getLastTo()); + assertFalse(mc.next()); + } + + /** + * Tests creating a new message when the message buffer is full and the + * message that should be removed is the message being sent + */ + public void testNewMessageToFullBufferWhileTransferring() { + int m3Size = BUFFER_SIZE-1; + int m1Size = BUFFER_SIZE/2; + + Message m1 = new Message(h1,h3, msgId1, m1Size); + h1.createNewMessage(m1); + Message m2 = new Message(h1,h4, msgId2, BUFFER_SIZE/2); + h1.createNewMessage(m2); + checkCreates(2); + + h3.connect(h1); + updateAllNodes(); // transfer of msgId1 should start + + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + clock.advance(1); + updateAllNodes(); // should still be transferring + assertFalse(mc.next()); + + // creating a new message should cause dropping the msgId2 but + // not msgId1 (which is being transferred) -> buffer should become + // "over full" + Message m3 = new Message(h1,h4, msgId3, m3Size); + h1.createNewMessage(m3); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertTrue(mc.getLastDropped()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertEquals(msgId3, mc.getLastMsg().getId()); + assertTrue(h1.getBufferOccupancy() > 100); // buffer occupancy > 100% + + assertFalse(mc.next()); + + clock.advance((m1Size/TRANSMIT_SPEED) + 1); + updateAllNodes(); // now transmission should be done + + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + assertTrue(mc.next()); // now should drop the transferred message + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertTrue(mc.getLastDropped()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + // buffer occupancy should drop back under 100 % + assertTrue(h1.getBufferOccupancy() < 100); + + // should start transferring msgId3 + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(msgId3, mc.getLastMsg().getId()); + + assertFalse(mc.next()); + } + + public void testTtlExpiry() { + final int TIME_STEP = 10; + Message m1 = new Message(h1,h3, msgId1, 1); + h1.createNewMessage(m1); + checkCreates(1); + + clock.advance(TIME_STEP); + updateAllNodes(); + assertFalse(mc.next()); + + // relay msg1 from h1 to h2 + h1.connect(h2); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + clock.advance(TIME_STEP); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + + assertFalse(mc.next()); + + clock.advance((TTL-1)*60 - TIME_STEP*2); + updateAllNodes(); + assertFalse(mc.next()); + Message m2 = new Message(h4,h3, msgId2, 1); + h4.createNewMessage(m2); + checkCreates(1); + + clock.advance(61); + updateAllNodes(); + + // h1 and h2 should delete the expired message + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h1, mc.getLastFrom()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h2, mc.getLastFrom()); + assertEquals(msgId1, mc.getLastMsg().getId()); + + assertFalse(mc.next()); // h4 shouldn't remove the msg just yet + + clock.advance((TTL-1)*60 -61); + updateAllNodes(); + assertFalse(mc.next()); // not yet either + clock.advance(61); + + updateAllNodes(); // but now it's time for h4 to remove the msg + + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(h4, mc.getLastFrom()); + assertEquals(msgId2, mc.getLastMsg().getId()); + + assertFalse(mc.next()); + } + + public void testResponse() { + Message m1 = new Message(h1,h3, msgId1, 1); + m1.setResponseSize(1); + h1.createNewMessage(m1); + h1.connect(h2); + updateAllNodes(); + clock.advance(10); + updateAllNodes(); + h2.connect(h3); + updateAllNodes(); + + // started h2->h3 relay + mc.reset(); + + clock.advance(10); + updateAllNodes(); + + // finished relay + assertTrue(mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + + // h3 should reply by creating a reply message.. + assertTrue(mc.next()); + assertEquals(mc.TYPE_CREATE, mc.getLastType()); + assertEquals(routing.ActiveRouter.RESPONSE_PREFIX + msgId1, + mc.getLastMsg().getId()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(h1, mc.getLastTo()); + + // .. and starting its transfer + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertEquals(routing.ActiveRouter.RESPONSE_PREFIX + msgId1, + mc.getLastMsg().getId()); + assertEquals(h3, mc.getLastFrom()); + assertEquals(h2, mc.getLastTo()); + + assertFalse(mc.next()); + } + + private void newMessage(String id, DTNHost from, DTNHost to) { + Message m = new Message(from, to, id, 1); + from.createNewMessage(m); + } + + /** + * Runs a message exchange between node h1 and another node + * @param withDestination If true, the other node is the final destination + * of the messages, if false, the other node is not the final dst + * @return The order of the messages in a space delimited string + */ + private String runMessageExchange(boolean withDestination) { + String msgIds = ""; + int nrof = 5; + DTNHost dst = h4; + DTNHost other = h2; + + clock.setTime(0.0); + newMessage("1", h1, dst); + clock.advance(2.5); + newMessage("2", h1, dst); + clock.advance(3.5); + newMessage("3", h1, dst); + clock.advance(1.5); + newMessage("3", h1, dst); + clock.advance(2.0); + newMessage("4", h1, dst); + clock.advance(2.5);; + newMessage("5", h1, dst); + + if (withDestination) { + h1.connect(dst); + } + else { + h1.connect(other); + } + + mc.reset(); + updateAllNodes(); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + + for (int i=0; i < nrof; i++) { + msgIds += mc.getLastMsg().getId()+ " "; + clock.advance(10); + updateAllNodes(); + assertTrue("index " + i, mc.next()); + assertEquals(mc.TYPE_RELAY, mc.getLastType()); + if (i < nrof - 1) { + assertTrue("index " + i, mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + } + } + + assertFalse(mc.next()); + + return msgIds; + } + + public void testFifoSendingQ() throws Exception { + ts.putSetting(MessageRouter.SEND_QUEUE_MODE_S, + ""+MessageRouter.Q_MODE_FIFO); + this.setUp(); + + String expectedIds = "1 2 3 4 5 "; + + assertEquals(expectedIds, runMessageExchange(true)); + assertEquals(expectedIds, runMessageExchange(false)); + } + + public void testRandomSendingQ() throws Exception { + ts.putSetting(MessageRouter.SEND_QUEUE_MODE_S, + ""+MessageRouter.Q_MODE_RANDOM); + this.setUp(); + + String orderedIds = "1 2 3 4 5 "; + + assertNotSame(orderedIds, runMessageExchange(true)); + assertNotSame(orderedIds, runMessageExchange(false)); + } +} diff --git a/test/ExternalEventsQueueTest.java b/test/ExternalEventsQueueTest.java new file mode 100644 index 000000000..d284e56e8 --- /dev/null +++ b/test/ExternalEventsQueueTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.BinaryEventsReader; +import input.ExternalEvent; +import input.ExternalEventsQueue; +import input.ExternalEventsReader; +import input.MessageCreateEvent; +import input.StandardEventsReader; + +import java.io.File; +import java.io.PrintWriter; +import java.util.List; + +import junit.framework.TestCase; + +public class ExternalEventsQueueTest extends TestCase { + private final String[] stdinput = { +"1000.000 C MSG_365_D_1 p1 p2 100000", +"1533.405 S MSG_365_D_1 p1 p0", +"1542.000 A MSG_365_D_1 p1 p0", +"2200.000 C MSG_746_D_2 p1 p3 100000", +"3095.408 S MSG_746_D_2 p1 c64", +"3103.000 A MSG_746_D_2 p1 c64", +"8071.608 DE MSG_746_D_2 p1 p10", +" ", // empty line +"8091.608 DE MSG_365_D_1 p1 p10", +"100502.200 DR MSG_365_D_1 p10", +"# comment line", +"106202.613 R MSG_10644_D_5 c70" +}; + + private final double msgTimes[] = {1000.000, 1533.405, 1542.000, + 2200.000, 3095.408, 3103.000, 8071.608, 8091.608, + 100502.200, 106202.613}; + + private ExternalEventsQueue eeq; + private File tempFile; + + protected void setUp() throws Exception { + java.util.Locale.setDefault(java.util.Locale.US); + super.setUp(); + String TMP = ".tmp"; + tempFile = File.createTempFile("eeqTest", TMP); + + PrintWriter out = new PrintWriter(tempFile); + + for (String s : stdinput) { + out.println(s); + } + out.close(); + } + + + public void testEEQ() { + int preload = 10; + eeq = new ExternalEventsQueue(tempFile.getAbsolutePath(),preload); + checkEeq(eeq, preload); + + preload = 1; + eeq = new ExternalEventsQueue(tempFile.getAbsolutePath(),preload); + checkEeq(eeq, preload); + } + + + public void testBinaryEEQ() throws Exception{ + int preload = 7; + File tmpBinFile = File.createTempFile("TempBinTest", + BinaryEventsReader.BINARY_EXT); + String binFileName = tmpBinFile.getAbsolutePath(); + ExternalEventsReader r = new StandardEventsReader(tempFile); + List events = r.readEvents(100); + BinaryEventsReader.storeToBinaryFile(binFileName, events); + + eeq = new ExternalEventsQueue(binFileName, preload); + checkEeq(eeq, preload); + + assertTrue(tmpBinFile.delete()); // make sure all locks are gone + } + + + private void checkEeq(ExternalEventsQueue eeq, int preloadVal) { + ExternalEvent ee; + assertEquals(msgTimes[0],eeq.nextEventsTime()); + assertEquals(preloadVal, eeq.eventsLeftInBuffer()); + + ee = eeq.nextEvent(); + assertTrue(ee instanceof MessageCreateEvent); + + for (int i=1; i < msgTimes.length; i++) { + assertEquals(msgTimes[i], eeq.nextEventsTime()); + ee = eeq.nextEvent(); + assertTrue(ee instanceof ExternalEvent); + assertEquals(msgTimes[i], ee.getTime()); + } + } +} diff --git a/test/ExternalMovementReaderTest.java b/test/ExternalMovementReaderTest.java new file mode 100644 index 000000000..c53f75d87 --- /dev/null +++ b/test/ExternalMovementReaderTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.ExternalMovementReader; + +import java.io.File; +import java.io.PrintWriter; +import java.util.List; + +import util.Tuple; + +import junit.framework.TestCase; +import core.Coord; + +public class ExternalMovementReaderTest extends TestCase { + private ExternalMovementReader r; + private static final String INPUT = + "0 0 0 0 0 0\n"+ + "10 1 10 10\n"+ + "10 2 10 20 1010\n" + + "10 3 10 30\n" + + "20 1 20 10 dummyData\n" + + "20 2 20 20\n" + + "\n"+ + "20 3 30 30\n" + + "30 1 30 20\n" + + "30 2 30 30\n" + + "30 3 40 30"; + private static final String [] ids = {"1","2","3"}; + private static final double [] times = {10,20,30}; + private static final Coord [][] coords = + { {new Coord(10,10), new Coord(10,20), new Coord(10,30)}, + {new Coord(20,10), new Coord(20,20), new Coord(30,30)}, + {new Coord(30,20), new Coord(30,30), new Coord(40,30)} }; + + + protected void setUp() throws Exception { + super.setUp(); + + File tmpFile = File.createTempFile("EMRTest","tmp"); + tmpFile.deleteOnExit(); + + PrintWriter pw = new PrintWriter(tmpFile); + pw.println(INPUT); + pw.close(); + + r = new ExternalMovementReader(tmpFile.getAbsolutePath()); + } + + public void testReader() { + List> list; + + for (int i=0; i> list, String[] ids, + Coord[] coords) { + + assertEquals(ids.length, list.size()); + + for (int i=0; i coords = p.getCoords(); + // should move between n1 and n2 + for (int i=0; i coords = p.getCoords(); + // should move between n1 and n2 + for (int i=0; i cost 1-0.5/2 */ + assertEquals( 1 - 0.5/2 , r1.getCost(h1, h2)); + assertEquals( 1 - (1+0.5)/2 , r1.getCost(h1, h3)); + + disconnect(h1); + h1.connect(h3); + assertEquals( 1 - (0.5/2)/2 , r1.getCost(h1, h2)); + assertEquals( 1 - (1+(1+0.5)/2)/2 , r1.getCost(h1, h3)); + /* probabilities sum to 1.0 */ + assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3))); + + h1.connect(h4); + assertEquals( 1 - ((0.5/2)/2)/2 , r1.getCost(h1, h2)); + assertEquals( 1 - ((1+(1+0.5)/2)/2)/2 , r1.getCost(h1, h3)); + assertEquals( 1 - 0.5 , r1.getCost(h1, h4)); + assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3)) + + (1-r1.getCost(h1, h4))); + + disconnect(h1); + h1.connect(h2); // reconnect to h2 + assertEquals( 1 - (1 + ((0.5/2)/2)/2)/2 , r1.getCost(h1, h2)); + assertEquals( 1 - (((1+(1+0.5)/2)/2)/2)/2 , r1.getCost(h1, h3)); + assertEquals( 1 - 0.5/2 , r1.getCost(h1, h4)); + assertEquals(1.0, (1-r1.getCost(h1, h2)) + (1-r1.getCost(h1, h3)) + + (1-r1.getCost(h1, h4))); + + } + + public void testThreshold() { + int msgSize = 90; + + Message m1 = new Message(h1,h5, msgId1, msgSize); + h1.createNewMessage(m1); + checkCreates(1); + h1.connect(h2); + + /* thresholds should be zero before any transfers */ + assertEquals(0, r1.calcThreshold()); + assertEquals(0, r2.calcThreshold()); + + /* simple delivery of msgId1 from h1 to h2 */ + updateAllNodes(); + checkTransferStart(h1, h2, msgId1); + assertFalse(mc.next()); + clock.advance(5); + updateAllNodes(); + assertFalse(mc.next()); // transfer should not be ready yet + clock.advance(5); // now it should be done + updateAllNodes(); + checkDelivered(h1, h2, msgId1, false); + + disconnect(h1); + assertEquals(1, r1.calcThreshold()); + assertEquals(2, r2.calcThreshold()); + + h2.connect(h3); + deliverMessage(h2, h3, msgId1, msgSize, false); + disconnect(h2); + assertEquals(2, r2.calcThreshold()); + /* msg at h3 has traveled 2 hops and "bsize > avgTransferredBytes > 0" + * so threshold should be only msg's hopcount+1 */ + assertEquals(3, r3.calcThreshold()); + } + + public void testAckedMessageDeleting() { + int msgSize = 10; + Message m1 = new Message(h1,h5, msgId1, msgSize); + h1.createNewMessage(m1); + checkCreates(1); + + h1.connect(h2); + deliverMessage(h1, h2, msgId1, msgSize, false); + disconnect(h1); + + h1.connect(h3); + deliverMessage(h1, h3, msgId1, msgSize, false); + disconnect(h1); + + h1.connect(h5); + deliverMessage(h1, h5, msgId1, msgSize, true); + disconnect(h1); + + assertFalse(mc.next()); + h1.connect(h2); // h1 should notify h2 of the delivered msg + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(msgId1, mc.getLastMsg().getId()); + assertEquals(h2, mc.getLastFrom()); + // the deleted msg truly came from h1? + assertEquals(h1, mc.getLastMsg().getHops().get(0)); + assertFalse(mc.next()); + + // new msg to h3 + Message m2 = new Message(h3,h1, msgId2, msgSize); + h3.createNewMessage(m2); + checkCreates(1); + + h3.connect(h2); // h2 should notify h3 which should delete msgId1 + assertTrue(mc.next()); + assertEquals(mc.TYPE_DELETE, mc.getLastType()); + assertEquals(msgId1, mc.getLastMsg().getId()); + assertEquals(h3, mc.getLastFrom()); + assertFalse(mc.next()); + /* msgId2 should NOT be deleted but it should be transferred to h2 + * during the next update*/ + deliverMessage(h3, h2, msgId2, msgSize, false); + + } + + public void testRouting() { + int msgSize = 10; + DTNHost th1 = utils.createHost(c0, "temp1"); + DTNHost th2 = utils.createHost(c0, "temp2"); + DTNHost th3 = utils.createHost(c0, "temp3"); + DTNHost th4 = utils.createHost(c0, "temp4"); + + h4.connect(th1); + h4.connect(h5); + disconnect(h4); + h4.connect(th1); + disconnect(h4); + /* h4 should have probs: h5:0.25, th1:0.75 */ + + h3.connect(th2); + h3.connect(h4); + disconnect(h3); + /* h3 probs: h4:0.5, th2:0.5 + * h4 probs: h3:0.5, th1:0.375, h5:0.125 */ + + h2.connect(th3); + disconnect(h2); + h2.connect(h3); + h2.connect(th3); + disconnect(h2); + h2.connect(th3); + disconnect(h2); + /* h2 probs: th3:0.875, h3:0.125 + * h3 probs: h2:0.5, h4:0.25, th2:0.25 */ + + h1.connect(th4); + h1.connect(h2); + disconnect(h1); + /* h1 probs: th4:0.5, h2:0.5 + * h2 probs: h1:0.5, th3:0.4375, h3:0.0625*/ + + h4.connect(h5); + disconnect(h4); + /* h4 probs: h3:0.25, th1:0.1875, h5:0.5625 + * these changes should not be visible to h3! */ + Message m1 = new Message(h1,h5, msgId1, msgSize); + h1.createNewMessage(m1); + + /* msg with path h1 -> h2 -> h3 -> h4 -> h5 */ + double trueCost = (1-0.5) + (1-0.0625) + (1-0.25) + (1-0.125); + double calcCost = r1.getCost(h1, h5); + assertEquals(trueCost, calcCost); + } + + /** + * Tests that more recent meeting probability sets replace older ones + * but not vice versa. + */ + public void testMpsTimeStamps() { + /* create some messages so we can ask costs to destinations */ + int msgIndx = 1; + Message m1 = new Message(h1,h2, ""+msgIndx++, 1); + h1.createNewMessage(m1); + Message m2 = new Message(h1,h1, ""+msgIndx++, 1); + h1.createNewMessage(m2); + Message m3 = new Message(h1,h3, ""+msgIndx++, 1); + h1.createNewMessage(m3); + Message m4 = new Message(h3,h2, ""+msgIndx++, 1); + h3.createNewMessage(m4); + Message m5 = new Message(h3,h3, ""+msgIndx++, 1); + h3.createNewMessage(m5); + Message m6 = new Message(h4,h3, ""+msgIndx++, 1); + h4.createNewMessage(m6); + Message m7 = new Message(h4,h4, ""+msgIndx++, 1); + h4.createNewMessage(m7); + Message m8 = new Message(h2,h2, ""+msgIndx++, 1); + h2.createNewMessage(m8); + Message m9 = new Message(h2,h4, ""+msgIndx++, 1); + h2.createNewMessage(m9); + + h1.connect(h2); + disconnect(h1); + /* now we should have + * h1': h2:1.0; h2:h2' + * h2': h1:1.0; h1:h1' */ + + assertEquals(0.0, r1.getCost(h1, h2)); + assertEquals(0.0, r1.getCost(h2, h1)); + + clock.advance(1.0); + h1.connect(h3); + disconnect(h1); + /* h1'': h2:0.5, h3:0.5; h2:h2', h3:h3' + * h3': h1:1.0; h1:h1'', h2:h2' */ + + assertEquals(0.5, r1.getCost(h1, h2)); + /* h3 received h1's other probs properly? */ + assertEquals(0.5, r3.getCost(h1, h2)); + assertEquals(0.5, r3.getCost(h1, h3)); + + clock.advance(1.0); + h1.connect(h4); + disconnect(h1); + /* h1''': h2:0.25, h3:0.25, h4:0.5; h2:h2', h3:h3', h4:h4' + * h4': h1:1.0; h1:h1''', h2:h2', h3:h3'*/ + + assertEquals(0.75, r4.getCost(h1, h3)); + assertEquals(0.5, r4.getCost(h1, h4)); + + clock.advance(1.0); + h2.connect(h3); + disconnect(h2); + /* h2'': h1:0.5, h3:0.5; h1:h1'', h3:h3'' (both from h3) + * h3'': h1:0.5, h2:0.5; h1:h1'', h2:h2'' (h1's probs should remain) */ + + assertEquals(0.5, r2.getCost(h1, h2)); // test the received h1'' + assertEquals(0.5, r3.getCost(h1, h2)); // is h1'' also still in h3? + + clock.advance(1.0); + h1.connect(h2); + disconnect(h1); + /* h1'''': h2:0.625, h3:0.125, h4:0.25; h2:h2''', h3:h3'', h4:h4' + * h2''': h1:0.75, h3:0.25; h1:h1'''', h2:h3'', h4:h4' */ + + /* msg path h2->h1->h4 */ + assertEquals((1-0.75)+(1-0.25), r2.getCost(h2, h4)); + } +} diff --git a/test/MessageChecker.java b/test/MessageChecker.java new file mode 100644 index 000000000..42616bec8 --- /dev/null +++ b/test/MessageChecker.java @@ -0,0 +1,159 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.util.ArrayList; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +/** + * Message event checker for tests. + */ +public class MessageChecker implements MessageListener { + private Message lastMsg; + private DTNHost lastFrom; + private DTNHost lastTo; + private Boolean lastDropped; + private Boolean lastFirstDelivery; + private String lastType; + private ArrayList queue; + + public final String TYPE_NONE = "none"; + public final String TYPE_DELETE = "delete"; + public final String TYPE_ABORT = "abort"; + public final String TYPE_RELAY = "relay"; + public final String TYPE_CREATE = "create"; + public final String TYPE_START = "start"; + + public MessageChecker() { + reset(); + } + + public void reset() { + this.queue = new ArrayList(); + this.lastType = TYPE_NONE; + this.lastMsg = null; + this.lastFrom = null; + this.lastTo = null; + this.lastDropped = null; + this.lastFirstDelivery = null; + } + + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + this.add(m, where, null, TYPE_DELETE, dropped, null); + } + + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + this.add(m, from, to, TYPE_ABORT, null, null); + } + + public void messageTransferred(Message m, DTNHost from, DTNHost to, + boolean firstDelivery) { + this.add(m, from, to, TYPE_RELAY, null, firstDelivery); + } + + public void newMessage(Message m) { + this.add(m, m.getFrom(), m.getTo(), TYPE_CREATE, null, null); + } + + + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + this.add(m, from, to, TYPE_START, null, null); + } + + public boolean next() { + if (this.queue.size() == 0) { + return false; + } + + MsgCheckerEvent e = this.queue.remove(0); + + this.lastMsg = e.msg; + this.lastFrom = e.from; + this.lastTo = e.to; + this.lastType = e.type; + this.lastFirstDelivery = e.delivered; + this.lastDropped = e.dropped; + return true; + + } + + private void add(Message m, DTNHost from, DTNHost to, String type, Boolean + dropped, Boolean delivered) { + this.queue.add(new MsgCheckerEvent(m,from,to,type,dropped,delivered)); + } + + /** + * @return the lastFirstDelivery + */ + public Boolean getLastFirstDelivery() { + return lastFirstDelivery; + } + + /** + * @return the lastDropped + */ + public Boolean getLastDropped() { + return lastDropped; + } + + /** + * @return the lastFrom + */ + public DTNHost getLastFrom() { + return lastFrom; + } + + /** + * @return the lastMsg + */ + public Message getLastMsg() { + return lastMsg; + } + + /** + * @return the lastTo + */ + public DTNHost getLastTo() { + return lastTo; + } + + /** + * @return the lastType + */ + public String getLastType() { + return lastType; + } + + public String toString() { + return this.queue.size() + " event(s) : " + this.queue; + } + + private class MsgCheckerEvent { + private Message msg; + private DTNHost from; + private DTNHost to; + private Boolean dropped; + private Boolean delivered; + private String type; + + public MsgCheckerEvent(Message m, DTNHost from, DTNHost to, + String type, Boolean dropped, Boolean delivered) { + this.msg = m; + this.from = from; + this.to = to; + this.type = type; + this.dropped = dropped; + this.delivered = delivered; + } + + public String toString() { + return this.type + " (" + this.from + "->" + this.to+") " + + this.msg; + } + } +} diff --git a/test/MessageGraphvizReportTest.java b/test/MessageGraphvizReportTest.java new file mode 100644 index 000000000..530c112d7 --- /dev/null +++ b/test/MessageGraphvizReportTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Vector; + +import junit.framework.TestCase; +import report.MessageGraphvizReport; +import core.Coord; +import core.DTNHost; +import core.Message; +import core.MessageListener; + +public class MessageGraphvizReportTest extends TestCase { + private File outFile; + private MessageGraphvizReport r; + private TestUtils utils; + + public void setUp() throws IOException { + TestSettings ts = new TestSettings(); + outFile = File.createTempFile("mgtest", ".tmp"); + outFile.deleteOnExit(); + + ts.putSetting("MessageGraphvizReport.output", outFile.getAbsolutePath()); + ts.putSetting("MessageGraphvizReport.interval" , ""); + + Vector ml = new Vector(); + r = new MessageGraphvizReport(); + ml.add(r); + utils = new TestUtils(null, ml, ts); + } + + private void generateMessages() { + Coord c1 = new Coord(0,0); + Coord c2 = new Coord(1,0); + Coord c3 = new Coord(2,0); + + utils.setTransmitRange(2); + DTNHost h1 = utils.createHost(c1,"h1"); + DTNHost h2 = utils.createHost(c2,"h2"); + DTNHost h3 = utils.createHost(c3,"h3"); + + h1.createNewMessage(new Message(h1, h3, "M1", 1)); + h1.sendMessage("M1", h2); + h2.messageTransferred("M1", h1); + h2.sendMessage("M1", h3); + h3.messageTransferred("M1", h2); + h3.createNewMessage(new Message(h3, h2, "M2", 1)); + h3.sendMessage("M2", h2); + h2.messageTransferred("M2", h3); + } + + public void testDone() throws IOException{ + BufferedReader reader; + + generateMessages(); + r.done(); + + reader = new BufferedReader(new FileReader(outFile)); + reader.readLine(); // read comment lines + reader.readLine(); // read comment lines + assertEquals("digraph " + MessageGraphvizReport.GRAPH_NAME + + " {", reader.readLine()); + assertEquals("\th1->h2->h3;",reader.readLine()); + assertEquals("\th3->h2;",reader.readLine()); + assertEquals("}",reader.readLine()); + + reader.close(); + } + +} diff --git a/test/MessageTest.java b/test/MessageTest.java new file mode 100644 index 000000000..0ca1b592d --- /dev/null +++ b/test/MessageTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import junit.framework.TestCase; + +import org.junit.Before; +import org.junit.Test; + +import core.DTNHost; +import core.Message; +import core.SimClock; + +public class MessageTest extends TestCase { + + private Message msg; + private DTNHost from; + private DTNHost to; + private SimClock sc; + + @Before + public void setUp() throws Exception { + sc = SimClock.getInstance(); + sc.setTime(10); + + msg = new Message(from, to, "M", 100); + msg.setTtl(10); + + } + + @Test + public void testGetTtl() { + assertEquals(10, msg.getTtl()); + + sc.advance(50); + assertEquals(9, msg.getTtl()); + + sc.advance(120); + assertEquals(7, msg.getTtl()); + + sc.advance(180); + assertEquals(4, msg.getTtl()); + + sc.advance(240); + assertEquals(0, msg.getTtl()); + + + } + + @Test + public void testAddProperty() { + String value1 = "value1"; + String value2 = "value2"; + msg.addProperty("foo", value1); + msg.addProperty("bar", value2); + + assertEquals(value1, msg.getProperty("foo")); + assertEquals(value2, msg.getProperty("bar")); + } + + +} diff --git a/test/ModuleCommunicationBusTest.java b/test/ModuleCommunicationBusTest.java new file mode 100644 index 000000000..02fe6a3f3 --- /dev/null +++ b/test/ModuleCommunicationBusTest.java @@ -0,0 +1,106 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import junit.framework.TestCase; + +import org.junit.Before; +import org.junit.Test; + +import core.ModuleCommunicationBus; +import core.ModuleCommunicationListener; + +public class ModuleCommunicationBusTest extends TestCase { + + private ModuleCommunicationBus b; + private static final String TST_VAL = "test-value"; + private String notifyKey; + private Object notifyValue; + private ModuleCommunicationListener mcl; + + @Before + public void setUp() throws Exception { + b = new ModuleCommunicationBus(); + this.notifyKey = null; + this.notifyValue = null; + + this.mcl = new ModuleCommunicationListener() { + public void moduleValueChanged(String key, Object newValue) { + notifyKey = key; + notifyValue = newValue; + } + }; + + } + + @Test + public void testGetProperty() { + assertNull(b.getProperty("test")); + b.addProperty("test", TST_VAL); + assertEquals(TST_VAL, b.getProperty("test").toString()); + assertNull(b.getProperty("invalidValue")); + + b.addProperty("test2", "value2"); + assertEquals("value2", b.getProperty("test2".toString())); + assertEquals(TST_VAL, b.getProperty("test").toString()); + } + + @Test + public void testUpdateProperty() { + b.addProperty("test", TST_VAL); + assertEquals(TST_VAL, b.getProperty("test").toString()); + b.updateProperty("test", "new value"); + assertEquals("new value", b.getProperty("test").toString()); + } + + @Test + public void testSubscribe() { + String key = "subtst"; + + b.addProperty(key, "test"); + b.subscribe(key, mcl); + assertNull(notifyKey); + assertNull(notifyValue); + + b.updateProperty(key, "test2"); + assertEquals(key, notifyKey); + assertEquals("test2", notifyValue.toString()); + + b.updateProperty(key, "newTest"); + assertEquals(key, notifyKey); + assertEquals("newTest", notifyValue.toString()); + } + + @Test + public void testUnsubscribe() { + String key = "unsubtst"; + String tstVal = "unsubtstvalue"; + b.subscribe(key, mcl); + b.updateProperty(key, tstVal); + b.unsubscribe(key, mcl); + + b.updateProperty(key, "newvalue"); + assertEquals("newvalue", b.getProperty(key).toString()); + assertEquals(key, notifyKey); + assertEquals(tstVal, notifyValue.toString()); + } + + @Test + public void testUpdateDouble() { + String key = "doubletst"; + Double val = 15.5; + + b.addProperty(key, val); + assertEquals(16.5, b.updateDouble(key, 1.0)); + assertEquals(16.5, b.getDouble(key, -1.0)); + + assertEquals(13.3, b.updateDouble(key, -3.2)); + assertEquals(13.3, b.getDouble(key, -1.0)); + + assertEquals(-16.7, b.updateDouble(key, -30)); + assertEquals(-16.7, b.getDouble(key, -1.0)); + } + +} diff --git a/test/PointsOfInterestTest.java b/test/PointsOfInterestTest.java new file mode 100644 index 000000000..2f1df8d57 --- /dev/null +++ b/test/PointsOfInterestTest.java @@ -0,0 +1,217 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.WKTMapReader; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.util.Random; + +import junit.framework.TestCase; +import movement.map.MapNode; +import movement.map.PointsOfInterest; +import movement.map.SimMap; +import core.Coord; +import core.Settings; + +/** + * Test for selecting Points Of Interest from different node groups. + * Tests that the probability of getting a node from a specific group is + * approximately same as the defined probability. + */ +public class PointsOfInterestTest extends TestCase { + + /* Topology: n7--n5 + * | | + * n1--n2--n6--n3 + * | + * n4 + */ + private static final String MAP_DATA = + // n1 n2 n6 n3 + "LINESTRING (1.0 1.0, 2.0 1.0, 3.0 1.0, 4.0 1.0) \n" + + // n1 n4 + "LINESTRING (1.0 1.0, 1.0 2.0)\n"; + + private static final String MAP_DATA2 = + // n2 n7 n5 n6 + "LINESTRING (2.0 1.0, 2.0 0.0, 3.0 0.0, 3.0 1.0)\n"; + + private static final String[] POINTS_IN_MAP = { + "POINT (1.0 1.0)\n POINT (2.0 1.0)", + "POINT (4.0 1.0)\n POINT (1.0 2.0)", + "POINT (3.0 1.0)\n" + }; + + private static final Coord[][] COORDS_IN_MAP = { + {new Coord(1,1), new Coord(2,1)}, + {new Coord(4,1), new Coord(1,2)}, + {new Coord(3,1)} + }; + + private PointsOfInterest pois; + private int nrofMapNodes; + + protected void setUpWith(double[] poiProbs, int rngSeed, int [] okNodes) + throws Exception { + super.setUp(); + + Settings.init(null); + StringReader input = new StringReader(MAP_DATA); + + WKTMapReader reader = new WKTMapReader(true); + try { + reader.addPaths(input, 1); + input = new StringReader(MAP_DATA2); + reader.addPaths(input, 2); + } catch (IOException e) { + fail(e.toString()); + } + + SimMap map = reader.getMap(); + this.nrofMapNodes = map.getNodes().size(); + + File[] poiFiles = new File[POINTS_IN_MAP.length]; + for (int i=0; i path) { + int i; + assertEquals(realPath.length, path.size() + 1); + + for (i=0; i12->13->14->20 */ + oracle.addEntry(45, 3, 12, 2); + oracle.addEntry(50, 12, 13, 2); + oracle.addEntry(55, 13, 14, 2); + oracle.addEntry(57, 14, 20, 2); + comparePaths(new int[]{1,3,12,13,14,20}, d.getShortestPath(1, 20, 0)); + + /* misses the first hop to 3, takes direct late */ + comparePaths(new int[]{1, 20}, d.getShortestPath(1, 20, 30)); + + /* starts directly at 3 but too late for multihop */ + oracle.addEntry(55, 3, 11, 5); + comparePaths(new int[]{3, 11, 20}, d.getShortestPath(3, 20, 50)); + + /* starts directly at 3, early enough for multihop */ + comparePaths(new int[]{3,12,13,14,20}, d.getShortestPath(3, 20, 40)); + } + +} diff --git a/test/ScheduledUpdatesQueueTest.java b/test/ScheduledUpdatesQueueTest.java new file mode 100644 index 000000000..f3a3733dc --- /dev/null +++ b/test/ScheduledUpdatesQueueTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.ScheduledUpdatesQueue; +import junit.framework.TestCase; +import core.SimClock; + +/** + * Tests for the ScheduledUpdatesQueue + */ +public class ScheduledUpdatesQueueTest extends TestCase { + private static double MAX = Double.MAX_VALUE; + private ScheduledUpdatesQueue suq; + private SimClock sc = SimClock.getInstance(); + + protected void setUp() throws Exception { + super.setUp(); + SimClock.reset(); + suq = new ScheduledUpdatesQueue(); + } + + public void testUpdates() { + assertEquals(MAX, suq.nextEventsTime()); + suq.addUpdate(1); + suq.addUpdate(1.5); + suq.addUpdate(20); + suq.addUpdate(3); + suq.addUpdate(0); + suq.addUpdate(5.3); + + assertEquals(0.0, suq.nextEventsTime()); + assertEquals(0.0, suq.nextEvent().getTime()); + + assertEquals(1.0, suq.nextEventsTime()); + assertEquals(1.0, suq.nextEventsTime()); // twice the same request + assertEquals(1.0, suq.nextEvent().getTime()); + + assertEquals(1.5, suq.nextEvent().getTime()); + assertEquals(3.0, suq.nextEvent().getTime()); + assertEquals(5.3, suq.nextEvent().getTime()); + assertEquals(20.0, suq.nextEvent().getTime()); + + assertEquals(MAX, suq.nextEventsTime()); + assertEquals(MAX, suq.nextEvent().getTime()); + } + + public void testInterlavedRequests() { + suq.addUpdate(4); + suq.addUpdate(7); + suq.addUpdate(9); + + sc.setTime(1.0); + assertEquals(4.0, suq.nextEvent().getTime()); + + suq.addUpdate(8.5); + + suq.addUpdate(3); // to the top + assertEquals(3.0, suq.nextEvent().getTime()); + + suq.addUpdate(10); // to the bottom + sc.setTime(4.0); + assertEquals(7.0, suq.nextEvent().getTime()); + + sc.setTime(7.5); + assertEquals(8.5, suq.nextEvent().getTime()); + sc.setTime(8.8); + assertEquals(9.0, suq.nextEvent().getTime()); + sc.setTime(9.8); + assertEquals(10.0, suq.nextEvent().getTime()); + sc.setTime(15); + assertEquals(MAX, suq.nextEvent().getTime()); + } + + public void testNegativeAndZeroValues() { + suq.addUpdate(3.2); + suq.addUpdate(-2.1); + suq.addUpdate(0); + suq.addUpdate(15); + suq.addUpdate(-4); + suq.addUpdate(0.1); + + sc.setTime(-5); + + assertEquals(-4.0, suq.nextEvent().getTime()); + assertEquals(-2.1, suq.nextEvent().getTime()); + assertEquals(0.0, suq.nextEvent().getTime()); + assertEquals(0.1, suq.nextEvent().getTime()); + assertEquals(3.2, suq.nextEvent().getTime()); + assertEquals(15.0, suq.nextEvent().getTime()); + assertEquals(MAX, suq.nextEvent().getTime()); + } + + public void testDuplicateValues() { + suq.addUpdate(4.0); + suq.addUpdate(5.0); + suq.addUpdate(4.0); // these should be merged to the first value + suq.addUpdate(4.0); + suq.addUpdate(1.0); + suq.addUpdate(1.0); + suq.addUpdate(8.0); + + assertEquals(1.0, suq.nextEvent().getTime()); + assertEquals(4.0, suq.nextEvent().getTime()); + assertEquals(5.0, suq.nextEvent().getTime()); + assertEquals(8.0, suq.nextEvent().getTime()); + } +} diff --git a/test/SettingsTest.java b/test/SettingsTest.java new file mode 100644 index 000000000..4212238f9 --- /dev/null +++ b/test/SettingsTest.java @@ -0,0 +1,219 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.io.File; +import java.io.PrintWriter; + +import junit.framework.TestCase; +import core.Settings; + +/** + * Tests Settings class' different setting getting methods + */ +public class SettingsTest extends TestCase { + private static final String IRS_S = "invalidRunSetting"; + + private static final String CSV_RS_S = "csvRunSetting"; + private static final int[] CSV_RS_V = {1,2,3,4}; + + private static final String TST = "tstSetting"; + private static final String TST_RES = "tst"; + private static final String[] INPUT = { + "Ns.setting1 = 1", + "Ns.setting2 = true", + TST + " = " + TST_RES, + "tstSetting2 = tst2", + "double = 1.1", + "csvDoubles = 1.1,2.2,3.3", + "csvInts 1,2,3", + "booleanTrue = true", + "booleanFalse = false", + "int = 1", + "runSetting = [val1 ; val2;val3; val4 ]", + IRS_S + " = [val1 ; val2", + CSV_RS_S + " = [" + CSV_RS_V[0]+","+CSV_RS_V[1]+";"+CSV_RS_V[2]+","+CSV_RS_V[3]+"]", + "Ns.runSetting = [ ; ; 2; ]", + "DefNs.runSetting = 1" + + }; + + private String RS_S = "runSetting"; + + + private Settings s; + + protected void setUp() throws Exception { + super.setUp(); + File tempFile = File.createTempFile("settingsTest", ".tmp"); + tempFile.deleteOnExit(); + + PrintWriter out = new PrintWriter(tempFile); + + for (String s : INPUT) { + out.println(s); + } + out.close(); + + Settings.init(tempFile.getAbsolutePath()); + s = new Settings(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + Settings.setRunIndex(0); + } + + + public void testContains() { + assertTrue(s.contains("Ns.setting1")); + assertTrue(s.contains("Ns.setting2")); + } + + public void testGetSetting() { + assertEquals("1", s.getSetting("Ns.setting1")); + assertEquals("true", s.getSetting("Ns.setting2")); + } + + public void testGetDouble() { + assertEquals(1.1, s.getDouble("double")); + } + + public void testGetCsvSetting() { + String[] csv = s.getCsvSetting("csvInts",3); + assertEquals(csv.length, 3); + assertEquals("1",csv[0]); + assertEquals("2",csv[1]); + assertEquals("3",csv[2]); + } + + public void testGetCsvDoubles() { + double[] csv = s.getCsvDoubles("csvDoubles",3); + assertEquals(csv.length, 3); + assertEquals(1.1,csv[0]); + assertEquals(2.2,csv[1]); + assertEquals(3.3,csv[2]); + } + + public void testGetCsvDoublesUnknownAmount() { + double[] csv = s.getCsvDoubles("csvDoubles"); + assertEquals(csv.length, 3); + assertEquals(1.1,csv[0]); + assertEquals(2.2,csv[1]); + assertEquals(3.3,csv[2]); + } + + public void testGetCsvInts() { + int[] csv = s.getCsvInts("csvInts",3); + assertEquals(csv.length, 3); + assertEquals(1,csv[0]); + assertEquals(2,csv[1]); + assertEquals(3,csv[2]); + } + + public void testGetCsvIntsUnknownAmount() { + int[] csv = s.getCsvInts("csvInts"); + assertEquals(csv.length, 3); + assertEquals(1,csv[0]); + assertEquals(2,csv[1]); + assertEquals(3,csv[2]); + } + + public void testGetInt() { + assertEquals(1,s.getInt("int")); + } + + public void testGetBoolean() { + assertTrue(s.getBoolean("booleanTrue")); + assertFalse(s.getBoolean("booleanFalse")); + } + + public void testCreateIntializedObject() { + Object o = s.createIntializedObject("movement.RandomWaypoint"); + assertTrue(o instanceof movement.RandomWaypoint); + } + + + public void testValueFillString() { + String test = "1-%%tstSetting%%-2-%%tstSetting2%%"; + String result = s.valueFillString(test); + assertEquals("1-tst-2-tst2",result); + + result = s.valueFillString("%%"+TST+"%%-aaa"); + assertEquals(TST_RES + "-aaa",result); + + result = s.valueFillString("%%"+TST+"%%"); + assertEquals(TST_RES,result); + } + + public void testRunIndex() { + assertEquals(s.getSetting(RS_S), "val1"); + Settings.setRunIndex(1); + assertEquals(s.getSetting(RS_S), "val2"); + Settings.setRunIndex(2); + assertEquals(s.getSetting(RS_S), "val3"); + Settings.setRunIndex(3); + assertEquals(s.getSetting(RS_S), "val4"); + Settings.setRunIndex(4); + assertEquals(s.getSetting(RS_S), "val1"); // should wrap around + Settings.setRunIndex(5); + assertEquals(s.getSetting(RS_S), "val2"); + } + + public void testRunIndexContains() { + assertFalse(s.contains("Ns.runSetting")); + Settings.setRunIndex(2); + assertTrue(s.contains("Ns.runSetting")); + } + + /** + * Test filling empty values of run index from secondary namespace + */ + public void testEmptyRunIndex() { + String rs = "runSetting"; + Settings s = new Settings("Ns"); + s.setSecondaryNamespace("DefNs"); + assertEquals(s.getInt(rs), 1); + Settings.setRunIndex(1); + assertEquals(s.getInt(rs), 1); + + Settings.setRunIndex(2); + assertEquals(s.getInt(rs), 2); // the only defined value + + Settings.setRunIndex(3); + assertEquals(s.getInt(rs), 1); + } + + public void testRunIndexCSVs() { + // test CSVs + int [] vals = s.getCsvInts(CSV_RS_S, 2); + assertEquals(CSV_RS_V[0],vals[0]); + assertEquals(CSV_RS_V[1],vals[1]); + + Settings.setRunIndex(1); + vals = s.getCsvInts(CSV_RS_S, 2); + assertEquals(CSV_RS_V[2],vals[0]); + assertEquals(CSV_RS_V[3],vals[1]); + + Settings.setRunIndex(2); // wrap around + vals = s.getCsvInts(CSV_RS_S, 2); + assertEquals(CSV_RS_V[0],vals[0]); + assertEquals(CSV_RS_V[1],vals[1]); + } + + public void testInvalidRunIndex() { + assertEquals("[val1 ; val2",s.getSetting(IRS_S)); + } + + /** + * Tests disabled run-specific variables + */ + public void testNoRun() { + Settings.setRunIndex(-1); + assertEquals("[val1 ; val2;val3; val4 ]", s.getSetting(RS_S)); + } + +} diff --git a/test/StationaryMovement.java b/test/StationaryMovement.java new file mode 100644 index 000000000..5ea0bbaa4 --- /dev/null +++ b/test/StationaryMovement.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import movement.MovementModel; +import movement.Path; +import core.Coord; + +/** + * A dummy stationary "movement" model where nodes do not move for testing + * purposes + */ +public class StationaryMovement extends MovementModel { + private Coord loc; + + public StationaryMovement(Coord location) { + if (location == null) { + this.loc = new Coord(0,0); + } + else { + this.loc = location; + } + } + + /** + * Returns the only location of this movement model + * @return the only location of this movement model + */ + @Override + public Coord getInitialLocation() { + return loc; + } + + @Override + public boolean isActive() { + return true; + } + + /** + * Returns a single coordinate path (using the only possible coordinate) + * @return a single coordinate path + */ + @Override + public Path getPath() { + Path p = new Path(0); + p.addWaypoint(loc); + return p; + } + + @Override + public double nextPathAvailable() { + return Double.MAX_VALUE; // no new paths available + } + + @Override + public StationaryMovement replicate() { + return new StationaryMovement(loc); + } + +} diff --git a/test/TestDTNHost.java b/test/TestDTNHost.java new file mode 100644 index 000000000..9f8e4f30f --- /dev/null +++ b/test/TestDTNHost.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.util.List; + +import routing.PassiveRouter; +import core.Coord; +import core.DTNHost; +import core.Message; +import core.ModuleCommunicationBus; +import core.NetworkInterface; +import core.Settings; +import core.SimClock; + +/** + * A test stub of DTNHost for testing. All fields are public so they can be + * easily read from test cases. + */ +public class TestDTNHost extends DTNHost { + public double lastUpdate = 0; + public int nrofConnect = 0; + public int nrofUpdate = 0; + public Message recvMessage; + public DTNHost recvFrom; + public String abortedId; + public DTNHost abortedFrom; + public int abortedBytesRemaining; + + public String transferredId; + public DTNHost transferredFrom; + + + public TestDTNHost(List li, + ModuleCommunicationBus comBus, Settings testSettings) { + super(null,null,"TST", li, comBus, + new StationaryMovement(new Coord(0,0)), + new PassiveRouter( + (testSettings == null ? new TestSettings() : + testSettings))); + } + + @Override + public void connect(DTNHost anotherHost) { + this.nrofConnect++; + } + + @Override + public void update(boolean up) { + this.nrofUpdate++; + this.lastUpdate = SimClock.getTime(); + } + + @Override + public int receiveMessage(Message m, DTNHost from) { + this.recvMessage = m; + this.recvFrom = from; + return routing.MessageRouter.RCV_OK; + } + + @Override + public void messageAborted(String id, DTNHost from, int bytesRemaining) { + this.abortedId = id; + this.abortedFrom = from; + this.abortedBytesRemaining = bytesRemaining; + } + + @Override + public void messageTransferred(String id, DTNHost from) { + this.transferredId = id; + this.transferredFrom = from; + } +} diff --git a/test/TestInterface.java b/test/TestInterface.java new file mode 100644 index 000000000..490f2554f --- /dev/null +++ b/test/TestInterface.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import core.CBRConnection; +import core.Connection; +import core.DTNHost; +import core.NetworkInterface; +import core.Settings; + +public class TestInterface extends NetworkInterface { + + public TestInterface(Settings s) { + super(s); + } + + public TestInterface(TestInterface ti) { + super(ti); + } + + /** + * Replication function + */ + public NetworkInterface replicate() { + return new TestInterface(this); + } + + /** + * Gives the currentTransmit Speed + */ + public int getTransmitSpeed() { + return transmitSpeed; + } + + /** + * Gives the currentTransmit Range + */ + public double getTransmitRange() { + return transmitRange; + } + + /** + * Connects the interface to another interface. + * + * Overload this in a derived class. Check the requirements for + * the connection to work in the derived class, then call + * connect(Connection, NetworkInterface) for the actual connection. + * @param anotherInterface The host to connect to + */ + public void connect(NetworkInterface anotherInterface) { + Connection con = new CBRConnection(this.getHost(),this, + anotherInterface.getHost(),anotherInterface, transmitSpeed); + this.connect(con, anotherInterface); + } + + /** + * Updates the state of current connections (ie tears down connections + * that are out of range, recalculates transmission speeds etc.). + */ + public void update() { + for (int i=0; i conListeners; + private List msgListeners; + private String groupId = "h"; + private List allHosts; + private MessageRouter mr; + + private ModuleCommunicationBus comBus; + private TestSettings settings; + + public static String IFACE_NS = "interface"; + + /** + * Creates a test utils object suitable for creating new hosts. + * @param cl Connection listeners for the hosts + * @param ml Message -"- + * @param settings Setting object given to message router + */ + public TestUtils(List cl, List ml, + TestSettings settings) { + this.conListeners = cl; + this.msgListeners = ml; + this.allHosts = new ArrayList(); + this.settings = settings; + this.mr = new PassiveRouter(settings); + + this.comBus = new ModuleCommunicationBus(); + } + + public void setMessageRouterProto(MessageRouter mr) { + this.mr = mr; + } + + /** + * @param conListeners the ConnectionListeners to set + */ + public void setConListeners(List conListeners) { + this.conListeners = conListeners; + } + + /** + * @param groupId the groupId to set + */ + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + /** + * @param msgListeners the MessageListeners to set + */ + public void setMsgListeners(List msgListeners) { + this.msgListeners = msgListeners; + } + + /** + * @param transmitRange the transmitRange to set + */ + public void setTransmitRange(double transmitRange) { + this.comBus.updateProperty(NetworkInterface.RANGE_ID, transmitRange); + } + + /** + * Creates a host to a location with stationary movement model and + * MessageRouter router. + * @param loc The location of the host + * @param name Name of the host (or null for default) + * @return The new host + */ + public DTNHost createHost(Coord loc, String name) { + MovementModel mmProto = new StationaryMovement(loc); + return createHost(mmProto, name); + } + + /** + * Creates a host with defined movement model + * @param mmProto The prototype of the movement model + * @param name name of the host + * @return the host + */ + public DTNHost createHost(MovementModel mmProto, String name) { + if (settings.getNameSpace() == null) { + settings.setNameSpace(IFACE_NS); + } + if (!this.settings.contains(NetworkInterface.TRANSMIT_RANGE_S)) { + settings.putSetting(NetworkInterface.TRANSMIT_RANGE_S, "1.0"); + settings.putSetting(NetworkInterface.TRANSMIT_SPEED_S, "1"); + } + + NetworkInterface ni = new TestInterface(settings); + ni.setClisteners(conListeners); + List li = new ArrayList(); + li.add(ni); + DTNHost host = new DTNHost(msgListeners, null, groupId, + li, comBus, mmProto, mr); + if (name != null) { + host.setName(name); + } + + this.allHosts.add(host); + return host; + } + + /** + * Creates a host to a location with stationary movement model and + * default name. + * @param loc The location of the host + * @return The new host + */ + public DTNHost createHost(Coord loc) { + return this.createHost(loc, null); + } + + /** + * Creates a host to location (0,0) with stationary movement model + * and default name. + * @return The new host + */ + public DTNHost createHost() { + return this.createHost(new Coord(0,0)); + } + + public List getAllHosts() { + return this.allHosts; + } +} diff --git a/test/TotalContactTimeReportTest.java b/test/TotalContactTimeReportTest.java new file mode 100644 index 000000000..a9d221703 --- /dev/null +++ b/test/TotalContactTimeReportTest.java @@ -0,0 +1,138 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.Vector; + +import junit.framework.TestCase; +import report.Report; +import report.TotalContactTimeReport; +import core.ConnectionListener; +import core.Coord; +import core.DTNHost; +import core.SimClock; + +public class TotalContactTimeReportTest extends TestCase { + private BufferedReader ctReader; + private File outFile; + private SimClock clock; + private TotalContactTimeReport ctr; + + private DTNHost h1, h2, h3; + private Coord c1 = new Coord(0,0); + private Coord c2 = new Coord(1,0); + private Coord c3 = new Coord(2,0); + private Coord away = new Coord(1000,1000); + + private final String SET_PREFIX = "TotalContactTimeReport."; + + protected void setUp() throws Exception { + super.setUp(); + SimClock.reset(); + outFile = File.createTempFile("cttest", ".tmp"); + outFile.deleteOnExit(); + + TestSettings ts = new TestSettings(); + ts.putSetting(SET_PREFIX + + report.Report.PRECISION_SETTING, "1"); // drop precision to 1 + ts.putSetting(SET_PREFIX + report.ContactTimesReport.GRANULARITY, "5"); + + ts.putSetting(SET_PREFIX + Report.OUTPUT_SETTING, + outFile.getAbsolutePath()); + + clock = SimClock.getInstance(); + ctr = new TotalContactTimeReport(); + + Vector cl = new Vector(); + cl.add(ctr); + TestUtils utils = new TestUtils(cl, null, ts); + + utils.setTransmitRange(3); // make sure everyone can connect + h1 = utils.createHost(c1); + h2 = utils.createHost(c2); + h3 = utils.createHost(c3); + } + + private void done() throws Exception { + ctr.done(); + ctReader = new BufferedReader(new FileReader(outFile)); + } + + public void testReport() throws Exception { + clock.advance(5); + h1.connect(h2); + clock.advance(10); + disc(h2); + ctr.updated(null); + h1.connect(h2); + clock.advance(1); + ctr.updated(null); // less time than granularity has passed -> suppress + clock.advance(4); + ctr.updated(null); // now should report + + checkValues(new String[] {"15.0 10.0", "20.0 15.0"}); + } + + public void testMultipleTimes() throws Exception { + clock.advance(10); + h1.connect(h2); + clock.advance(10); + disc(h2); + ctr.updated(null); + h2.connect(h3); + clock.advance(5); + ctr.updated(null); + + checkValues(new String[] {"20.0 10.0", "25.0 15.0"}); + } + + public void testOverlappingTimes() throws Exception { + clock.advance(5); + h1.connect(h2); + clock.advance(5); + ctr.updated(null); // h1-h2 connected for 5s -> @10: 5s + h2.connect(h3); + clock.advance(10); + ctr.updated(null); // h1-h2 for 15s and h2-h3 for 10s -> @20: 25s + h1.setLocation(away); + h1.update(true); // h1-h2 disconnected + clock.advance(10); + disc(h3); // h2-h3 connected for 20s + h1-h2 15s -> @30: 35s + ctr.updated(null); + clock.advance(10); + ctr.updated(null); // no more active connections -> should suppress this + + h2.connect(h3); + clock.advance(5); + ctr.updated(null); // h2-h3 5s -> @45: 40s + + checkValues(new String[] {"10.0 5.0", "20.0 25.0", "30.0 35.0", + "45.0 40.0"}); + } + + private void disc(DTNHost host) { + Coord loc = host.getLocation(); + host.setLocation(away); + host.update(true); + host.setLocation(loc); + } + + private void checkValues(String[] values) throws Exception { + done(); + // read header line away + assertTrue(ctReader.ready()); + assertEquals(TotalContactTimeReport.HEADER, ctReader.readLine()); + + for (String value : values) { + assertEquals(value,ctReader.readLine()); + } + assertEquals(null,ctReader.readLine()); // no more times left + + } + +} diff --git a/test/WKTPointReaderTest.java b/test/WKTPointReaderTest.java new file mode 100644 index 000000000..4977a8e4f --- /dev/null +++ b/test/WKTPointReaderTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.WKTReader; + +import java.io.StringReader; +import java.util.List; + +import junit.framework.TestCase; +import core.Coord; + +public class WKTPointReaderTest extends TestCase { + + private WKTReader r; + + private final String POINT_DATA = + "POINT (2552448.388211649 6673384.4020657055) \n"+ + "POINT (2552275.9398973365 6673509.820852942)\n"+ + "POINT (2552361.289603607 6673630.088457832)\n"+ + "LINESTRING (1.0 2.0, 2.0 3.0)\n"+ // should skip this line + "POINT (2552782.3212060533 6673285.5993876355)\n"; + + private final Coord[] POINTS = { + new Coord(2552448.388211649, 6673384.4020657055), + new Coord(2552275.9398973365, 6673509.820852942), + new Coord(2552361.289603607, 6673630.088457832), + new Coord(2552782.3212060533, 6673285.5993876355) + }; + + protected void setUp() throws Exception { + super.setUp(); + r = new WKTReader(); + } + + public void testReader() throws Exception { + StringReader input = new StringReader(POINT_DATA); + List coords = r.readPoints(input); + + assertEquals(POINTS.length, coords.size()); + + for (int i=0; i nh) { + MapNode n1,n2,n3,n4,n5,n8,n9; + + // right amount of nodes? + assertEquals(NROF_TST_NODES, nh.size()); + + n1 = nh.get(n1c); + n2 = nh.get(n2c); + n3 = nh.get(new Coord(8,1)); + n4 = nh.get(new Coord(1,3)); + n5 = nh.get(new Coord(3,0)); + n8 = nh.get(new Coord(2,3)); + n9 = nh.get(n9c); + + // all nodes exist? + assertNotNull(n1); + assertNotNull(n2); + assertNotNull(n3); + assertNotNull(n4); + assertNotNull(n5); + assertNotNull(n8); + assertNotNull(n9); + + // nodes have correct amount of neighbors? + assertEquals(2, n1.getNeighbors().size()); + assertEquals(3, n2.getNeighbors().size()); + assertEquals(1, n3.getNeighbors().size()); + assertEquals(2, n4.getNeighbors().size()); + assertEquals(2, n5.getNeighbors().size()); + assertEquals(2, n8.getNeighbors().size()); + assertEquals(1, n9.getNeighbors().size()); + } + + public void testFromFile() throws IOException { + File wktFile = File.createTempFile("WKTReaderTest","tmp"); + wktFile.deleteOnExit(); + PrintWriter pw = new PrintWriter(wktFile); + WKTMapReader reader; + + pw.println(TST_TOPOLOGY); + pw.close(); + reader = setUpWith(new FileReader(wktFile)); + + basicNodesTests(reader); + topologyTest(reader.getNodesHash()); + } + + public void testMultiLineString() { + String multiline = "MULTILINESTRING ((1.0 1.0, 2.0 1.0, 3.0 1.0),"+ + "(1.0 1.0, 1.0 2.0))"; + StringReader input = new StringReader(multiline); + Map nh; + + WKTMapReader reader = setUpWith(input); + nh = reader.getNodesHash(); + + assertEquals(4, nh.size()); + } + + public void testReadContents() throws IOException { + String c1 = "lorem ipsum dolor sit amet"; + String c2 = "lorem ipsum\r\ndolor sit\n\r amet"; + String internal = "(lorem),(ipsum)"; + String cont = "ACTION ("+c1+")"; + String cont2 = "ACTION ("+c2+")"; + String cont3 = "MLS ("+internal+")"; + + WKTMapReader r = new WKTMapReader(true); + + StringReader s = new StringReader(cont3); + assertEquals(internal, r.readNestedContents(s)); + + s = new StringReader(cont); + assertEquals(c1,r.readNestedContents(s)); + + s = new StringReader(cont2); + // should convert newline to space + c2 = c2.replaceAll("(\r|\n)", " "); + assertEquals(c2,r.readNestedContents(s)); + } + + public void testMapOperations() { + String wkt = "LINESTRING (1.0 1.0, 2.0 5.0)\n" + + "LINESTRING (1.0 1.0, 1.0 3.0)\n"; + WKTMapReader reader = setUpWith(new StringReader(wkt)); + SimMap map = reader.getMap(); + + Coord max = map.getMaxBound(); + Coord min = map.getMinBound(); + + assertEquals(2.0, max.getX()); + assertEquals(5.0, max.getY()); + assertEquals(1.0, min.getX()); + assertEquals(1.0, min.getY()); + + map.translate(-1, -1); + max = map.getMaxBound(); + min = map.getMinBound(); + + assertEquals(1.0, max.getX()); + assertEquals(4.0, max.getY()); + assertEquals(0.0, min.getX()); + assertEquals(0.0, min.getY()); + + } + + public void testMultipleMapFiles() throws Exception { + File wktFile1 = File.createTempFile("WKTReaderTest","tmp"); + File wktFile2 = File.createTempFile("WKTReaderTest","tmp"); + File wktFile3 = File.createTempFile("WKTReaderTest","tmp"); + wktFile1.deleteOnExit(); + wktFile2.deleteOnExit(); + wktFile3.deleteOnExit(); + + PrintWriter pw = new PrintWriter(wktFile1); + pw.println(TST_TOPOLOGY); + pw.close(); + pw = new PrintWriter(wktFile2); + pw.println(ADD_TOPOLOGY); + pw.close(); + pw = new PrintWriter(wktFile3); + pw.println(ADD_TOPOLOGY2); + pw.close(); + + WKTMapReader reader = new WKTMapReader(true); + reader.addPaths(wktFile1, 1); + reader.addPaths(wktFile2, 2); + reader.addPaths(wktFile3, 31); + + basicNodesTests(reader); + + SimMap map = reader.getMap(); + + // n1 should be of type 1 + MapNode n1 = map.getNodeByCoord(n1c); + assertTrue(n1.isType(1)); + assertTrue(n1.isType(new int [] {2,1})); + assertFalse(n1.isType(2)); + + // n10 should be of type 2 + assertTrue(map.getNodeByCoord(n10c).isType(2)); + assertFalse(map.getNodeByCoord(n10c).isType(1)); + + // n9 should be type1, type2 and type31 + MapNode n9 = map.getNodeByCoord(n9c); + assertTrue(n9.isType(2)); + assertTrue(n9.isType(1)); + assertTrue(n9.isType(31)); + assertFalse(n9.isType(4)); + + assertTrue(n9.isType(new int [] {1,2,31})); + assertTrue(n9.isType(new int [] {5,2})); + assertTrue(n9.isType(new int [] {1,5})); + assertTrue(n9.isType(new int [] {5,7,31})); + assertFalse(n9.isType(new int [] {5,7,8})); + + // n11 should be only 31 + assertTrue(map.getNodeByCoord(n11c).isType(31)); + assertFalse(map.getNodeByCoord(n11c).isType(2)); + } + + private void basicNodesTests(WKTMapReader reader) { + Collection col = reader.getNodes(); + + // contains something + assertTrue(col.size() > 0); + + for (MapNode n : col) { + // no lonely nodes + assertTrue(n.getNeighbors().size() >= 1); + } + } + +} diff --git a/test/WorldTest.java b/test/WorldTest.java new file mode 100644 index 000000000..f54a9b5eb --- /dev/null +++ b/test/WorldTest.java @@ -0,0 +1,149 @@ +/* + * Copyright 2010 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ +package test; + +import input.EventQueue; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import core.DTNHost; +import core.ModuleCommunicationBus; +import core.NetworkInterface; +import core.SimClock; +import core.UpdateListener; +import core.World; + + +/** + * Tests for the World class + * TODO: much more tests + */ +public class WorldTest extends TestCase { + /* for rounding errors with SimClock */ + private static final double TIME_DELTA = 0.00001; + private World world; + private boolean simulateConnections = true; + private int worldSizeX = 100; + private int worldSizeY = 100; + private double upInterval = 0.1; + private List testHosts; + private List eQueues; + + protected void setUp() throws Exception { + super.setUp(); + SimClock.reset(); + TestSettings testSettings = new TestSettings(); + testSettings.setNameSpace(TestUtils.IFACE_NS); + testSettings.putSetting(NetworkInterface.TRANSMIT_RANGE_S, "1.0"); + testSettings.putSetting(NetworkInterface.TRANSMIT_SPEED_S, "1"); + + this.eQueues = new ArrayList(); + this.testHosts = new ArrayList(); + for (int i=0; i<10; i++) { + NetworkInterface ni = new TestInterface(testSettings); + List li = new ArrayList(); + li.add(ni); + ModuleCommunicationBus comBus = new ModuleCommunicationBus(); + + this.testHosts.add(new TestDTNHost(li, comBus, testSettings)); + } + + TestScenario ts = new TestScenario(); + this.world = new World(ts.getHosts(),ts.getWorldSizeX(), + ts.getWorldSizeY(),ts.getUpdateInterval(), + ts.getUpdateListeners(), ts.simulateConnections(), + ts.getExternalEvents() ); + } + + public void testUpdate() { + double endTime = 1000; + int nrofRounds = (int)(endTime/upInterval); + + for (int i=0; i getUpdateListeners() { + return new ArrayList(); + } + + public List getHosts() { + ArrayList hs = new ArrayList(); + for (TestDTNHost h : testHosts) { + hs.add(h); + } + return hs; + } + + public boolean simulateConnections() { + return simulateConnections; + } + + public List getExternalEvents() { + return eQueues; + } + + public double getMaxHostRange() { + return 10; + } + + protected void createHosts() { + this.hosts = new ArrayList(); + } + } +} diff --git a/test/package.html b/test/package.html new file mode 100644 index 000000000..88f91ece0 --- /dev/null +++ b/test/package.html @@ -0,0 +1,8 @@ + + + + +Provides some unit and integration tests for the classes. + + + \ No newline at end of file diff --git a/toolkit/Common.pm b/toolkit/Common.pm new file mode 100644 index 000000000..6a5aa9095 --- /dev/null +++ b/toolkit/Common.pm @@ -0,0 +1,60 @@ +package Toolkit; + +# Common methods (parseArgs & debug) for toolkit programs + +use strict; +use warnings; + +our @EXPORT = qw(parseArgs debug); + +my $quietMode = 0; + +# Parses INFILE and OUTFILE from command line arguments +# and shows help or toggles quiet mode if requested. +sub parseArgs { + my $progName = shift; + my $infile; + my $outfile; + +# show help with -h, -?, /h, /? or -help (etc.) + if (defined $ARGV[0] and $ARGV[0] =~ m/^[-\/][h\?]/) { + print "$progName\n"; +print 'Usage: [-h] [-q] + -h : show this help + -q : quiet mode (nothing is printed to stderr) +Default infile and outfile are stdin and stdout. +Discarded lines and "errors" are printed to stderr. +'; + exit(); +} + + if (defined $ARGV[0] and $ARGV[0] =~ m/^-q/) { + $quietMode = 1; + shift @ARGV; + } + + $infile = shift @ARGV;; + $outfile = shift @ARGV; + + if ($infile) { + open(INFILE, $infile) or die "Can't open $infile : $!"; + } + else { + open(INFILE, "<-") or die "Can't read from stdin"; + } + + if ($outfile) { + open OUTFILE, ">$outfile" or die "Can't open $outfile : $!"; + } + else { + open(OUTFILE, ">-") or die "Can't open stdout"; + } +} + +# Prints errors and debug information to stderr (unless $quietMode is set) +sub debug { + my $txt = shift; + print STDERR "$txt\n" unless $quietMode; +} + +1; diff --git a/toolkit/ccdfPlotter.pl b/toolkit/ccdfPlotter.pl new file mode 100755 index 000000000..423fe128b --- /dev/null +++ b/toolkit/ccdfPlotter.pl @@ -0,0 +1,201 @@ +#! /usr/bin/perl + +package Toolkit; + +# (C)CDF gnuplot plotter + +use strict; +use warnings; +use Getopt::Long; + +# path to the gnuplot program +my $gnuplot = "gnuplot"; + +my ( + $outfile, $constTotalSum, $hitCountIndex, + $labelRe, $term, $range, + $params, $comp, $logscale, $help +); + +my $usage = ' +usage: -out + [-comp] + [-log] + [-total ] + [-index ] + [-label ] + [-params ] + [-term ] + [-range ] + fileNames... +'; + +GetOptions( + "total=i" => \$constTotalSum, + "index=i" => \$hitCountIndex, + "label=s" => \$labelRe, + "params=s" => \$params, + "out=s" => \$outfile, + "term=s" => \$term, + "range=s" => \$range, + "comp!" => \$comp, + "log!" => \$logscale, + "help|?!" => \$help +); + +if ($help) { + print '(Complementary) Cumulative Distribution plotter. Creates CDF plots +from timestamped hitcount reports using gnuplot. All given input files +are plotted to the same graph.'; + print "\n$usage"; + print ' +options: + +out Output file name\'s prefix + +total If defined, the total value against which cumulative values are compared. + By default, total is calculated from the input file. + +index Index (which of whitespace delimeted fields) of the hitcount value. + Default = 1 (first field after time stamp). Zero value reports hitcount + of 1 for each line. + +comp Do Complementary CDF instead of normal CDF + +label A regular expression which is used to parse labels for plots from the + input file names. Use capture groups to get the content(s). + Default = \'([^_]*)_\' (everything up to the first underscore) + +params Gnuplot plotting style parameters. Default = \'smooth unique\' + +term Name of the terminal used for gnuplot output. Use "na" for no terminal + (only the gnuplot output file is created). Default = emf + +range Range of x-values in the resulting graph (e.g. 0:100). + Default = no range, i.e. automatic scaling by gnuplot +'; + exit(); +} + +if ( not defined $outfile or not @ARGV ) { + print "Missing required parameter(s)\n"; + print $usage; + exit(); +} + +$hitCountIndex = 1 unless defined $hitCountIndex; +$term = "emf" unless defined $term; +$params = "smooth unique" unless defined $params; +$labelRe = '([^_]*)_' unless defined $labelRe; + +my $plotfile = "$outfile.gnuplot"; + +open( PLOT, ">$plotfile" ) or die "Can't open plot output file $plotfile : $!"; +if ($logscale) { + print PLOT "set logscale x\n"; +} +if ($comp) { + print PLOT "set ylabel \"1-P(X <= x)\"\n"; +} +else { + print PLOT "set ylabel \"P(X <= x)\"\n"; +} +if ( defined($range) ) { + print PLOT "set xrange [$range]\n"; +} + +if ( not $term eq "na" ) { + my ($suffix) = $term=~ /(\S+)/; + print PLOT "set terminal $term\n"; + print PLOT "set output \"$outfile.$suffix\"\n"; +} +print PLOT "plot "; + +my $round = 0; +while ( my $infile = shift(@ARGV) ) { + if ( $round > 0 ) { + print PLOT ", "; + } + $round++; + + open( INFILE, "$infile" ) or die "Can't open $infile : $!"; + + # strip 1-3 char extension (if any) + if ( $infile =~ m/.*\.\w{1,3}/ ) { + ($infile) = $infile =~ m/(.*)\.\w{1,3}/; + } + + my $cdffile = "$infile.cdf"; + + my $totalSum; + my $hitcount; + my $time; + my @values; + + open( OUTFILE, ">$cdffile" ) or die "Can't open output file $cdffile : $!"; + + if ( defined $constTotalSum ) { + $totalSum = $constTotalSum; + } + else { + while () { + @values = split; + next if $values[0] eq "#"; # skip comment lines + + if ( $hitCountIndex > 0 ) { + $totalSum += $values[$hitCountIndex]; + } + else { + $totalSum += 1; + } + } + seek( INFILE, 0, 0 ); + } + + my $cumSum = 0; + + while () { + @values = split; + next if $values[0] eq "#"; + + $time = $values[0]; + if ( $hitCountIndex > 0 ) { + $hitcount = $values[$hitCountIndex]; + } + else { + $hitcount = 1; + } + + if ( $hitcount > 0 ) { + $cumSum += $hitcount; + my $finalValue; + if ($comp) { + $finalValue = 1 - ( $cumSum / $totalSum ); + } + else { + $finalValue = ( $cumSum / $totalSum ); + } + print OUTFILE "$time ", $finalValue, "\n"; + } + } + + close(OUTFILE); + close(INFILE); + + print PLOT "'$cdffile'"; + if ( defined($labelRe) ) { # extract label for legend + my @labels = $infile =~ m/$labelRe/; + die "Cant' extract label using \'$labelRe\' from $infile" + unless @labels; + print PLOT " title \"@labels\""; + } + print PLOT " $params"; + +} + +print PLOT "\n"; +close(PLOT); + +if ( not $term eq "na" ) { + system("$gnuplot $plotfile") == 0 or die "Can't run gnuplot: $?"; +} diff --git a/toolkit/createCircles.pl b/toolkit/createCircles.pl new file mode 100755 index 000000000..a4c6963b0 --- /dev/null +++ b/toolkit/createCircles.pl @@ -0,0 +1,60 @@ +#! /usr/bin/perl +package Toolkit; + +use strict; +use warnings; +use Getopt::Long; +use Math::Trig; + +# Creates node settings for a circular network with given number of rings + +# prefix of hosts +my $hostPrefix = "g"; +# number of rings + +my ($rings, $radius, $help); + +GetOptions("rings=n" => \$rings, + "radius=n" => \$radius, + "help|?!" => \$help); + +unless (defined($help)) { + unless (defined($rings) and defined($radius)) { + print "Missing required parameters\n"; + $help = 1; + } +} + +if ($help) { + print "Usage: + -rings -radius \n"; + exit(); +} + +my $orig = $rings * $radius + 2*$radius; +my $hostID = 1; +for (my $ring = 0; $ring <= $rings; $ring++) { + + if ($ring==0) { + my $nrOfHosts = 1; + for (my $tmp = 1; $tmp <= $rings; $tmp++) { + $nrOfHosts+= $tmp*6; + } + print "Scenario.nrofHostGroups = $nrOfHosts\n"; + print "Group.movementModel = StationaryMovement\n"; + print "Group.nrofHosts = 1\n"; + print "Group.groupID = $hostPrefix\n"; + print "Group$hostID.nodeLocation = $orig, $orig\n"; + $hostID++; + } else { + my $nodes = $ring*6; + my $angle = 2*pi/$nodes; + for (my $node = 0; $node < $nodes; $node++) { + my $x = int($orig + $ring*$radius*cos($node*$angle)); + my $y = int($orig + $ring*$radius*sin($node*$angle)); + print "Group$hostID.nodeLocation = $x , $y\n"; + $hostID++; + } + } + +} diff --git a/toolkit/createCreates.pl b/toolkit/createCreates.pl new file mode 100755 index 000000000..dc1bca5cb --- /dev/null +++ b/toolkit/createCreates.pl @@ -0,0 +1,90 @@ +#! /usr/bin/perl +package Toolkit; + +use strict; +use warnings; +use Getopt::Long; + +# Creates external message create events (random uniform dist) + +# smallest time step between two consecutive messages +my $step = 0.1; +# time stamp precision (number of decimals) +my $prec = 1; +# prefix of message IDs +my $msgPrefix = "M"; +# prefix of hosts +my $hostPrefix = ""; +# index of first message +my $msgIndex = 1; + +my ($randSeed, $nrofMessages, $times, $hosts, $sizes, $rsizes, $help); + +GetOptions("seed=i" => \$randSeed, "time=s" => \$times, + "nrof=i" => \$nrofMessages, + "hosts=s" => \$hosts, + "sizes=s" => \$sizes, + "rsizes=s" => \$rsizes, + "help|?!" => \$help); + +unless (defined($help)) { + unless (defined($times) and defined($nrofMessages) + and defined($hosts) and defined($sizes)) { + print "Missing required parameters\n"; + $help = 1; + } +} + +if ($help) { + print 'Usage: + -time : -nrof + -hosts : -sizes : + [-rsizes :] [-seed ] + + Minimum values are inclusive, max values are exclusive. +'; + exit(); +} + +my ($minHost, $maxHost) = $hosts =~ m/(\d+):(\d+)/; +my ($start, $end) = $times =~ m/(\d+):(\d+)/; +my ($minSize, $maxSize) = $sizes =~ m/(\d+):(\d+)/; + +my ($rMinSize, $rMaxSize); + +if (defined($rsizes)) { + ($rMinSize, $rMaxSize) = $rsizes =~ m/(\d+):(\d+)/; +} + +my $nrof = 0; +die "minHost >= maxHost" if $minHost >= $maxHost; + +if (defined($randSeed)) { + srand($randSeed); +} + +for (my $time = $start; $time < $end; $time += $step) { + my $prob = $step * (($nrofMessages - $nrof) / ($end - $time)); + + if (rand() < $prob) { + my $from = int(rand() * ($maxHost-$minHost) + $minHost); + my $to = $from; + while ($to == $from) { # make sure $to and $from are not the same + $to = int(rand() * ($maxHost-$minHost) + $minHost); + } + my $size = int(rand() * ($maxSize-$minSize) + $minSize); + + printf "%.${prec}f",$time; + print "\tC\t$msgPrefix$msgIndex\t$hostPrefix$from\t$hostPrefix$to"; + print "\t$size"; + + if (defined($rMinSize) and defined($rMaxSize)) { + my $rsize = int(rand() * ($rMaxSize-$rMinSize) + $rMinSize); + print "\t$rsize"; + } + print "\n"; + + $msgIndex++; + $nrof++; + } +} diff --git a/toolkit/delProb.pl b/toolkit/delProb.pl new file mode 100755 index 000000000..d48a5f771 --- /dev/null +++ b/toolkit/delProb.pl @@ -0,0 +1,98 @@ +#! /usr/bin/perl +package Toolkit; + +# Distance vs. Delivery probability from DistanceDelayReport + +use strict; +use warnings; + +if (not defined $ARGV[0] or not defined $ARGV[1]) { + print "Usage: [plotXrangeMax]\n"; + exit(); +} + +my $infile = $ARGV[0]; +open(INFILE, "$infile") or die "Can't open $infile : $!"; + +my $granularity = $ARGV[1]; +my $xRange = $ARGV[2]; + +# strip 1-3 char extension (if any) +if ($infile =~ m/.*\.\w{1,3}/) { + ($infile) = $infile =~ m/(.*)\.\w{1,3}/; +} + +my $outfile = "$infile.dp"; +my $plotfile = "$infile.dp.gnuplot"; + +my @nrofDelivered; +my @nrofNotDelivered; +my $maxIndex = 0; + +open(PLOT, ">$plotfile") or die "Can't open plot output file $plotfile : $!"; +open(OUTFILE, ">$outfile") or die "Can't open output file $outfile : $!"; + +while () { + if (m/^#/) { + next; # skip comment lines + } + + my ($dist, $time) = m/^([\d\.-]+) ([\d\.-]+)/; + die "invalid input line $_" unless defined $dist; + + my $index = int($dist / $granularity); # map distance values to table indexes + + if ($time == -1) { + $nrofNotDelivered[$index] = 0 unless defined $nrofNotDelivered[$index]; + $nrofNotDelivered[$index]++; + } + else { + $nrofDelivered[$index] = 0 unless defined $nrofDelivered[$index]; + $nrofDelivered[$index]++; + } + + if ($index > $maxIndex) { + $maxIndex = $index; + } +} + +for (my $i=0; $i <= $maxIndex; $i++) { + my $del = $nrofDelivered[$i]; + my $nDel = $nrofNotDelivered[$i]; + my $delProb; + + if (not defined($del) and not defined($nDel)) { + next; # skip distance slots that don't have any data + } + elsif (not defined($del) or $del == 0) { + $delProb = 0; # nothing delivered + } + elsif (not defined($nDel) or $nDel == 0) { + $delProb = 1; # everything delivered + } + else { + $delProb = $del / ($del + $nDel); + } + + my $dist = $granularity * ($i+1); + + print OUTFILE "$dist $delProb\n"; +} + + +print PLOT "set xlabel \"distance\"\n"; +print PLOT "set ylabel \"delivery probability\"\n"; +print PLOT "set yrange[0:1]\n"; + +if (defined $xRange) { + print PLOT "set xrange[0:$xRange]\n"; +} + +print PLOT "set terminal emf\n"; +print PLOT "plot '$outfile'\n"; + +close(INFILE); +close(OUTFILE); +close(PLOT); + +system("gnuplot $plotfile > $outfile.emf") == 0 or die "Error running gnuplot: $?"; diff --git a/toolkit/dieselnetConverter.pl b/toolkit/dieselnetConverter.pl new file mode 100644 index 000000000..2d005c525 --- /dev/null +++ b/toolkit/dieselnetConverter.pl @@ -0,0 +1,126 @@ +#! /usr/local/bin/perl + +# UMass Dieselnet -> the ONE trace converter +# Suitable (at least) for "DieselNet Fall 2007" from +# http://traces.cs.umass.edu/index.php/Network/Network + +package Toolkit; +use strict; +use warnings; +use FileHandle; +use Getopt::Long; + +my $usage = ' +usage: -out [-help] [-first ] + +'; + +my ($help, $outFileName, $first); + +GetOptions("out=s"=>\$outFileName, "first=i"=>\$first, "help|?!" => \$help); + +$first = -1 unless defined $first; # no adjustment by default + +if (not $help and (not $outFileName or not @ARGV)) { + print "Missing required parameter(s)\n"; + print $usage; + exit(); +} + +if ($help) { + print 'Dieselnet trace converter.'; + print "\n$usage"; + print ' +options: +out Name of the output file + +first Time stamp for the first connection event. Adjusts all timestamps so + that the first event happens at this time (by N seconds from the start + of the simulation). By default, the times are not adjusted at all. +'; + exit(); +} + +# Input example: +# PVTA_3201 PVTA_3117 0:16:14 235560.0 584.0 42.38768 -72.52352 + +# Output example: +# 974 CONN 12 7 up +# 1558 CONN 12 7 down + +my $inputFile = shift @ARGV; +my $inFh = new FileHandle; +my $outFh = new FileHandle; +$inFh->open("<$inputFile") or die "Can't open input file $inputFile"; +$outFh->open(">$outFileName") or die "Can't create outputfile $outFileName"; + +print $outFh "# Connection trace file for the ONE. Converted from $inputFile \n"; + +my @lines = <$inFh>; # read whole file to array +my @output; +my $nextNodeId = 0; +my ($nodeId1, $nodeId2, %nodeIds); + +foreach (@lines) { + if (m/^\s$/) { + next; # skip empty lines + } + + my ($node1, $node2, $h, $m, $s, $duration) = + m/(\w+) (\w+) (\d+):(\d+):(\d+) [\d\.E]+ (\d+\.\d+)/; + die "Invalid input line: $_" unless ($node1 and $node2); + my $time = $h * 3600 + $m * 60 + $s; + + # map node IDs consistently to network addresses + if (exists $nodeIds{$node1}) { + $nodeId1 = $nodeIds{$node1}; + } + else { + $nodeId1 = $nextNodeId; + $nodeIds{$node1} = $nextNodeId; + $nextNodeId++; + } + if (exists $nodeIds{$node2}) { + $nodeId2 = $nodeIds{$node2}; + } + else { + $nodeId2 = $nextNodeId; + $nodeIds{$node2} = $nextNodeId; + $nextNodeId++; + } + + my $conEndTime = $time + $duration; + push(@output, "$time CONN $nodeId1 $nodeId2 up"); + push(@output, "$conEndTime CONN $nodeId1 $nodeId2 down"); +} + +# sort result by time stamp +@output = sort +{ + my ($t1) = $a =~ m/^(\d+)/; + my ($t2) = $b =~ m/^(\d+)/; + $t1 <=> $t2; +} @output; + +# adjust time stamps (if requested with cmd line option) +if ($first != -1) { + my ($firstTime) = $output[0] =~ m/^(\d+)/; + my $diff = $firstTime - $first; + print "Adjusting timestamps by $diff seconds\n"; + foreach (@output) { + my ($ts) = m/^(\d+)/; + my $newTime = $ts - $diff; + s/$ts/$newTime/; + } +} + +# print all the result lines to output file +print $outFh join("\n", @output); + +print "Node name to network ID mapping:\n"; +while (my ($k,$v) = each %nodeIds ) { + print "$k => $v\n"; +} + +$outFh->close(); +$inFh->close(); \ No newline at end of file diff --git a/toolkit/dtnsim2parser.pl b/toolkit/dtnsim2parser.pl new file mode 100755 index 000000000..21f0456f6 --- /dev/null +++ b/toolkit/dtnsim2parser.pl @@ -0,0 +1,79 @@ +#! /usr/local/bin/perl + +package Toolkit; + +# dtnsim2 output parser v0.1 + +# Apply patches to dtnsim2 and run it with verbose mode 8. +# Then apply this script to dtnsim2's output and use the result +# as the external events file for simulation. + +# This version should convert all events properly at least for +# epidemic simulations. + +use strict; +use warnings; +use Common; # parseArgs and debug methods + +parseArgs("dtnsim2parser"); + +# actions that are mapped +my %commandMapping = ( + 'Sending' => 'C',# message created + 'C_MSG_SENDING' => 'S', # started transfer + 'ACCEPTED' => 'DE', # Accepted -> delivered + 'C_DOWN_SEND_ABORT' => 'A', # aborted transfer + 'REFUSED' => 'A', # Refusing -> aborting + 'DROPPED epidemic' => 'DR', + 'Removing copy of' => 'R' + ); + +# actions that are ignored at the moment +my %ignoreCommands = ('C_MSG_SENT' => 1, + 'C_MSG_DELIVERED' => 1, + 'DELIVERED_FIRST' => 1, + 'DELIVERED_NEXT' => 1 + ); + +while() { + # timestamp action msgId + my ($time, $action, $id) = m/^(\d+\.\d+): ([\w\s]+):? (MSG_\d+_D_\d+)_\(\d+\)/; + + unless ($time and $action and $id) { + debug ("Discarded: $_"); + next; + } + + my $actionCode = $commandMapping{$action}; + + die "Unknown action '" , $action,"'\n" unless $actionCode or $ignoreCommands{$action}; + next unless $actionCode; + + my $lastPart; + + if ($actionCode eq 'C') { + m/NODE_'(\w+)' => NODE_'(\w+)'\); Size: (\d+); result: (\w+)/; + die "Couldn't parse CREATE line $_ \n" unless $1 and $2 and $3; + my ($h1, $h2, $size, $result) = ($1, $2, $3, $4); + + if ($result ne "true") { + debug ("Failed create: $_"); + next; + } + + $lastPart = "$h1\t$h2\t$size"; + } + elsif ($actionCode eq 'DR' or $actionCode eq 'R') { + my ($host) = m/at (\w+)$/; + die "Couldn't parse host from $_\n" unless $host; + $lastPart = $host; + } + else { + my ($h1, $h2) = m/CONTACT_'(\w+)->(\w+)'/; + die "Couldn't parse contact from $_\n" unless $h1 and $h2; + $lastPart = "$h1\t$h2"; + } + + print OUTFILE "$time\t$actionCode\t$id\t$lastPart\n"; + +} diff --git a/toolkit/dtnsim2patches/DummyEpidemicHandler.java.diff b/toolkit/dtnsim2patches/DummyEpidemicHandler.java.diff new file mode 100644 index 000000000..ee329f376 --- /dev/null +++ b/toolkit/dtnsim2patches/DummyEpidemicHandler.java.diff @@ -0,0 +1,5 @@ +255c255,256 +< network.vprint("Removing copy of " + m + " - ACKed or delivered to final destination."); +--- +> network.vprint("Removing copy of " + m + " at " + this.parent.getName()); +> // ACKed or delivered to final destination. diff --git a/toolkit/dtnsim2patches/EpidemicKnowledgeHandler.java.diff b/toolkit/dtnsim2patches/EpidemicKnowledgeHandler.java.diff new file mode 100644 index 000000000..947c5501d --- /dev/null +++ b/toolkit/dtnsim2patches/EpidemicKnowledgeHandler.java.diff @@ -0,0 +1,10 @@ +212c212,213 +< network.vprint("Removing copy of " + m + " - ACKed or delivered to final destination."); +--- +> network.vprint("Removing copy of " + m + " at " + this.parent.getName()); +> // ACKed or delivered to final destination. +312c313,314 +< parent.getNetwork().vprint("DROPPED epidemic " + m + " to free buffer space for " + forMsg); +--- +> parent.getNetwork().vprint("DROPPED epidemic " + m + " to free buffer space for " + forMsg + +> " at " + parent.getName()); diff --git a/toolkit/dtnsim2patches/README.txt b/toolkit/dtnsim2patches/README.txt new file mode 100644 index 000000000..a5a73dabb --- /dev/null +++ b/toolkit/dtnsim2patches/README.txt @@ -0,0 +1 @@ +Patches that have to be applied to dtnsim2 sources for dtnsim2parser to work properly. diff --git a/toolkit/getAverages.pl b/toolkit/getAverages.pl new file mode 100644 index 000000000..ad8cf226c --- /dev/null +++ b/toolkit/getAverages.pl @@ -0,0 +1,100 @@ +#! /usr/bin/perl + +# Gets averages from multiple time-stamped files + +package Toolkit; +use strict; +use warnings; +use Getopt::Long; +use FileHandle; + +my $error; +my $help; + +my $usage = ' +usage: [-error] [-help] +'; + +GetOptions("error!" => \$error, "help|?!" => \$help); + +if (not $help and not @ARGV) { + print "Missing required parameter(s)\n"; + print $usage; + exit(); +} + +if ($help) { + print 'Report file value averager. Counts and prints out average for +each line over multiple files. +Expected syntax for input files: